Skip to content

Comments

Fix/agent action 500 error#731

Merged
paullizer merged 3 commits intoDevelopmentfrom
fix/agent-action-500-error
Feb 23, 2026
Merged

Fix/agent action 500 error#731
paullizer merged 3 commits intoDevelopmentfrom
fix/agent-action-500-error

Conversation

@paullizer
Copy link
Contributor

@paullizer paullizer commented Feb 23, 2026

(v0.237.049)

Bug Fixes

  • Plugin Schema Validation $ref Resolution Fix

    • Fixed HTTP 500 error when creating or saving user plugins (actions). The JSON schema validator could not resolve $ref: '#/definitions/AuthType' because the Plugin sub-schema was extracted without a RefResolver, losing access to the parent schema's definitions block.
    • Root Cause: validate_plugin() created a Draft7Validator using only schema['definitions']['Plugin'], which did not include the definitions section containing AuthType. The validate_agent() function already handled this correctly with RefResolver.from_schema(schema).
    • Solution: Added a RefResolver created from the full schema so that $ref pointers resolve correctly during validation.
    • (Ref: json_schema_validation.py, plugin.schema.json, AuthType definition, RefResolver)
  • Personal Agent Missing user_id Fix

    • Fixed issue where personal agents were saved to Cosmos DB without a user_id field, making them invisible to the user who created them.
    • Root Cause: save_personal_agent() built a cleaned_agent dict with the correct user_id, id, and metadata, but the second half of the function switched to operating on the raw agent_data parameter. The final upsert_item(body=agent_data) saved the object that never had user_id assigned.
    • Solution: Changed all agent_data references after sanitization to use cleaned_agent consistently, ensuring user_id and all other fields are included in the persisted document.
    • (Ref: functions_personal_agents.py, save_personal_agent, Cosmos DB personal agents container)
  • Global Agent Creation Blocked by global_selected_agent Check Fix

    • Fixed HTTP 400 error "There must be at least one agent matching the global_selected_agent" when adding or editing global agents.
    • Root Cause: The add and edit agent routes performed a post-save check verifying that a global agent matched the global_selected_agent setting. This check was incorrect for add operations (adding an agent can never remove the selected one) and had a side-effect bug where the agent was already persisted before the 400 error was returned.
    • Solution: Removed the post-save global_selected_agent enforcement from the add and edit routes. The delete route already correctly prevents deletion of the selected agent.
    • (Ref: route_backend_agents.py, global agent add/edit routes, global_selected_agent setting)

Copilot AI review requested due to automatic review settings February 23, 2026 22:05
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a backend 500 occurring around agent/actions configuration flows by tightening payload persistence and schema validation, and by relaxing a post-save global-selected-agent constraint.

Changes:

  • Removes post-save enforcement that required an agent matching global_selected_agent after add/edit.
  • Fixes plugin JSON schema validation by enabling $ref resolution during validation.
  • Ensures save_personal_agent() persists the sanitized cleaned_agent payload to Cosmos.

Reviewed changes

Copilot reviewed 3 out of 4 changed files in this pull request and generated 4 comments.

File Description
application/single_app/route_backend_agents.py Removes the post-save global_selected_agent match enforcement in add/edit agent routes.
application/single_app/json_schema_validation.py Adds a schema resolver so $ref (e.g., #/definitions/AuthType) resolves during plugin validation.
application/single_app/functions_personal_agents.py Persists the sanitized agent payload (cleaned_agent) and keeps defaults applied consistently to that object.
.gitignore Ignores additional local/temp artifacts.
Comments suppressed due to low confidence (1)

application/single_app/route_backend_agents.py:508

  • Since this PR is a bug fix, please add a short fix note under docs/explanation/fixes/ describing the root cause and validation steps (and include the current VERSION from application/single_app/config.py). This makes it much easier to track why the 500 happened and how we verified it won’t regress.
        result = save_global_agent(cleaned_agent)
        if not result:
            return jsonify({'error': 'Failed to save agent.'}), 500

        log_event("Agent added", extra={"action": "add", "agent": {k: v for k, v in cleaned_agent.items() if k != 'id'}, "user": str(get_current_user_id())})
        # --- HOT RELOAD TRIGGER ---
        setattr(builtins, "kernel_reload_needed", True)
        return jsonify({'success': True})

Comment on lines 160 to +164
# Store sensitive keys in Key Vault if enabled
agent_data = keyvault_agent_save_helper(agent_data, agent_data.get('id', ''), scope="user")
if agent_data.get('max_completion_tokens') is None:
agent_data['max_completion_tokens'] = -1
result = cosmos_personal_agents_container.upsert_item(body=agent_data)
cleaned_agent = keyvault_agent_save_helper(cleaned_agent, cleaned_agent.get('id', ''), scope="user")
if cleaned_agent.get('max_completion_tokens') is None:
cleaned_agent['max_completion_tokens'] = -1
result = cosmos_personal_agents_container.upsert_item(body=cleaned_agent)
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change fixes persistence to use the sanitized cleaned_agent, but there isn't an existing functional test that asserts save_personal_agent() actually persists sanitized fields (e.g., trimmed/normalized names) rather than the raw input. Please add a regression test under functional_tests/ that would have failed before this change and passes now, so we don't reintroduce the 500 later.

Copilot generated this review using guidance from repository custom instructions.
Comment on lines 137 to +152
# Validate required fields
required_fields = ['name', 'display_name', 'description', 'instructions']
for field in required_fields:
if field not in agent_data:
agent_data[field] = ''
if field not in cleaned_agent:
cleaned_agent[field] = ''

# Set defaults for optional fields
agent_data.setdefault('azure_openai_gpt_deployment', '')
agent_data.setdefault('azure_openai_gpt_api_version', '')
agent_data.setdefault('azure_agent_apim_gpt_deployment', '')
agent_data.setdefault('azure_agent_apim_gpt_api_version', '')
agent_data.setdefault('enable_agent_gpt_apim', False)
agent_data.setdefault('reasoning_effort', '')
agent_data.setdefault('actions_to_load', [])
agent_data.setdefault('other_settings', {})
cleaned_agent.setdefault('azure_openai_gpt_deployment', '')
cleaned_agent.setdefault('azure_openai_gpt_api_version', '')
cleaned_agent.setdefault('azure_agent_apim_gpt_deployment', '')
cleaned_agent.setdefault('azure_agent_apim_gpt_api_version', '')
cleaned_agent.setdefault('enable_agent_gpt_apim', False)
cleaned_agent.setdefault('reasoning_effort', '')
cleaned_agent.setdefault('actions_to_load', [])
cleaned_agent.setdefault('other_settings', {})

Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The required/optional field defaulting is now applied in multiple places in this function (e.g., setdefault loops earlier, then required_fields loop, then more setdefault calls). Since this code was just touched, it would be good to consolidate the defaulting into a single block to reduce the chance of future drift between the different lists.

Copilot uses AI. Check for mistakes.
if not found:
return jsonify({'error': 'There must be at least one agent matching the global_selected_agent.'}), 400


Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the post-save global_selected_agent enforcement removed, edit_agent can effectively rename an agent without updating settings['global_selected_agent']. If the edited agent is currently selected, this will leave global_selected_agent pointing at a non-existent name and can cause the runtime to silently fall back to a different agent. Consider either disallowing renames (require payload name == URL param) or, if renaming is allowed, update global_selected_agent to the new name when it matches the old one.

Suggested change
# If the edited agent is currently selected as the global agent,
# update the selection to point at the (potentially) new name.
try:
settings = get_settings()
if settings.get('global_selected_agent') == agent_name:
settings['global_selected_agent'] = cleaned_agent.get('name', agent_name)
update_settings(settings)
except Exception as settings_exc:
# Log but do not fail the edit if updating selection settings fails.
log_event(
"Edit agent succeeded but updating global_selected_agent failed",
level=logging.WARNING,
extra={
"action": "edit",
"agent_name": agent_name,
"new_agent_name": cleaned_agent.get("name"),
"error": str(settings_exc),
},
)

Copilot uses AI. Check for mistakes.
Comment on lines +46 to +48
# Use RefResolver so $ref pointers (e.g. #/definitions/AuthType) resolve against the full schema
resolver = RefResolver.from_schema(schema)
validator = Draft7Validator(schema['definitions']['Plugin'], resolver=resolver)
Copy link

Copilot AI Feb 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

RefResolver is deprecated in recent jsonschema releases, and this repo doesn't appear to pin or explicitly depend on jsonschema in application/single_app/requirements.txt. Since this code now relies on reference resolution for plugin validation, consider either (1) migrating to the newer referencing-based API supported by jsonschema 4.x, or (2) explicitly adding/pinning a compatible jsonschema version to requirements to avoid unexpected breakage on dependency upgrades.

Copilot uses AI. Check for mistakes.
@paullizer paullizer requested a review from Bionic711 February 23, 2026 22:42
@paullizer paullizer merged commit f78e8a5 into Development Feb 23, 2026
5 checks passed
@paullizer paullizer deleted the fix/agent-action-500-error branch February 23, 2026 22:45
paullizer added a commit that referenced this pull request Feb 23, 2026
* Update .gitignore

* fixed personal and global agent and action bugs

* Update release_notes.md
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant