diff --git a/specs/platform-openapi.json b/specs/platform-openapi.json index 3d1bc0d..9c4067f 100644 --- a/specs/platform-openapi.json +++ b/specs/platform-openapi.json @@ -408,6 +408,211 @@ "description": "Sandbox", "type": "string" }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, "team": { "description": "Owning team", "type": "string" @@ -527,6 +732,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -684,6 +893,10 @@ "description": "Sandbox", "type": "string" }, + "source_solution": { + "$ref": "#/components/schemas/AgentSourceSolution", + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call." + }, "team": { "description": "Owning team", "type": "string" @@ -1606,6 +1819,24 @@ ], "type": "object" }, + "AgentSourceSolution": { + "description": "Compact read-path summary of the Solution and AgentTemplate that an agent\nwas last provisioned from.\n\nReturned as an optional `source_solution` field on `GET /api/v1/agents/:id`\nwhen the agent has a `last_applied_template_config` that can be resolved\nto a parent Solution. Null for hand-built agents (no tracked template) and\nfor agents whose tracked template or parent Solution has been deleted.\n\nUnlike the `POST /agents/:id/upgrade` response, this summary does NOT\ncompute a change plan. It issues 4 DB queries for system-scoped Solutions\n(template config fetch, parent Solution fetch, current_version preload,\nchildren list) and 5 for org-scoped Solutions (adds the system-scope\ncounterpart lookup for upgrade-availability). This is fast enough for a\nsingle-agent GET but is intentionally not issued on list endpoints.\n", + "properties": { + "solution": { + "$ref": "#/components/schemas/SolutionSummary", + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version." + }, + "template": { + "$ref": "#/components/schemas/UpgradeTemplateSummary", + "description": "AgentTemplate config the agent was last provisioned from." + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, "AgentTool": { "description": "API schema for an agent tool.", "properties": { @@ -1723,6 +1954,13 @@ "action": { "type": "string" }, + "field_changes": { + "description": "Field-level diff for update entries. Populated only when action is \"update\". Each entry names the field and provides old/new values as returned by the upgrade merge.", + "items": { + "$ref": "#/components/schemas/AgentUpgradeFieldChange" + }, + "type": "array" + }, "id": { "type": "string" }, @@ -1749,6 +1987,32 @@ ], "type": "object" }, + "AgentUpgradeFieldChange": { + "description": "One field-level diff entry within an agent upgrade change.\n\nFor `:agent_base` entries, two optional annotations are included:\n\n * `baseline` — the value set by the last-applied template version\n (pinned to `last_applied_template_config_version_id`). `null` when\n no baseline is available (legacy agent, deleted version).\n\n * `locally_edited` — `true` when the agent's current value differs from\n `baseline` (the operator changed the field after the last apply, so this\n upgrade will clobber a local edit). `false` when the agent matches the\n baseline. `null` when baseline is unavailable.\n\nChild entries (tool/routine/skill/computer) never carry these annotations —\ntheir shapes keep plain `{field, old, new}`.\n", + "properties": { + "baseline": { + "description": "Value set by the last-applied template (pinned baseline). Populated only on agent_base field_changes; null when baseline is unavailable." + }, + "field": { + "description": "Name of the field that changed", + "type": "string" + }, + "locally_edited": { + "description": "True when the agent value differs from baseline (local edit will be clobbered). Populated only on agent_base field_changes; null when baseline is unavailable.", + "type": "boolean" + }, + "new": { + "description": "Incoming field value (string, atom-as-string, number, boolean, or null)" + }, + "old": { + "description": "Previous field value (string, atom-as-string, number, boolean, or null)" + } + }, + "required": [ + "field" + ], + "type": "object" + }, "AgentUpgradeResponse": { "description": "Wire shape for `POST /api/v1/agents/:agent/upgrade`.\n", "properties": { @@ -1791,6 +2055,9 @@ "mode": { "type": "string" }, + "review_fingerprint": { + "type": "string" + }, "status": { "type": "string" }, @@ -4727,6 +4994,57 @@ ], "type": "object" }, + "StorageFile": { + "description": "API schema for a storage file.", + "properties": { + "content_type": { + "description": "MIME content type", + "type": "string" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "filename": { + "description": "Original filename", + "type": "string" + }, + "id": { + "description": "File ID", + "type": "string" + }, + "image_source": { + "$ref": "#/components/schemas/ImageSource", + "description": "Image source metadata" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "sandbox": { + "description": "Sandbox", + "type": "string" + }, + "size": { + "description": "File size in bytes", + "type": "integer" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "url": { + "description": "Signed download URL", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, "Team": { "description": "API schema for a team.", "properties": { @@ -5161,6 +5479,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -5652,31 +5974,236 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - } - ] - }, - "app": { - "description": "Application", - "type": "string" - }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "app": { + "description": "Application", + "type": "string" + }, "attachments": { "description": "Entry attachments", "items": { @@ -5771,6 +6298,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -10881,6 +11412,10 @@ "description": "Safe agent email override", "type": "string" }, + "expected_review_fingerprint": { + "description": "Optional stale-review precondition. Pass the `review_fingerprint` from a dry_run response when applying the reviewed diff.", + "type": "string" + }, "identity": { "description": "Safe identity prompt override", "type": "string" @@ -10947,6 +11482,9 @@ "404": { "description": "Agent not found; Template not found" }, + "409": { + "description": "Agent template changed since review; prepare the diff again." + }, "422": { "description": "Agent has no tracked template; Template has no parent Solution; Config is not an agent template; Validation failed" } @@ -14658,6 +15196,82 @@ ] } }, + "/api/v1/files": { + "post": { + "operationId": "post_api_v1_files", + "parameters": [], + "requestBody": { + "content": { + "application/json": { + "schema": { + "properties": { + "agent": { + "description": "Agent ID — derives org_id from the agent", + "type": "string" + }, + "content_type": { + "description": "MIME type", + "type": "string" + }, + "data": { + "description": "Base64-encoded file content", + "type": "string" + }, + "filename": { + "description": "Filename", + "type": "string" + }, + "org": { + "description": "Organization ID", + "type": "string" + }, + "team": { + "description": "Owning team ID", + "type": "string" + }, + "user": { + "description": "Owning user ID", + "type": "string" + } + }, + "required": [ + "data", + "content_type", + "filename" + ], + "type": "object" + } + } + }, + "required": true + }, + "responses": { + "201": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StorageFile" + } + } + }, + "description": "Successful response" + }, + "401": { + "description": "Unauthorized" + }, + "403": { + "description": "Forbidden - app scope required" + }, + "422": { + "description": "Validation failed or invalid base64" + } + }, + "x-auth": [ + "publishable_key", + "bearer" + ] + } + }, "/api/v1/files/{file}/avatar": { "get": { "operationId": "get_api_v1_files__file_avatar", @@ -19488,66 +20102,271 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "created_at": { - "description": "Creation timestamp", - "format": "date-time", - "type": "string" - }, - "id": { - "description": "Membership ID", - "type": "string" - }, - "joined_at": { - "description": "Join timestamp", - "format": "date-time", - "type": "string" - }, - "metadata": { - "description": "Membership metadata", - "type": "object" - }, - "name": { - "description": "Member name", - "type": "string" - }, - "profile_picture": { - "description": "Profile picture", - "properties": { - "file": { - "description": "Storage file", - "type": "string" - }, - "height": { - "description": "Image height in pixels", - "type": "integer" - }, - "media": { - "description": "Media", - "type": "string" - }, - "mime_type": { - "description": "Image MIME type", - "type": "string" - }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Membership ID", + "type": "string" + }, + "joined_at": { + "description": "Join timestamp", + "format": "date-time", + "type": "string" + }, + "metadata": { + "description": "Membership metadata", + "type": "object" + }, + "name": { + "description": "Member name", + "type": "string" + }, + "profile_picture": { + "description": "Profile picture", + "properties": { + "file": { + "description": "Storage file", + "type": "string" + }, + "height": { + "description": "Image height in pixels", + "type": "integer" + }, + "media": { + "description": "Media", + "type": "string" + }, + "mime_type": { + "description": "Image MIME type", + "type": "string" + }, "refresh_url": { "description": "URL to refresh signed URL", "type": "string" @@ -19595,6 +20414,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -19846,6 +20669,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -20320,6 +21147,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -20510,76 +21341,281 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "type": "array" - }, - "role": { - "description": "User's role in the thread", - "type": "string" - }, - "sandbox": { - "description": "Sandbox identifier", - "type": "string" - }, - "settings": { - "description": "Thread settings", - "properties": { - "agent_enabled": { - "description": "Whether the agent is enabled for this thread", - "type": "boolean" - } - }, - "type": "object" - }, - "slug": { - "description": "Thread slug", - "type": "string" - }, - "sub_threads": { - "description": "Sub-threads", - "items": { - "type": "object" - }, - "type": "array" - }, - "team": { - "description": "Owning team", - "type": "string" - }, - "title": { - "description": "Thread title", - "type": "string" - }, - "ttl": { - "description": "Time-to-live in seconds", - "type": "integer" - }, - "unread_count": { - "description": "Unread message count", - "type": "integer" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "User's role in the thread", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier", + "type": "string" + }, + "settings": { + "description": "Thread settings", + "properties": { + "agent_enabled": { + "description": "Whether the agent is enabled for this thread", + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Thread slug", + "type": "string" + }, + "sub_threads": { + "description": "Sub-threads", + "items": { + "type": "object" + }, + "type": "array" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "title": { + "description": "Thread title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds", + "type": "integer" + }, + "unread_count": { + "description": "Unread message count", + "type": "integer" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" }, "user": { "description": "Owning user", @@ -21576,6 +22612,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -23129,6 +24169,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -23603,6 +24647,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -23793,80 +24841,285 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "type": "array" - }, - "role": { - "description": "User's role in the thread", - "type": "string" - }, - "sandbox": { - "description": "Sandbox identifier", - "type": "string" - }, - "settings": { - "description": "Thread settings", - "properties": { - "agent_enabled": { - "description": "Whether the agent is enabled for this thread", - "type": "boolean" - } - }, - "type": "object" - }, - "slug": { - "description": "Thread slug", - "type": "string" - }, - "sub_threads": { - "description": "Sub-threads", - "items": { - "type": "object" - }, - "type": "array" - }, - "team": { - "description": "Owning team", - "type": "string" - }, - "title": { - "description": "Thread title", - "type": "string" - }, - "ttl": { - "description": "Time-to-live in seconds", - "type": "integer" - }, - "unread_count": { - "description": "Unread message count", - "type": "integer" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "User's role in the thread", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier", + "type": "string" + }, + "settings": { + "description": "Thread settings", + "properties": { + "agent_enabled": { + "description": "Whether the agent is enabled for this thread", + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Thread slug", + "type": "string" + }, + "sub_threads": { + "description": "Sub-threads", + "items": { + "type": "object" + }, + "type": "array" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "title": { + "description": "Thread title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds", + "type": "integer" + }, + "unread_count": { + "description": "Unread message count", + "type": "integer" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" } }, "required": [ @@ -24530,81 +25783,286 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - } - ] - }, - "app": { - "description": "Application", - "type": "string" - }, - "attachments": { - "description": "Entry attachments", - "items": { - "type": "object" - }, - "type": "array" - }, - "automation_run": { - "description": "Automation run", - "type": "string" - }, - "content": { - "description": "Longer explanation (markdown)", - "type": "string" - }, - "correlation_id": { - "description": "Correlation ID for grouped entries", - "type": "string" - }, - "created_at": { - "description": "Creation timestamp", - "format": "date-time", - "type": "string" - }, - "id": { - "description": "Entry ID (afe_...)", - "type": "string" - }, - "kind": { - "description": "Entry kind", - "type": "string" - }, - "level": { - "description": "Severity level", - "type": "string" - }, - "metadata": { - "description": "Entry metadata", - "type": "object" - }, - "org": { - "description": "Organization", - "type": "string" - }, - "routine_run": { - "description": "Routine run", - "type": "string" - }, - "sandbox": { - "description": "Sandbox identifier", + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + } + ] + }, + "app": { + "description": "Application", + "type": "string" + }, + "attachments": { + "description": "Entry attachments", + "items": { + "type": "object" + }, + "type": "array" + }, + "automation_run": { + "description": "Automation run", + "type": "string" + }, + "content": { + "description": "Longer explanation (markdown)", + "type": "string" + }, + "correlation_id": { + "description": "Correlation ID for grouped entries", + "type": "string" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "id": { + "description": "Entry ID (afe_...)", + "type": "string" + }, + "kind": { + "description": "Entry kind", + "type": "string" + }, + "level": { + "description": "Severity level", + "type": "string" + }, + "metadata": { + "description": "Entry metadata", + "type": "object" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "routine_run": { + "description": "Routine run", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier", "type": "string" }, "session_record": { @@ -24649,6 +26107,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -25100,57 +26562,262 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "before_cursor": { - "description": "Cursor for paging earlier messages (nil when at the start of history)", - "type": "string" - }, - "is_transient": { - "description": "Whether this thread is ephemeral (transient threads are not persisted long-term)", - "type": "boolean" - }, - "members": { - "description": "Active members of the chat room", - "items": { - "description": "API schema for a chat member (user or agent).", - "properties": { - "agent": { - "description": "Agent object (for agent members)", - "properties": { - "acl": { - "description": "Access control list. Contains grants array with principal_type, principal, and actions. Null when no ACL restrictions are applied.", - "properties": { - "add": { - "description": "Patch mode: grants to add or merge into existing", - "items": { - "description": "API schema for a single ACL grant entry.", - "properties": { - "actions": { - "description": "List of allowed actions (e.g. read, write)", - "items": { - "type": "string" - }, - "type": "array" - }, - "principal": { + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "before_cursor": { + "description": "Cursor for paging earlier messages (nil when at the start of history)", + "type": "string" + }, + "is_transient": { + "description": "Whether this thread is ephemeral (transient threads are not persisted long-term)", + "type": "boolean" + }, + "members": { + "description": "Active members of the chat room", + "items": { + "description": "API schema for a chat member (user or agent).", + "properties": { + "agent": { + "description": "Agent object (for agent members)", + "properties": { + "acl": { + "description": "Access control list. Contains grants array with principal_type, principal, and actions. Null when no ACL restrictions are applied.", + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into existing", + "items": { + "description": "API schema for a single ACL grant entry.", + "properties": { + "actions": { + "description": "List of allowed actions (e.g. read, write)", + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { "description": "Principal identifier (UUID for user/team/org/agent_user, role name for org_role, omit for everyone)", "type": "string" }, @@ -25281,72 +26948,281 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "membership_type": { - "description": "Membership type", - "type": "string" - }, - "type": { - "description": "Member type (user or agent)", - "type": "string" - }, - "user": { - "description": "User object (for user members)", - "properties": { - "alias": { - "description": "User alias/handle", - "type": "string" - }, - "email": { - "description": "User email address", - "type": "string" - }, - "id": { - "description": "User ID", - "type": "string" - }, - "metadata": { - "description": "User metadata", - "type": "object" - }, - "name": { - "description": "User display name. Null when the user has not set a name.", - "type": "string" - }, - "org": { - "description": "Organization", - "type": "string" - }, - "org_name": { - "description": "Organization display name. Null when the user is not in an org, or when the org association was not preloaded by the caller.", - "type": "string" - }, - "org_role": { - "description": "User's role within their org: \"admin\", \"member\", or \"viewer\". Null when the user is not in an org. Used by clients to gate org-admin UI surfaces.", - "type": "string" - }, - "sandbox": { - "description": "Sandbox", - "type": "string" - } + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "membership_type": { + "description": "Membership type", + "type": "string" + }, + "type": { + "description": "Member type (user or agent)", + "type": "string" + }, + "user": { + "description": "User object (for user members)", + "properties": { + "alias": { + "description": "User alias/handle", + "type": "string" + }, + "email": { + "description": "User email address", + "type": "string" + }, + "id": { + "description": "User ID", + "type": "string" + }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, + "metadata": { + "description": "User metadata", + "type": "object" + }, + "name": { + "description": "User display name. Null when the user has not set a name.", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "org_name": { + "description": "Organization display name. Null when the user is not in an org, or when the org association was not preloaded by the caller.", + "type": "string" + }, + "org_role": { + "description": "User's role within their org: \"admin\", \"member\", or \"viewer\". Null when the user is not in an org. Used by clients to gate org-admin UI surfaces.", + "type": "string" + }, + "sandbox": { + "description": "Sandbox", + "type": "string" + } }, "required": [ "id" @@ -25915,6 +27791,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -26389,6 +28269,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -26579,62 +28463,267 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "type": "array" - }, - "role": { - "description": "User's role in the thread", - "type": "string" - }, - "sandbox": { - "description": "Sandbox identifier", - "type": "string" - }, - "settings": { - "description": "Thread settings", - "properties": { - "agent_enabled": { - "description": "Whether the agent is enabled for this thread", - "type": "boolean" - } - }, - "type": "object" - }, - "slug": { - "description": "Thread slug", - "type": "string" - }, - "sub_threads": { - "description": "Sub-threads", - "items": { - "type": "object" - }, - "type": "array" - }, - "team": { - "description": "Owning team", - "type": "string" - }, - "title": { - "description": "Thread title", + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "User's role in the thread", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier", + "type": "string" + }, + "settings": { + "description": "Thread settings", + "properties": { + "agent_enabled": { + "description": "Whether the agent is enabled for this thread", + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Thread slug", + "type": "string" + }, + "sub_threads": { + "description": "Sub-threads", + "items": { + "type": "object" + }, + "type": "array" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "title": { + "description": "Thread title", "type": "string" }, "ttl": { @@ -26840,6 +28929,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -27314,6 +29407,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -27504,74 +29601,279 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "type": "array" - }, - "role": { - "description": "User's role in the thread", - "type": "string" - }, - "sandbox": { - "description": "Sandbox identifier", - "type": "string" - }, - "settings": { - "description": "Thread settings", - "properties": { - "agent_enabled": { - "description": "Whether the agent is enabled for this thread", - "type": "boolean" - } - }, - "type": "object" - }, - "slug": { - "description": "Thread slug", - "type": "string" - }, - "sub_threads": { - "description": "Sub-threads", - "items": { - "type": "object" - }, - "type": "array" - }, - "team": { - "description": "Owning team", - "type": "string" - }, - "title": { - "description": "Thread title", - "type": "string" - }, - "ttl": { - "description": "Time-to-live in seconds", - "type": "integer" - }, - "unread_count": { - "description": "Unread message count", - "type": "integer" - }, - "updated_at": { - "description": "Last update timestamp", + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "type": "array" + }, + "role": { + "description": "User's role in the thread", + "type": "string" + }, + "sandbox": { + "description": "Sandbox identifier", + "type": "string" + }, + "settings": { + "description": "Thread settings", + "properties": { + "agent_enabled": { + "description": "Whether the agent is enabled for this thread", + "type": "boolean" + } + }, + "type": "object" + }, + "slug": { + "description": "Thread slug", + "type": "string" + }, + "sub_threads": { + "description": "Sub-threads", + "items": { + "type": "object" + }, + "type": "array" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "title": { + "description": "Thread title", + "type": "string" + }, + "ttl": { + "description": "Time-to-live in seconds", + "type": "integer" + }, + "unread_count": { + "description": "Unread message count", + "type": "integer" + }, + "updated_at": { + "description": "Last update timestamp", "format": "date-time", "type": "string" }, @@ -28195,61 +30497,266 @@ "description": "Sandbox", "type": "string" }, - "team": { - "description": "Owning team", - "type": "string" - }, - "updated_at": { - "description": "Last update timestamp", - "format": "date-time", - "type": "string" - }, - "user": { - "description": "Owning user", - "type": "string" - } - }, - "required": [ - "id" - ], - "type": "object" - }, - "before_cursor": { - "description": "Cursor for paging earlier messages (nil when at the start of history)", - "type": "string" - }, - "is_transient": { - "description": "Whether this thread is ephemeral (transient threads are not persisted long-term)", - "type": "boolean" - }, - "members": { - "description": "Active members of the chat room", - "items": { - "description": "API schema for a chat member (user or agent).", - "properties": { - "agent": { - "description": "Agent object (for agent members)", - "properties": { - "acl": { - "description": "Access control list. Contains grants array with principal_type, principal, and actions. Null when no ACL restrictions are applied.", - "properties": { - "add": { - "description": "Patch mode: grants to add or merge into existing", - "items": { - "description": "API schema for a single ACL grant entry.", - "properties": { - "actions": { - "description": "List of allowed actions (e.g. read, write)", - "items": { - "type": "string" - }, - "type": "array" - }, - "principal": { - "description": "Principal identifier (UUID for user/team/org/agent_user, role name for org_role, omit for everyone)", - "type": "string" - }, - "principal_type": { + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, + "team": { + "description": "Owning team", + "type": "string" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "user": { + "description": "Owning user", + "type": "string" + } + }, + "required": [ + "id" + ], + "type": "object" + }, + "before_cursor": { + "description": "Cursor for paging earlier messages (nil when at the start of history)", + "type": "string" + }, + "is_transient": { + "description": "Whether this thread is ephemeral (transient threads are not persisted long-term)", + "type": "boolean" + }, + "members": { + "description": "Active members of the chat room", + "items": { + "description": "API schema for a chat member (user or agent).", + "properties": { + "agent": { + "description": "Agent object (for agent members)", + "properties": { + "acl": { + "description": "Access control list. Contains grants array with principal_type, principal, and actions. Null when no ACL restrictions are applied.", + "properties": { + "add": { + "description": "Patch mode: grants to add or merge into existing", + "items": { + "description": "API schema for a single ACL grant entry.", + "properties": { + "actions": { + "description": "List of allowed actions (e.g. read, write)", + "items": { + "type": "string" + }, + "type": "array" + }, + "principal": { + "description": "Principal identifier (UUID for user/team/org/agent_user, role name for org_role, omit for everyone)", + "type": "string" + }, + "principal_type": { "description": "Principal type: user, team, org, org_role, agent, or everyone", "type": "string" } @@ -28283,99 +30790,304 @@ "type": "string" } }, - "required": [ - "principal_type", - "actions" - ], - "type": "object" + "required": [ + "principal_type", + "actions" + ], + "type": "object" + }, + "type": "array" + }, + "remove": { + "description": "Patch mode: principals to remove from existing", + "items": { + "description": "API schema for identifying a principal to remove from an ACL.", + "properties": { + "principal": { + "description": "Principal identifier to remove (omit for everyone)", + "type": "string" + }, + "principal_type": { + "description": "Principal type to remove", + "type": "string" + } + }, + "required": [ + "principal_type" + ], + "type": "object" + }, + "type": "array" + } + }, + "type": "object" + }, + "app": { + "description": "Application", + "type": "string" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "default_model": { + "description": "Default AI model", + "type": "string" + }, + "email": { + "description": "Agent email", + "type": "string" + }, + "id": { + "description": "Agent ID (agi_...)", + "type": "string" + }, + "identity": { + "description": "Identity prompt", + "type": "string" + }, + "last_applied_template_config": { + "description": "Config id of the AgentTemplate this agent was last provisioned/updated from", + "type": "string" + }, + "lookup_key": { + "description": "Unique lookup key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary metadata", + "type": "object" + }, + "name": { + "description": "Agent name", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "org_name": { + "description": "Organization display name. Null when the agent is not in an org, or when the org association was not preloaded by the caller.", + "type": "string" + }, + "originator": { + "description": "Free-form source or author of the agent", + "type": "string" + }, + "phone_number": { + "description": "Agent phone number", + "type": "string" + }, + "sandbox": { + "description": "Sandbox", + "type": "string" + }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } }, - "type": "array" + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" }, - "remove": { - "description": "Patch mode: principals to remove from existing", - "items": { - "description": "API schema for identifying a principal to remove from an ACL.", - "properties": { - "principal": { - "description": "Principal identifier to remove (omit for everyone)", - "type": "string" - }, - "principal_type": { - "description": "Principal type to remove", - "type": "string" - } + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" }, - "required": [ - "principal_type" - ], - "type": "object" + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } }, - "type": "array" + "required": [ + "id", + "kind" + ], + "type": "object" } }, + "required": [ + "solution", + "template" + ], "type": "object" }, - "app": { - "description": "Application", - "type": "string" - }, - "created_at": { - "description": "Creation timestamp", - "format": "date-time", - "type": "string" - }, - "default_model": { - "description": "Default AI model", - "type": "string" - }, - "email": { - "description": "Agent email", - "type": "string" - }, - "id": { - "description": "Agent ID (agi_...)", - "type": "string" - }, - "identity": { - "description": "Identity prompt", - "type": "string" - }, - "last_applied_template_config": { - "description": "Config id of the AgentTemplate this agent was last provisioned/updated from", - "type": "string" - }, - "lookup_key": { - "description": "Unique lookup key", - "type": "string" - }, - "metadata": { - "description": "Arbitrary metadata", - "type": "object" - }, - "name": { - "description": "Agent name", - "type": "string" - }, - "org": { - "description": "Organization", - "type": "string" - }, - "org_name": { - "description": "Organization display name. Null when the agent is not in an org, or when the org association was not preloaded by the caller.", - "type": "string" - }, - "originator": { - "description": "Free-form source or author of the agent", - "type": "string" - }, - "phone_number": { - "description": "Agent phone number", - "type": "string" - }, - "sandbox": { - "description": "Sandbox", - "type": "string" - }, "team": { "description": "Owning team", "type": "string" @@ -28418,6 +31130,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -29010,6 +31726,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -29484,6 +32204,10 @@ "description": "User ID", "type": "string" }, + "is_system_user": { + "description": "Whether this user is a system user", + "type": "boolean" + }, "metadata": { "description": "User metadata", "type": "object" @@ -29674,6 +32398,211 @@ "description": "Sandbox", "type": "string" }, + "source_solution": { + "description": "Source Solution and AgentTemplate summary for agents provisioned from a Solution. Null for hand-built agents and agents whose tracked template or parent Solution has been deleted. Only populated on single-agent GET responses (from/3 with :show), never on list endpoints. Includes upgrade_available, latest_version, and latest_solution to support rendering an upgrade-available badge without a separate dry-run call.", + "properties": { + "solution": { + "description": "Source Solution summary including upgrade_available, latest_version, and latest_solution when the agent's org-scoped Solution is behind the system-scope version.", + "properties": { + "category_keys": { + "description": "SolutionCategory keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "created_at": { + "description": "Creation timestamp", + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Short tagline / summary (from Solution body)", + "type": "string" + }, + "id": { + "description": "Solution config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Always \"Solution\"", + "type": "string" + }, + "latest_solution": { + "description": "When `upgrade_available` is true, the system-scope Solution config ID that should be used as the upgrade source. Null otherwise.", + "type": "string" + }, + "latest_version": { + "description": "When `upgrade_available` is true, the higher system-scope `solution_version` available to upgrade to. Null otherwise.", + "type": "string" + }, + "lookup_key": { + "description": "Stored lookup_key", + "type": "string" + }, + "metadata": { + "description": "Arbitrary Solution metadata (e.g. category)", + "type": "object" + }, + "name": { + "description": "Display name (from Solution body)", + "type": "string" + }, + "org": { + "description": "Organization", + "type": "string" + }, + "owners": { + "description": "Owner scopes this Solution appears under. Members: `\"system\"` (app-level system scope) and/or `\"org\"` (viewer's org scope).", + "items": { + "type": "string" + }, + "type": "array" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded. Null when the Solution has no README. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "solution_id": { + "description": "Stable Solution UUID (from Solution body)", + "type": "string" + }, + "solution_version": { + "description": "Solution semver (from Solution body)", + "type": "string" + }, + "tag_keys": { + "description": "SolutionTag keys from the Solution body", + "items": { + "type": "string" + }, + "type": "array" + }, + "template_kind": { + "description": "Wrapped template kind — `\"AgentTemplate\"`, `\"AutomationTemplate\"`, `\"AgentRoutineTemplate\"`, `\"AgentToolTemplate\"`, `\"AgentComputerTemplate\"`, or `\"SolutionTemplateRef\"` for ref-mode bundles.", + "type": "string" + }, + "templates": { + "description": "Template configs bundled by this Solution, in declaration order — the first entry is the deployable template the Solution wraps; the rest are sibling templates the wrapped template references.", + "items": { + "description": "Template row nested under a `SolutionSummary`.\n\nImported Solutions persist each wrapped/bundled template as a Config\nchild of the Solution. This schema exposes that child identity so\nclients can display and group Solutions at template granularity.\n", + "properties": { + "description": { + "description": "Short prose blurb from the template body's `description:` field. Optional — null when the body doesn't set one. Used as the card subhead in the Library carousel.", + "type": "string" + }, + "display_name": { + "description": "Human-facing label from the template body's `display_name:` field. Optional — null when the body doesn't set one. Library carousels use this for the card title, falling back to a humanized `name`.", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...). Null for inline-only templates.", + "type": "string" + }, + "kind": { + "description": "Template config kind, or `SolutionTemplateRef` / `SolutionTemplatePath` when unresolved.", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key.", + "type": "string" + }, + "name": { + "description": "Canonical name from the template body. For `AgentTemplate` this doubles as the human-facing label; for `AgentToolTemplate` it's the LLM-facing tool function identifier (snake_case); for `AgentRoutineTemplate` it's the routine identifier (kebab-case). Clients rendering carousels should prefer `display_name` and fall back to humanizing `name`.", + "type": "string" + }, + "readme_url": { + "description": "Relative path to the public README endpoint with a signed token already embedded, scoped to this template's bundled markdown asset. Null when the Solution body's `templates[].readme_path` is unset for this entry. Token expires in 1 hour — refresh via `GET /api/v1/solutions/:solution`.", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path.", + "type": "string" + } + }, + "required": [ + "kind" + ], + "type": "object" + }, + "type": "array" + }, + "updated_at": { + "description": "Last update timestamp", + "format": "date-time", + "type": "string" + }, + "upgrade_available": { + "description": "True when this Solution is installed at the viewer's org scope and the app-level system scope carries a higher `solution_version`. Always false for system-only rows.", + "type": "boolean" + }, + "virtual_path": { + "description": "Stored virtual_path (dedupe key across owners)", + "type": "string" + } + }, + "required": [ + "id", + "kind", + "templates", + "owners", + "upgrade_available" + ], + "type": "object" + }, + "template": { + "description": "AgentTemplate config the agent was last provisioned from.", + "properties": { + "created_at": { + "format": "date-time", + "type": "string" + }, + "description": { + "description": "Template description from the config body", + "type": "string" + }, + "display_name": { + "description": "Template display name from the config body", + "type": "string" + }, + "id": { + "description": "Template config ID (cfg_...)", + "type": "string" + }, + "kind": { + "description": "Template config kind", + "type": "string" + }, + "lookup_key": { + "description": "Stored template lookup_key", + "type": "string" + }, + "name": { + "description": "Template name from the config body", + "type": "string" + }, + "updated_at": { + "format": "date-time", + "type": "string" + }, + "virtual_path": { + "description": "Stored template virtual_path", + "type": "string" + } + }, + "required": [ + "id", + "kind" + ], + "type": "object" + } + }, + "required": [ + "solution", + "template" + ], + "type": "object" + }, "team": { "description": "Owning team", "type": "string" diff --git a/src/archastro/platform/types/common.py b/src/archastro/platform/types/common.py index c2845b4..c6994be 100644 --- a/src/archastro/platform/types/common.py +++ b/src/archastro/platform/types/common.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: 2ff0288f177d +# Content hash: 2b0ec0cf1c54 from datetime import datetime @@ -82,6 +82,19 @@ class Actor(BaseModel): profile_picture: ImageSource | None = None # Profile picture +# Compact Config row summary for templates referenced by an agent upgrade. +class UpgradeTemplateSummary(BaseModel): + created_at: datetime | None = None + description: str | None = None # Template description from the config body + display_name: str | None = None # Template display name from the config body + id: str # Template config ID (cfg_...) + kind: str # Template config kind + lookup_key: str | None = None # Stored template lookup_key + name: str | None = None # Template name from the config body + updated_at: datetime | None = None + virtual_path: str | None = None # Stored template virtual_path + + # One entry in `AgentCreateResponse.installed_configs` a slim summary # of a config the install transaction created. # `key` is the caller-supplied identifier for the input that produced @@ -131,19 +144,6 @@ class WorkerStatus(BaseModel): status: str # Worker state: queued, executing, retrying, completed, discarded, or cancelled -# Compact Config row summary for templates referenced by an agent upgrade. -class UpgradeTemplateSummary(BaseModel): - created_at: datetime | None = None - description: str | None = None # Template description from the config body - display_name: str | None = None # Template display name from the config body - id: str # Template config ID (cfg_...) - kind: str # Template config kind - lookup_key: str | None = None # Stored template lookup_key - name: str | None = None # Template name from the config body - updated_at: datetime | None = None - virtual_path: str | None = None # Stored template virtual_path - - # API schema for a media variant. class MediaVariant(BaseModel): content_type: str | None = None # File content type @@ -584,6 +584,20 @@ class RoutinePreset(BaseModel): unique: bool +# API schema for a storage file. +class StorageFile(BaseModel): + content_type: str | None = None # MIME content type + created_at: datetime | None = None # Creation timestamp + filename: str | None = None # Original filename + id: str # File ID + image_source: ImageSource | None = None # Image source metadata + org: str | None = None # Organization + sandbox: str | None = None # Sandbox + size: int | None = None # File size in bytes + updated_at: datetime | None = None # Last update timestamp + url: str | None = None # Signed download URL + + # Schema for config validation result. class ValidationResult(BaseModel): errors: list[str] | None = None # List of validation errors @@ -613,6 +627,72 @@ class WorkingMemoryEntryListResponse(BaseModel): total_pages: int | None = None # Total number of pages +# Template row nested under a `SolutionSummary`. +# Imported Solutions persist each wrapped/bundled template as a Config +# child of the Solution. This schema exposes that child identity so +# clients can display and group Solutions at template granularity. +class SolutionTemplateSummary(BaseModel): + description: str | None = None + display_name: str | None = None + id: str | None = None # Template config ID (cfg_...). Null for inline-only templates. + kind: str + lookup_key: str | None = None # Stored template lookup_key. + name: str | None = None + readme_url: str | None = None + virtual_path: str | None = None # Stored template virtual_path. + + +# Catalog row for `GET /api/v1/solutions`. One entry per imported +# Solution config the ID + storage location + vanity fields lifted +# from the Solution body, plus the list of owners it appears under +# (`"system"`, `"org"`) so callers can tell where it came from. +# Multi-owner entries are produced when the same Solution (same +# `solution_id`) exists at both the app-level system scope and the +# viewer's org scope. The list endpoint dedupes by `solution_id` and +# merges the owners list. When the system-scope row's version is +# higher than the org-scope row's, `upgrade_available` is `true` and +# `latest_version` carries the system version. +class SolutionSummary(BaseModel): + category_keys: list[str] | None = None # SolutionCategory keys from the Solution body + created_at: datetime | None = None # Creation timestamp + description: str | None = None # Short tagline / summary (from Solution body) + id: str # Solution config ID (cfg_...) + kind: str # Always "Solution" + latest_solution: str | None = None + latest_version: str | None = None + lookup_key: str | None = None # Stored lookup_key + metadata: dict[str, object] | None = None # Arbitrary Solution metadata (e.g. category) + name: str | None = None # Display name (from Solution body) + org: str | None = None # Organization + owners: list[str] + readme_url: str | None = None + solution_id: str | None = None # Stable Solution UUID (from Solution body) + solution_version: str | None = None # Solution semver (from Solution body) + tag_keys: list[str] | None = None # SolutionTag keys from the Solution body + template_kind: str | None = None + templates: list[SolutionTemplateSummary] + updated_at: datetime | None = None # Last update timestamp + upgrade_available: bool + virtual_path: str | None = None # Stored virtual_path (dedupe key across owners) + + +# Compact read-path summary of the Solution and AgentTemplate that an agent +# was last provisioned from. +# Returned as an optional `source_solution` field on `GET /api/v1/agents/:id` +# when the agent has a `last_applied_template_config` that can be resolved +# to a parent Solution. Null for hand-built agents (no tracked template) and +# for agents whose tracked template or parent Solution has been deleted. +# Unlike the `POST /agents/:id/upgrade` response, this summary does NOT +# compute a change plan. It issues 4 DB queries for system-scoped Solutions +# (template config fetch, parent Solution fetch, current_version preload, +# children list) and 5 for org-scoped Solutions (adds the system-scope +# counterpart lookup for upgrade-availability). This is fast enough for a +# single-agent GET but is intentionally not issued on list endpoints. +class AgentSourceSolution(BaseModel): + solution: SolutionSummary + template: UpgradeTemplateSummary # AgentTemplate config the agent was last provisioned from. + + # API schema for an agent. class Agent(BaseModel): acl: Acl | None = None @@ -631,6 +711,7 @@ class Agent(BaseModel): originator: str | None = None # Free-form source or author of the agent phone_number: str | None = None # Agent phone number sandbox: str | None = None # Sandbox + source_solution: AgentSourceSolution | None = None team: str | None = None # Owning team updated_at: datetime | None = None # Last update timestamp user: str | None = None # Owning user @@ -892,9 +973,29 @@ class AgentToolListResponse(BaseModel): data: list[AgentTool] # List of agent tools +# One field-level diff entry within an agent upgrade change. +# For `:agent_base` entries, two optional annotations are included: +# * `baseline` the value set by the last-applied template version +# (pinned to `last_applied_template_config_version_id`). `null` when +# no baseline is available (legacy agent, deleted version). +# * `locally_edited` `true` when the agent's current value differs from +# `baseline` (the operator changed the field after the last apply, so this +# upgrade will clobber a local edit). `false` when the agent matches the +# baseline. `null` when baseline is unavailable. +# Child entries (tool/routine/skill/computer) never carry these annotations +# their shapes keep plain `{field, old, new}`. +class AgentUpgradeFieldChange(BaseModel): + baseline: object | None = None + field: str # Name of the field that changed + locally_edited: bool | None = None + new: object | None = None + old: object | None = None + + # One child-resource change produced by an agent upgrade. class AgentUpgradeChange(BaseModel): action: str + field_changes: list[AgentUpgradeFieldChange] | None = None id: str | None = None key: str | None = None name: str | None = None @@ -916,59 +1017,11 @@ class AgentUpgradeResult(BaseModel): changes: list[AgentUpgradeChange] dry_run: bool mode: str + review_fingerprint: str | None = None status: str summary: AgentUpgradeSummary -# Template row nested under a `SolutionSummary`. -# Imported Solutions persist each wrapped/bundled template as a Config -# child of the Solution. This schema exposes that child identity so -# clients can display and group Solutions at template granularity. -class SolutionTemplateSummary(BaseModel): - description: str | None = None - display_name: str | None = None - id: str | None = None # Template config ID (cfg_...). Null for inline-only templates. - kind: str - lookup_key: str | None = None # Stored template lookup_key. - name: str | None = None - readme_url: str | None = None - virtual_path: str | None = None # Stored template virtual_path. - - -# Catalog row for `GET /api/v1/solutions`. One entry per imported -# Solution config the ID + storage location + vanity fields lifted -# from the Solution body, plus the list of owners it appears under -# (`"system"`, `"org"`) so callers can tell where it came from. -# Multi-owner entries are produced when the same Solution (same -# `solution_id`) exists at both the app-level system scope and the -# viewer's org scope. The list endpoint dedupes by `solution_id` and -# merges the owners list. When the system-scope row's version is -# higher than the org-scope row's, `upgrade_available` is `true` and -# `latest_version` carries the system version. -class SolutionSummary(BaseModel): - category_keys: list[str] | None = None # SolutionCategory keys from the Solution body - created_at: datetime | None = None # Creation timestamp - description: str | None = None # Short tagline / summary (from Solution body) - id: str # Solution config ID (cfg_...) - kind: str # Always "Solution" - latest_solution: str | None = None - latest_version: str | None = None - lookup_key: str | None = None # Stored lookup_key - metadata: dict[str, object] | None = None # Arbitrary Solution metadata (e.g. category) - name: str | None = None # Display name (from Solution body) - org: str | None = None # Organization - owners: list[str] - readme_url: str | None = None - solution_id: str | None = None # Stable Solution UUID (from Solution body) - solution_version: str | None = None # Solution semver (from Solution body) - tag_keys: list[str] | None = None # SolutionTag keys from the Solution body - template_kind: str | None = None - templates: list[SolutionTemplateSummary] - updated_at: datetime | None = None # Last update timestamp - upgrade_available: bool - virtual_path: str | None = None # Stored virtual_path (dedupe key across owners) - - # Wire shape for `POST /api/v1/agents/:agent/upgrade`. class AgentUpgradeResponse(BaseModel): agent: Agent | None = None # Updated agent. Null for dry-run responses. diff --git a/src/archastro/platform/types/users.py b/src/archastro/platform/types/users.py index 9e1f95d..43b3f98 100644 --- a/src/archastro/platform/types/users.py +++ b/src/archastro/platform/types/users.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: d05037052403 +# Content hash: c5464bec4976 from datetime import datetime @@ -14,6 +14,7 @@ class User(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization diff --git a/src/archastro/platform/v1/resources/agents.py b/src/archastro/platform/v1/resources/agents.py index f7b21c2..8db1f79 100644 --- a/src/archastro/platform/v1/resources/agents.py +++ b/src/archastro/platform/v1/resources/agents.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: 36cd4542c0d3 +# Content hash: 762a37915e73 from __future__ import annotations @@ -326,6 +326,7 @@ class AgentThreadsInput(TypedDict, total=False): class AgentUpgradeInput(TypedDict, total=False): dry_run: bool | None # Return the upgrade diff without writing changes email: str | None # Safe agent email override + expected_review_fingerprint: str | None identity: str | None # Safe identity prompt override metadata: dict[str, object] | None # Safe metadata override mode: Literal["reapply", "replace"] | None diff --git a/src/archastro/platform/v1/resources/files.py b/src/archastro/platform/v1/resources/files.py index 53cac02..fe55547 100644 --- a/src/archastro/platform/v1/resources/files.py +++ b/src/archastro/platform/v1/resources/files.py @@ -1,16 +1,32 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: 91ffe2981ffb +# Content hash: 9081589966b0 from __future__ import annotations +from typing import Required, TypedDict + from ...runtime.http_client import HttpClient, SyncHttpClient +from ...types.common import StorageFile + + +class FileCreateInput(TypedDict, total=False): + agent: str | None # Agent ID — derives org_id from the agent + content_type: Required[str] # MIME type + data: Required[str] # Base64-encoded file content + filename: Required[str] # Filename + org: str | None # Organization ID + team: str | None # Owning team ID + user: str | None # Owning user ID class AsyncFileResource: def __init__(self, http: HttpClient): self._http = http + async def create(self, input: FileCreateInput) -> StorageFile: + return await self._http.request("/api/v1/files", method="POST", body=input) + async def avatar(self, file: str, token: str) -> dict[str, str]: query: dict[str, object] = {} query["token"] = token @@ -21,6 +37,9 @@ class FileResource: def __init__(self, http: SyncHttpClient): self._http = http + def create(self, input: FileCreateInput) -> StorageFile: + return self._http.request("/api/v1/files", method="POST", body=input) + def avatar(self, file: str, token: str) -> dict[str, str]: query: dict[str, object] = {} query["token"] = token diff --git a/src/archastro/platform/v1/resources/teams.py b/src/archastro/platform/v1/resources/teams.py index 310e11e..44ea384 100644 --- a/src/archastro/platform/v1/resources/teams.py +++ b/src/archastro/platform/v1/resources/teams.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: a814dd81d212 +# Content hash: 90ede59bd117 from __future__ import annotations @@ -223,6 +223,58 @@ class MemberListResponseDataItemAgentAcl(BaseModel): remove: list[MemberListResponseDataItemAgentAclRemoveItem] | None = None +class MemberListResponseDataItemAgentSourceSolutionSolutionTemplatesItem(BaseModel): + description: str | None = None + display_name: str | None = None + id: str | None = None # Template config ID (cfg_...). Null for inline-only templates. + kind: str + lookup_key: str | None = None # Stored template lookup_key. + name: str | None = None + readme_url: str | None = None + virtual_path: str | None = None # Stored template virtual_path. + + +class MemberListResponseDataItemAgentSourceSolutionSolution(BaseModel): + category_keys: list[str] | None = None # SolutionCategory keys from the Solution body + created_at: datetime | None = None # Creation timestamp + description: str | None = None # Short tagline / summary (from Solution body) + id: str # Solution config ID (cfg_...) + kind: str # Always "Solution" + latest_solution: str | None = None + latest_version: str | None = None + lookup_key: str | None = None # Stored lookup_key + metadata: dict[str, object] | None = None # Arbitrary Solution metadata (e.g. category) + name: str | None = None # Display name (from Solution body) + org: str | None = None # Organization + owners: list[str] + readme_url: str | None = None + solution_id: str | None = None # Stable Solution UUID (from Solution body) + solution_version: str | None = None # Solution semver (from Solution body) + tag_keys: list[str] | None = None # SolutionTag keys from the Solution body + template_kind: str | None = None + templates: list[MemberListResponseDataItemAgentSourceSolutionSolutionTemplatesItem] + updated_at: datetime | None = None # Last update timestamp + upgrade_available: bool + virtual_path: str | None = None # Stored virtual_path (dedupe key across owners) + + +class MemberListResponseDataItemAgentSourceSolutionTemplate(BaseModel): + created_at: datetime | None = None + description: str | None = None # Template description from the config body + display_name: str | None = None # Template display name from the config body + id: str # Template config ID (cfg_...) + kind: str # Template config kind + lookup_key: str | None = None # Stored template lookup_key + name: str | None = None # Template name from the config body + updated_at: datetime | None = None + virtual_path: str | None = None # Stored template virtual_path + + +class MemberListResponseDataItemAgentSourceSolution(BaseModel): + solution: MemberListResponseDataItemAgentSourceSolutionSolution + template: MemberListResponseDataItemAgentSourceSolutionTemplate + + class MemberListResponseDataItemAgent(BaseModel): acl: MemberListResponseDataItemAgentAcl | None = None app: str | None = None # Application @@ -240,6 +292,7 @@ class MemberListResponseDataItemAgent(BaseModel): originator: str | None = None # Free-form source or author of the agent phone_number: str | None = None # Agent phone number sandbox: str | None = None # Sandbox + source_solution: MemberListResponseDataItemAgentSourceSolution | None = None team: str | None = None # Owning team updated_at: datetime | None = None # Last update timestamp user: str | None = None # Owning user @@ -259,6 +312,7 @@ class MemberListResponseDataItemUser(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization @@ -290,6 +344,7 @@ class TeamThreadListResponseDataItemCreator(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization @@ -414,6 +469,7 @@ class TeamThreadListResponseDataItemParticipantsItem(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization @@ -445,6 +501,62 @@ class TeamThreadListResponseDataItemParticipatingAgentsItemAcl(BaseModel): remove: list[TeamThreadListResponseDataItemParticipatingAgentsItemAclRemoveItem] | None = None +class TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItem( + BaseModel +): + description: str | None = None + display_name: str | None = None + id: str | None = None # Template config ID (cfg_...). Null for inline-only templates. + kind: str + lookup_key: str | None = None # Stored template lookup_key. + name: str | None = None + readme_url: str | None = None + virtual_path: str | None = None # Stored template virtual_path. + + +class TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolution(BaseModel): + category_keys: list[str] | None = None # SolutionCategory keys from the Solution body + created_at: datetime | None = None # Creation timestamp + description: str | None = None # Short tagline / summary (from Solution body) + id: str # Solution config ID (cfg_...) + kind: str # Always "Solution" + latest_solution: str | None = None + latest_version: str | None = None + lookup_key: str | None = None # Stored lookup_key + metadata: dict[str, object] | None = None # Arbitrary Solution metadata (e.g. category) + name: str | None = None # Display name (from Solution body) + org: str | None = None # Organization + owners: list[str] + readme_url: str | None = None + solution_id: str | None = None # Stable Solution UUID (from Solution body) + solution_version: str | None = None # Solution semver (from Solution body) + tag_keys: list[str] | None = None # SolutionTag keys from the Solution body + template_kind: str | None = None + templates: list[ + TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItem + ] + updated_at: datetime | None = None # Last update timestamp + upgrade_available: bool + virtual_path: str | None = None # Stored virtual_path (dedupe key across owners) + + +class TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolutionTemplate(BaseModel): + created_at: datetime | None = None + description: str | None = None # Template description from the config body + display_name: str | None = None # Template display name from the config body + id: str # Template config ID (cfg_...) + kind: str # Template config kind + lookup_key: str | None = None # Stored template lookup_key + name: str | None = None # Template name from the config body + updated_at: datetime | None = None + virtual_path: str | None = None # Stored template virtual_path + + +class TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolution(BaseModel): + solution: TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolution + template: TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolutionTemplate + + class TeamThreadListResponseDataItemParticipatingAgentsItem(BaseModel): acl: TeamThreadListResponseDataItemParticipatingAgentsItemAcl | None = None app: str | None = None # Application @@ -462,6 +574,9 @@ class TeamThreadListResponseDataItemParticipatingAgentsItem(BaseModel): originator: str | None = None # Free-form source or author of the agent phone_number: str | None = None # Agent phone number sandbox: str | None = None # Sandbox + source_solution: TeamThreadListResponseDataItemParticipatingAgentsItemSourceSolution | None = ( + None + ) team: str | None = None # Owning team updated_at: datetime | None = None # Last update timestamp user: str | None = None # Owning user diff --git a/src/archastro/platform/v1/resources/threads.py b/src/archastro/platform/v1/resources/threads.py index 831cd35..3285e31 100644 --- a/src/archastro/platform/v1/resources/threads.py +++ b/src/archastro/platform/v1/resources/threads.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: 0dfcebd9509d +# Content hash: 8e5bcac22385 from __future__ import annotations @@ -58,6 +58,7 @@ class ThreadMemberListResponseDataItemUser(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization diff --git a/src/archastro/platform/v1/resources/users.py b/src/archastro/platform/v1/resources/users.py index 2139326..eb03ccb 100644 --- a/src/archastro/platform/v1/resources/users.py +++ b/src/archastro/platform/v1/resources/users.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: 0c44ddb99e15 +# Content hash: 9a41761cb254 from __future__ import annotations @@ -109,6 +109,7 @@ class UserThreadListResponseDataItemCreator(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization @@ -233,6 +234,7 @@ class UserThreadListResponseDataItemParticipantsItem(BaseModel): alias: str | None = None # User alias/handle email: str | None = None # User email address id: str # User ID + is_system_user: bool | None = None # Whether this user is a system user metadata: dict[str, object] | None = None # User metadata name: str | None = None # User display name. Null when the user has not set a name. org: str | None = None # Organization @@ -264,6 +266,62 @@ class UserThreadListResponseDataItemParticipatingAgentsItemAcl(BaseModel): remove: list[UserThreadListResponseDataItemParticipatingAgentsItemAclRemoveItem] | None = None +class UserThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItem( + BaseModel +): + description: str | None = None + display_name: str | None = None + id: str | None = None # Template config ID (cfg_...). Null for inline-only templates. + kind: str + lookup_key: str | None = None # Stored template lookup_key. + name: str | None = None + readme_url: str | None = None + virtual_path: str | None = None # Stored template virtual_path. + + +class UserThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolution(BaseModel): + category_keys: list[str] | None = None # SolutionCategory keys from the Solution body + created_at: datetime | None = None # Creation timestamp + description: str | None = None # Short tagline / summary (from Solution body) + id: str # Solution config ID (cfg_...) + kind: str # Always "Solution" + latest_solution: str | None = None + latest_version: str | None = None + lookup_key: str | None = None # Stored lookup_key + metadata: dict[str, object] | None = None # Arbitrary Solution metadata (e.g. category) + name: str | None = None # Display name (from Solution body) + org: str | None = None # Organization + owners: list[str] + readme_url: str | None = None + solution_id: str | None = None # Stable Solution UUID (from Solution body) + solution_version: str | None = None # Solution semver (from Solution body) + tag_keys: list[str] | None = None # SolutionTag keys from the Solution body + template_kind: str | None = None + templates: list[ + UserThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolutionTemplatesItem + ] + updated_at: datetime | None = None # Last update timestamp + upgrade_available: bool + virtual_path: str | None = None # Stored virtual_path (dedupe key across owners) + + +class UserThreadListResponseDataItemParticipatingAgentsItemSourceSolutionTemplate(BaseModel): + created_at: datetime | None = None + description: str | None = None # Template description from the config body + display_name: str | None = None # Template display name from the config body + id: str # Template config ID (cfg_...) + kind: str # Template config kind + lookup_key: str | None = None # Stored template lookup_key + name: str | None = None # Template name from the config body + updated_at: datetime | None = None + virtual_path: str | None = None # Stored template virtual_path + + +class UserThreadListResponseDataItemParticipatingAgentsItemSourceSolution(BaseModel): + solution: UserThreadListResponseDataItemParticipatingAgentsItemSourceSolutionSolution + template: UserThreadListResponseDataItemParticipatingAgentsItemSourceSolutionTemplate + + class UserThreadListResponseDataItemParticipatingAgentsItem(BaseModel): acl: UserThreadListResponseDataItemParticipatingAgentsItemAcl | None = None app: str | None = None # Application @@ -281,6 +339,9 @@ class UserThreadListResponseDataItemParticipatingAgentsItem(BaseModel): originator: str | None = None # Free-form source or author of the agent phone_number: str | None = None # Agent phone number sandbox: str | None = None # Sandbox + source_solution: UserThreadListResponseDataItemParticipatingAgentsItemSourceSolution | None = ( + None + ) team: str | None = None # Owning team updated_at: datetime | None = None # Last update timestamp user: str | None = None # Owning user diff --git a/tests/contract/v1/test_agents.py b/tests/contract/v1/test_agents.py index 719cc6a..5d49ff9 100644 --- a/tests/contract/v1/test_agents.py +++ b/tests/contract/v1/test_agents.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: eb340d907d3d +# Content hash: 4a6a66b29917 import pytest @@ -1204,6 +1204,16 @@ def test_agents_upgrade_error_404(): ec.close() +def test_agents_upgrade_error_409(): + ec = _error_client(409) + try: + with pytest.raises(ApiError) as exc_info: + ec.v1.agents.upgrade("test-value", {}) + assert exc_info.value.status == 409 + finally: + ec.close() + + def test_agents_upgrade_error_422(): ec = _error_client(422) try: @@ -1268,6 +1278,17 @@ async def test_async_agents_upgrade_error_404(): await ec.close() +@pytest.mark.asyncio +async def test_async_agents_upgrade_error_409(): + ec = _async_error_client(409) + try: + with pytest.raises(ApiError) as exc_info: + await ec.v1.agents.upgrade("test-value", {}) + assert exc_info.value.status == 409 + finally: + await ec.close() + + @pytest.mark.asyncio async def test_async_agents_upgrade_error_422(): ec = _async_error_client(422) diff --git a/tests/contract/v1/test_files.py b/tests/contract/v1/test_files.py index ea114c7..a3404b6 100644 --- a/tests/contract/v1/test_files.py +++ b/tests/contract/v1/test_files.py @@ -1,6 +1,6 @@ # Copyright (c) 2026 ArchAstro Inc. All Rights Reserved. # This file is auto-generated by @archastro/sdk-generator. Do not edit. -# Content hash: 115825f932e8 +# Content hash: 33a926166587 import pytest @@ -42,6 +42,104 @@ def _async_error_client(code: int) -> AsyncPlatformClient: ) +def test_files_create_success(): + client = _client() + try: + result = client.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert result is not None + finally: + client.close() + + +def test_files_create_error_401(): + ec = _error_client(401) + try: + with pytest.raises(ApiError) as exc_info: + ec.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert exc_info.value.status == 401 + finally: + ec.close() + + +def test_files_create_error_403(): + ec = _error_client(403) + try: + with pytest.raises(ApiError) as exc_info: + ec.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert exc_info.value.status == 403 + finally: + ec.close() + + +def test_files_create_error_422(): + ec = _error_client(422) + try: + with pytest.raises(ApiError) as exc_info: + ec.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert exc_info.value.status == 422 + finally: + ec.close() + + +@pytest.mark.asyncio +async def test_async_files_create_success(): + client = _async_client() + try: + result = await client.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert result is not None + finally: + await client.close() + + +@pytest.mark.asyncio +async def test_async_files_create_error_401(): + ec = _async_error_client(401) + try: + with pytest.raises(ApiError) as exc_info: + await ec.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert exc_info.value.status == 401 + finally: + await ec.close() + + +@pytest.mark.asyncio +async def test_async_files_create_error_403(): + ec = _async_error_client(403) + try: + with pytest.raises(ApiError) as exc_info: + await ec.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert exc_info.value.status == 403 + finally: + await ec.close() + + +@pytest.mark.asyncio +async def test_async_files_create_error_422(): + ec = _async_error_client(422) + try: + with pytest.raises(ApiError) as exc_info: + await ec.v1.files.create( + {"content_type": "test-value", "data": "test-value", "filename": "test-value"} + ) + assert exc_info.value.status == 422 + finally: + await ec.close() + + def test_files_avatar_success(): client = _client() try: