{ "components": { "schemas": { "AddCommentRequest": { "description": "Request body for `POST /sessions/{id}/comments`.", "properties": { "anchor_content": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Plain-text snapshot of the selected range, used to re-anchor the comment after file edits. `None` if not provided.", "title": "Anchor Content" }, "body": { "description": "The comment text.", "title": "Body", "type": "string" }, "end_index": { "description": "0-based absolute character offset (exclusive) within the file where the anchor range ends.", "title": "End Index", "type": "integer" }, "path": { "description": "File path relative to workspace root, e.g. `\"src/App.tsx\"`.", "title": "Path", "type": "string" }, "start_index": { "description": "0-based absolute character offset (inclusive) within the file where the anchor range begins.", "title": "Start Index", "type": "integer" } }, "required": [ "path", "body", "start_index", "end_index" ], "title": "AddCommentRequest", "type": "object" }, "AgentObject": { "description": "API representation of a registered agent.", "properties": { "builtin": { "default": false, "description": "Whether this is a server-*seeded* built-in agent (deterministic, name-derived id) as opposed to an operator/user-registered template (random id, e.g. via `omnigent server --agent`) or a session-scoped upload. The Web UI's new-session picker uses this to decide whether a same-named `omnigent run` upload may shadow the catalog entry: seeded built-ins are protected, while a user-registered template is superseded by a newer same-named upload. Always `False` for session-scoped agents.", "title": "Builtin", "type": "boolean" }, "created_at": { "description": "Unix epoch timestamp of creation.", "title": "Created At", "type": "integer" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional free-text description of the agent's purpose.", "title": "Description" }, "harness": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The agent's harness/kind, e.g. `\"codex\"`, `\"codex-native\"`, or `\"claude-native\"` for `executor.type: omnigent` agents, otherwise the executor type (`\"claude_sdk\"`, `\"agents_sdk\"`). `None` when the bundle cannot be loaded. Lets the Web UI Add Agent picker recognise an agent's kind (Codex vs Claude) without hardcoding by name slug.", "title": "Harness" }, "id": { "description": "Unique agent identifier, e.g. `\"ag_abc123\"`.", "title": "Id", "type": "string" }, "mcp_servers": { "description": "MCP servers the agent is connected to (secret fields omitted). Empty list when the spec declares no MCP servers or when the bundle cannot be loaded.", "items": { "$ref": "#/components/schemas/MCPServerSummary" }, "title": "Mcp Servers", "type": "array" }, "mcp_servers_editable": { "default": false, "description": "Whether the MCP list can be edited through the session UI. Built-in template agents are read-only; session-scoped uploaded agents are editable.", "title": "Mcp Servers Editable", "type": "boolean" }, "name": { "description": "Human-readable agent name, e.g. `\"research-agent\"`.", "title": "Name", "type": "string" }, "object": { "default": "agent", "description": "Fixed resource type, always `\"agent\"`.", "title": "Object", "type": "string" }, "policies": { "description": "Guardrails policies declared on the agent. Each entry summarises the policy name, type, and phases. Empty list when the spec declares no policies or when the bundle cannot be loaded.", "items": { "$ref": "#/components/schemas/PolicySummary" }, "title": "Policies", "type": "array" }, "skills": { "description": "Skills bundled in the agent spec (`skills//SKILL.md`). Lets the Web UI's new-session composer offer a slash-command menu before a session (and its runner) exists. Host-discovered skills are runner-owned, so they are NOT listed here \u2014 the session snapshot's `skills` field carries the merged set once a runner is bound. Empty list when the spec bundles no skills or when the bundle cannot be loaded.", "items": { "$ref": "#/components/schemas/SkillSummary" }, "title": "Skills", "type": "array" }, "terminals": { "description": "Terminal names declared in the spec's `terminals:` block, in declaration order, e.g. `[\"shell\"]`. The Web UI gates its \"new terminal\" affordance on this list (creation is only offered for agents with terminal access) and offers these names as the launchable choices. Empty list when the spec declares no terminals or when the bundle cannot be loaded.", "items": { "type": "string" }, "title": "Terminals", "type": "array" }, "updated_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Unix epoch timestamp of the last update, or `None` if never updated.", "title": "Updated At" }, "version": { "default": 1, "description": "Monotonic version counter. Starts at 1, incremented on each update.", "title": "Version", "type": "integer" } }, "required": [ "id", "name", "created_at" ], "title": "AgentObject", "type": "object" }, "Body_update_session_agent_v1_sessions__session_id__agent_put": { "properties": { "bundle": { "contentMediaType": "application/octet-stream", "title": "Bundle", "type": "string" } }, "required": [ "bundle" ], "title": "Body_update_session_agent_v1_sessions__session_id__agent_put", "type": "object" }, "Body_upload_session_file_v1_sessions__session_id__resources_files_post": { "properties": { "file": { "contentMediaType": "application/octet-stream", "title": "File", "type": "string" } }, "required": [ "file" ], "title": "Body_upload_session_file_v1_sessions__session_id__resources_files_post", "type": "object" }, "CancelledEvent": { "description": "Terminal event for a turn cancelled before completion.", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The final response object with `status=\"cancelled\"`." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.cancelled", "description": "Always `\"response.cancelled\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "CancelledEvent", "type": "object" }, "ChildSessionList": { "description": "Paginated list of child sessions; `data` is a page of `ChildSessionSummary`.", "properties": { "data": { "items": { "$ref": "#/components/schemas/ChildSessionSummary" }, "title": "Data", "type": "array" }, "first_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "First Id" }, "has_more": { "default": false, "title": "Has More", "type": "boolean" }, "last_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Id" }, "object": { "const": "list", "default": "list", "title": "Object", "type": "string" } }, "title": "ChildSessionList", "type": "object" }, "ChildSessionSummary": { "description": "Summary of a sub-agent (child) session under a parent session.\n\nPowers `GET /v1/sessions/{id}/child_sessions`. Lets the web /\nREPL debug surface enumerate sub-agent calls spawned from a\nparent session without parsing parent `function_call_output`\nJSON handles (the legacy TUI Ctrl+O path). The endpoint is the\ncanonical \"historical truth\" source; the existing transient\n`session.created` SSE event handles live incremental updates.\n\nFields are derived from the child `Conversation` plus its\nlatest `Task` (newest by `created_at`).", "properties": { "agent_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Agent id recorded on the latest task, e.g. `\"ag_abc123\"`. `None` if the child has no tasks yet (rare \u2014 `_spawn_one` creates a task atomically with the conversation).", "title": "Agent Id" }, "agent_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Agent type recorded on the latest task, e.g. `\"researcher\"`. Mirrors the `tool` prefix in `title` and is provided alongside it because the title is a denormalized string while `agent_name` is the durable per-task value.", "title": "Agent Name" }, "busy": { "default": false, "description": "`True` when the child's session loop is live. Mirrors the algorithm used by `GET /v1/sessions/{id}` to compute `status`: read the live in-memory cache first (`\"running\"`/`\"waiting\"` \u2192 busy), and fall back to the latest task's status on cache miss (`\"queued\"` / `\"in_progress\"` \u2192 busy). For NO_DBOS sessions the tasks table is not populated during active runs, so the cache consult is what keeps the rail's \"Working\" badge correct.", "title": "Busy", "type": "boolean" }, "created_at": { "description": "Unix epoch timestamp of child creation.", "title": "Created At", "type": "integer" }, "current_task_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Latest task id for the child (newest by `created_at`), e.g. `\"task_abc123\"`. `None` if no tasks exist.", "title": "Current Task Id" }, "current_task_status": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Status of the latest task, e.g. `\"completed\"`, `\"in_progress\"`, `\"failed\"`. `None` if no tasks exist.", "title": "Current Task Status" }, "id": { "description": "Child conversation/session identifier, e.g. `\"conv_child123\"`.", "title": "Id", "type": "string" }, "kind": { "default": "sub_agent", "description": "Conversation kind discriminator, always `\"sub_agent\"` for rows surfaced by this endpoint.", "title": "Kind", "type": "string" }, "labels": { "additionalProperties": { "type": "string" }, "description": "Session-scoped guardrails labels on the child conversation (mirrors `ConversationObject.labels`).", "title": "Labels", "type": "object" }, "last_message_preview": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Single-line preview of the most recent message item in the child's conversation, truncated to ~150 chars with a trailing ellipsis when longer. `None` when the child has no message items yet (rare \u2014 the spawn tool immediately commits a user message). Lets the UI render a real-time \"what's the sub-agent saying right now\" line without fetching the child's full item history.", "title": "Last Message Preview" }, "last_task_error": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "description": "Error details from the child's most recent failed run, e.g. `{\"code\": \"required_terminal_exited\", \"message\": \"...\"}`. `None` when the child has no durable failure detail. This is the typed projection of runner-owned failure labels; clients should not parse those labels directly.", "title": "Last Task Error" }, "object": { "default": "child_session", "description": "Fixed resource type, always `\"child_session\"`.", "title": "Object", "type": "string" }, "parent_session_id": { "description": "Parent conversation id (echo of the route's `session_id` path parameter), e.g. `\"conv_parent987\"`. Stable join key for clients that cache child rows across multiple parents.", "title": "Parent Session Id", "type": "string" }, "pending_elicitations_count": { "default": 0, "description": "Number of approval / input prompts the child is currently blocked on, read from the server's `omnigent.runtime.pending_elicitations` index. `> 0` means the sub-agent is parked awaiting user input \u2014 the Agents rail renders an \"awaiting input\" badge so a fanned-out sub-agent that needs attention is visible without opening its chat. Mirrors `SessionListItem.pending_elicitations_count`.", "title": "Pending Elicitations Count", "type": "integer" }, "session_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Sub-agent instance name, the suffix of `title` after the first `\":\"`, e.g. `\"auth\"`. `None` if `title` is `None` or missing a colon.", "title": "Session Name" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Sub-agent title, `\"{agent_type}:{session_name}\"` as written by `omnigent.tools.builtins.spawn._spawn_one`, e.g. `\"researcher:auth\"`. `None` only for legacy / malformed rows; the spawn path always sets it.", "title": "Title" }, "tool": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "UI-facing sub-agent label. For Omnigent-spawned children this is derived from the prefix of `title` before the first `\":\"`, e.g. `\"researcher\"`. For Codex-native children this is the Codex-assigned `agent_nickname` when available, then `agent_role`, then `\"Codex\"`. Falls back to the raw title for legacy / malformed rows; `None` only when `title` itself is `None` or empty.", "title": "Tool" }, "updated_at": { "description": "Unix epoch timestamp of the child's most recent update.", "title": "Updated At", "type": "integer" } }, "required": [ "id", "parent_session_id", "created_at", "updated_at" ], "title": "ChildSessionSummary", "type": "object" }, "ClearCodexGoalResponse": { "description": "Response body for `DELETE /v1/sessions/{id}/codex_goal`.", "properties": { "cleared": { "description": "`True` when Codex removed an existing goal; `False` when no goal was present.", "title": "Cleared", "type": "boolean" } }, "required": [ "cleared" ], "title": "ClearCodexGoalResponse", "type": "object" }, "ClientTaskCancelEvent": { "description": "Server-side request that the client cancel a tunneled tool call.\n\nEmitted by `omnigent/runtime/workflow.py` when a parent\ncancellation needs to propagate to a long-running async client\ntool. Wire shape matches `workflow.py:4258-4266`.", "properties": { "call_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Synthetic `call_id` the SDK uses to reconcile the local task; `None` when no pending tool call row exists for the task.", "title": "Call Id" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "task_id": { "description": "Identifier of the client-side task being cancelled, e.g. `\"resp_async_abc\"`.", "title": "Task Id", "type": "string" }, "type": { "const": "response.client_task.cancel", "description": "Always `\"response.client_task.cancel\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "task_id" ], "title": "ClientTaskCancelEvent", "type": "object" }, "CodexGoalObject": { "description": "Current Codex goal state for a Codex-native session.\n\nMirrors Codex app-server's `ThreadGoal` shape using Omnigent's\nsnake-case API convention. `created_at` and `updated_at` are optional\nbecause older app-server documentation examples omit them even though the\ncurrent protocol includes them.", "properties": { "created_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Unix timestamp when the goal was created, e.g. `1776272400`. `None` when not provided by Codex.", "title": "Created At" }, "objective": { "description": "Goal objective text, e.g. `\"Finish the migration and keep tests green\"`.", "title": "Objective", "type": "string" }, "status": { "description": "Raw Codex goal lifecycle status, e.g. `\"active\"`.", "title": "Status", "type": "string" }, "thread_id": { "description": "Codex app-server thread id, e.g. `\"thr_123\"`.", "title": "Thread Id", "type": "string" }, "time_used_seconds": { "description": "Wall-clock seconds spent on this goal, e.g. `60`.", "minimum": 0.0, "title": "Time Used Seconds", "type": "integer" }, "token_budget": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "description": "Optional token budget, e.g. `40000`. `None` means no explicit budget is set.", "title": "Token Budget" }, "tokens_used": { "description": "Tokens spent while pursuing this goal, e.g. `1024`.", "minimum": 0.0, "title": "Tokens Used", "type": "integer" }, "updated_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Unix timestamp when the goal was last updated, e.g. `1776272460`. `None` when not provided by Codex.", "title": "Updated At" } }, "required": [ "thread_id", "objective", "status", "tokens_used", "time_used_seconds" ], "title": "CodexGoalObject", "type": "object" }, "CodexGoalResponse": { "description": "Response body for reading or setting a Codex-native session goal.", "properties": { "goal": { "anyOf": [ { "$ref": "#/components/schemas/CodexGoalObject" }, { "type": "null" } ], "description": "Current goal state, or `None` when the session has no persisted Codex goal." } }, "required": [ "goal" ], "title": "CodexGoalResponse", "type": "object" }, "CompactionCompletedEvent": { "description": "Conversation history compaction has finished.\n\nEmitted after compaction completes \u2014 either by the server after\n`compact_conversation_now()` (explicit `/compact`), or by a\nharness that compacted its own internal context. Clients that\nrendered a \"Compacting\u2026\" spinner on\n`CompactionInProgressEvent` should upgrade it to the\npermanent \"Conversation compacted\" marker on this event.\n\nWhen emitted by a harness, `summary` and `summary_model`\nare populated so the runner can persist a compaction item for\nsession resume. When emitted by the server's explicit\n`/compact` path, those fields are `None`.", "properties": { "compacted_messages": { "anyOf": [ { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "default": null, "title": "Compacted Messages" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "summary": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Text summary of the compacted conversation, or `None` for server-side compaction (already persisted).", "title": "Summary" }, "summary_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Model used for summarization, or `None` if truncation-based or server-side.", "title": "Summary Model" }, "total_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Tiktoken estimate of the post-compaction message context size, e.g. `8421`. Used by clients to update the context-ring immediately without waiting for the next `response.completed` usage report. `None` when token counting is unavailable.", "title": "Total Tokens" }, "type": { "const": "response.compaction.completed", "description": "Always `\"response.compaction.completed\"`.", "title": "Type", "type": "string" } }, "required": [ "type" ], "title": "CompactionCompletedEvent", "type": "object" }, "CompactionData": { "description": "Data payload for a compaction summary item.\n\nStored as a conversation item of `type=\"compaction\"`.\nThe summary covers all items from the start of the\nconversation (or the previous compaction item) through\nthe item identified by `last_item_id`.", "properties": { "compacted_messages": { "anyOf": [ { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "Compacted Messages" }, "last_item_id": { "description": "The item ID (inclusive) of the last conversation item covered by this summary, e.g. `\"msg_abc123\"`. Items at positions <= this item are summarized and do not need to be loaded for prompt construction.", "title": "Last Item Id", "type": "string" }, "model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The model used to generate the summary, e.g. `\"openai/gpt-4o\"`.", "title": "Model" }, "summary": { "description": "The LLM-generated summary text covering all conversation items up through `last_item_id`, e.g. `\"User asked to analyze a dataset. Agent loaded data.csv and computed statistics.\"`.", "title": "Summary", "type": "string" }, "token_count": { "description": "Approximate token count of the summary text, for budget tracking, e.g. `342`.", "title": "Token Count", "type": "integer" }, "window_id": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Window Id" } }, "required": [ "summary", "last_item_id", "token_count" ], "title": "CompactionData", "type": "object" }, "CompactionFailedEvent": { "description": "Conversation history compaction failed.\n\nEmitted by `omnigent/server/routes/sessions.py` when\n`compact_conversation_now()` raises. Clients that rendered a\n\"Compacting\u2026\" spinner on `CompactionInProgressEvent`\nshould dismiss it without leaving a permanent marker, since the\nconversation history was not modified.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.compaction.failed", "description": "Always `\"response.compaction.failed\"`.", "title": "Type", "type": "string" } }, "required": [ "type" ], "title": "CompactionFailedEvent", "type": "object" }, "CompactionInProgressEvent": { "description": "Conversation history is being compacted.\n\nEmitted by `omnigent/runtime/compaction.py` while a\ncompaction step runs so clients can render a \"summarizing\nhistory\u2026\" indicator. Wire shape matches `compaction.py:765`.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.compaction.in_progress", "description": "Always `\"response.compaction.in_progress\"`.", "title": "Type", "type": "string" } }, "required": [ "type" ], "title": "CompactionInProgressEvent", "type": "object" }, "CompletedEvent": { "description": "Terminal event for a successfully completed turn.\n\nCarries the final\n`omnigent.server.schemas.ResponseObject`.", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The final response object with `status=\"completed\"`." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.completed", "description": "Always `\"response.completed\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "CompletedEvent", "type": "object" }, "ConversationDeleted": { "description": "Confirmation payload returned after deleting a conversation.", "properties": { "deleted": { "default": true, "description": "Always `True`.", "title": "Deleted", "type": "boolean" }, "id": { "description": "ID of the deleted conversation, e.g. `\"conv_abc123\"`.", "title": "Id", "type": "string" }, "object": { "default": "conversation.deleted", "description": "Fixed resource type, always `\"conversation.deleted\"`.", "title": "Object", "type": "string" } }, "required": [ "id" ], "title": "ConversationDeleted", "type": "object" }, "ConversationItem": { "description": "A persisted item with a store-assigned ID.", "properties": { "created_at": { "description": "Unix epoch timestamp of creation.", "title": "Created At", "type": "integer" }, "created_by": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Identity of the human actor who authored this item, or `None` for agent/tool/system items and single-user mode. Lets owner and collaborator messages be distinguished.", "title": "Created By" }, "data": { "anyOf": [ { "$ref": "#/components/schemas/MessageData" }, { "$ref": "#/components/schemas/FunctionCallData" }, { "$ref": "#/components/schemas/FunctionCallOutputData" }, { "$ref": "#/components/schemas/ErrorData" }, { "$ref": "#/components/schemas/ReasoningData" }, { "$ref": "#/components/schemas/CompactionData" }, { "$ref": "#/components/schemas/NativeToolData" }, { "$ref": "#/components/schemas/ResourceEventData" }, { "$ref": "#/components/schemas/RoutingDecisionData" }, { "$ref": "#/components/schemas/SlashCommandData" }, { "$ref": "#/components/schemas/TerminalCommandData" } ], "description": "The typed data payload (MessageData, etc.).", "title": "Data" }, "id": { "description": "Store-assigned item ID, e.g. `\"msg_abc123\"`.", "title": "Id", "type": "string" }, "response_id": { "description": "The task/response ID this item belongs to.", "title": "Response Id", "type": "string" }, "status": { "description": "Item status, e.g. `\"completed\"`.", "title": "Status", "type": "string" }, "type": { "description": "Item type, e.g. `\"message\"`, `\"function_call\"`.", "title": "Type", "type": "string" } }, "required": [ "id", "type", "status", "response_id", "created_at", "data" ], "title": "ConversationItem", "type": "object" }, "ConversationRef": { "description": "Lightweight reference to a conversation, used in request and\nresponse bodies where only the conversation ID is needed.", "properties": { "id": { "description": "Conversation identifier, e.g. `\"conv_abc123\"`.", "title": "Id", "type": "string" } }, "required": [ "id" ], "title": "ConversationRef", "type": "object" }, "CopyFilesRequest": { "description": "Request to copy files from a lineage ancestor into a session.\n\nThe destination session is the path parameter; `source_session_id`\nmust be a STRICT ancestor of the destination up its\n`parent_conversation_id` chain (spawn lineage) \u2014 the destination may\nnot name itself as the source. The copy creates new child-scoped rows \u2014\nit does not grant cross-session read access.", "properties": { "file_ids": { "description": "Non-empty, unique ids of the source-owned files to copy, e.g. `[\"file_abc123\"]`.", "items": { "minLength": 1, "type": "string" }, "minItems": 1, "title": "File Ids", "type": "array", "uniqueItems": true }, "source_session_id": { "description": "Session that owns the source files, e.g. `\"conv_parent\"`. Must be a strict ancestor of the destination.", "title": "Source Session Id", "type": "string" } }, "required": [ "source_session_id", "file_ids" ], "title": "CopyFilesRequest", "type": "object" }, "CreateDefaultPolicyRequest": { "description": "Request body for `POST /v1/policies`.", "properties": { "factory_params": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "description": "Optional dict of kwargs passed to the handler when it is a factory function. Only valid for `type=\"python\"`, e.g. `{\"limit\": 10}`.", "title": "Factory Params" }, "handler": { "description": "Dotted import path (python) or HTTPS URL (url), e.g. `\"github_mcp_policy.block_non_misc_push\"` or `\"https://example.com/policies/eval\"`.", "title": "Handler", "type": "string" }, "name": { "description": "Human-readable policy name. Must be globally unique, e.g. `\"block_non_feature_branch_push\"`.", "title": "Name", "type": "string" }, "type": { "description": "Handler discriminator: `\"python\"`, `\"url\"`,", "title": "Type", "type": "string" } }, "required": [ "name", "type", "handler" ], "title": "CreateDefaultPolicyRequest", "type": "object" }, "CreateDirectoryRequest": { "description": "Request body for `POST /v1/hosts/{host_id}/directories`.", "properties": { "path": { "description": "Absolute path of the directory to create on the host machine, e.g. `\"/Users/corey/projects/new-app\"`, or a tilde-prefixed path (`\"~/scratch\"`) the host expands against its own process owner. Missing parents are created.", "title": "Path", "type": "string" } }, "required": [ "path" ], "title": "CreateDirectoryRequest", "type": "object" }, "CreateSessionPolicyRequest": { "description": "Request body for `POST /v1/sessions/{session_id}/policies`.", "properties": { "factory_params": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "description": "Optional dict of kwargs passed to the handler when it is a factory function. Only valid for `type=\"python\"`, e.g. `{\"limit\": 10}`.", "title": "Factory Params" }, "handler": { "description": "Dotted import path (python) or HTTPS URL (url), e.g. `\"github_mcp_policy.block_non_misc_push\"` or `\"https://example.com/policies/eval\"`.", "title": "Handler", "type": "string" }, "name": { "description": "Human-readable policy name. Must be unique within the session, e.g. `\"block_non_feature_branch_push\"`.", "title": "Name", "type": "string" }, "type": { "description": "Handler discriminator: `\"python\"` or `\"url\"`.", "title": "Type", "type": "string" } }, "required": [ "name", "type", "handler" ], "title": "CreateSessionPolicyRequest", "type": "object" }, "CreatedEvent": { "description": "Initial event emitted at the start of every streaming response.\n\nCarries the freshly-allocated\n`omnigent.server.schemas.ResponseObject` (status will\nbe `\"queued\"` or `\"in_progress\"` depending on whether the\ntask started immediately).", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The newly-allocated response object." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.created", "description": "Always `\"response.created\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "CreatedEvent", "type": "object" }, "ElicitationRequestEvent": { "description": "Synchronous request for a decision from upstream.\n\nEmitted by Omnigent (or, under the new contract, by a harness)\nwhen the LLM / a tool / a policy needs a verdict before\nproceeding. The consumer replies via\n`POST /v1/sessions/{session_id}/events` with\n`type == \"approval\"` and\n`omnigent.server.schemas.ElicitationResult` fields in\n`data`. This preserves MCP request/reply correlation by id\nwithout threading elicitations through PATCH.\n\nWire shape matches the existing emit at\n`omnigent/runtime/policies/approval.py:175`.", "properties": { "elicitation_id": { "description": "Unique correlation id for this request \u2014 appears in the consumer's approval event payload, e.g. `\"elicit_abc123\"`.", "title": "Elicitation Id", "type": "string" }, "method": { "const": "elicitation/create", "default": "elicitation/create", "description": "MCP method literal \u2014 always `\"elicitation/create\"` (the value of `_MCP_ELICITATION_METHOD` in `omnigent/runtime/policies/approval.py`).", "title": "Method", "type": "string" }, "params": { "$ref": "#/components/schemas/ElicitationRequestParams", "description": "The MCP-shaped params block carrying the prompt and (form-mode only) the requested schema." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.elicitation_request", "description": "Always `\"response.elicitation_request\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "elicitation_id", "params" ], "title": "ElicitationRequestEvent", "type": "object" }, "ElicitationRequestParams": { "additionalProperties": true, "description": "Inner `params` block of a `ElicitationRequestEvent`.\n\nThe standard fields (`mode`, `message`, `requestedSchema`,\n`url`) mirror MCP's `ElicitRequestFormParams` /\n`ElicitRequestUrlParams` byte-for-byte (Principle 8 \u2014 adopt\nMCP's wire shape verbatim where it overlaps). The\nAP-specific extensions (`phase`, `policy_name`,\n`content_preview`, `target_session_id`) carry policy-engine\ncontext and mirrored-child routing for the consumer's renderer;\nMCP's `extra=\"allow\"` config permits them under the same params\nblock. Wire shape matches\n`omnigent/runtime/policies/approval.py:175`.", "properties": { "content_preview": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Truncated preview of the underlying request payload (\u22641024 chars in current AP), for the consumer's renderer.", "title": "Content Preview" }, "message": { "description": "Human-readable prompt the consumer renders, e.g. `\"Approve running 'rm -rf /tmp/cache'?\"`.", "title": "Message", "type": "string" }, "mode": { "default": "form", "description": "MCP-standard discriminator. `\"form\"` collects structured input via `requestedSchema`; `\"url\"` directs upstream to an external URL for OAuth / out-of-band interaction.", "enum": [ "form", "url" ], "title": "Mode", "type": "string" }, "phase": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Omnigent policy-engine phase the elicitation belongs to, e.g. `\"pre_tool_use\"`.", "title": "Phase" }, "policy_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Omnigent policy that triggered the elicitation, e.g. `\"approve_shell_commands\"`.", "title": "Policy Name" }, "requestedSchema": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "default": null, "description": "JSON-Schema dict for form mode (or `None` for url mode). camelCase preserved per MCP spec, e.g. `{\"type\": \"object\", \"properties\": {\"approve\": {\"type\": \"boolean\"}}}`.", "title": "Requestedschema" }, "target_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "AP session whose resolve endpoint owns this elicitation, e.g. `\"conv_child123\"`. Present when a child/sub-agent prompt is mirrored into an ancestor stream; `None` means resolve against the current session.", "title": "Target Session Id" }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "External URL for url mode (or `None` for form mode), e.g. `\"https://oauth.example.com/authorize?...\"`.", "title": "Url" } }, "required": [ "message" ], "title": "ElicitationRequestParams", "type": "object" }, "ElicitationResolvedEvent": { "description": "Signal that a previously-published elicitation is no longer\noutstanding, even though no UI `approval` verdict was\ndelivered through `POST /v1/sessions/{id}/events`.\n\nEmitted by the runner when its own `_pending_approvals`\nFuture is popped without a verdict (the runner's wait timed\nout, the turn was cancelled, the harness exited) so the AP\nserver's `omnigent.runtime.pending_elicitations`\nindex can decrement the sidebar badge in lockstep with the\nunderlying awaiter's lifecycle. Without this signal, the AP\nserver has no way to learn that the prompt is dead and the\nbadge stays stuck.\n\nIdempotent on the consumer side: the Omnigent server's index\ndecrement is a no-op when the id isn't tracked, so the\nrunner can fire-and-forget on every Future cleanup.", "properties": { "elicitation_id": { "description": "Correlation id of the elicitation being cleared, e.g. `\"elicit_abc123\"`. Must match the id of a prior `ElicitationRequestEvent`.", "title": "Elicitation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.elicitation_resolved", "description": "Always `\"response.elicitation_resolved\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "elicitation_id" ], "title": "ElicitationResolvedEvent", "type": "object" }, "ErrorData": { "description": "Data for a persisted error banner item.\n\nThese items mirror `response.error` events so clients can render\nthe same error banner after reconnect / refresh. They are listed in\n`NON_CONTENT_ITEM_TYPES` because they are operator-visible\ntranscript metadata, not content the next agent turn should receive.", "properties": { "code": { "description": "Stable error classifier, e.g. `\"native_terminal_start_failed\"`.", "title": "Code", "type": "string" }, "message": { "description": "Human-readable error message, e.g. `\"Native Codex requires the 'codex' CLI on PATH.\"`.", "title": "Message", "type": "string" }, "source": { "description": "Error source, e.g. `\"execution\"`.", "enum": [ "llm", "execution", "tool" ], "title": "Source", "type": "string" } }, "required": [ "source", "code", "message" ], "title": "ErrorData", "type": "object" }, "ErrorDetail": { "description": "Machine-readable error information attached to a failed response.", "properties": { "code": { "description": "Error code string, e.g. `\"server_error\"`, `\"invalid_input\"`.", "title": "Code", "type": "string" }, "message": { "description": "Human-readable error description.", "title": "Message", "type": "string" } }, "required": [ "code", "message" ], "title": "ErrorDetail", "type": "object" }, "ErrorEvent": { "description": "Non-recoverable error reported during the turn.\n\nEmitted from multiple sites in\n`omnigent/runtime/workflow.py` \u2014 terminal LLM failures\n(`_emit_llm_error_event`), execution timeouts\n(`_handle_execution_timeout`), and the agent-loop catch-all\n(`except Exception`). Wire shape matches those emits.", "properties": { "error": { "$ref": "#/components/schemas/RetryErrorDetail", "description": "Classified error description." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "source": { "description": "Origin of the error \u2014 `\"llm\"` for LLM-call failures, `\"execution\"` for timeouts, `\"tool\"` for tool failures (currently emitted by retry exhaustion paths).", "enum": [ "llm", "execution", "tool" ], "title": "Source", "type": "string" }, "tool_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Tool identifier when `source == \"tool\"`; `None` for the other sources.", "title": "Tool Name" }, "type": { "const": "response.error", "description": "Always `\"response.error\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "source", "error" ], "title": "ErrorEvent", "type": "object" }, "FailedEvent": { "description": "Terminal event for a turn that ended with an error.\n\nCarries the final\n`omnigent.server.schemas.ResponseObject` whose\n`error` field describes the failure.", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The final response object with `status=\"failed\"` and `error` populated." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.failed", "description": "Always `\"response.failed\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "FailedEvent", "type": "object" }, "FunctionCallData": { "description": "Data for a function_call item.\n\n**Parameters**\n\n- `agent` \u2014 Agent name. Serialized as `\"model\"` in JSON.", "properties": { "arguments": { "description": "JSON-encoded arguments string.", "title": "Arguments", "type": "string" }, "call_id": { "description": "Unique call identifier from the LLM, e.g. `\"call_abc123\"`.", "title": "Call Id", "type": "string" }, "model": { "title": "Model", "type": "string" }, "name": { "description": "Tool function name, e.g. `\"search.web\"`.", "title": "Name", "type": "string" } }, "required": [ "model", "name", "arguments", "call_id" ], "title": "FunctionCallData", "type": "object" }, "FunctionCallOutputData": { "description": "Data for a function_call_output item.", "properties": { "call_id": { "description": "The call_id this output corresponds to, e.g. `\"call_abc123\"`.", "title": "Call Id", "type": "string" }, "output": { "description": "The tool's string result.", "title": "Output", "type": "string" } }, "required": [ "call_id", "output" ], "title": "FunctionCallOutputData", "type": "object" }, "GrantPermissionRequest": { "description": "Request body for `PUT /v1/sessions/{id}/permissions`.", "properties": { "level": { "description": "Numeric permission level: `1` = read, `2` = edit, `3` = manage.", "maximum": 3.0, "minimum": 1.0, "title": "Level", "type": "integer" }, "user_id": { "description": "The user to grant access to, e.g. `\"alice@example.com\"` or `\"__public__\"` for public read access.", "title": "User Id", "type": "string" } }, "required": [ "user_id", "level" ], "title": "GrantPermissionRequest", "type": "object" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "title": "Detail", "type": "array" } }, "title": "HTTPValidationError", "type": "object" }, "HeartbeatEvent": { "description": "Keepalive event emitted on a fixed cadence during streaming.\n\nLets consumers detect stalled producers via missed-interval\ntiming. Cadence is set by `_HEARTBEAT_INTERVAL_S` in\n`omnigent/runtime/workflow.py` (15 seconds at the time of\nwriting). Wire shape matches the existing emit at\n`omnigent/runtime/workflow.py:4636-4639`.\n\nPer `designs/SERVER_HARNESS_CONTRACT.md` \u00a7Heartbeats, the\nevent MAY carry timing metadata so consumers can do richer\ndead-detection than \"did anything arrive\":\n\n- `server_time` is the producer's wall-clock at emission,\n letting consumers detect clock drift between producer and\n consumer.\n- `last_event_seq` is the `sequence_number` of the most\n recent NON-heartbeat event (or `None` when this is the\n first heartbeat before any user-visible event), letting\n consumers detect dropped events on reconnect.\n\nBoth fields are optional on the wire (`None` round-trips as\nomitted) so older AP\u2192harness pairs that pre-date the field\naddition still parse cleanly.", "properties": { "last_event_seq": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Sequence number of the last non- heartbeat event seen on the same stream, e.g. `42`. `None` before any user-visible event has fired (first heartbeat of the turn, before deltas land), or when the producer chose not to populate it.", "title": "Last Event Seq" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "server_time": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "ISO 8601 UTC timestamp at emission, e.g. `\"2026-04-27T15:30:00Z\"`. `None` when the producer chose not to populate it (legacy emitters).", "title": "Server Time" }, "type": { "const": "response.heartbeat", "description": "Always `\"response.heartbeat\"`.", "title": "Type", "type": "string" } }, "required": [ "type" ], "title": "HeartbeatEvent", "type": "object" }, "InProgressEvent": { "description": "Event emitted once the task transitions to in-progress.\n\nAlways follows `response.created` (and `response.queued`\nfor background tasks).", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The response object with `status=\"in_progress\"`." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.in_progress", "description": "Always `\"response.in_progress\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "InProgressEvent", "type": "object" }, "IncompleteDetails": { "description": "Details explaining why a response is incomplete.", "properties": { "reason": { "description": "Reason the response stopped early, e.g. `\"max_output_tokens\"`, `\"max_tool_calls\"`.", "title": "Reason", "type": "string" } }, "required": [ "reason" ], "title": "IncompleteDetails", "type": "object" }, "IncompleteEvent": { "description": "Terminal event for a turn that ended without completing\n(e.g. hit the iteration cap or token budget).", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The final response object with `status=\"incomplete\"` and `incomplete_details` populated describing the reason." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.incomplete", "description": "Always `\"response.incomplete\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "IncompleteEvent", "type": "object" }, "LaunchRunnerRequest": { "description": "Request body for `POST /v1/hosts/{host_id}/runners`.", "properties": { "git": { "anyOf": [ { "$ref": "#/components/schemas/SessionGitOptions" }, { "type": "null" } ], "description": "Optional git worktree options. In create mode the server creates a worktree for a new branch off `workspace` on the host and binds the runner to it (the fork-resume path; mirrors `POST /v1/sessions`). In bind mode (`existing_worktree=True`) `workspace` already IS a worktree \u2014 no worktree is created; `branch_name` is recorded as the session's `git_branch` for display and opt-in cleanup. `None` binds `workspace` directly. `host_id` is always present (it is in the path), so no host check is needed here." }, "session_id": { "description": "Session to bind the new runner to, e.g. `\"conv_abc123\"`.", "title": "Session Id", "type": "string" }, "workspace": { "description": "Absolute path on the host machine to use as the runner's working directory, e.g. `\"/Users/corey/projects/frontend\"`. When `git` is set, this is interpreted as the source repository directory and the runner starts in the created worktree instead.", "title": "Workspace", "type": "string" } }, "required": [ "session_id", "workspace" ], "title": "LaunchRunnerRequest", "type": "object" }, "MCPServerSummary": { "description": "Safe subset of an MCP server's configuration for API exposure.\n\nSecret-bearing fields (`headers`, `env`) are intentionally\nexcluded. This model is the wire shape returned inside\n`AgentObject` so clients can display which MCP servers\nan agent is connected to without leaking credentials.", "properties": { "args": { "description": "Command-line arguments for `transport=\"stdio\"` servers, e.g. `[\"mcp-server-github\"]`. Empty list when unset.", "items": { "type": "string" }, "title": "Args", "type": "array" }, "command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Executable path for `transport=\"stdio\"` servers, e.g. `\"uvx\"`. `None` for http servers.", "title": "Command" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional free-text description from the spec, e.g. `\"GitHub MCP server\"`. `None` when unset.", "title": "Description" }, "name": { "description": "Server name as declared in the agent spec, e.g. `\"github\"`.", "title": "Name", "type": "string" }, "transport": { "description": "Transport type \u2014 `\"stdio\"` or `\"http\"`.", "title": "Transport", "type": "string" }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "HTTP(S) endpoint URL for `transport=\"http\"` servers, e.g. `\"https://mcp.example.com/sse\"`. `None` for stdio servers.", "title": "Url" } }, "required": [ "name", "transport" ], "title": "MCPServerSummary", "type": "object" }, "MessageData": { "description": "Data for a message item (user or assistant).\n\n**Parameters**\n\n- `agent` \u2014 Agent name (required for assistant messages, absent for user). Serialized as `\"model\"` in JSON.", "properties": { "content": { "description": "Heterogeneous content blocks, e.g. `[{\"type\": \"input_text\", \"text\": \"Hello\"}]`.", "items": { "additionalProperties": true, "type": "object" }, "title": "Content", "type": "array" }, "interrupted": { "default": false, "description": "`True` when an assistant message is a durable partial response from an interrupted external-native turn, e.g. Codex `turn/completed` with status `\"interrupted\"`. Defaults to `False` and is omitted from serialized payloads in that case.", "title": "Interrupted", "type": "boolean" }, "is_meta": { "default": false, "description": "`True` for durable context that must be replayed to agents but hidden from user-facing transcripts, e.g. injected skill instructions. Defaults to `False` and is omitted from serialized payloads in that case.", "title": "Is Meta", "type": "boolean" }, "model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Model" }, "role": { "description": "`\"user\"` or `\"assistant\"`.", "enum": [ "user", "assistant" ], "title": "Role", "type": "string" } }, "required": [ "role", "content" ], "title": "MessageData", "type": "object" }, "ModelUsage": { "description": "Cumulative token/cost usage attributed to a single LLM model.\n\nOne value in the `usage_by_model` map on `SessionResponse` /\n`SessionUsageEvent`, keyed by the raw harness-reported model id\n(e.g. `\"claude-sonnet-4-6\"`, `\"databricks-gpt-5-5\"`). Counts are\nsummed over the session's subtree (itself + sub-agent descendants), so a\nparent folds in sub-agents that ran a different model. Token buckets\nmirror the flat per-session breakdown.", "properties": { "cache_creation_input_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Cumulative tokens written to the prompt cache, e.g. `2000`. `None` when not recorded.", "title": "Cache Creation Input Tokens" }, "cache_read_input_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Cumulative tokens read from the prompt cache, e.g. `8000`. `None` when not recorded.", "title": "Cache Read Input Tokens" }, "input_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Cumulative non-cached input (prompt) tokens for this model over the subtree, e.g. `12000`. `None` when not recorded.", "title": "Input Tokens" }, "output_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Cumulative output (completion) tokens, e.g. `3400`. `None` when not recorded.", "title": "Output Tokens" }, "total_cost_usd": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Cumulative USD spend attributed to this model, e.g. `0.42`. Present **only when this model's turns were priced** (same \"priced \u27fa key present\" contract as the session total); `None` when the model is unpriced, so the sum of priced per-model costs equals the session `total_cost_usd`.", "title": "Total Cost Usd" }, "total_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Cumulative total tokens (counts cache buckets too, as the harness reports), e.g. `15400`. `None` when not recorded.", "title": "Total Tokens" } }, "title": "ModelUsage", "type": "object" }, "NativeToolData": { "description": "A provider-native tool output item (e.g. `web_search_call`).\n\nThese are executed server-side by the LLM provider and returned\nas opaque dicts. Agent-plane persists and replays them so the\nLLM sees its own tool results on subsequent iterations.", "properties": { "item": { "additionalProperties": true, "description": "The raw dict from the Responses API output, e.g. `{\"type\": \"web_search_call\", \"id\": \"ws_abc\", \"status\": \"completed\", \"action\": {...}}`.", "title": "Item", "type": "object" } }, "required": [ "item" ], "title": "NativeToolData", "type": "object" }, "OutputFileDoneEvent": { "description": "A streamed file output completed materializing.\n\nEmitted by `_emit_file_annotation_events` in\n`omnigent/runtime/workflow.py` once per file annotation in\nthe assistant's output. `filename` and `content_type` are\nonly populated when the originating annotation carried them.", "properties": { "content_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "MIME content type if the annotation supplied one, e.g. `\"application/pdf\"`. `None` otherwise.", "title": "Content Type" }, "file_id": { "description": "Identifier of the materialized file, e.g. `\"file_abc123\"`.", "title": "File Id", "type": "string" }, "filename": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Original filename if the annotation supplied one, e.g. `\"report.pdf\"`. `None` otherwise.", "title": "Filename" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.output_file.done", "description": "Always `\"response.output_file.done\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "file_id" ], "title": "OutputFileDoneEvent", "type": "object" }, "OutputItemDoneEvent": { "description": "A conversation output item completed during the turn.\n\nCarries any item type the conversation persists (message,\nfunction_call, function_call_output, reasoning, compaction,\nnative_tool, \u2026). The `item` payload's wire shape merges\ncommon fields (`id`, `type`, `status`) with the\ntype-specific data fields \u2014 it is NOT nested as\n`{type, data}`.", "properties": { "item": { "additionalProperties": true, "description": "The completed item dict. Heterogeneous and item-type-specific; see `omnigent/entities/conversation.py` for the per-type `*Data` shapes that drive serialization. Example for a function_call item: `{\"id\": \"fc_abc123\", \"type\": \"function_call\", \"status\": \"action_required\", \"name\": \"search.web\", \"arguments\": \"{\\\"q\\\": \\\"foo\\\"}\", \"call_id\": \"call_xyz\"}`.", "title": "Item", "type": "object" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.output_item.done", "description": "Always `\"response.output_item.done\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "item" ], "title": "OutputItemDoneEvent", "type": "object" }, "OutputTextDeltaEvent": { "description": "Incremental assistant-text token emitted during streaming.\n\nWire shape matches the existing raw-dict emit at\n`omnigent/runtime/workflow.py:1352-1356`.", "properties": { "delta": { "description": "The text fragment for this chunk, e.g. `\"Hello\"`.", "title": "Delta", "type": "string" }, "final": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "default": null, "description": "`True` on the last chunk of a terminal-observed message; `None` otherwise. Signals the web UI that no further chunks for `message_id` will arrive.", "title": "Final" }, "index": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "0-based chunk order within the message, e.g. `3`. `None` when not terminal-observed streaming.", "title": "Index" }, "message_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "For terminal-observed streaming (claude-native), the vendor's stable per-message id, e.g. `\"2ca51d97-2f0f-493a-aed7-85a5b56c5747\"`. Lets the web UI scope an in-flight buffer to one assistant message and reconcile it against the final item. `None` for ordinary in-process task streaming, where deltas already group by the active response.", "title": "Message Id" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.output_text.delta", "description": "Always `\"response.output_text.delta\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "delta" ], "title": "OutputTextDeltaEvent", "type": "object" }, "PaginatedList": { "description": "A paginated list response following cursor-based pagination.", "properties": { "data": { "description": "Page of results. Items are heterogeneous (`ResponseObject`, `ConversationObject`, `FileObject`, or dicts) and list is invariant, so no single concrete type satisfies all callers.", "items": {}, "title": "Data", "type": "array" }, "first_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ID of the first item in the page, or `None` if the page is empty, e.g. `\"resp_abc123\"`.", "title": "First Id" }, "has_more": { "default": false, "description": "Whether more items exist beyond this page.", "title": "Has More", "type": "boolean" }, "last_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ID of the last item in the page, or `None` if the page is empty, e.g. `\"resp_xyz789\"`.", "title": "Last Id" }, "object": { "default": "list", "description": "Fixed resource type, always `\"list\"`.", "title": "Object", "type": "string" } }, "title": "PaginatedList", "type": "object" }, "PermissionObject": { "description": "API representation of a session permission grant.", "properties": { "conversation_id": { "description": "The session, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "level": { "description": "Numeric permission level (1=read, 2=edit, 3=manage).", "title": "Level", "type": "integer" }, "user_id": { "description": "The grantee, e.g. `\"alice@example.com\"`.", "title": "User Id", "type": "string" } }, "required": [ "user_id", "conversation_id", "level" ], "title": "PermissionObject", "type": "object" }, "PolicyDeniedEvent": { "description": "Signal that a policy DENY was enforced on a native harness turn.\n\nA native harness (Claude Code, Codex, ...) routes each tool call and\nprompt through Omnigent's policy engine via the vendor command-hook\n(`POST /v1/sessions/{id}/policies/evaluate`). The DENY verdict is\nreturned synchronously to that hook, so unlike the SDK/wrap path there is\nno stream-visible signal that a native action was blocked \u2014 only the\n*effect* (the blocked tool never runs). This event surfaces the decision\nitself on the session stream so observers (the web UI, the capability\nbench) can see a native DENY as a positive signal rather than infer it\nfrom an absence.\n\nFire-and-forget and observational: it does not gate the turn (the hook\nresponse already did that) and carries no correlation id.", "properties": { "conversation_id": { "description": "Session/conversation id the DENY applies to, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "phase": { "default": "", "description": "The policy phase the DENY landed on, e.g. `\"tool_call\"`.", "title": "Phase", "type": "string" }, "reason": { "default": "", "description": "Human-readable deny reason from the deciding policy, e.g. `\"Blocked by policy.\"`.", "title": "Reason", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.policy_denied", "description": "Always `\"response.policy_denied\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id" ], "title": "PolicyDeniedEvent", "type": "object" }, "PolicySummary": { "description": "Safe subset of a policy's spec for API exposure.\n\nExposes the policy name, type, and phases so the UI can\ndisplay which guardrails are active on an agent. The full\npolicy body (prompt text, callable path, label conditions)\nis intentionally excluded \u2014 this is a summary for display,\nnot a full spec.", "properties": { "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Short detail string about the policy implementation. For function policies: the callable dotted path. For prompt policies: the first line of the prompt. `None` when not available.", "title": "Description" }, "name": { "description": "Policy name as declared in the agent spec, e.g. `\"block_long_sleep\"`.", "title": "Name", "type": "string" }, "on": { "description": "List of phase selectors the policy fires on, e.g. `[\"tool_call\"]` or `[\"request\", \"response\"]`.", "items": { "type": "string" }, "title": "On", "type": "array" }, "type": { "description": "Policy type discriminator \u2014 `\"function\"` or `\"prompt\"`.", "title": "Type", "type": "string" } }, "required": [ "name", "type", "on" ], "title": "PolicySummary", "type": "object" }, "PresenceViewer": { "description": "One user currently viewing a session (holding its SSE stream open).", "properties": { "idle": { "default": false, "description": "Whether every stream the user holds reports an idle (backgrounded) tab. The web greys idle viewers' avatars.", "title": "Idle", "type": "boolean" }, "joined_at": { "description": "ISO 8601 UTC timestamp of when the user joined, e.g. `\"2026-06-10T17:00:00Z\"`. Stable across reconnects within the server's leave-grace window.", "title": "Joined At", "type": "string" }, "user_id": { "description": "The viewer's authenticated identity, e.g. `\"alice@example.com\"`. Never the reserved single-user `\"local\"` sentinel \u2014 presence only tracks distinct human actors (see `attribution_user`).", "title": "User Id", "type": "string" } }, "required": [ "user_id", "joined_at" ], "title": "PresenceViewer", "type": "object" }, "QueuedEvent": { "description": "Optional event emitted between `created` and `in_progress`\nfor background tasks that are queued before they start.\n\nForeground streaming responses skip this event.", "properties": { "response": { "$ref": "#/components/schemas/ResponseObject", "description": "The response object with `status=\"queued\"`." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.queued", "description": "Always `\"response.queued\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "response" ], "title": "QueuedEvent", "type": "object" }, "ReadStatePutRequest": { "additionalProperties": false, "description": "Request body for `PUT /v1/sessions/{session_id}/read-state`.\n\nSets the *calling user's* read tracking for one session. Mirrors the\ntwo values the web client keeps per session: a \"last seen\" wall-clock\nbaseline (seconds since epoch) and an explicit \"marked unread\"\noverride. The unread dot shows when `updated_at > last_seen` and the\nsession is finished; `unread` separately pins the override so the\nthread the user is *viewing* (or a running one) still surfaces the dot\nwhere the automatic \"seen\" logic would otherwise suppress it.", "properties": { "last_seen": { "description": "Wall-clock baseline in seconds, e.g. `1717000000`. Marking seen sets this to \"now\"; marking unread pins it to `updated_at - 1` so the row reads unseen.", "title": "Last Seen", "type": "integer" }, "unread": { "description": "Whether this session is explicitly flagged unread for the caller.", "title": "Unread", "type": "boolean" } }, "required": [ "last_seen", "unread" ], "title": "ReadStatePutRequest", "type": "object" }, "ReasoningData": { "description": "Data for a reasoning item.\n\n**Parameters**\n\n- `agent` \u2014 Agent name. Serialized as `\"model\"` in JSON.", "properties": { "content": { "anyOf": [ { "items": { "additionalProperties": { "type": "string" }, "type": "object" }, "type": "array" }, { "type": "null" } ], "description": "Raw reasoning content blocks, or `None` if redacted.", "title": "Content" }, "encrypted_content": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Encrypted reasoning content, or `None`.", "title": "Encrypted Content" }, "model": { "title": "Model", "type": "string" }, "summary": { "description": "Summary text blocks, e.g. `[{\"type\": \"summary_text\", \"text\": \"...\"}]`.", "items": { "additionalProperties": { "type": "string" }, "type": "object" }, "title": "Summary", "type": "array" } }, "required": [ "model", "summary" ], "title": "ReasoningData", "type": "object" }, "ReasoningStartedEvent": { "description": "Marker emitted once when a reasoning block begins.\n\nFired even when the reasoning content itself is encrypted /\nredacted (so no delta events follow), letting clients render\na \"thinking\u2026\" indicator regardless of provider verification\nstatus. Wire shape matches `omnigent/runtime/workflow.py:1350`.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.reasoning.started", "description": "Always `\"response.reasoning.started\"`.", "title": "Type", "type": "string" } }, "required": [ "type" ], "title": "ReasoningStartedEvent", "type": "object" }, "ReasoningSummaryTextDeltaEvent": { "description": "Incremental reasoning-summary token.\n\nEmitted when `reasoning.summary` is configured on the\nrequest. Wire shape matches\n`omnigent/runtime/workflow.py:1370-1373`.", "properties": { "delta": { "description": "The summary text fragment, e.g. `\"Will use the search tool to gather context.\"`.", "title": "Delta", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.reasoning_summary_text.delta", "description": "Always `\"response.reasoning_summary_text.delta\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "delta" ], "title": "ReasoningSummaryTextDeltaEvent", "type": "object" }, "ReasoningTextDeltaEvent": { "description": "Incremental reasoning-text token (full chain-of-thought).\n\nOnly emitted by providers that surface reasoning content\n(e.g. OpenAI o-series with appropriate verification). Wire\nshape matches `omnigent/runtime/workflow.py:1358-1364`.", "properties": { "delta": { "description": "The reasoning text fragment, e.g. `\"Considering the user's intent...\"`.", "title": "Delta", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "response.reasoning_text.delta", "description": "Always `\"response.reasoning_text.delta\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "delta" ], "title": "ReasoningTextDeltaEvent", "type": "object" }, "ResourceEventData": { "description": "Data payload for a persisted resource lifecycle event.\n\nThese items are written to the conversation store when a\nsession resource is created or deleted, so reconnecting\nclients can discover resource history without replaying the\nlive SSE stream. The agent loop filters them out of the\nLLM's message context (they are metadata, not conversation\ncontent).", "properties": { "event_type": { "description": "The SSE event type literal, e.g. `\"session.resource.created\"` or `\"session.resource.deleted\"`.", "title": "Event Type", "type": "string" }, "resource": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "description": "Full resource object dict for `created` events. `None` for `deleted` events.", "title": "Resource" }, "resource_id": { "description": "Opaque id of the affected resource, e.g. `\"terminal_bash_s1\"` or `\"file_abc123\"`.", "title": "Resource Id", "type": "string" }, "resource_type": { "description": "Kind of resource, e.g. `\"terminal\"`, `\"file\"`, `\"environment\"`.", "title": "Resource Type", "type": "string" } }, "required": [ "event_type", "resource_id", "resource_type" ], "title": "ResourceEventData", "type": "object" }, "ResponseObject": { "description": "API representation of a response (task execution result).", "properties": { "background": { "default": false, "description": "Whether this response was created as a background task.", "title": "Background", "type": "boolean" }, "completed_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Unix epoch timestamp of completion, or `None` if not yet complete.", "title": "Completed At" }, "conversation": { "anyOf": [ { "$ref": "#/components/schemas/ConversationRef" }, { "type": "null" } ], "default": null, "description": "Reference to the owning conversation." }, "created_at": { "description": "Unix epoch timestamp of creation.", "title": "Created At", "type": "integer" }, "error": { "anyOf": [ { "$ref": "#/components/schemas/ErrorDetail" }, { "type": "null" } ], "default": null, "description": "Error details if the response failed." }, "id": { "description": "Unique response identifier, e.g. `\"resp_abc123\"`.", "title": "Id", "type": "string" }, "incomplete_details": { "anyOf": [ { "$ref": "#/components/schemas/IncompleteDetails" }, { "type": "null" } ], "default": null, "description": "Details if the response is incomplete (e.g. hit token limit)." }, "instructions": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Per-request system instructions override, or `None`.", "title": "Instructions" }, "model": { "description": "Agent name that produced this response, e.g. `\"research-agent\"`.", "title": "Model", "type": "string" }, "object": { "default": "response", "description": "Fixed resource type, always `\"response\"`.", "title": "Object", "type": "string" }, "output": { "description": "Heterogeneous output items (messages, reasoning, function_calls) serialized as dicts; shape varies by item type. Empty for non-completed responses.", "items": { "additionalProperties": true, "type": "object" }, "title": "Output", "type": "array" }, "previous_response_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "ID of the prior response in the conversation thread, or `None` for the first turn.", "title": "Previous Response Id" }, "reasoning": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "default": null, "description": "Reasoning configuration, e.g. `{\"effort\": \"medium\"}`.", "title": "Reasoning" }, "status": { "description": "Lifecycle status, one of `\"queued\"`, `\"in_progress\"`, `\"completed\"`, `\"failed\"`, `\"incomplete\"`, `\"cancelled\"`.", "title": "Status", "type": "string" }, "store": { "default": true, "description": "Whether this response is persisted. Always `True`.", "title": "Store", "type": "boolean" }, "usage": { "anyOf": [ { "$ref": "#/components/schemas/Usage" }, { "type": "null" } ], "default": null, "description": "Token usage statistics, or `None` if not yet available." } }, "required": [ "id", "status", "model", "created_at" ], "title": "ResponseObject", "type": "object" }, "RetryErrorDetail": { "description": "Error block carried by `RetryEvent` and `ErrorEvent`.\n\nMirrors the shape that `llm_retry.py` and `tool_retry.py`\nemit today \u2014 flat `code` / `message` plus an optional\n`detail` for provider-specific structured fields.", "properties": { "code": { "description": "Stable error classifier, e.g. `\"timeout\"`, `\"rate_limit\"`.", "title": "Code", "type": "string" }, "detail": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "default": null, "description": "Optional provider-specific structured fields (e.g. `{\"status_code\": 429, \"retry_after\": 5}`); `None` when the classifier had no extra context.", "title": "Detail" }, "message": { "description": "Human-readable summary, e.g. `\"Connection timed out after 30s\"`.", "title": "Message", "type": "string" } }, "required": [ "code", "message" ], "title": "RetryErrorDetail", "type": "object" }, "RetryEvent": { "description": "A retryable failure was caught and a retry is scheduled.\n\nEmitted by `omnigent/runtime/llm_retry.py` (LLM calls)\nand `omnigent/runtime/tool_retry.py` (tool calls) before\nsleeping for the backoff delay. Wire shape matches\n`llm_retry.py:329-340` and `tool_retry.py:168-180`.", "properties": { "attempt": { "description": "1-based count of the upcoming attempt (i.e. attempt that will run AFTER this delay), e.g. `2` for the first retry.", "title": "Attempt", "type": "integer" }, "delay_seconds": { "description": "Seconds the producer will sleep before retrying, rounded to two decimals, e.g. `1.5`.", "title": "Delay Seconds", "type": "number" }, "error": { "$ref": "#/components/schemas/RetryErrorDetail", "description": "Classified error description for the failure being retried." }, "max_attempts": { "description": "Total tries allowed by the retry policy, e.g. `3`. Lets clients render \"attempt 2 of 3\".", "title": "Max Attempts", "type": "integer" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "source": { "description": "Origin of the retried failure \u2014 `\"llm\"` for LLM-call retries, `\"tool\"` for tool-call retries.", "enum": [ "llm", "tool" ], "title": "Source", "type": "string" }, "tool_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Tool identifier when `source == \"tool\"`, e.g. `\"search.web\"`. `None` for LLM retries.", "title": "Tool Name" }, "type": { "const": "response.retry", "description": "Always `\"response.retry\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "source", "attempt", "max_attempts", "delay_seconds", "error" ], "title": "RetryEvent", "type": "object" }, "RoutingDecisionData": { "description": "Data payload for an intelligent model-router decision item.\n\nEmitted by the server-side smart routing path at the START of an\nadvised turn and persisted\nas a display-only transcript item so the model the router chose shows\nin the conversation flow the moment the turn begins. Listed in\n`NON_CONTENT_ITEM_TYPES` so the agent loop's history filter\nskips it \u2014 the brain never sees (or answers) its own router note. The\nrunner's harness-input builder also drops every non\nmessage/function_call type, a second guarantee it stays out of the\nmodel's context.", "properties": { "agent": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Agent" }, "applied": { "description": "`True` when the brain actually ran on `model` this turn (optimize mode, no user pin); `False` when the router only WOULD have picked it (advise/shadow mode, or a user model pin won) \u2014 the UI renders \"would have picked\".", "title": "Applied", "type": "boolean" }, "model": { "description": "The concrete brain model the router chose, e.g. `\"databricks-claude-opus-4-8\"`.", "title": "Model", "type": "string" }, "rationale": { "description": "The router's one-line explanation, shown as muted secondary text, e.g. `\"Multi-file refactor needs deep reasoning.\"`.", "title": "Rationale", "type": "string" } }, "required": [ "model", "applied", "rationale" ], "title": "RoutingDecisionData", "type": "object" }, "SandboxStatus": { "description": "Managed-sandbox launch progress for a `host_type=\"managed\"` session.\n\nCarried on the session snapshot only while the session's\nbackground sandbox launch is in flight or has failed; `None`\nfor sessions without a managed launch and once the launch\nsucceeds (the session then looks like any host-bound session).", "properties": { "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Failure detail when `stage == \"failed\"`, e.g. `\"managed sandbox launch failed: spend limit reached\"`. `None` otherwise.", "title": "Error" }, "stage": { "description": "Current launch stage, e.g. `\"provisioning\"` \u2014 one of `SandboxLaunchStage`, in pipeline order: `provisioning` (creating the sandbox) \u2192 `cloning` (cloning the repository workspace; skipped when the session has none) \u2192 `starting` (starting the in-sandbox host) \u2192 `connecting` (launching the agent runner) \u2192 `ready` / `failed`.", "enum": [ "provisioning", "cloning", "starting", "connecting", "ready", "failed" ], "title": "Stage", "type": "string" } }, "required": [ "stage" ], "title": "SandboxStatus", "type": "object" }, "SendCommentsRequest": { "description": "Request body for `POST .../comments/send`.", "properties": { "comment_ids": { "description": "IDs of comments to send.", "items": { "type": "string" }, "title": "Comment Ids", "type": "array" }, "instruction": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional custom instruction prefix; defaults to the standard \"Please address the following file review comments.\" header.", "title": "Instruction" } }, "required": [ "comment_ids" ], "title": "SendCommentsRequest", "type": "object" }, "ServerStreamEvent": { "discriminator": { "mapping": { "response.cancelled": "#/components/schemas/CancelledEvent", "response.client_task.cancel": "#/components/schemas/ClientTaskCancelEvent", "response.compaction.completed": "#/components/schemas/CompactionCompletedEvent", "response.compaction.failed": "#/components/schemas/CompactionFailedEvent", "response.compaction.in_progress": "#/components/schemas/CompactionInProgressEvent", "response.completed": "#/components/schemas/CompletedEvent", "response.created": "#/components/schemas/CreatedEvent", "response.elicitation_request": "#/components/schemas/ElicitationRequestEvent", "response.elicitation_resolved": "#/components/schemas/ElicitationResolvedEvent", "response.error": "#/components/schemas/ErrorEvent", "response.failed": "#/components/schemas/FailedEvent", "response.heartbeat": "#/components/schemas/HeartbeatEvent", "response.in_progress": "#/components/schemas/InProgressEvent", "response.incomplete": "#/components/schemas/IncompleteEvent", "response.output_file.done": "#/components/schemas/OutputFileDoneEvent", "response.output_item.done": "#/components/schemas/OutputItemDoneEvent", "response.output_text.delta": "#/components/schemas/OutputTextDeltaEvent", "response.policy_denied": "#/components/schemas/PolicyDeniedEvent", "response.queued": "#/components/schemas/QueuedEvent", "response.reasoning.started": "#/components/schemas/ReasoningStartedEvent", "response.reasoning_summary_text.delta": "#/components/schemas/ReasoningSummaryTextDeltaEvent", "response.reasoning_text.delta": "#/components/schemas/ReasoningTextDeltaEvent", "response.retry": "#/components/schemas/RetryEvent", "session.agent_changed": "#/components/schemas/SessionAgentChangedEvent", "session.changed_files.invalidated": "#/components/schemas/SessionChangedFilesInvalidatedEvent", "session.child_session.updated": "#/components/schemas/SessionChildSessionUpdatedEvent", "session.collaboration_mode": "#/components/schemas/SessionCollaborationModeEvent", "session.created": "#/components/schemas/SessionCreatedEvent", "session.heartbeat": "#/components/schemas/SessionHeartbeatEvent", "session.input.consumed": "#/components/schemas/SessionInputConsumedEvent", "session.interrupted": "#/components/schemas/SessionInterruptedEvent", "session.model": "#/components/schemas/SessionModelEvent", "session.model_options": "#/components/schemas/SessionModelOptionsEvent", "session.presence": "#/components/schemas/SessionPresenceEvent", "session.reasoning_effort": "#/components/schemas/SessionReasoningEffortEvent", "session.resource.created": "#/components/schemas/SessionResourceCreatedEvent", "session.resource.deleted": "#/components/schemas/SessionResourceDeletedEvent", "session.sandbox_status": "#/components/schemas/SessionSandboxStatusEvent", "session.skills": "#/components/schemas/SessionSkillsEvent", "session.status": "#/components/schemas/SessionStatusEvent", "session.superseded": "#/components/schemas/SessionSupersededEvent", "session.terminal.activity": "#/components/schemas/SessionTerminalActivityEvent", "session.terminal_pending": "#/components/schemas/SessionTerminalPendingEvent", "session.todos": "#/components/schemas/SessionTodosEvent", "session.usage": "#/components/schemas/SessionUsageEvent", "turn.cancelled": "#/components/schemas/TurnCancelledEvent", "turn.completed": "#/components/schemas/TurnCompletedEvent", "turn.failed": "#/components/schemas/TurnFailedEvent", "turn.started": "#/components/schemas/TurnStartedEvent" }, "propertyName": "type" }, "oneOf": [ { "$ref": "#/components/schemas/SessionStatusEvent" }, { "$ref": "#/components/schemas/SessionUsageEvent" }, { "$ref": "#/components/schemas/SessionModelEvent" }, { "$ref": "#/components/schemas/SessionReasoningEffortEvent" }, { "$ref": "#/components/schemas/SessionCollaborationModeEvent" }, { "$ref": "#/components/schemas/SessionAgentChangedEvent" }, { "$ref": "#/components/schemas/SessionTodosEvent" }, { "$ref": "#/components/schemas/SessionTerminalPendingEvent" }, { "$ref": "#/components/schemas/SessionSandboxStatusEvent" }, { "$ref": "#/components/schemas/SessionSkillsEvent" }, { "$ref": "#/components/schemas/SessionModelOptionsEvent" }, { "$ref": "#/components/schemas/SessionInputConsumedEvent" }, { "$ref": "#/components/schemas/SessionInterruptedEvent" }, { "$ref": "#/components/schemas/SessionCreatedEvent" }, { "$ref": "#/components/schemas/SessionSupersededEvent" }, { "$ref": "#/components/schemas/SessionPresenceEvent" }, { "$ref": "#/components/schemas/SessionResourceCreatedEvent" }, { "$ref": "#/components/schemas/SessionResourceDeletedEvent" }, { "$ref": "#/components/schemas/SessionChildSessionUpdatedEvent" }, { "$ref": "#/components/schemas/SessionChangedFilesInvalidatedEvent" }, { "$ref": "#/components/schemas/SessionTerminalActivityEvent" }, { "$ref": "#/components/schemas/OutputTextDeltaEvent" }, { "$ref": "#/components/schemas/ReasoningStartedEvent" }, { "$ref": "#/components/schemas/ReasoningTextDeltaEvent" }, { "$ref": "#/components/schemas/ReasoningSummaryTextDeltaEvent" }, { "$ref": "#/components/schemas/OutputItemDoneEvent" }, { "$ref": "#/components/schemas/OutputFileDoneEvent" }, { "$ref": "#/components/schemas/HeartbeatEvent" }, { "$ref": "#/components/schemas/SessionHeartbeatEvent" }, { "$ref": "#/components/schemas/ElicitationRequestEvent" }, { "$ref": "#/components/schemas/ElicitationResolvedEvent" }, { "$ref": "#/components/schemas/PolicyDeniedEvent" }, { "$ref": "#/components/schemas/CreatedEvent" }, { "$ref": "#/components/schemas/QueuedEvent" }, { "$ref": "#/components/schemas/InProgressEvent" }, { "$ref": "#/components/schemas/CompletedEvent" }, { "$ref": "#/components/schemas/FailedEvent" }, { "$ref": "#/components/schemas/CancelledEvent" }, { "$ref": "#/components/schemas/IncompleteEvent" }, { "$ref": "#/components/schemas/RetryEvent" }, { "$ref": "#/components/schemas/ErrorEvent" }, { "$ref": "#/components/schemas/CompactionInProgressEvent" }, { "$ref": "#/components/schemas/CompactionCompletedEvent" }, { "$ref": "#/components/schemas/CompactionFailedEvent" }, { "$ref": "#/components/schemas/ClientTaskCancelEvent" }, { "$ref": "#/components/schemas/TurnStartedEvent" }, { "$ref": "#/components/schemas/TurnCompletedEvent" }, { "$ref": "#/components/schemas/TurnFailedEvent" }, { "$ref": "#/components/schemas/TurnCancelledEvent" } ] }, "SessionAgentChangedEvent": { "description": "Bound-agent change on a live session.\n\nEmitted by the switch-agent route after the session's agent binding\nis rewritten in place. Connected clients re-derive their cached\nsession state (harness presentation labels, bound agent id/name)\nfrom a fresh snapshot \u2014 the chat UI's native-vs-SDK message\nlifecycle depends on those labels, so a stale cache drops the first\npost-switch message (it reappears only when the transcript\nround-trip lands).", "properties": { "agent_id": { "description": "The session-scoped clone now bound to the session, e.g. `\"ag_abc123\"`.", "title": "Agent Id", "type": "string" }, "agent_name": { "description": "Display name of the agent the session now runs, e.g. `\"claude-native-ui\"`. Deliberately the clean target-agent name \u2014 not the clone row's `\"\u2026 (switch ag_\u2026)\"` disambiguation name \u2014 because clients render it verbatim. Category: **transient** (SSE-only). The switch is persisted on the conversation row, so on reconnect clients read the new binding from the session snapshot rather than from a replayed event.", "title": "Agent Name", "type": "string" }, "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.agent_changed", "description": "Always `\"session.agent_changed\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "agent_id", "agent_name" ], "title": "SessionAgentChangedEvent", "type": "object" }, "SessionChangedFilesInvalidatedEvent": { "description": "The session's changed-files list may have changed \u2014 refetch it.\n\nA coarse \"something changed\" signal (per-file events aren't available\nfor git-mode workspaces) emitted by the runner after a file-mutating\ntool. The web treats it as a refetch trigger for the changed-files\npanel; transient (not persisted \u2014 the REST list is source of truth).", "properties": { "environment_id": { "default": "default", "description": "Environment whose changes were invalidated, e.g. `\"default\"`.", "title": "Environment Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Owning session/conversation id.", "title": "Session Id", "type": "string" }, "type": { "const": "session.changed_files.invalidated", "description": "Always `\"session.changed_files.invalidated\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "session_id" ], "title": "SessionChangedFilesInvalidatedEvent", "type": "object" }, "SessionChildSessionUpdatedEvent": { "description": "A child (sub-agent) session's status changed \u2014 pushed to the PARENT.\n\nLets the parent's resource rail update a child's status without\npolling `GET \u2026/child_sessions`. Carries the full\n`ChildSessionSummary` so the web patches its cache directly.", "properties": { "child": { "additionalProperties": true, "description": "A PARTIAL `ChildSessionSummary` \u2014 the snapshot-on-connect sends the full summary, while live runner deltas carry only the fields that changed (a status delta omits `last_message_preview`; a preview delta carries only it). The web merges present fields over the cached row, so the payload is an open dict rather than the strict model.", "title": "Child", "type": "object" }, "child_session_id": { "description": "The child session id, e.g. `\"conv_child_abc123\"`.", "title": "Child Session Id", "type": "string" }, "conversation_id": { "description": "The PARENT (carrier) session id.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.child_session.updated", "description": "Always `\"session.child_session.updated\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "child_session_id", "child" ], "title": "SessionChildSessionUpdatedEvent", "type": "object" }, "SessionCollaborationModeEvent": { "description": "Active collaboration-mode update from a Codex-native session.\n\nEmitted after the web UI toggles Codex collaboration mode, and after the\nCodex forwarder observes a `thread/settings/updated` notification from\nthe native Codex TUI. Lets connected clients show a clear Plan-mode\nindicator without a reload.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "mode": { "description": "The active collaboration mode string, e.g. `\"plan\"` or `\"default\"`. Category: **transient** (SSE-only). The server also writes `omnigent.codex_native.collaboration_mode` on the conversation labels, so reconnect clients restore the same state from the session snapshot.", "title": "Mode", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.collaboration_mode", "description": "Always `\"session.collaboration_mode\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "mode" ], "title": "SessionCollaborationModeEvent", "type": "object" }, "SessionCreatedEvent": { "description": "A child (sub-agent) session was spawned from this session.\n\nEmitted by `omnigent/tools/builtins/spawn.py:_spawn_one`\nonto the **parent** session's conversation stream after the\nchild conversation row is created and the child task has been\nstarted. Per the session-rearchitecture spec \u00a73 (\"Event types\nand direction\") and \u00a77 (\"Flow: client interacts with\nsub-agent\"), this lets clients watching the parent session's\nSSE subscribe directly to the child's stream without polling\nhistory for the tunneled `function_call` item.\n\nThe wire shape is FLAT (not enveloped):\n`{\"type\": \"session.created\", \"conversation_id\": , \"child_session_id\": , \"agent_id\": , \"parent_session_id\": , \"sequence_number\": null}`.\n\nThe existing tunneled `function_call` ConversationItem\n(carried inside `OutputItemDoneEvent`) is retained\nfor compatibility \u2014 clients that don't yet implement the\n\"subscribe to child stream\" pattern can keep rendering sub-\nagent calls from the parent's persistent history.", "properties": { "agent_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Registered agent id the child runs as, e.g. `\"agent_xyz\"`. `None` is permitted only for legacy spawn paths that did not record an agent id; new code MUST set it.", "title": "Agent Id" }, "child_session_id": { "description": "The newly-created child session id, e.g. `\"conv_child456\"`. Same as `conversation_id` on the child's own stream when consumers pivot to it.", "title": "Child Session Id", "type": "string" }, "conversation_id": { "description": "The PARENT session/conversation id \u2014 this event rides the parent's stream, e.g. `\"conv_parent123\"`.", "title": "Conversation Id", "type": "string" }, "parent_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Echo of `conversation_id` for consumers that key on a dedicated \"parent\" field rather than the carrier `conversation_id`. Always equal to `conversation_id`; included for forward-compat with clients that may relay these events across stream boundaries. Category: **transient** (SSE-only). The corresponding durable record of \"a child session exists\" lives in the conversation store as the child conversation row itself (`parent_conversation_id` foreign key) and the parent's tunneled `function_call` item \u2014 reconnecting clients discover children by walking the parent's persisted history, not by replaying this event.", "title": "Parent Session Id" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.created", "description": "Always `\"session.created\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "child_session_id" ], "title": "SessionCreatedEvent", "type": "object" }, "SessionForkRequest": { "additionalProperties": false, "description": "Request body for `POST /v1/sessions/{source_id}/fork`.\n\nCreates a deep copy of an existing session's items into a new\nsession. All fields are optional.", "properties": { "agent_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Built-in agent to bind the fork to, switching it away from the source's agent/harness (e.g. fork a Claude session into a Codex one, or a Claude-SDK session into Claude Code). When `None`, the fork keeps the source's agent. Must be a built-in agent (one listed by `GET /v1/agents`).", "title": "Agent Id" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Title for the forked session. When `None`, the server derives `\"Fork of \"`.", "title": "Title" }, "up_to_response_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Truncation point for the copied history, e.g. `\"resp_abc123\"`. When set, only items up to and including the last item of that response are copied \u2014 items after it are dropped from the fork. When `None` (default), the full history is copied.", "title": "Up To Response Id" } }, "title": "SessionForkRequest", "type": "object" }, "SessionGitOptions": { "description": "Git worktree options for `POST /v1/sessions`.\n\nRequires `host_id` to be set (and therefore `workspace`, which\nis interpreted as the source repository directory). Two modes,\nselected by `existing_worktree`:\n\n- **create** (default): the server creates a git worktree on the\n host for a new branch and starts the runner in that worktree\n instead of the picked directory.\n- **bind** (`existing_worktree=True`): `workspace` already IS a\n pre-existing worktree; no worktree is created. `branch_name` is\n recorded as the session's `git_branch` for display and opt-in\n cleanup, and `base_branch` must not be set.\n\nSee designs/SESSION_GIT_WORKTREE.md.", "properties": { "base_branch": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional base ref to branch from, e.g. `\"main\"` or `\"origin/main\"`. `None` branches from the source repository's current `HEAD`. Create mode only \u2014 invalid with `existing_worktree`.", "title": "Base Branch" }, "branch_name": { "description": "In create mode, the new branch to create and check out, e.g. `\"feature/login\"`. In bind mode, the branch already checked out in the existing worktree. Validated against git ref-format rules; invalid names fail with `invalid_input`.", "title": "Branch Name", "type": "string" }, "existing_worktree": { "default": false, "description": "When `True`, bind to the pre-existing worktree at `workspace` instead of creating one (see above).", "title": "Existing Worktree", "type": "boolean" } }, "required": [ "branch_name" ], "title": "SessionGitOptions", "type": "object" }, "SessionHeartbeatEvent": { "description": "Idle-stream keepalive on `GET /v1/sessions/{id}/stream`.\n\nEmitted by the session-stream route on a fixed cadence whenever\nthe underlying publish queue has been quiet (no turn in flight,\nno resource events). Distinct from `HeartbeatEvent`\n(`response.heartbeat`), which is per-turn and is driven by\nthe runtime workflow while a response is producing output.\n\nWhy this exists: the session stream stays open across many turns\nand through idle periods (waiting for the user to type). Without\na periodic emit, intermediate proxies, OS-level sockets, and the\nclient's SSE read-timeout can leave a half-open stream\nundetected for minutes after a network event (laptop sleep,\nWi-Fi handoff). The heartbeat puts a regular byte on the wire\nso the client's read-timeout and the server's\n`request.is_disconnected()` check both fire promptly.\n\nConsumers MAY ignore the payload entirely (the bytes crossing\nthe wire are sufficient). The optional `server_time` mirrors\n`HeartbeatEvent` for symmetry and debugging.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "server_time": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "ISO 8601 UTC timestamp at emission, e.g. `\"2026-05-25T10:30:00Z\"`. `None` when the producer chose not to populate it.", "title": "Server Time" }, "type": { "const": "session.heartbeat", "description": "Always `\"session.heartbeat\"`.", "title": "Type", "type": "string" } }, "required": [ "type" ], "title": "SessionHeartbeatEvent", "type": "object" }, "SessionInputConsumedEvent": { "description": "A queued input item was materialized into conversation history.\n\nEmitted by `POST /v1/sessions/{id}/events` once per accepted\ninput item at the moment it is persisted into conversation\nhistory (either onto a steered active turn or as the seed item\nof a freshly-started one). Wire shape uses the NESTED envelope:\n`{\"type\": \"session.input.consumed\", \"data\": , \"sequence_number\": null}`.\n\nThe event name is **provisional** \u2014 it may be renamed in a\nfuture revision. Consumers should reference\n`SessionInputConsumedEvent` (or its `type` literal)\nrather than hardcoding the wire string.", "properties": { "data": { "$ref": "#/components/schemas/SessionInputConsumedPayload", "description": "The decoded queued-item payload \u2014 see `SessionInputConsumedPayload`." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.input.consumed", "description": "Always `\"session.input.consumed\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "data" ], "title": "SessionInputConsumedEvent", "type": "object" }, "SessionInputConsumedPayload": { "description": "Inner payload of a `SessionInputConsumedEvent`.\n\nEmitted by the sessions route handler at the moment a client\ninput is persisted into `conversation_items`. Carries the\npersisted-item shape so clients can render the input (e.g.\nthe user's message bubble) at the moment of acceptance.", "properties": { "cleared_pending_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "When this consumed message drains a `omnigent.runtime.pending_inputs` entry (a native- terminal web message round-tripping back from the transcript), the drained entry's id, e.g. `\"pending_a1b2c3\"`. Lets a client drop the matching optimistic bubble by id instead of by position. `None` for non-native messages and for messages that matched no pending entry (e.g. typed directly in the TUI).", "title": "Cleared Pending Id" }, "created_by": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Email of the human actor who posted the item, e.g. `\"alice@example.com\"`. `None` for agent/tool/system items and single-user mode. Mirrors `ConversationItem.to_api_dict` for live attribution.", "title": "Created By" }, "data": { "additionalProperties": true, "description": "Decoded item payload, e.g. `{\"role\": \"user\", \"content\": [{\"type\": \"input_text\", \"text\": \"Hello\"}]}`. Heterogeneous and `type`-specific.", "title": "Data", "type": "object" }, "item_id": { "description": "Stable identifier of the conversation item just persisted, e.g. `\"item_abc123\"`.", "title": "Item Id", "type": "string" }, "type": { "description": "The item type discriminator \u2014 `\"message\"` for user messages, `\"function_call_output\"` for tool results, etc. Mirrors `omnigent.server.schemas.SessionEventInput`'s `type` field.", "title": "Type", "type": "string" } }, "required": [ "item_id", "type", "data" ], "title": "SessionInputConsumedPayload", "type": "object" }, "SessionInterruptedEvent": { "description": "User-triggered cancel reached the loop.\n\nEmitted by `_publish_interrupted` in\n`omnigent/server/routes/sessions.py` when a client posts\na `{\"type\": \"interrupt\"}` to `POST /v1/sessions/{id}/events`. Co-emitted with\n`IncompleteEvent` (with the underlying response carrying\n`incomplete_details.reason == \"user_interrupt\"`) so off-the-\nshelf Responses parsers still close cleanly. Wire shape uses\nthe NESTED envelope verbatim from the existing emit site.", "properties": { "data": { "$ref": "#/components/schemas/SessionInterruptedPayload", "description": "The interrupt metadata \u2014 see `SessionInterruptedPayload`." }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.interrupted", "description": "Always `\"session.interrupted\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "data" ], "title": "SessionInterruptedEvent", "type": "object" }, "SessionInterruptedPayload": { "description": "Inner payload of a `SessionInterruptedEvent`.\n\nBuilt by `_publish_interrupted` in\n`omnigent/server/routes/sessions.py`.", "properties": { "requested_at": { "description": "Unix epoch seconds when the interrupt request reached the server, e.g. `1704067200`.", "title": "Requested At", "type": "integer" }, "response_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Optional active response id for terminal-backed integrations, e.g. `\"codex_turn_abc123\"`.", "title": "Response Id" } }, "required": [ "requested_at" ], "title": "SessionInterruptedPayload", "type": "object" }, "SessionLabelsResponse": { "description": "Lightweight response body for `GET /v1/sessions/{id}/labels`.", "properties": { "id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Id", "type": "string" }, "labels": { "additionalProperties": { "type": "string" }, "description": "Session-scoped guardrails labels. Empty dict when no labels have been written.", "title": "Labels", "type": "object" } }, "required": [ "id" ], "title": "SessionLabelsResponse", "type": "object" }, "SessionList": { "description": "Paginated list of sessions; `data` is a page of `SessionListItem`.", "properties": { "data": { "items": { "$ref": "#/components/schemas/SessionListItem" }, "title": "Data", "type": "array" }, "first_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "First Id" }, "has_more": { "default": false, "title": "Has More", "type": "boolean" }, "last_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Id" }, "object": { "const": "list", "default": "list", "title": "Object", "type": "string" } }, "title": "SessionList", "type": "object" }, "SessionListItem": { "description": "Lightweight session summary for `GET /v1/sessions` list responses.\n\nSame shape as `SessionResponse` minus `items`.", "properties": { "agent_id": { "description": "Durable identifier of the bound agent.", "title": "Agent Id", "type": "string" }, "agent_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Human-readable name of the bound agent, e.g. `\"research-agent\"`. `None` when the agent row cannot be found.", "title": "Agent Name" }, "archived": { "default": false, "description": "Whether the session is archived. Archived sessions are returned by `GET /v1/sessions` only when the request passes `include_archived=true`; the sidebar groups them into a dedicated \"Archived\" section. `False` for normal sessions.", "title": "Archived", "type": "boolean" }, "comments_count": { "default": 0, "description": "Total number of review comments (any status) on this session. Together with `comments_updated_at` it forms a change fingerprint: an add or edit bumps the timestamp, a delete changes the count, so the web client can invalidate its cached comment list when either field changes in a `WS /v1/sessions/updates` frame. `0` when the session has no comments or the server has no comment store wired.", "title": "Comments Count", "type": "integer" }, "comments_updated_at": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Unix epoch **microseconds** of the most recently mutated comment on this session (max `updated_at` across its comments). Microsecond precision keeps back-to-back mutations within one second distinguishable while staying an exact integer in JavaScript; clients only compare it for change. `None` when the session has no comments or the server has no comment store wired.", "title": "Comments Updated At" }, "created_at": { "description": "Unix epoch seconds of creation.", "title": "Created At", "type": "integer" }, "external_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Runtime-native session id this conversation wraps, e.g. a Claude Code session uuid for `omnigent claude` sessions. `None` for regular AP-only conversations. Lets the sidebar / picker render a runtime badge without a follow-up GET.", "title": "External Session Id" }, "git_branch": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Git branch checked out in the session's worktree, e.g. `\"feature/login\"`. Set only when the session was created with a server-created git worktree; `None` otherwise. The Web UI uses a non-`None` value to offer the \"delete local branch\" cleanup checkbox on session delete. See designs/SESSION_GIT_WORKTREE.md.", "title": "Git Branch" }, "host_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Host that launched the runner for this session.", "title": "Host Id" }, "host_online": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Whether the session's host tunnel is live (status online and fresh within the host liveness TTL). `None` when the session has no `host_id` (CLI/local). Distinguishes \"runner down but host can relaunch\" from \"host offline\" for the open-session view; not used by the sidebar.", "title": "Host Online" }, "id": { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "title": "Id", "type": "string" }, "labels": { "additionalProperties": { "type": "string" }, "description": "Session-scoped guardrails labels.", "title": "Labels", "type": "object" }, "owner": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The user_id of the session owner, or `None` when permissions are disabled. Included so the sidebar can display the owner without a separate API call.", "title": "Owner" }, "pending_elicitations_count": { "default": 0, "description": "Number of approval prompts currently waiting on this session. Powers the sidebar's \"needs attention\" badge so a user with several sessions running can tell which ones are blocked on them without opening each chat. Sourced from the Omnigent server's in-memory `omnigent.runtime.pending_elicitations` index, which mirrors every `response.elicitation_request` event passing through `session_stream` and decrements when a verdict is dispatched. `0` when the session has no outstanding elicitations.", "title": "Pending Elicitations Count", "type": "integer" }, "permission_level": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "The requesting user's numeric permission level on this session: `1` = read, `2` = edit, `3` = manage. `None` when permissions are disabled.", "title": "Permission Level" }, "reasoning_effort": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session reasoning-effort hint.", "title": "Reasoning Effort" }, "runner_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Runner currently bound to the session.", "title": "Runner Id" }, "runner_online": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Strict runner liveness \u2014 `True` iff a runner tunnel is currently registered for this session. Matches `GET /health`'s `runner_online` value. Strict: a dead runner on a live host reads `False` here (no host-relaunch optimism folded in), unlike the legacy conflated value. `None` when the server has no runner liveness lookup wired.", "title": "Runner Online" }, "status": { "description": "Derived session lifecycle status.", "enum": [ "idle", "running", "waiting", "failed" ], "title": "Status", "type": "string" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional human-readable title.", "title": "Title" }, "updated_at": { "description": "Unix epoch seconds of last update.", "title": "Updated At", "type": "integer" }, "viewer_last_seen": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "The *requesting user's* \"last seen\" wall-clock baseline in seconds for this session, or `None` when they have never seen it. Per-viewer (built from the server's in-memory per-user read-state, written by `PUT /v1/sessions/{id}/read-state`); the unread dot shows when `updated_at > viewer_last_seen` and the session is finished. In-memory only \u2014 resets on a server restart.", "title": "Viewer Last Seen" }, "viewer_unread": { "default": false, "description": "Whether the *requesting user* explicitly marked this session unread. Per-viewer; lifts the active-row dot suppression on the client. `False` by default.", "title": "Viewer Unread", "type": "boolean" }, "workspace": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Absolute path on disk where the runner cd's, e.g. `\"/Users/corey/universe/src/foo\"`. `None` for sessions that haven't been bound to a host workspace.", "title": "Workspace" } }, "required": [ "id", "agent_id", "status", "created_at", "updated_at" ], "title": "SessionListItem", "type": "object" }, "SessionModelEvent": { "description": "Active-model update from a terminal-backed integration.\n\nEmitted after an `external_model_change` POST from the\n`omnigent claude` transcript forwarder when the model is\nswitched inside the Claude Code terminal (a `/model` command or\nthe in-TUI picker). Lets the web model picker reflect a TUI-side\nswitch without a reload.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "model": { "description": "Tier alias the session is now on, e.g. `\"opus\"` \u2014 Claude Code's version-agnostic alias, matching the picker's vocabulary (not a pinned `\"claude-opus-4-8\"` id). Category: **transient** (SSE-only). The server also writes `model_override` on the conversation, so on reconnect clients restore the selection from the snapshot's `model_override` rather than from a replayed event.", "title": "Model", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.model", "description": "Always `\"session.model\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "model" ], "title": "SessionModelEvent", "type": "object" }, "SessionModelOptionsEvent": { "description": "Signal that a codex-native session's model catalog has resolved.\n\nModel options are fetched from the bound runner's live\nCodex app-server via `model/list` and cached on the session\nsnapshot. The initial snapshot can return an empty list while\nthis background fetch is in flight; this event tells connected\nclients to re-read the snapshot and apply its now-populated\n`model_options`.\n\nCarries no payload beyond the conversation id. The snapshot's\n`model_options` field remains the source of truth.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`. Category: **transient** (SSE-only). On reconnect, clients seed Codex model / effort controls from the session snapshot.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.model_options", "description": "Always `\"session.model_options\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id" ], "title": "SessionModelOptionsEvent", "type": "object" }, "SessionPresenceEvent": { "description": "The session's viewer list changed \u2014 full state, not a delta.\n\nEmitted on `GET /v1/sessions/{id}/stream` whenever a user\njoins, leaves (after the server-side grace window absorbs\nreconnect churn), or flips their idle aggregate, and once to\neach newly-connected stream as a snapshot-on-connect. Every\nevent carries the COMPLETE viewer list so clients replace their\nstate wholesale \u2014 missed events self-heal on the next event or\nreconnect. Viewers are scoped to the session *tree* (the root\nconversation and every sub-agent conversation under it), so a\nuser on a sub-agent page and a user on the root page appear in\neach other's lists. See `omnigent/server/presence.py` and\n`designs/UI/PRESENCE.md`.", "properties": { "conversation_id": { "description": "The conversation whose stream delivered this event \u2014 the root or a sub-agent conversation, e.g. `\"conv_abc123\"`. Matches the streamed conversation (not necessarily the tree's root) so clients can guard events by the conversation they are viewing.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.presence", "description": "Always `\"session.presence\"`.", "title": "Type", "type": "string" }, "viewers": { "description": "All users currently viewing any conversation in the session tree (including the receiving user \u2014 the web filters self out for display), ordered by join time.", "items": { "$ref": "#/components/schemas/PresenceViewer" }, "title": "Viewers", "type": "array" } }, "required": [ "type", "conversation_id", "viewers" ], "title": "SessionPresenceEvent", "type": "object" }, "SessionReasoningEffortEvent": { "description": "Active reasoning-effort update from a terminal-backed integration.\n\nEmitted after an `external_reasoning_effort_change` POST from a native\nterminal forwarder when the user changes the thinking level inside the\nterminal UI. Lets the web effort picker reflect a TUI-side switch without\na reload.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "reasoning_effort": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Reasoning effort now active for the session, e.g. `\"medium\"`, or `None` when Codex cleared to its default. Category: **transient** (SSE-only). The server also writes `reasoning_effort` on the conversation, so on reconnect clients restore the selection from the session snapshot rather than from a replayed event.", "title": "Reasoning Effort" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.reasoning_effort", "description": "Always `\"session.reasoning_effort\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id" ], "title": "SessionReasoningEffortEvent", "type": "object" }, "SessionResourceCreatedEvent": { "description": "A session resource was created.\n\nEmitted when a terminal is launched, a file is uploaded, or\nany other resource is materialized under a session. Wire shape\nis FLAT: `{\"type\": \"session.resource.created\", \"resource\": }`.", "properties": { "resource": { "additionalProperties": true, "description": "The newly created resource object.", "title": "Resource", "type": "object" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.resource.created", "description": "Always `\"session.resource.created\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "resource" ], "title": "SessionResourceCreatedEvent", "type": "object" }, "SessionResourceDeletedEvent": { "description": "A session resource was deleted.\n\nEmitted when a terminal is closed, a file is deleted, or\nany other resource is removed from a session.", "properties": { "resource_id": { "description": "Opaque id of the deleted resource.", "title": "Resource Id", "type": "string" }, "resource_type": { "description": "Type of the deleted resource, e.g. `\"terminal\"`, `\"file\"`.", "title": "Resource Type", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Owning session/conversation id.", "title": "Session Id", "type": "string" }, "type": { "const": "session.resource.deleted", "description": "Always `\"session.resource.deleted\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "resource_id", "resource_type", "session_id" ], "title": "SessionResourceDeletedEvent", "type": "object" }, "SessionResourceObject": { "additionalProperties": false, "description": "API representation of a session-scoped resource handle.", "properties": { "environment": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "For terminal resources, the environment id the terminal actually runs in. Omitted for non-terminal resources.", "title": "Environment" }, "id": { "description": "Opaque resource identifier, e.g. `\"default\"` or `\"terminal_bash_s1\"`.", "title": "Id", "type": "string" }, "metadata": { "additionalProperties": true, "description": "Resource-type-specific metadata.", "title": "Metadata", "type": "object" }, "name": { "description": "Human-readable display name. Not required to be globally unique.", "title": "Name", "type": "string" }, "object": { "const": "session.resource", "description": "Fixed resource type, always `\"session.resource\"`.", "title": "Object", "type": "string" }, "session_id": { "description": "Owning session/conversation id.", "title": "Session Id", "type": "string" }, "type": { "description": "Resource kind, initially `\"environment\"`, `\"terminal\"`, or `\"file\"`.", "enum": [ "environment", "terminal", "file" ], "title": "Type", "type": "string" } }, "required": [ "id", "object", "type", "session_id", "name" ], "title": "SessionResourceObject", "type": "object" }, "SessionResourcePaginatedList": { "description": "Public paginated list of session resources.", "properties": { "data": { "items": { "$ref": "#/components/schemas/SessionResourceObject" }, "title": "Data", "type": "array" }, "first_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "First Id" }, "has_more": { "default": false, "title": "Has More", "type": "boolean" }, "last_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Id" }, "object": { "const": "list", "default": "list", "title": "Object", "type": "string" } }, "title": "SessionResourcePaginatedList", "type": "object" }, "SessionResponse": { "description": "API representation of a session.\n\nReturned by `POST /v1/sessions`, `GET /v1/sessions/{id}`,\nand `PATCH /v1/sessions/{id}`.", "properties": { "active_response_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Response id of the turn currently in flight, or `None` when the session is idle. Sourced from the server's `_session_active_response_cache` at snapshot build time so a client connecting mid-turn can reopen a streaming `activeResponse` \u2014 the SSE stream is snapshot + live tail with no replay, so the turn-start `running` edge that carried this id is not re-sent on reconnect. Today only native-terminal forwarders (claude-native) stamp a turn id on their status edges; other harnesses leave this `None`.", "title": "Active Response Id" }, "agent_id": { "description": "Durable identifier of the bound agent, e.g. `\"ag_abc123\"`. Stable across renames of the agent.", "title": "Agent Id", "type": "string" }, "agent_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Human-readable name of the bound agent, e.g. `\"research-agent\"`. Loaded from the agent row at snapshot-build time. `None` when the agent row cannot be found (deleted or orphaned session).", "title": "Agent Name" }, "archived": { "default": false, "description": "Whether the session is archived. Archived sessions are hidden from the default sidebar listing and surface only behind the \"Show archived\" toggle. `False` for normal sessions. Toggled via `PATCH /v1/sessions/{id}`.", "title": "Archived", "type": "boolean" }, "background_task_count": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Background shells (claude-native) still running as of the last status edge, so a reload re-shows \"N shells still running\" even though the session has settled to `\"idle\"`. `None` (the default / omitted) when no shells are tracked.", "title": "Background Task Count" }, "context_window": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "The model's context window size in tokens as looked up server-side from litellm's registry (or from the `AP_CONTEXT_WINDOW_OVERRIDE` env var), e.g. `200_000`. `None` when the model is not in litellm's registry and no override is set.", "title": "Context Window" }, "cost_control_mode_override": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session cost-control switch: `\"on\"` activates the spec's configured cost-control mode, `\"off\"` disables cost control for this session. `None` means no override is active (the spec default applies). Set at create time or via `PATCH /v1/sessions/{id}` (the web \"Cost Optimized\" toggle); read by the cost-control advisor pipeline.", "title": "Cost Control Mode Override" }, "created_at": { "description": "Unix epoch seconds of creation.", "title": "Created At", "type": "integer" }, "external_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Runtime-native session id this conversation wraps, e.g. a Claude Code session uuid for `omnigent claude` sessions. `None` for regular AP-only conversations. Populated by the wrapper bridge.", "title": "External Session Id" }, "git_branch": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Git branch checked out in the session's worktree, e.g. `\"feature/login\"`. Set only when the session was created with a server-created git worktree; `None` otherwise. The Web UI uses a non-`None` value to offer the \"delete local branch\" cleanup checkbox on session delete. See designs/SESSION_GIT_WORKTREE.md.", "title": "Git Branch" }, "harness": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The bound agent's canonical harness, e.g. `\"claude-sdk\"` or `\"openai-agents\"`. Lets the client render the active credential for the correct provider family instead of inferring it from the model string (which is wrong when the agent declares no model). `None` when the agent cannot be looked up.", "title": "Harness" }, "host_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Host that launched (or should launch) the runner for this session, e.g. `\"host_a1b2c3d4...\"`. `None` for CLI-initiated sessions.", "title": "Host Id" }, "host_online": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Whether the session's host tunnel is live (status online and fresh within the host liveness TTL). `None` when the session has no `host_id` (CLI/local). Used only to choose what the open view shows when `runner_online` is `False` \u2014 host alive \u21d2 \"send a message to wake the runner\"; host dead \u21d2 \"reconnect / fork\". Never participates in the reachability decision.", "title": "Host Online" }, "host_resumable": { "default": false, "description": "Whether this session is bound to a dormant managed host the server can wake in place (its provider sets `SandboxLauncher.can_resume`). The open view reads it only when `host_online` is `False`, to split a confirmed host-down into a recoverable \"asleep\" state (send a message \u2014 the relaunch path resumes the sandbox) versus the terminal `host_offline` dead-end (reconnect from your machine / fork). `False` for non-managed or non-resumable hosts.", "title": "Host Resumable", "type": "boolean" }, "id": { "description": "Unique session identifier (also the underlying conversation ID), e.g. `\"conv_abc123\"`.", "title": "Id", "type": "string" }, "items": { "description": "Committed conversation items in chronological order. Empty for a freshly created session.", "items": { "$ref": "#/components/schemas/ConversationItem" }, "title": "Items", "type": "array" }, "labels": { "additionalProperties": { "type": "string" }, "description": "Session-scoped guardrails labels. Empty dict when no labels have been written.", "title": "Labels", "type": "object" }, "last_task_error": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "description": "Error details from the most recently failed task. Only present when `status == \"failed\"` and the task stored an error. Lets clients display the failure reason on historical load without relying on the transient `response.error` SSE event (which may have been emitted before the web client subscribed). Format mirrors the `RetryErrorDetail` SSE shape: `{\"code\": \"executor_error\", \"message\": \"...\"}`. `None` in all other cases.", "title": "Last Task Error" }, "last_total_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "Total token count (input + output) from the most recently completed task's `usage`, e.g. `45231`. `None` when no task has completed yet. Lets clients seed their context-ring on conversation resume without waiting for the next `response.completed` SSE event.", "title": "Last Total Tokens" }, "llm_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The LLM model identifier from the bound agent's spec, e.g. `\"anthropic/claude-sonnet-4-6\"`. `None` when the agent has no explicit `llm:` block or the agent cannot be looked up.", "title": "Llm Model" }, "model_options": { "description": "Codex app-server `model/list` options for codex-native sessions, including each model's supported reasoning efforts. Empty for non-codex-native sessions or while the bound runner / Codex app-server cannot answer yet.", "items": { "additionalProperties": true, "type": "object" }, "title": "Model Options", "type": "array" }, "model_override": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session LLM model override, e.g. `\"claude-opus-4-7\"`. `None` means no override is active (the agent's `llm_model` applies). Set via `PATCH /v1/sessions/{id}` or the REPL's `/model` command; both write the same column so the web UI and the TUI stay in sync.", "title": "Model Override" }, "parent_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "For sub-agent sessions, the parent conversation's id, e.g. `\"conv_parent987\"`. `None` for top-level sessions. Lets clients identify a session as a child and link back to its parent without an extra round-trip \u2014 the same conversation row exposes this via `parent_conversation_id` internally.", "title": "Parent Session Id" }, "pending_elicitations": { "description": "Outstanding approval prompts on this session at the moment the snapshot was built \u2014 the original `response.elicitation_request` event dicts. Lets the UI render the ApprovalCard on cold load, since the live SSE stream has no replay and a prompt emitted before the user opened the chat would otherwise vanish. Empty list when no prompts are outstanding. Sourced from the Omnigent server's in-memory `omnigent.runtime.pending_elicitations` index.", "items": { "additionalProperties": true, "type": "object" }, "title": "Pending Elicitations", "type": "array" }, "pending_inputs": { "description": "Un-consumed web-composer user messages on native-terminal (claude-native / codex-native) sessions at snapshot time, each `{\"pending_id\", \"content\"}`. Native sessions don't persist a web message at POST time (the transcript forwarder is the single writer), so a client that posted then navigated away / rebound would lose its optimistic bubble; replaying these re-hydrates it. Empty list otherwise. Sourced from the in-memory `omnigent.runtime.pending_inputs` index.", "items": { "additionalProperties": true, "type": "object" }, "title": "Pending Inputs", "type": "array" }, "permission_level": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "description": "The requesting user's numeric permission level on this session: `1` = read, `2` = edit, `3` = manage. `None` when permissions are disabled (single-user mode without a permission store).", "title": "Permission Level" }, "reasoning_effort": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session reasoning-effort hint. Accepted metadata values are `\"none\"`, `\"minimal\"`, `\"low\"`, `\"medium\"`, `\"high\"`, `\"xhigh\"`, and `\"max\"`. Provider-specific support is validated when a turn executes. `None` means use the agent default.", "title": "Reasoning Effort" }, "root_conversation_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The id of this session's spawn-tree root, e.g. `\"conv_root1\"`. Equals `id` for top-level sessions; for sub-agents it points at the top-level ancestor. Lets orchestration tools (e.g. `sys_session_close`) confirm a target shares the caller's spawn tree over the REST path. `None` only when the underlying row predates the `root_conversation_id` column (not expected post-migration).", "title": "Root Conversation Id" }, "runner_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Runner currently bound to this session, e.g. `\"runner_abc123\"`. `None` until a client binds one via `PATCH /v1/sessions/{id}`.", "title": "Runner Id" }, "runner_online": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Strict runner liveness \u2014 `True` iff a runner tunnel is currently registered for this session. This is the sole reachability signal: `True` means the client can chat normally. It does **not** fold in host-relaunch optimism (a dead runner on a live host reads `False` here, not `True`) \u2014 the open-session view pairs it with `host_online` to decide what to show. `None` when the server has no runner liveness lookup wired.", "title": "Runner Online" }, "sandbox_status": { "anyOf": [ { "$ref": "#/components/schemas/SandboxStatus" }, { "type": "null" } ], "description": "Managed-sandbox launch progress while the session's background sandbox launch is in flight or has failed \u2014 see `SandboxStatus`. `None` for sessions without a managed launch and once the launch succeeds. Sourced from the Omnigent server's in-memory `_session_sandbox_status_cache` at snapshot build time, so a client opening the session mid-launch sees the current stage." }, "skills": { "description": "Skills the bound agent has access to \u2014 the merged result of the agent spec's bundled `skills` and the host-scope skills discovered along the agent workdir / `~/.claude/skills/` (subject to the spec's `skills_filter`). Mirrors what the TUI passes to the runner at startup. Empty list when the agent spec cannot be loaded, or when bundled + host discovery yields nothing.", "items": { "$ref": "#/components/schemas/SkillSummary" }, "title": "Skills", "type": "array" }, "status": { "description": "Session lifecycle status. One of `\"idle\"` (no loop running), `\"running\"` (loop executing), `\"waiting\"` (loop parked on background work / sub-agents), or `\"failed\"` (terminal failure). Current read paths collapse `\"waiting\"` -> `\"running\"` before building this snapshot; the literal stays a superset of what the runtime can produce so a server that forwards the raw status never 500s on serialization.", "enum": [ "idle", "running", "waiting", "failed" ], "title": "Status", "type": "string" }, "sub_agent_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "For sub-agent sessions, the sub-agent type name within the parent's spec tree, e.g. `\"summarizer\"`. `None` for top-level sessions.", "title": "Sub Agent Name" }, "terminal_launch_args": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Pass-through CLI args the native terminal wrapper (claude / codex) was launched with, e.g. `[\"--dangerously-skip-permissions\"]`. `None` for non-native sessions or a native session launched with none. Lets the launcher reproduce the command on resume.", "title": "Terminal Launch Args" }, "terminal_pending": { "default": false, "description": "`True` while the runner is auto-creating a terminal-first session's terminal (claude-native / codex-native), so the Web UI shows a spinner on the Terminal pill instead of a silent greyed-out button. Cleared to `False` once the terminal lands or auto-create fails; from then on the client relies purely on whether a terminal resource exists. Sourced from the Omnigent server's in-memory `_session_terminal_pending_cache` at snapshot build time, so a client connecting mid-spin-up still sees the spinner.", "title": "Terminal Pending", "type": "boolean" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional human-readable title, e.g. `\"debugging auth flow\"`. `None` when unset.", "title": "Title" }, "todos": { "description": "Current Claude Code todo list items for `omnigent claude` sessions, as raw dicts from Claude's todo JSON file. Each dict has `content`, `status`, and `activeForm` keys. Empty list for non-claude-native sessions or when no todos have been reported yet. Sourced from the Omnigent server's in-memory `_session_todos_cache`.", "items": { "additionalProperties": true, "type": "object" }, "title": "Todos", "type": "array" }, "total_cost_usd": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "description": "Cumulative LLM spend for this session in USD, e.g. `0.42`. `None` when the session is **unpriced** \u2014 no turn has been priced yet (the model is absent from the pricing catalog, or no usage has been recorded) \u2014 so clients render \"\u2014\" rather than a misleading `$0.00`. Server-computed (cache-aware for relay/codex, exact billing for claude-native), the same total the cost-budget policy gates on. Lets clients seed their cost indicator on resume without waiting for the next `session.usage` SSE event.", "title": "Total Cost Usd" }, "usage_by_model": { "anyOf": [ { "additionalProperties": { "$ref": "#/components/schemas/ModelUsage" }, "type": "object" }, { "type": "null" } ], "description": "Per-model breakdown of the same subtree usage, keyed by the raw harness model id, e.g. `{\"claude-sonnet-4-6\": ModelUsage(input_tokens=12000, ...)}`. `None` when no per-model usage has been recorded (older sessions recorded before this field existed, or before the first turn). Lets the UI show which models a session spent its tokens / budget on.", "title": "Usage By Model" }, "workspace": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Absolute path on disk where the runner cd's, e.g. `\"/Users/corey/universe/src/foo\"`. Set when the session was bound to a host workspace at create-time, or when the CLI captured `os.getcwd()` at session-create. Always `None` when not yet validated against a host. When a git worktree was created for the session, this is the worktree directory path.", "title": "Workspace" } }, "required": [ "id", "agent_id", "status", "created_at" ], "title": "SessionResponse", "type": "object" }, "SessionSandboxStatusEvent": { "description": "Managed-sandbox launch progress for a `host_type=\"managed\"` session.\n\nA managed create returns before its sandbox exists; the Omnigent\nserver emits this event as the background launch pipeline advances\nso the Web UI can show live provisioning progress on the session\npage instead of a silent dead chat: sandbox provision \u2192 repository\nclone \u2192 host startup \u2192 runner connect \u2192 ready, or a terminal\nfailure with the reason.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Failure detail when `stage == \"failed\"`, e.g. `\"managed sandbox launch failed: spend limit reached\"`. `None` otherwise. Category: **transient** (SSE-only). On reconnect, clients seed the progress indicator from the session snapshot's `sandbox_status` field, which is populated by `_session_sandbox_status_cache` at snapshot build time.", "title": "Error" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "stage": { "description": "The launch stage just entered, e.g. `\"provisioning\"` \u2014 see `SandboxStatus` for the full pipeline order.", "enum": [ "provisioning", "cloning", "starting", "connecting", "ready", "failed" ], "title": "Stage", "type": "string" }, "type": { "const": "session.sandbox_status", "description": "Always `\"session.sandbox_status\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "stage" ], "title": "SessionSandboxStatusEvent", "type": "object" }, "SessionSkillsEvent": { "description": "Signal that a session's runner-owned skills have resolved.\n\nSkills are discovered against the bound runner's filesystem and\nfetched off the session-snapshot hot path: the snapshot kicks a\nsingle background fetch (`_load_runner_skills` in\n`omnigent/server/routes/sessions.py`) and serves `[]` until\nit lands. This event fires the moment that background fetch\npopulates the per-session skills cache, so a connected web client\ncan re-read the snapshot and fill its slash-command menu instead\nof waiting for the next bind.\n\nCarries no payload beyond the conversation id \u2014 it is a \"skills\nare ready, re-read the snapshot\" nudge, mirroring the\ninvalidate-then-refetch shape used by\n`SessionChangedFilesInvalidatedEvent`. The snapshot's\n`skills` field (now cache-backed) stays the source of truth.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`. Category: **transient** (SSE-only). On reconnect, clients seed the menu from the session snapshot's `skills` field, which is populated by the runner-skills cache at snapshot build time.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.skills", "description": "Always `\"session.skills\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id" ], "title": "SessionSkillsEvent", "type": "object" }, "SessionStatusEvent": { "description": "Session lifecycle status transition.\n\nEmitted by the runtime / session route handler at every\ntransition between `launching` / `running` / `waiting` /\n`idle` / `failed`. Wire shape is\nFLAT (not enveloped): `{\"type\": \"session.status\", \"conversation_id\": \"...\", \"status\": \"...\", \"sequence_number\": null}`.\n\nThe `waiting` value is emitted by the runtime's parent agent\nloop when it parks on the `async_work_complete` drain\n(`_drain_async_completions(block_for_one=True)` in\n`omnigent/runtime/workflow.py`) \u2014 i.e. while the parent\nturn is suspended waiting for background tools or sub-agents\nto complete. Per the session-rearchitecture spec \u00a73\n(\"Event types and direction\"), `waiting` is the\nsession-status companion of the spec's `turn.waiting`\ntransient \u2014 clients should render the session as actively\nblocked-on-async-work, distinct from `running`. When the\ndrain wakes (a child completed), the runtime emits a follow-up\n`running` to resume.", "properties": { "background_task_count": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Background Task Count" }, "conversation_id": { "description": "The conversation/session identifier whose status changed, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "error": { "anyOf": [ { "$ref": "#/components/schemas/ErrorDetail" }, { "type": "null" } ], "default": null, "description": "Machine-readable failure detail, present only when `status == \"failed\"`. Carries the message the runner attached when a turn died \u2014 most importantly a SETUP-phase failure (spec resolution, spawn-env build) that ends the turn before any `response.failed` event is emitted. `None` for every non-failed transition. Clients render `error.message` as the terminal error line; without it a setup failure shows as a silent end. Category: **transient** (SSE-only). Status is rederived on reconnect from the cached last-relayed turn lifecycle event or by re-querying the runner; not persisted by the runtime." }, "response_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "Optional active response id for terminal-backed integrations, e.g. `\"codex_turn_abc123\"`. Clients use it to associate coarse session status edges with the assistant bubble they describe. `None` for ordinary in-process runtime edges.", "title": "Response Id" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "status": { "description": "New session status. `\"launching\"` (session or child task created, but no concrete harness start observed), `\"idle\"` (no loop running), `\"running\"` (loop executing), `\"waiting\"` (parent turn parked on the async-work drain), or `\"failed\"` (terminal failure).", "enum": [ "idle", "launching", "running", "waiting", "failed" ], "title": "Status", "type": "string" }, "type": { "const": "session.status", "description": "Always `\"session.status\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "status" ], "title": "SessionStatusEvent", "type": "object" }, "SessionSupersededEvent": { "description": "This conversation was superseded by another and clients should\nfollow to it.\n\nEmitted by `_publish_session_superseded` in\n`omnigent/server/routes/sessions.py` when the claude-native\nforwarder rotates a session away on a Claude `/clear` (the old\nconversation keeps its history but the live terminal moves to a\nfresh conversation \u2014 see `_post_clear_supersession` in\n`omnigent/claude_native_forwarder.py`). A client actively viewing\nthe superseded conversation auto-redirects to `target_conversation_id`.\n\nCategory: **transient** (SSE-only), live-only by design. There is no\nSSE replay: a client that connects after the rotation does not get\nthis event. The durable counterpart is the persisted notice message\nappended to the old conversation (a `message` item linking to the\nnew conversation), which a reloading client renders instead of being\nforce-redirected.\n\nThe wire shape is FLAT (not enveloped):\n`{\"type\": \"session.superseded\", \"conversation_id\": , \"target_conversation_id\": , \"reason\": \"clear\"}`.", "properties": { "conversation_id": { "description": "The superseded (old) conversation id this event rides the stream of, e.g. `\"conv_old\"`.", "title": "Conversation Id", "type": "string" }, "reason": { "const": "clear", "default": "clear", "description": "Why the session was superseded. Currently always `\"clear\"` (a Claude Code `/clear`); kept as a field so the client can branch on future supersession causes.", "title": "Reason", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "target_conversation_id": { "description": "The conversation to follow to, e.g. `\"conv_new\"`.", "title": "Target Conversation Id", "type": "string" }, "type": { "const": "session.superseded", "description": "Always `\"session.superseded\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "target_conversation_id" ], "title": "SessionSupersededEvent", "type": "object" }, "SessionSwitchAgentRequest": { "additionalProperties": false, "description": "Request body for `POST /v1/sessions/{id}/switch-agent`.\n\nRebinds an existing session in place to a different agent/harness,\nkeeping the same session (transcript, comments, files, workspace).\nUnlike fork, no new session is created.", "properties": { "agent_id": { "description": "Built-in agent to switch the session to, e.g. `\"ag_builtin_codex\"`. Must be a built-in agent (one listed by `GET /v1/agents`) and different from the session's current agent.", "title": "Agent Id", "type": "string" } }, "required": [ "agent_id" ], "title": "SessionSwitchAgentRequest", "type": "object" }, "SessionTerminalActivityEvent": { "description": "A terminal's pane produced output (runner-determined activity pulse).\n\nPowers the web \"active\" badge for any terminal without a client PTY\nattach \u2014 the runner's per-terminal pane watcher emits this when the\npane content changes. Transient (a live pulse; not persisted, not in\nthe connect snapshot).", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Owning session/conversation id.", "title": "Session Id", "type": "string" }, "terminal_id": { "description": "Opaque terminal resource id, e.g. `\"terminal_zsh_s1\"`.", "title": "Terminal Id", "type": "string" }, "type": { "const": "session.terminal.activity", "description": "Always `\"session.terminal.activity\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "session_id", "terminal_id" ], "title": "SessionTerminalActivityEvent", "type": "object" }, "SessionTerminalPendingEvent": { "description": "Terminal spin-up status for a terminal-first session.\n\nTwo sources emit this event:\n\n1. The Omnigent server at `POST /v1/sessions` for host-launched\n terminal-first sessions \u2014 the earliest possible point, before\n the runner even starts, so the spinner appears immediately on\n session create rather than after the runner boots.\n2. The Omnigent relay when the runner's `session.terminal_pending` frame\n arrives \u2014 covers non-host-launched sessions (e.g. server-dispatched\n sub-agents) and carries the authoritative `pending=False` clear\n emitted by the runner's `finally` block.\n\nTogether they allow web to show a spinner on the Terminal pill\nwhile the backend boots the terminal instead of a silent greyed-out\nbutton, and to distinguish \"still starting up\" from \"no terminal\"\n(killed or never created).", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "pending": { "description": "`True` while the terminal is being created; `False` once it lands or auto-create fails. Category: **transient** (SSE-only). On reconnect, clients seed the spinner from the session snapshot's `terminal_pending` field, which is populated by `_session_terminal_pending_cache` at snapshot build time.", "title": "Pending", "type": "boolean" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "type": { "const": "session.terminal_pending", "description": "Always `\"session.terminal_pending\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "pending" ], "title": "SessionTerminalPendingEvent", "type": "object" }, "SessionTodosEvent": { "description": "Todo-list update from a Claude Code terminal-backed session.\n\nEmitted after an `external_session_todos` POST from the\n`omnigent claude` transcript forwarder, which captures todo\nupdates via `PostToolUse`/`TodoWrite` hook events from Claude\nCode and forwards them to the Omnigent server. Lets web render a\nlive todo panel in the right column without polling.", "properties": { "conversation_id": { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "todos": { "description": "Current todo items read from Claude's todo file. Each entry is a raw dict with `content` (str), `status` (`\"pending\"` | `\"in_progress\"` | `\"completed\"`), and `activeForm` (str, the gerund form) keys, e.g. `[{\"content\": \"Fix the bug\", \"status\": \"in_progress\", \"activeForm\": \"Fixing the bug\"}]`. Category: **transient** (SSE-only). On reconnect, clients seed the panel from the session snapshot's `todos` field, which is populated by `_session_todos_cache` at snapshot build time.", "items": { "additionalProperties": true, "type": "object" }, "title": "Todos", "type": "array" }, "type": { "const": "session.todos", "description": "Always `\"session.todos\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "conversation_id", "todos" ], "title": "SessionTodosEvent", "type": "object" }, "SessionUsageEvent": { "description": "Token-usage update from a terminal-backed integration.\n\nEmitted after an `external_session_usage` POST from an\nout-of-AP runtime (e.g. the `omnigent claude` transcript\nforwarder). Either field may be absent; clients should leave\ncached values untouched for missing fields.", "properties": { "context_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "`input + cache_creation + cache_read` from the latest assistant `message.usage`. `None` on a window-only broadcast.", "title": "Context Tokens" }, "context_window": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Resolved window in tokens (e.g. 200_000 normally, 1_000_000 with `opus[1m]` / `sonnet[1m]`). `None` on a tokens-only broadcast.", "title": "Context Window" }, "conversation_id": { "description": "Session identifier.", "title": "Conversation Id", "type": "string" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "total_cost_usd": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "default": null, "description": "Cumulative session spend in USD after this update, e.g. `0.42` \u2014 the server-computed total the cost-budget policy gates on. Present **only when the session is priced**; omitted (`None`, stripped by `exclude_none`) when unpriced or on a broadcast that carries no cost change, so the client keeps its prior value (the snapshot seeds the initial \"\u2014\" for an unpriced session). Once a session is priced the total only grows, so it never reverts to unpriced.", "title": "Total Cost Usd" }, "type": { "const": "session.usage", "description": "Always `\"session.usage\"`.", "title": "Type", "type": "string" }, "usage_by_model": { "anyOf": [ { "additionalProperties": { "$ref": "#/components/schemas/ModelUsage" }, "type": "object" }, { "type": "null" } ], "default": null, "description": "Per-model breakdown of the same subtree usage after this update, keyed by raw harness model id, e.g. `{\"claude-sonnet-4-6\": ModelUsage(input_tokens=12000, ...)}`. `None` (stripped by `exclude_none`) on a broadcast that carries no per-model change, so the client keeps its cached map. Category: **transient** (SSE-only). On reconnect, clients seed the ring from the session snapshot's `last_total_tokens` and `context_window`, the cost indicator from `total_cost_usd`, and the per-model token breakdown from `usage_by_model`.", "title": "Usage By Model" } }, "required": [ "type", "conversation_id" ], "title": "SessionUsageEvent", "type": "object" }, "SetCodexGoalRequest": { "additionalProperties": false, "description": "Request body for `PUT /v1/sessions/{id}/codex_goal`.", "properties": { "objective": { "description": "Goal objective text, e.g. `\"Finish the migration and keep tests green\"`. Must be non-empty after trimming and no longer than 4000 characters, matching Codex app-server's goal contract.", "maxLength": 4000, "minLength": 1, "title": "Objective", "type": "string" }, "status": { "anyOf": [ { "enum": [ "active", "paused" ], "type": "string" }, { "type": "null" } ], "description": "Optional user-selected goal status. `\"active\"` starts or resumes the goal, and `\"paused\"` stores it paused. Omit this field to preserve Codex's current lifecycle state.", "title": "Status" }, "token_budget": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "description": "Optional positive token budget, e.g. `40000`. Explicit JSON `null` clears the Codex goal budget; omitting the field leaves it absent from the forwarded request.", "title": "Token Budget" } }, "required": [ "objective" ], "title": "SetCodexGoalRequest", "type": "object" }, "SkillSummary": { "description": "Safe subset of a discovered skill for API exposure.\n\nSurfaces the skill name and one-line description so clients\n(e.g. the web composer's slash-command menu) can list which\nskills the session has access to. The full skill `content`\nis intentionally omitted \u2014 it's only loaded server-side when\nthe harness invokes the skill, and it can be large.", "properties": { "description": { "description": "One-line summary from the SKILL.md frontmatter, e.g. `\"Triage open GitHub issues in the repo.\"`.", "title": "Description", "type": "string" }, "name": { "description": "Skill identifier as parsed from the SKILL.md frontmatter, e.g. `\"triage-issues\"`. Lowercase kebab-case.", "title": "Name", "type": "string" } }, "required": [ "name", "description" ], "title": "SkillSummary", "type": "object" }, "SlashCommandData": { "description": "Data payload for a slash-command invocation observed in a\nharness transcript (today: Claude Code's embedded TUI).\n\nListed in `NON_CONTENT_ITEM_TYPES` so the agent loop's\nhistory filter skips it \u2014 a downstream LLM never sees this as a\nphantom tool call. Field names mirror `function_call` so the\nweb renderer can reuse the tool-card layout.\n\n**Parameters**\n\n- `agent` \u2014 Harness/agent name, e.g. `\"claude-native-ui\"`. Serialized as `\"model\"` for parity with other items.", "properties": { "arguments": { "description": "Raw `` text. Empty when none.", "title": "Arguments", "type": "string" }, "kind": { "default": "skill", "description": "`\"skill\"` for plugin/Skill invocations, `\"command\"` for surfaced CLI built-ins (`/effort`, `/clear`, `/compact`, `/model`, `/ultrareview`). The web renderer uses this to pick the prefix label and icon. Defaults to `\"skill\"` so persisted items predating this field deserialize without backfill.", "enum": [ "skill", "command" ], "title": "Kind", "type": "string" }, "model": { "title": "Model", "type": "string" }, "name": { "description": "Command name with leading `/` stripped, e.g. `\"dev-productivity:simplify\"`.", "title": "Name", "type": "string" }, "output": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "`` text when present, else `None` (the common case \u2014 Skills act via the next assistant turn, not stdout).", "title": "Output" } }, "required": [ "model", "name", "arguments" ], "title": "SlashCommandData", "type": "object" }, "TerminalCommandData": { "description": "Data payload for a runner-side terminal command (`!cmd`) observed\nin a harness transcript (today: Claude Code's embedded TUI).\n\nListed in `NON_CONTENT_ITEM_TYPES` so the agent loop never\ninjects this as phantom content into the LLM's message history.\n\nClaude Code writes two sibling transcript records per `!cmd`\ninvocation: one `` record and one combined\n``/`` record. Each maps to one\n`terminal_command` item with `kind=\"input\"` or\n`kind=\"output\"` respectively.", "properties": { "input": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "The raw command string, e.g. `\"pwd\"`. Present when `kind=\"input\"`, `None` otherwise.", "title": "Input" }, "kind": { "description": "`\"input\"` for the command text, `\"output\"` for the combined stdout/stderr result.", "enum": [ "input", "output" ], "title": "Kind", "type": "string" }, "stderr": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Captured stderr text. Present when `kind=\"output\"`, `None` otherwise.", "title": "Stderr" }, "stdout": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Captured stdout text. Present when `kind=\"output\"`, `None` otherwise.", "title": "Stdout" } }, "required": [ "kind" ], "title": "TerminalCommandData", "type": "object" }, "TurnCancelledEvent": { "description": "Emitted when a turn is interrupted by the user or system.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "title": "Session Id", "type": "string" }, "type": { "const": "turn.cancelled", "description": "Fixed literal `\"turn.cancelled\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "session_id" ], "title": "TurnCancelledEvent", "type": "object" }, "TurnCompletedEvent": { "description": "Emitted when a turn finishes successfully with no pending work.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "title": "Session Id", "type": "string" }, "type": { "const": "turn.completed", "description": "Fixed literal `\"turn.completed\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "session_id" ], "title": "TurnCompletedEvent", "type": "object" }, "TurnFailedEvent": { "description": "Emitted when a turn fails due to an LLM error, timeout, or crash.", "properties": { "error": { "additionalProperties": true, "description": "Error details, e.g. `{\"message\": \"LLM timeout\", \"type\": \"TimeoutError\"}`.", "title": "Error", "type": "object" }, "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "title": "Session Id", "type": "string" }, "type": { "const": "turn.failed", "description": "Fixed literal `\"turn.failed\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "session_id" ], "title": "TurnFailedEvent", "type": "object" }, "TurnStartedEvent": { "description": "Emitted when the runner starts a new turn for a session.", "properties": { "sequence_number": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "title": "Sequence Number" }, "session_id": { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "title": "Session Id", "type": "string" }, "type": { "const": "turn.started", "description": "Fixed literal `\"turn.started\"`.", "title": "Type", "type": "string" } }, "required": [ "type", "session_id" ], "title": "TurnStartedEvent", "type": "object" }, "UpdateCodexGoalStatusRequest": { "additionalProperties": false, "description": "Request body for `PATCH /v1/sessions/{id}/codex_goal/status`.\n\nCodex app-server represents pause/resume as `thread/goal/set` status\nupdates. Omnigent exposes the two user-driven transitions explicitly:\n`\"paused\"` pauses an active goal, and `\"active\"` resumes a paused,\nblocked, or usage-limited goal.", "properties": { "status": { "description": "Target Codex goal status, either `\"paused\"` or `\"active\"`.", "enum": [ "active", "paused" ], "title": "Status", "type": "string" } }, "required": [ "status" ], "title": "UpdateCodexGoalStatusRequest", "type": "object" }, "UpdateCommentRequest": { "description": "Request body for `PATCH /sessions/{id}/comments/{comment_id}`.", "properties": { "body": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New comment body. `None` leaves it unchanged.", "title": "Body" }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New status, e.g. `\"addressed\"`. `None` leaves it unchanged.", "title": "Status" } }, "title": "UpdateCommentRequest", "type": "object" }, "UpdateDefaultPolicyRequest": { "additionalProperties": false, "description": "Request body for `PATCH /v1/policies/{policy_id}`.\n\nAll fields are optional; `None` fields are left unchanged.\nUnknown fields (including `type`, which is immutable) are\nrejected with `422`.", "properties": { "enabled": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "New enabled flag. `None` leaves it unchanged.", "title": "Enabled" }, "handler": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New handler path or URL. `None` leaves it unchanged.", "title": "Handler" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New policy name. `None` leaves it unchanged.", "title": "Name" } }, "title": "UpdateDefaultPolicyRequest", "type": "object" }, "UpdateSessionPolicyRequest": { "additionalProperties": false, "description": "Request body for `PATCH /v1/sessions/{session_id}/policies/{policy_id}`.\n\nAll fields are optional; `None` fields are left unchanged.\nUnknown fields (including `type`, which is immutable) are\nrejected with `422`.", "properties": { "enabled": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "New enabled flag. `None` leaves it unchanged.", "title": "Enabled" }, "handler": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New handler path or URL. `None` leaves it unchanged.", "title": "Handler" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New policy name. `None` leaves it unchanged.", "title": "Name" } }, "title": "UpdateSessionPolicyRequest", "type": "object" }, "UpdateSessionRequest": { "additionalProperties": false, "description": "Request body for `PATCH /v1/sessions/{id}`.\n\nThe Alpha runner-state pivot makes this endpoint the mutable\nsession affinity primitive when `runner_id` is provided. The\nserver validates that the runner is online, then replaces\n`conversations.runner_id`. Existing session metadata updates\nremain supported for clients that update title, labels, or\nreasoning effort through the sessions API.", "properties": { "archived": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "New archived state. `True` archives (hides the session from the default sidebar listing), `False` unarchives, `None` leaves unchanged. Owner-only (unlike `title`, which needs only edit access).", "title": "Archived" }, "collaboration_mode": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Codex-native collaboration-mode string. `\"plan\"` enters Plan mode and `\"default\"` returns to Default mode for subsequent Codex turns. Only valid for sessions stamped with the codex-native wrapper label. Omitted leaves unchanged.", "title": "Collaboration Mode" }, "cost_control_mode_override": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session cost-control switch: `\"on\"` activates the spec's configured cost-control mode, `\"off\"` disables cost control for this session. Explicit JSON `null` clears the override back to the spec default; omitting the field leaves it unchanged (`\"off\"` is a real value here, so the field's *presence* \u2014 not a clear alias \u2014 is the clear signal, unlike `model_override`).", "title": "Cost Control Mode Override" }, "external_session_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Runtime-native session id captured by a wrapper bridge (e.g. Claude Code's session uuid for `omnigent claude` sessions). Idempotent on same-value writes; the server rejects attempts to overwrite an already-set different value with `invalid_input` to surface programmer errors. `None` leaves unchanged.", "title": "External Session Id" }, "labels": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "description": "Guardrails labels to upsert. Merges with existing labels; keys not present are left untouched.", "title": "Labels" }, "model_override": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session LLM model override, e.g. `\"claude-opus-4-7\"`. The value is forwarded as-is to the executor at turn start; the server does not enumerate valid models. Clear aliases such as `\"default\"`, `\"off\"`, or `\"reset\"` remove the override (matching the REPL's `/model` semantics). `None` leaves unchanged.", "title": "Model Override" }, "reasoning_effort": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Per-session reasoning-effort hint. Accepted metadata values are `\"none\"`, `\"minimal\"`, `\"low\"`, `\"medium\"`, `\"high\"`, `\"xhigh\"`, and `\"max\"`. Provider-specific support is validated when a turn executes. Clear aliases such as `\"default\"` remove the session override. `None` leaves unchanged.", "title": "Reasoning Effort" }, "runner_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Identifier of a registered runner, e.g. `\"runner_abc123\"`. `None` leaves runner binding unchanged.", "title": "Runner Id" }, "silent": { "default": false, "description": "When `True`, persist metadata changes but skip the runner-side side effects \u2014 specifically the native `/effort` / `/model` / Codex collaboration-mode forwards into the live runtime. Used by automatic bind-time handoffs (web's sticky-pref apply on session switch, the REPL's pre-create `/model` snapshot) where injecting a visible slash command into a freshly-spawned pane would render as an unexpected \"Command model X\" item before the user has sent anything. Default `False` preserves the user-driven picker / `/model` behaviour where the live forward IS the desired feedback.", "title": "Silent", "type": "boolean" }, "terminal_launch_args": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Per-session native-terminal pass-through args, e.g. `[\"--dangerously-skip-permissions\"]`. A list (including `[]`) replaces the stored value wholesale \u2014 resume is last-write-wins, never an append. Bounds (count / length) are validated server-side. `None` leaves unchanged.", "title": "Terminal Launch Args" }, "title": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New title, e.g. `\"debugging auth flow\"`. `None` leaves unchanged.", "title": "Title" } }, "title": "UpdateSessionRequest", "type": "object" }, "UpsertMCPServerRequest": { "description": "Request body for creating or updating a session agent MCP server.\n\nSecret-bearing fields (`headers` and `env`) are intentionally\nnot accepted by the UI route. Existing secrets are preserved when a\nserver is edited without changing transport.", "properties": { "args": { "items": { "type": "string" }, "maxItems": 64, "title": "Args", "type": "array" }, "command": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Command" }, "description": { "anyOf": [ { "maxLength": 512, "type": "string" }, { "type": "null" } ], "title": "Description" }, "name": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z0-9_-][A-Za-z0-9_.-]{0,127}$", "title": "Name", "type": "string" }, "transport": { "enum": [ "http", "stdio" ], "title": "Transport", "type": "string" }, "url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Url" } }, "required": [ "name", "transport" ], "title": "UpsertMCPServerRequest", "type": "object" }, "Usage": { "description": "Token usage statistics for a response.", "properties": { "cache_creation_input_tokens": { "default": 0, "description": "Prompt tokens written to the provider prompt cache (cache creation), billed at a premium rate. Like `cache_read_input_tokens`, this is separate from `input_tokens`; `0` when not reported.", "title": "Cache Creation Input Tokens", "type": "integer" }, "cache_read_input_tokens": { "default": 0, "description": "Prompt tokens served from a provider prompt cache (cache hit), billed at a reduced rate. Reported by Anthropic-style providers as a count *separate* from `input_tokens` (which carries only the non-cached portion); `0` when the provider does not break out cache usage. Consumed by the cache-aware server-side cost path.", "title": "Cache Read Input Tokens", "type": "integer" }, "context_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "default": null, "description": "Context-fill estimate for the next turn \u2014 set only by executors that make multiple LLM sub-calls per turn (e.g. `openai-agents`). For single-call executors this is absent and `total_tokens` serves the same purpose. The toolbar context ring and `/context` command use this field when present, falling back to `total_tokens`.", "title": "Context Tokens" }, "cost_usd": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "default": null, "description": "Authoritative per-turn cost in USD reported directly by the harness/provider (e.g. GitHub Copilot's AI-credit total). When present, the server-side cost path uses it in preference to the catalog token-price estimate; `None` when the harness doesn't report a cost (the common case, where cost is computed from token counts x catalog pricing).", "title": "Cost Usd" }, "input_tokens": { "default": 0, "description": "Number of input (prompt) tokens consumed.", "title": "Input Tokens", "type": "integer" }, "model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "default": null, "description": "The LLM model the harness actually used for this turn, e.g. `\"claude-opus-4-8\"` or `\"databricks-gpt-5-5\"`. Reported by relay executors so the server-side cost path can price the turn even when the agent spec pins no `llm.model` (e.g. supervisors that delegate / use the harness default). `None` when the executor doesn't report it; the cost path then falls back to the session override / spec model.", "title": "Model" }, "output_tokens": { "default": 0, "description": "Number of output (completion) tokens generated.", "title": "Output Tokens", "type": "integer" }, "output_tokens_details": { "$ref": "#/components/schemas/UsageDetails", "description": "Breakdown of output token usage (e.g. reasoning tokens)." }, "total_tokens": { "default": 0, "description": "Sum of input and output tokens across all LLM sub-calls for this turn (billing total).", "title": "Total Tokens", "type": "integer" } }, "title": "Usage", "type": "object" }, "UsageDetails": { "description": "Breakdown of output token usage.", "properties": { "reasoning_tokens": { "default": 0, "description": "Number of tokens consumed by chain-of-thought reasoning.", "title": "Reasoning Tokens", "type": "integer" } }, "title": "UsageDetails", "type": "object" }, "ValidationError": { "properties": { "ctx": { "title": "Context", "type": "object" }, "input": { "title": "Input" }, "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "title": "Location", "type": "array" }, "msg": { "title": "Message", "type": "string" }, "type": { "title": "Error Type", "type": "string" } }, "required": [ "loc", "msg", "type" ], "title": "ValidationError", "type": "object" } }, "securitySchemes": { "proxyHeaderAuth": { "description": "Trusted-proxy identity header (header-auth mode, the default). The header name is configurable via `OMNIGENT_AUTH_HEADER`.", "in": "header", "name": "X-Forwarded-Email", "type": "apiKey" }, "sessionCookieAuth": { "description": "Signed session cookie minted after an interactive OIDC or accounts login (oidc / accounts auth modes). Named `ap_session` over HTTP (the advertised local default); under HTTPS the secure `__Host-ap_session` prefixed form is used instead.", "in": "cookie", "name": "ap_session", "type": "apiKey" } } }, "info": { "description": "Omnigent is an open-source meta-harness for building and running AI agents. This is the REST API exposed by the Omnigent server: use it to create and drive **sessions**, manage **agents**, **hosts**, and **runners**, attach **contextual policies**, post **comments**, and work with session **resources** \u2014 files, terminals, and sandboxed environments.\n\n## Base URL\n\nOmnigent is self-hosted. The server binds `http://127.0.0.1:6767` by default (`omnigent server`); point the base URL at your own deployment.\n\n## Authentication\n\nThere is no API-key or bearer-token scheme. Identity is supplied by the deployment's configured auth provider (`OMNIGENT_AUTH_PROVIDER`):\n\n- **Trusted proxy header** (default) \u2014 an upstream proxy injects an identity header (`X-Forwarded-Email`, configurable). Single-user local runtimes fall back to a reserved `local` user.\n- **Session cookie** \u2014 a signed session cookie minted after an interactive OIDC or accounts login. It is named `ap_session` over HTTP (the advertised local default) and `__Host-ap_session` under HTTPS, where the `__Host-` prefix guards against subdomain cookie-tossing.\n\nAuth is configured server-side; clients send the cookie or proxy header according to your deployment.\n\n## Streaming\n\n`GET /v1/sessions/{session_id}/stream` streams Server-Sent Events (`text/event-stream`). Each event conforms to the `ServerStreamEvent` schema documented below.\n", "title": "Omnigent Server", "version": "0.1.0" }, "openapi": "3.2.0", "paths": { "/api/version": { "get": { "description": "Return the installed omnigent package version.\n\nUsed by the web UI to include version info in bug reports.\n\n**Returns:** `{\"version\": \"\"}`, e.g. `{\"version\": \"0.1.0\"}`.", "operationId": "version_api_version_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "type": "string" }, "title": "Response Version Api Version Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "Version", "tags": [ "system" ] } }, "/health": { "get": { "description": "Liveness check with optional session-scoped runner status.\n\nWithout session params, returns `{\"status\": \"ok\"}` (bare\nliveness). With `session_id`, adds a single `session`\nobject. With `session_ids` (comma-separated), adds a\n`sessions` dict keyed by id \u2014 used by the sidebar to\nbatch-check all visible sessions in one request. The batch\npath runs a single SQL `IN` query, not N per-id round-trips.\n\nEach per-session object carries both `runner_online` (strict\nrunner reachability) and `host_online` (host tunnel live, or\n`None` when the session has no host binding) \u2014 see\n`~omnigent.server.routes.sessions.SessionLiveness`.\n\n**Returns:** `{\"status\": \"ok\"}` with optional `session` and/or `sessions` fields. Each session object has shape `{\"runner_online\": bool, \"host_online\": bool | None, \"host_version\": str | None}` (the single `session` object also includes its `id`). `host_version` is the bound host's reported version, or `None` when there's no host binding / the version isn't resolvable on this replica.", "operationId": "health_health_get", "parameters": [ { "description": "Optional single session id, e.g. `\"conv_abc123\"`.", "in": "query", "name": "session_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Session Id" } }, { "description": "Optional comma-separated session ids for batch lookup, e.g. `\"conv_abc,conv_def,conv_ghi\"`.", "in": "query", "name": "session_ids", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Session Ids" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Health Health Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Health", "tags": [ "system" ] } }, "/v1/agents": { "get": { "description": "List built-in agents with cursor-based pagination.\n\nReturns only built-in agents \u2014 `agent_store.list()` filters\n`session_id IS NULL` \u2014 so session-scoped agents never appear.\n\n**Returns:** A `PaginatedList` of built-in agents.", "operationId": "list_builtin_agents_v1_agents_get", "parameters": [ { "description": "Maximum number of agents to return (1-1000).", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor \u2014 return agents after this id.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor \u2014 return agents before this id.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "Sort order, `\"asc\"` or `\"desc\"`.", "in": "query", "name": "order", "required": false, "schema": { "default": "desc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedList" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Builtin Agents", "tags": [ "agents" ] } }, "/v1/harnesses": { "get": { "operationId": "list_harnesses_v1_harnesses_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, "title": "Response List Harnesses V1 Harnesses Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "List Harnesses", "tags": [ "harnesses" ] } }, "/v1/hosts": { "get": { "description": "List all hosts owned by the authenticated user.\n\nReturns both online and offline hosts, with live runner\ninformation for online hosts.\n\n**Returns:** `{\"hosts\": [...]}` with host details.", "operationId": "list_hosts_v1_hosts_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, "title": "Response List Hosts V1 Hosts Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "List Hosts", "tags": [ "hosts" ] } }, "/v1/hosts/{host_id}": { "get": { "description": "Get details for a single host.\n\n**Returns:** Host details dict.\n\n**Raises**\n\n- `HTTPException` \u2014 404 if the host does not exist.", "operationId": "get_host_v1_hosts__host_id__get", "parameters": [ { "description": "Host identifier, e.g. `\"host_a1b2c3d4...\"`.", "in": "path", "name": "host_id", "required": true, "schema": { "title": "Host Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Get Host V1 Hosts Host Id Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Host", "tags": [ "hosts" ] } }, "/v1/hosts/{host_id}/directories": { "post": { "description": "Create a new directory on a host.\n\nBacks the Web UI workspace picker's \"New folder\" action so a\nuser can make a fresh directory to start a session in without\ndropping to a terminal. Owner-scoped exactly like the\nfilesystem browse endpoints (`GET /v1/hosts/{id}/filesystem`):\nonly the host owner can create directories, and \u2014 like browse \u2014\nthis is NOT scoped to a session. The workspace-boundary check\nstill runs at session-create time, so creating a directory here\ndoes not by itself grant an agent access to it.\n\n**Parameters**\n\n- `body` \u2014 Request body carrying the absolute (or tilde-prefixed) `path` to create.\n\n**Returns:** `{\"object\": \"directory\", \"path\": \"\"}`.\n\n**Raises**\n\n- `HTTPException` \u2014 404 if host not found, 403 if not owned by caller, 409 if host is offline or the directory could not be created (already exists / permission denied), 400 on path validation, 504 on host timeout, 502 on host I/O failure.", "operationId": "create_host_directory_v1_hosts__host_id__directories_post", "parameters": [ { "description": "Host identifier, e.g. `\"host_a1b2c3d4...\"`.", "in": "path", "name": "host_id", "required": true, "schema": { "title": "Host Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDirectoryRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Create Host Directory V1 Hosts Host Id Directories Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Create Host Directory", "tags": [ "hosts" ] } }, "/v1/hosts/{host_id}/filesystem": { "get": { "description": "List the contents of the host daemon's home directory.\n\nEmpty trailing path \u2192 forward `~` to the host (the host\nexpands against its own process owner). Used by the\nWeb UI's directory picker to show the \"root\" view.\n\n**Returns:** `{\"object\": \"list\", \"data\": [...], \"has_more\": bool}` mirroring the existing session-scoped filesystem endpoint shape.\n\n**Raises**\n\n- `HTTPException` \u2014 404 if host not found, 403 if not owned by caller, 409 if host is offline, 504 on host timeout, 502 on host I/O failure.", "operationId": "list_host_filesystem_root_v1_hosts__host_id__filesystem_get", "parameters": [ { "description": "Host identifier, e.g. `\"host_a1b2c3d4...\"`.", "in": "path", "name": "host_id", "required": true, "schema": { "title": "Host Id", "type": "string" } }, { "description": "Max entries per page.", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Optional forward pagination cursor (entry path), e.g. `\"/Users/corey/projects/m\"`.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Optional backward pagination cursor.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Host Filesystem Root V1 Hosts Host Id Filesystem Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Host Filesystem Root", "tags": [ "hosts" ] } }, "/v1/hosts/{host_id}/filesystem/{path}": { "get": { "description": "List the contents of a directory on a host.\n\nUsed by the Web UI's directory picker (and stat-style\nexistence checks) to render the host's filesystem before\nany runner exists. Owner-scoped: only the host owner can\nbrowse. NOT scoped to a session \u2014 this endpoint exposes\nthe entire host filesystem to the authenticated host owner\nper `designs/SESSION_WORKSPACE_SELECTION.md` \"Security\nsurface\".\n\n**Returns:** `{\"object\": \"list\", \"data\": [...], \"has_more\": bool}`.\n\n**Raises**\n\n- `HTTPException` \u2014 404 (host or path missing), 403 (not owner), 409 (offline), 400 (path validation), 504 (timeout), 502 (host I/O).", "operationId": "list_host_filesystem_v1_hosts__host_id__filesystem__path__get", "parameters": [ { "description": "Host identifier.", "in": "path", "name": "host_id", "required": true, "schema": { "title": "Host Id", "type": "string" } }, { "description": "Absolute path on the host (e.g. `\"/Users/corey/universe\"`) OR a tilde-prefixed path (`\"~/foo\"`). The host expands `~` itself. FastAPI's `:path` converter strips the leading `/` from the URL, so we re-add it for absolute paths.", "in": "path", "name": "path", "required": true, "schema": { "title": "Path", "type": "string" } }, { "description": "Max entries per page.", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Optional forward pagination cursor.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Optional backward pagination cursor.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Host Filesystem V1 Hosts Host Id Filesystem Path Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Host Filesystem", "tags": [ "hosts" ] } }, "/v1/hosts/{host_id}/runners": { "post": { "description": "Launch a runner on a host for a session.\n\nGenerates a binding token, writes the expected runner_id\nto the session row, sends the launch command to the host,\nand waits for the host's acknowledgement.\n\n**Parameters**\n\n- `body` \u2014 Launch request with `session_id` and `workspace`.\n\n**Returns:** `{\"runner_id\": ..., \"status\": \"launching\"}`.\n\n**Raises**\n\n- `HTTPException` \u2014 404 if host not found, 409 if host offline, 403 if caller doesn't own the host, 400 if session already has a runner.", "operationId": "launch_runner_v1_hosts__host_id__runners_post", "parameters": [ { "description": "Target host, e.g. `\"host_a1b2c3d4...\"`.", "in": "path", "name": "host_id", "required": true, "schema": { "title": "Host Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LaunchRunnerRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Launch Runner V1 Hosts Host Id Runners Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Launch Runner", "tags": [ "hosts" ] } }, "/v1/hosts/{host_id}/worktrees": { "get": { "description": "List the git worktrees of a repository on a host.\n\nUsed by the Web UI's new-session worktree picker to show the\nworktrees a session can start in directly. Owner-scoped exactly\nlike the filesystem browse endpoints; NOT scoped to a session.\nA path that is not a git repository is reported as 400 so the\npicker can quietly fall back to \"no worktrees\".\n\n**Returns:** `{\"object\": \"list\", \"data\": [{path, branch, is_main, detached}, ...]}` (main first).\n\n**Raises**\n\n- `HTTPException` \u2014 404 if host not found, 403 if not owned by caller, 409 if host is offline/unresponsive, 400 on path validation or a non-git path.", "operationId": "list_host_worktrees_v1_hosts__host_id__worktrees_get", "parameters": [ { "description": "Host identifier, e.g. `\"host_a1b2c3d4...\"`.", "in": "path", "name": "host_id", "required": true, "schema": { "title": "Host Id", "type": "string" } }, { "description": "Absolute path inside the repo on the host to list worktrees for, e.g. `\"/Users/alice/myrepo\"`.", "in": "query", "name": "path", "required": true, "schema": { "title": "Path", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Host Worktrees V1 Hosts Host Id Worktrees Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Host Worktrees", "tags": [ "hosts" ] } }, "/v1/info": { "get": { "description": "Runtime capabilities probe for the SPA + CLI.\n\nReturned at app boot by the frontend (and by `omnigent login` when it needs to choose between flows). Drives\nconditional route registration and chrome on the SPA side\n\u2014 when `accounts_enabled` is false, the SPA never\nregisters `/login`, `/register`, `/members` and\nnever renders the AccountMenu, so the bundle behaves\nidentically to a pre-PR-2008 build for header / OIDC\ndeploys (in particular, the internal hosted product that\nsyncs from this repo).\n\nAuthentication: this endpoint is intentionally UNAUTHED\nso the SPA can probe it before holding a session cookie.\nIt exposes no sensitive state \u2014 only the active auth\nsource, the login URL, whether first-run admin setup is\nstill pending (`needs_setup`), coarse capability\nbooleans (`databricks_features`,\n`managed_sandboxes_enabled`), the short sandbox\nprovider name (`sandbox_provider`) the web UI labels the\nnew-session sandbox option with, and the installed\n`server_version` (already public via `/api/version`).", "operationId": "info_v1_info_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "anyOf": [ { "type": "boolean" }, { "type": "string" }, { "type": "null" } ] }, "title": "Response Info V1 Info Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "Info", "tags": [ "system" ] } }, "/v1/me": { "get": { "description": "Return the current user's identity.\n\nReads the user from the auth provider (same logic that\nsession routes use). The frontend calls this on load to\ndiscover who it is.\n\nAlso returns `is_admin` \u2014 the mode-agnostic admin signal\n(the shared `users.is_admin` column, set by the admin-list\npromotion at login). The SPA gates admin chrome on it in\nEVERY mode, including OIDC/SSO where the accounts-only\n`/auth/me` endpoint does not exist.\n\nWhen OIDC is active and the user is unauthenticated,\nreturns 401 with a `login_url` so the frontend knows\nwhere to redirect.\n\n**Returns:** `{\"user_id\": \"alice@example.com\", \"is_admin\": true}`, `{\"user_id\": null, \"is_admin\": false}` if unauthenticated in header mode, or 401 with `login_url` in OIDC mode.", "operationId": "me_v1_me_get", "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" } }, "summary": "Me", "tags": [ "system" ] } }, "/v1/policies": { "get": { "description": "List all default policies.\n\nRequires authentication in multi-user mode.\n\n**Returns:** `{\"object\": \"list\", \"data\": [...]}`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401 if unauthenticated in multi-user mode.", "operationId": "list_policies_v1_policies_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Policies V1 Policies Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "List Policies", "tags": [ "default_policies" ] }, "post": { "description": "Create a new default policy.\n\nRequires admin privileges in multi-user mode.\n\n**Parameters**\n\n- `body` \u2014 Policy payload including name, type, and handler.\n\n**Returns:** The created policy as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks admin privileges, or 409 if a policy with the same name already exists.", "operationId": "create_policy_v1_policies_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateDefaultPolicyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Create Policy V1 Policies Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Create Policy", "tags": [ "default_policies" ] } }, "/v1/policies/{policy_id}": { "delete": { "description": "Delete a default policy.\n\nIdempotent \u2014 deleting a missing policy returns 204.\nRequires admin privileges.\n\n**Returns:** `{\"deleted\": true}`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks admin privileges.", "operationId": "delete_policy_v1_policies__policy_id__delete", "parameters": [ { "description": "The policy to delete, e.g. `\"pol_abc123\"`.", "in": "path", "name": "policy_id", "required": true, "schema": { "title": "Policy Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Delete Policy V1 Policies Policy Id Delete", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Policy", "tags": [ "default_policies" ] }, "get": { "description": "Get a single default policy.\n\nRequires authentication in multi-user mode.\n\n**Returns:** The policy as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401 if unauthenticated, or 404 if the policy is not found.", "operationId": "get_policy_v1_policies__policy_id__get", "parameters": [ { "description": "The policy to retrieve, e.g. `\"pol_abc123\"`.", "in": "path", "name": "policy_id", "required": true, "schema": { "title": "Policy Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Get Policy V1 Policies Policy Id Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Policy", "tags": [ "default_policies" ] }, "patch": { "description": "Update a default policy's mutable fields.\n\n`type` is immutable \u2014 the caller must delete and\nre-create to change it. Requires admin privileges.\n\n**Parameters**\n\n- `body` \u2014 Fields to update; `None` fields are left unchanged.\n\n**Returns:** The updated policy as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks admin privileges, or 404 if the policy is not found.", "operationId": "update_policy_v1_policies__policy_id__patch", "parameters": [ { "description": "The policy to update, e.g. `\"pol_abc123\"`.", "in": "path", "name": "policy_id", "required": true, "schema": { "title": "Policy Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateDefaultPolicyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Update Policy V1 Policies Policy Id Patch", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Policy", "tags": [ "default_policies" ] } }, "/v1/policy-registry": { "get": { "description": "List all registered policy functions.\n\nReturns the full catalog of built-in policy callables\nwith their handler paths, descriptions, and parameter\nschemas.\n\n**Returns:** `{\"object\": \"list\", \"data\": [...]}`.", "operationId": "list_registry_v1_policy_registry_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Registry V1 Policy Registry Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "List Registry", "tags": [ "policy_registry" ] } }, "/v1/runners": { "get": { "description": "Return currently online runners owned by the requesting user.\n\nWhen auth is active, only runners whose tunnel was\nestablished by the same user are returned. Without auth,\nall online runners are listed (single-user / dev mode).\n\n**Returns:** A `{\"data\": [...]}` list with runner ids and advertised harnesses.", "operationId": "list_runners_v1_runners_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, "title": "Response List Runners V1 Runners Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "List Runners", "tags": [ "runners" ] } }, "/v1/runners/{runner_id}/status": { "get": { "description": "Return whether a runner currently has an open tunnel.\n\nWhen auth is active, a runner owned by a different user\nappears as offline to prevent enumeration.\n\n**Returns:** A JSON object with `runner_id` and `online`.", "operationId": "runner_status_v1_runners__runner_id__status_get", "parameters": [ { "description": "Stable runner id, e.g. `\"runner_0123456789abcdef\"`.", "in": "path", "name": "runner_id", "required": true, "schema": { "title": "Runner Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "boolean" } ] }, "title": "Response Runner Status V1 Runners Runner Id Status Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Runner Status", "tags": [ "runners" ] } }, "/v1/runners/{runner_id}/token": { "post": { "description": "Mint a short-lived owner bearer for a managed-sandbox runner.\n\nA managed sandbox runner has no user credential of its own; it\npresents its server-minted tunnel binding token\n(`X-Omnigent-Runner-Tunnel-Token`) and the server returns a\nshort-lived owner JWT the runner then uses on its HTTP callbacks\n(which gate on `require_user`). This is the HTTP analog of the\nrunner tunnel's binding-token handshake: the same SHA-256 gate\n(`token_bound_runner_id(token) == runner_id`) and the same\nowner resolution (`resolve_managed_runner_owner`), minting a\nbearer instead of registering a tunnel.\n\nThe binding-token match is required unconditionally \u2014 the\nallow-list shortcut honored on some other runner-token checks is\ndeliberately NOT accepted here, because this endpoint issues a\nfull owner credential and managed sandboxes always run\ntoken-bound (no allow-list).\n\n**Returns:** `{\"token\": , \"expires_at\": }`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401 when the binding token is absent, doesn't match `runner_id`, or resolves to no managed-launch owner; 400 when the active auth mode can't mint server-side (header/proxy, or no auth provider).", "operationId": "mint_runner_owner_token_v1_runners__runner_id__token_post", "parameters": [ { "description": "Token-bound runner id from the path.", "in": "path", "name": "runner_id", "required": true, "schema": { "title": "Runner Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "title": "Response Mint Runner Owner Token V1 Runners Runner Id Token Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Mint Runner Owner Token", "tags": [ "runners" ] } }, "/v1/sessions": { "get": { "description": "List sessions with cursor-based pagination.\n\nSessions are conversations with a non-`None` `agent_id`\n\u2014 i.e. those created via `POST /v1/sessions`.\nConversations without an agent binding are excluded.\n\n**Returns:** A `PaginatedList` of `SessionListItem`.", "operationId": "list_sessions_v1_sessions_get", "parameters": [ { "description": "Maximum number of sessions to return (1-1000, default 20).", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor \u2014 return sessions after this session ID in sort order, e.g. `\"conv_abc123\"`.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor \u2014 return sessions before this session ID.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "When set, only return sessions bound to this agent, e.g. `\"ag_abc123\"`. `None` returns sessions across all agents.", "in": "query", "name": "agent_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Agent Id" } }, { "description": "When set, only return sessions whose bound agent row has this name. This intentionally includes session-scoped agents that share a name but have distinct bundles. `None` disables the filter.", "in": "query", "name": "agent_name", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Agent Name" } }, { "description": "Sort direction, `\"desc\"` (newest-first) or `\"asc\"` (oldest-first).", "in": "query", "name": "order", "required": false, "schema": { "default": "desc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } }, { "description": "Column to sort on, `\"created_at\"` or `\"updated_at\"`.", "in": "query", "name": "sort_by", "required": false, "schema": { "default": "created_at", "pattern": "^(created_at|updated_at)$", "title": "Sort By", "type": "string" } }, { "description": "Case-insensitive substring filter on the session title or conversation content. `None` or empty string disables the filter. A session matches if its title contains the query or any of its conversation items' text does. Powers the sidebar's session search.", "in": "query", "name": "search_query", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Search Query" } }, { "description": "When `False` (default), archived sessions are omitted. When `True`, archived sessions are returned alongside active ones (the sidebar groups them into an \"Archived\" section). Powers the sidebar's \"Show archived\" toggle.", "in": "query", "name": "include_archived", "required": false, "schema": { "default": false, "title": "Include Archived", "type": "boolean" } }, { "description": "Conversation kind to return. `\"default\"` (the default) returns only top-level user-initiated sessions \u2014 the sidebar's view. `\"sub_agent\"` returns only sub-agent child sessions. `\"any\"` returns both; this lets the new-session agent picker discover agents that are only bound to sub-agent sessions (e.g. ones uploaded via `sys_session_create`).", "in": "query", "name": "kind", "required": false, "schema": { "default": "default", "pattern": "^(default|sub_agent|any)$", "title": "Kind", "type": "string" } }, { "in": "query", "name": "project", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Project" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionList" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Sessions", "tags": [ "sessions" ] }, "post": { "description": "Create a session.\n\n`application/json` preserves the existing contract: bind to\nan already-registered agent by `agent_id` and return the full\nsession snapshot. `multipart/form-data` is the Alpha\nrunner-state create path: the request carries a JSON\n`metadata` part and a `bundle` file part, then the server\nstores the bundle and creates the conversation row plus\nsession-scoped agent row in one database transaction.\n\n**Returns:** `SessionResponse` for JSON create, or `CreatedSessionResponse` for bundled create.\n\n**Raises**\n\n- `OmnigentError` \u2014 If metadata, bundle, or agent lookup validation fails, artifact storage is unavailable, or database creation fails.", "operationId": "create_session_v1_sessions_post", "responses": { "201": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" } }, "summary": "Create Session", "tags": [ "sessions" ] } }, "/v1/sessions/projects": { "get": { "description": "Return all project names for the authenticated user, ordered\nalphabetically.\n\nProjects are implicit: they exist while at least one session\nhas a `conversation_labels` row with `key=\"omni_project\"`.\n\n**Returns:** List of project names.", "operationId": "list_session_projects_v1_sessions_projects_get", "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" } }, "summary": "List Session Projects", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}": { "delete": { "description": "Delete a session and all associated resources.\n\nRequires owner-level access. Tears down tasks, runner-side\nresources (environments, terminals), session files, and the\nconversation row.\n\n**Returns:** A `ConversationDeleted` confirmation.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session or no access, 403 if insufficient permissions.", "operationId": "delete_session_v1_sessions__session_id__delete", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Opt-in git cleanup, as a query param (`?delete_branch=true`). When `True` and the session has a server-created worktree (`git_branch` set), the host removes the worktree directory and deletes its branch (`git worktree remove --force` then `git branch -D`). Ignored for sessions with no worktree. Best-effort: a cleanup failure does not block the delete. Defaults to `False` (worktree and branch left untouched). See designs/SESSION_GIT_WORKTREE.md.", "in": "query", "name": "delete_branch", "required": false, "schema": { "default": false, "title": "Delete Branch", "type": "boolean" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConversationDeleted" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Session", "tags": [ "sessions" ] }, "get": { "description": "Return a session snapshot: identity, status, and committed\nitems.\n\n**Returns:** The matching `SessionResponse`.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session exists.", "operationId": "get_session_v1_sessions__session_id__get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "When `False`, skip the committed-items read and return `items=[]`. The web chat surface passes `False` because it hydrates the transcript via the paginated `GET /sessions/{id}/items` endpoint in parallel and never reads the snapshot's copy; the items read is the single most expensive step of the snapshot build.", "in": "query", "name": "include_items", "required": false, "schema": { "default": true, "title": "Include Items", "type": "boolean" } }, { "description": "When `False`, skip the runner/host liveness lookup and return `runner_online`/`host_online` as `None`. The web chat surface passes `False` because it sources liveness from the `/health` poll and the WS stream, not the snapshot.", "in": "query", "name": "include_liveness", "required": false, "schema": { "default": true, "title": "Include Liveness", "type": "boolean" } }, { "description": "When `True`, refresh runner-derived snapshot overlays from the live session instead of serving stale AP-process caches. Browser reload/bind requests use this to recover from fixed bugs without restarting the AP server.", "in": "query", "name": "refresh_state", "required": false, "schema": { "default": false, "title": "Refresh State", "type": "boolean" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session", "tags": [ "sessions" ] }, "patch": { "description": "Update a session's mutable fields. When `runner_id` is\nprovided, this is the mutable affinity primitive for the Alpha\nrunner-state pivot: create-bind, resume-bind, and recover-bind\nall send the currently registered runner id, and the server\natomically replaces `conversations.runner_id` with that\nvalue using last-write-wins semantics. Title, labels, and\nreasoning-effort updates remain supported for existing\nsessions clients.\n\n**Parameters**\n\n- `body` \u2014 The validated `UpdateSessionRequest`.\n\n**Returns:** The updated `SessionResponse` snapshot.\n\n**Raises**\n\n- `OmnigentError` \u2014 400 if the runner is not registered; 404 if no session exists.", "operationId": "update_session_v1_sessions__session_id__patch", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSessionRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Session", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/agent": { "get": { "description": "Return the `AgentObject` for the session's bound agent.\n\nReplaces the standalone `GET /api/agents/{id}` endpoint by\nresolving the agent through the session's `agent_id` foreign\nkey. The caller only needs to know the session id.\n\n**Returns:** The bound agent's `AgentObject`.\n\n**Raises**\n\n- `OmnigentError` \u2014 If the session or agent is not found.", "operationId": "get_session_agent_v1_sessions__session_id__agent_get", "parameters": [ { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentObject" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Agent", "tags": [ "sessions" ] }, "put": { "description": "Replace the session's agent bundle with a new upload.\n\nValidates the new bundle, checks that the spec name matches\nthe existing agent, stores the bundle under a\ncontent-addressed key, updates the agent row, and warm-swaps\nthe cache. Idempotent when the bundle content is unchanged.\n\n**Parameters**\n\n- `bundle` \u2014 Uploaded `.tar.gz` agent bundle file.\n\n**Returns:** The updated `AgentObject`.\n\n**Raises**\n\n- `OmnigentError` \u2014 If the session or agent is not found, the bundle is invalid, or the spec name doesn't match.", "operationId": "update_session_agent_v1_sessions__session_id__agent_put", "parameters": [ { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_update_session_agent_v1_sessions__session_id__agent_put" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AgentObject" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Session Agent", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/agent/contents": { "get": { "description": "Download the raw `.tar.gz` agent bundle for the session's\nbound agent.\n\nReplaces `GET /api/agents/{id}/contents`. Runners call this\non cache miss to fetch the spec + bundled files.\n\n**Returns:** Raw bundle bytes as `application/gzip`.\n\n**Raises**\n\n- `OmnigentError` \u2014 If the session, agent, or bundle is not found.", "operationId": "get_session_agent_contents_v1_sessions__session_id__agent_contents_get", "parameters": [ { "description": "Session identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/gzip": {} }, "description": "Successful Response" }, "404": { "description": "Session or agent not found" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Agent Contents", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/agent/mcp-servers": { "get": { "description": "List safe MCP server summaries for a session's bound agent.", "operationId": "list_mcp_servers_v1_sessions__session_id__agent_mcp_servers_get", "parameters": [ { "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Mcp Servers V1 Sessions Session Id Agent Mcp Servers Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Mcp Servers", "tags": [ "session_mcp_servers" ] }, "post": { "description": "Create one MCP server declaration on a session-scoped agent.", "operationId": "create_mcp_server_v1_sessions__session_id__agent_mcp_servers_post", "parameters": [ { "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertMCPServerRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MCPServerSummary" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Create Mcp Server", "tags": [ "session_mcp_servers" ] } }, "/v1/sessions/{session_id}/agent/mcp-servers/{server_name}": { "delete": { "description": "Delete one MCP server declaration from a session-scoped agent.", "operationId": "delete_mcp_server_v1_sessions__session_id__agent_mcp_servers__server_name__delete", "parameters": [ { "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "in": "path", "name": "server_name", "required": true, "schema": { "title": "Server Name", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Mcp Server", "tags": [ "session_mcp_servers" ] }, "put": { "description": "Replace one MCP server declaration on a session-scoped agent.", "operationId": "update_mcp_server_v1_sessions__session_id__agent_mcp_servers__server_name__put", "parameters": [ { "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "in": "path", "name": "server_name", "required": true, "schema": { "title": "Server Name", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpsertMCPServerRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MCPServerSummary" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Mcp Server", "tags": [ "session_mcp_servers" ] } }, "/v1/sessions/{session_id}/child_sessions": { "get": { "description": "List sub-agent (child) sessions under a parent session.\n\nReturns a page of `ChildSessionSummary` objects\nderived from child conversations (`kind=\"sub_agent\"`,\n`parent_conversation_id=session_id`) plus each child's\nlatest task. Powers the web / REPL debug surfaces' \"child\nsessions\" panel without parsing parent\n`function_call_output` JSON handles. Pagination contract\nmatches `list_session_items` so existing client code\ncan reuse the same cursor logic.\n\n**Returns:** A `PaginatedList` of `ChildSessionSummary` objects.\n\n**Raises**\n\n- `OmnigentError` \u2014 403 if the caller lacks READ on `session_id`; 404 if no session exists there.", "operationId": "list_child_sessions_v1_sessions__session_id__child_sessions_get", "parameters": [ { "description": "Parent session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Maximum number of children to return (1-1000, default 20 \u2014 sub-agent fan-out is typically sparse compared to conversation items).", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor \u2014 return children whose id appears after this one in sort order, e.g. `\"conv_child123\"`.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor \u2014 return children before this one.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "Sort direction, `\"desc\"` (newest-first, default) or `\"asc\"`. Sort column is `created_at`.", "in": "query", "name": "order", "required": false, "schema": { "default": "desc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } }, { "description": "When set, only return children whose title starts with this agent type (the segment before the `\":\"`). Combined with `session_name` to form the exact title `\"{tool}:{session_name}\"` for server-side filtering.", "in": "query", "name": "tool", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Tool" } }, { "description": "When set alongside `tool`, only return children whose title matches `\"{tool}:{session_name}\"` exactly.", "in": "query", "name": "session_name", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Session Name" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChildSessionList" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Child Sessions", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/codex_goal": { "delete": { "description": "Clear the current Codex app-server goal.\n\n**Returns:** Whether Codex removed an existing goal.\n\n**Raises**\n\n- `OmnigentError` \u2014 400 for non-Codex sessions, 404 for missing sessions, or 503 when no live Codex runner can clear the goal.", "operationId": "clear_codex_goal_v1_sessions__session_id__codex_goal_delete", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ClearCodexGoalResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Clear Codex Goal", "tags": [ "sessions" ] }, "get": { "description": "Read the current Codex app-server goal for a Codex-native session.\n\n**Returns:** Current Codex goal state, or `goal=None` when no goal is set.\n\n**Raises**\n\n- `OmnigentError` \u2014 400 for non-Codex sessions, 404 for missing sessions, or 503 when no live Codex runner can read the goal.", "operationId": "get_codex_goal_v1_sessions__session_id__codex_goal_get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexGoalResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Codex Goal", "tags": [ "sessions" ] }, "put": { "description": "Set or replace the current Codex app-server goal.\n\n**Parameters**\n\n- `body` \u2014 Goal objective, optional token budget, and optional user-selected status.\n\n**Returns:** Current Codex goal state after the update.\n\n**Raises**\n\n- `OmnigentError` \u2014 400 for non-Codex sessions or blank objectives, 404 for missing sessions, or 503 when no live Codex runner can update the goal.", "operationId": "set_codex_goal_v1_sessions__session_id__codex_goal_put", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetCodexGoalRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexGoalResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Set Codex Goal", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/codex_goal/status": { "patch": { "description": "Pause or resume the current Codex app-server goal.\n\nCodex exposes this through `thread/goal/set` with only a status\nfield. The Omnigent API keeps that distinct from objective/budget\nedits so callers can implement Pause/Resume controls without\nresending the goal text.\n\n**Parameters**\n\n- `body` \u2014 Target status. `\"paused\"` pauses the goal and `\"active\"` resumes it.\n\n**Returns:** Current Codex goal state after the status update.\n\n**Raises**\n\n- `OmnigentError` \u2014 400 for non-Codex sessions, 404 for missing sessions, or 503 when no live Codex runner can update the goal.", "operationId": "update_codex_goal_status_v1_sessions__session_id__codex_goal_status_patch", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCodexGoalStatusRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CodexGoalResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Codex Goal Status", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/comments": { "get": { "description": "List comments for a session, optionally filtered by file.\n\nRequires `LEVEL_READ` on the session in multi-user mode.\n\n**Returns:** List of serialized comment dicts.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403/404 if the user lacks read permission.", "operationId": "list_comments_v1_sessions__session_id__comments_get", "parameters": [ { "description": "The session to query, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "When provided, only return comments for this file, e.g. `\"src/App.tsx\"`.", "in": "query", "name": "path", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Path" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "additionalProperties": true, "type": "object" }, "title": "Response List Comments V1 Sessions Session Id Comments Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Comments", "tags": [ "comments" ] }, "post": { "description": "Create a new review comment.\n\nRequires `LEVEL_EDIT` on the session in multi-user mode.\n\n**Parameters**\n\n- `body` \u2014 Comment payload including path, body text, and the two range fields (start_index, end_index).\n\n**Returns:** The created comment as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403/404 if the user lacks edit permission.", "operationId": "add_comment_v1_sessions__session_id__comments_post", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AddCommentRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Add Comment V1 Sessions Session Id Comments Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Add Comment", "tags": [ "comments" ] } }, "/v1/sessions/{session_id}/comments/send": { "post": { "description": "Mark comments as addressed and format them into an agent message.\n\nFetches each requested comment, marks it `addressed`,\nand formats the full set into a grouped, sorted message string\nsuitable for pasting into the chat composer.\n\nRequires `LEVEL_EDIT` on the session in multi-user mode because\nit transitions comment status from `draft` to `addressed`.\n\n**Parameters**\n\n- `body` \u2014 List of comment IDs to send, with an optional custom instruction prefix.\n\n**Returns:** `{\"formatted_message\": str, \"sent_comment_ids\": list[str]}`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403/404 if the user lacks edit permission, or 404 if any requested comment is not found or does not belong to this session.", "operationId": "send_to_agent_v1_sessions__session_id__comments_send_post", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SendCommentsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Send To Agent V1 Sessions Session Id Comments Send Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Send To Agent", "tags": [ "comments" ] } }, "/v1/sessions/{session_id}/comments/{comment_id}": { "delete": { "description": "Delete a comment.\n\nRequires `LEVEL_EDIT` on the session in multi-user mode, and\nadditionally that the caller is the comment's author \u2014 one\ncollaborator may not delete another user's comment.\n\n**Returns:** `{\"deleted\": true}`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403/404 if the user lacks edit permission, 403 if the caller is not the comment's author, or 404 if the comment is not found or does not belong to this session.", "operationId": "delete_comment_v1_sessions__session_id__comments__comment_id__delete", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "The comment to delete, e.g. `\"a1b2c3d4-...\"`.", "in": "path", "name": "comment_id", "required": true, "schema": { "title": "Comment Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Delete Comment V1 Sessions Session Id Comments Comment Id Delete", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Comment", "tags": [ "comments" ] }, "patch": { "description": "Update a comment's status and/or body text.\n\nRequires `LEVEL_EDIT` on the session in multi-user mode.\nEditing the `body` additionally requires the caller to be the\ncomment's author: rewriting another user's comment is forbidden,\nwhile changing only the `status` (e.g. marking it `\"addressed\"`)\nstays open to any editor as a shared review-workflow action.\n\n**Parameters**\n\n- `body` \u2014 Fields to update; `None` fields are left unchanged.\n\n**Returns:** The updated serialized comment.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403/404 if the user lacks edit permission, 403 if a body edit is attempted on another user's comment, or 404 if the comment is not found.", "operationId": "update_comment_v1_sessions__session_id__comments__comment_id__patch", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "The comment to update, e.g. `\"a1b2c3d4-...\"`.", "in": "path", "name": "comment_id", "required": true, "schema": { "title": "Comment Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateCommentRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Update Comment V1 Sessions Session Id Comments Comment Id Patch", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Comment", "tags": [ "comments" ] } }, "/v1/sessions/{session_id}/items": { "get": { "description": "List items in a session with cursor-based pagination.\n\nDelegates to the conversation items store \u2014 session_id is\nthe conversation_id. Same pagination contract as\n`GET /v1/conversations/{id}/items`.\n\n**Returns:** A `PaginatedList` of conversation items.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session exists.", "operationId": "list_session_items_v1_sessions__session_id__items_get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Maximum number of items to return (1-1000, default 100).", "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor \u2014 return items after this item ID, e.g. `\"msg_abc123\"`.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor \u2014 return items before this item ID.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "Sort order, `\"asc\"` (chronological, default) or `\"desc\"`.", "in": "query", "name": "order", "required": false, "schema": { "default": "asc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PaginatedList" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Session Items", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/labels": { "get": { "description": "Return only the labels for a session.\n\nNative runner bridge setup needs labels during harness spawn,\nbut the full session snapshot also loads history, skills,\nrunner status, and agent metadata. This endpoint keeps that\nspawn-time dependency to one authorized conversation read.\n\n**Returns:** The session id and labels.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session exists.", "operationId": "get_session_labels_v1_sessions__session_id__labels_get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionLabelsResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Labels", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/owner": { "get": { "description": "Return the owner of a session.\n\nRequires read-level access.\n\n**Returns:** `{\"owner\": \"\"}` or `{\"owner\": null}`.", "operationId": "get_session_owner_v1_sessions__session_id__owner_get", "parameters": [ { "description": "Session to look up, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Owner", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/permissions": { "get": { "description": "List all permission grants on a session.\n\nRequires manage-level access.\n\n**Returns:** List of `PermissionObject`.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session or no access.", "operationId": "list_permissions_v1_sessions__session_id__permissions_get", "parameters": [ { "description": "Session to list grants for, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/PermissionObject" }, "title": "Response 200 List Permissions V1 Sessions Session Id Permissions Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Permissions", "tags": [ "sessions" ] }, "put": { "description": "Grant or update a permission on a session.\n\nRequires manage-level access. Upserts the grant \u2014 can\nupgrade or downgrade an existing level. Auto-creates the\ngrantee user if they don't exist yet.\n\n**Parameters**\n\n- `body` \u2014 The grant request with `user_id` and `level`.\n\n**Returns:** The resulting `PermissionObject`.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session or no access, 401 if unauthenticated.", "operationId": "grant_permission_v1_sessions__session_id__permissions_put", "parameters": [ { "description": "Session to grant access to, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GrantPermissionRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PermissionObject" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Grant Permission", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/permissions/{target_user_id}": { "delete": { "description": "Revoke a user's permission on a session.\n\nRequires manage-level access. Cannot revoke your own\nmanage grant (prevents orphaned sessions). Returns 204\nwhether or not the grant existed (idempotent).\n\n**Returns:** 204 No Content.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session or no access, 403 if attempting to revoke own manage grant.", "operationId": "revoke_permission_v1_sessions__session_id__permissions__target_user_id__delete", "parameters": [ { "description": "Session to revoke access from, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "User whose grant to revoke, e.g. `\"alice@example.com\"`.", "in": "path", "name": "target_user_id", "required": true, "schema": { "title": "Target User Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Revoke Permission", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/policies": { "get": { "description": "List all policies for a session.\n\nReturns both store-persisted (`source=\"session\"`) and\nspec-declared (`source=\"spec\"`) policies. Spec policies\nhave `id=None` and cannot be patched or deleted.\n\nRequires `LEVEL_READ` on the session in multi-user mode.\n\n**Returns:** `{\"object\": \"list\", \"data\": [...]}`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks read permission, 404 if the session is not found.", "operationId": "list_policies_v1_sessions__session_id__policies_get", "parameters": [ { "description": "The session to query, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Policies V1 Sessions Session Id Policies Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Policies", "tags": [ "session_policies" ] }, "post": { "description": "Create a new session policy.\n\nRequires `LEVEL_EDIT` on the session in multi-user mode.\n\n**Parameters**\n\n- `body` \u2014 Policy payload including name, type, and handler.\n\n**Returns:** The created policy as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks edit permission, 404 if the session is not found, or 409 if a policy with the same name already exists.", "operationId": "create_policy_v1_sessions__session_id__policies_post", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSessionPolicyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Create Policy V1 Sessions Session Id Policies Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Create Policy", "tags": [ "session_policies" ] } }, "/v1/sessions/{session_id}/policies/evaluate": { "post": { "description": "Generic policy evaluation endpoint (proto-compatible).\n\nAccepts an `EvaluationRequest` JSON body whose `event`\nfield carries the phase (`PHASE_TOOL_CALL`,\n`PHASE_TOOL_RESULT`, `PHASE_LLM_REQUEST`,\n`PHASE_LLM_RESPONSE`), the event data, and optional\ncontext. Returns an `EvaluationResponse` with the policy\nverdict (`result`), an optional `reason`, and optional\n`data` for content-rewriting policies.\n\nUsed by Claude Code's `PreToolUse` and `PostToolUse`\ncommand hooks (via `omnigent.claude_native_hook`) to\nevaluate admin policies on native tool calls. Also usable\nby any client that speaks the proto-compatible JSON schema.\n\n**Returns:** `EvaluationResponse` JSON with `result`, `reason`, and optional `data`.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if the session doesn't exist, 400 if the body is malformed.", "operationId": "evaluate_policy_v1_sessions__session_id__policies_evaluate_post", "parameters": [ { "description": "Omnigent conversation id from the URL path.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Evaluate Policy", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/policies/{policy_id}": { "delete": { "description": "Delete a session policy.\n\nIdempotent \u2014 deleting a missing policy returns 204.\nRequires `LEVEL_EDIT`.\n\n**Returns:** `{\"deleted\": true}`.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks edit permission.", "operationId": "delete_policy_v1_sessions__session_id__policies__policy_id__delete", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "The policy to delete, e.g. `\"pol_abc123\"`.", "in": "path", "name": "policy_id", "required": true, "schema": { "title": "Policy Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Delete Policy V1 Sessions Session Id Policies Policy Id Delete", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Policy", "tags": [ "session_policies" ] }, "get": { "description": "Get a single session policy.\n\nRequires `LEVEL_READ` on the session in multi-user mode.\n\n**Returns:** The policy as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks read permission, or 404 if the policy is not found.", "operationId": "get_policy_v1_sessions__session_id__policies__policy_id__get", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "The policy to retrieve, e.g. `\"pol_abc123\"`.", "in": "path", "name": "policy_id", "required": true, "schema": { "title": "Policy Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Get Policy V1 Sessions Session Id Policies Policy Id Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Policy", "tags": [ "session_policies" ] }, "patch": { "description": "Update a session policy's mutable fields.\n\n`type` is immutable \u2014 the caller must delete and\nre-create to change it. Requires `LEVEL_EDIT`.\n\n**Parameters**\n\n- `body` \u2014 Fields to update; `None` fields are left unchanged.\n\n**Returns:** The updated policy as a serialized dict.\n\n**Raises**\n\n- `OmnigentError` \u2014 401/403 if the user lacks edit permission, or 404 if the policy is not found.", "operationId": "update_policy_v1_sessions__session_id__policies__policy_id__patch", "parameters": [ { "description": "The owning session, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "The policy to update, e.g. `\"pol_abc123\"`.", "in": "path", "name": "policy_id", "required": true, "schema": { "title": "Policy Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSessionPolicyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Update Policy V1 Sessions Session Id Policies Policy Id Patch", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Update Policy", "tags": [ "session_policies" ] } }, "/v1/sessions/{session_id}/read-state": { "put": { "description": "Set the calling user's read-state for one session.\n\nRequires `LEVEL_READ` on the session in multi-user mode \u2014 you can\nonly track read-state for sessions you can see. Stores the values\nverbatim (the client enforces the baseline's monotonicity and the\nunread semantics); the server does not interpret them against\nsession status. Returns `204` \u2014 the client already has the\noptimistic state and re-reads the authoritative value on the next\n`GET /v1/sessions` poll.\n\n**Parameters**\n\n- `body` \u2014 The validated `ReadStatePutRequest`.\n\n**Returns:** An empty `204 No Content` response.\n\n**Raises**\n\n- `OmnigentError` \u2014 403 if the caller lacks read access.", "operationId": "put_read_state_v1_sessions__session_id__read_state_put", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReadStatePutRequest" } } }, "required": true }, "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Put Read State", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/resources": { "get": { "description": "Return the runner-authoritative resource inventory for a session.\n\nRequires the session to be bound to a runner via\n`PATCH /v1/sessions/{id}`; raises `conflict` otherwise.\nThe server validates the session exists, then proxies to the\nrunner's `GET /v1/sessions/{id}/resources` endpoint. In\nunit-test / in-process setups with no runner router/client, the\nroute falls back to adapting the local terminal registry.", "operationId": "list_session_resources_v1_sessions__session_id__resources_get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Optional resource-type filter, e.g. `\"environment\"` / `\"terminal\"` / `\"file\"`. Forwarded to the runner (its registry applies it) and honored by the local-registry fallback and the file-store merge below.", "in": "query", "name": "type", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Type" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResourcePaginatedList" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Session Resources", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments": { "get": { "description": "Return only environment resources for a session.\n\n**Returns:** `PaginatedList` of environment resources.", "operationId": "list_session_environments_v1_sessions__session_id__resources_environments_get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Session Environments", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments/{environment_id}": { "get": { "description": "Return a single environment resource by id.\n\n**Returns:** The environment resource object.", "operationId": "get_session_environment_v1_sessions__session_id__resources_environments__environment_id__get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Opaque environment resource id, e.g. `\"default\"`.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Environment", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments/{environment_id}/changes": { "get": { "description": "List all files changed since session start (flat, registry-backed).\n\nReturns the watchdog change set for the session \u2014 every file\ncreated, modified, or deleted since the session began, regardless\nof directory depth. Use for the flat \"changed files\" view.\n\n**Returns:** Flat list of changed filesystem entries with `status`.", "operationId": "list_environment_filesystem_changes_v1_sessions__session_id__resources_environments__environment_id__changes_get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Environment Filesystem Changes", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments/{environment_id}/filesystem": { "get": { "description": "List root directory of an environment.\n\n**Returns:** PaginatedList of filesystem entries.", "operationId": "list_environment_root_v1_sessions__session_id__resources_environments__environment_id__filesystem_get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } }, { "description": "Maximum number of entries to return (1-1000, default 20).", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor entry id for forward pagination.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor entry id for backward pagination.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "Sort order, `\"asc\"` or `\"desc\"`.", "in": "query", "name": "order", "required": false, "schema": { "default": "desc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Environment Root", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments/{environment_id}/filesystem/{relative_path}": { "delete": { "description": "Delete a file or directory in an environment.\n\n**Returns:** Delete result.", "operationId": "delete_environment_path_v1_sessions__session_id__resources_environments__environment_id__filesystem__relative_path__delete", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } }, { "description": "Path relative to environment root.", "in": "path", "name": "relative_path", "required": true, "schema": { "title": "Relative Path", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Environment Path", "tags": [ "session_resources" ] }, "get": { "description": "Read a file or list a directory in an environment.\n\n**Returns:** File content or directory listing.", "operationId": "read_or_list_environment_path_v1_sessions__session_id__resources_environments__environment_id__filesystem__relative_path__get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } }, { "description": "Path relative to environment root.", "in": "path", "name": "relative_path", "required": true, "schema": { "title": "Relative Path", "type": "string" } }, { "description": "Maximum number of entries to return for directory listings (1-1000, default 20). Ignored for file reads.", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor entry id for forward pagination.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor entry id for backward pagination.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "Sort order, `\"asc\"` or `\"desc\"`.", "in": "query", "name": "order", "required": false, "schema": { "default": "desc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Read Or List Environment Path", "tags": [ "session_resources" ] }, "patch": { "description": "Edit a file in an environment via text replacement.\n\n**Returns:** Edit result.", "operationId": "edit_environment_file_v1_sessions__session_id__resources_environments__environment_id__filesystem__relative_path__patch", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } }, { "description": "Path relative to environment root.", "in": "path", "name": "relative_path", "required": true, "schema": { "title": "Relative Path", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Edit Environment File", "tags": [ "session_resources" ] }, "put": { "description": "Write/replace a file in an environment.\n\n**Returns:** Write result.", "operationId": "write_environment_file_v1_sessions__session_id__resources_environments__environment_id__filesystem__relative_path__put", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } }, { "description": "Path relative to environment root.", "in": "path", "name": "relative_path", "required": true, "schema": { "title": "Relative Path", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Write Environment File", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments/{environment_id}/search": { "get": { "description": "Search for files recursively by name/path substring and glob filters.\n\nProxies to the runner's search endpoint. Returns a flat list of\nmatching file entries (not directories) whose name or relative path\ncontains `q` (case-insensitive), optionally scoped by `include` /\n`exclude` globs. Requires at least one non-whitespace character in\n`q` to prevent accidental full-tree scans.\n\n**Returns:** JSON list response with matching filesystem entries.", "operationId": "search_environment_files_v1_sessions__session_id__resources_environments__environment_id__search_get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id, e.g. `\"default\"`.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } }, { "description": "Case-insensitive search substring, e.g. `\"test.md\"`. Must contain at least one non-whitespace character.", "in": "query", "name": "q", "required": true, "schema": { "minLength": 1, "pattern": ".*\\S.*", "title": "Q", "type": "string" } }, { "description": "Comma-separated glob patterns scoping which files are returned, e.g. `\"*.ts,src/**\"`.", "in": "query", "name": "include", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Include" } }, { "description": "Comma-separated glob patterns for files to drop, e.g. `\"**/node_modules,*.test.ts\"`.", "in": "query", "name": "exclude", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Exclude" } }, { "description": "Maximum number of results (1-500, default 500).", "in": "query", "name": "limit", "required": false, "schema": { "default": 500, "maximum": 500, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Search Environment Files", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/environments/{environment_id}/shell": { "post": { "description": "Execute a shell command in an environment.\n\n**Returns:** Shell result.", "operationId": "run_environment_shell_v1_sessions__session_id__resources_environments__environment_id__shell_post", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Environment resource id.", "in": "path", "name": "environment_id", "required": true, "schema": { "title": "Environment Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Run Environment Shell", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/files": { "get": { "description": "List files owned by a session.\n\n**Returns:** `PaginatedList` of session file resources.", "operationId": "list_session_files_v1_sessions__session_id__resources_files_get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Maximum number of files to return.", "in": "query", "name": "limit", "required": false, "schema": { "default": 20, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } }, { "description": "Cursor file ID for forward pagination.", "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "description": "Cursor file ID for backward pagination.", "in": "query", "name": "before", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Before" } }, { "description": "Sort direction, `\"desc\"` or `\"asc\"`.", "in": "query", "name": "order", "required": false, "schema": { "default": "desc", "pattern": "^(asc|desc)$", "title": "Order", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Session Files", "tags": [ "session_resources" ] }, "post": { "description": "Upload a file into the session file namespace.\n\nAccepts the multipart upload shape used by session file resources.\n\n**Parameters**\n\n- `file` \u2014 The uploaded file (multipart form data).\n\n**Returns:** The session file resource object.", "operationId": "upload_session_file_v1_sessions__session_id__resources_files_post", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_upload_session_file_v1_sessions__session_id__resources_files_post" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Upload Session File", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/files/{file_id}": { "delete": { "description": "Delete a session file resource and its artifact bytes.\n\n**Returns:** Deletion confirmation object.", "operationId": "delete_session_file_v1_sessions__session_id__resources_files__file_id__delete", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Unique file identifier.", "in": "path", "name": "file_id", "required": true, "schema": { "title": "File Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Session File", "tags": [ "session_resources" ] }, "get": { "description": "Retrieve metadata for a session file resource.\n\nVerifies that `file_id` belongs to `session_id`.\n\n**Returns:** The session file resource object.", "operationId": "get_session_file_v1_sessions__session_id__resources_files__file_id__get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Unique file identifier.", "in": "path", "name": "file_id", "required": true, "schema": { "title": "File Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session File", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/files/{file_id}/content": { "get": { "description": "Download raw content of a session file resource.\n\n**Returns:** Response with file bytes and Content-Type.", "operationId": "get_session_file_content_v1_sessions__session_id__resources_files__file_id__content_get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Unique file identifier.", "in": "path", "name": "file_id", "required": true, "schema": { "title": "File Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session File Content", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/files:copy": { "post": { "description": "Copy lineage-owned files into this (destination) session.\n\nAuthorizes by spawn lineage: `body.source_session_id` must be a\nSTRICT ancestor of this session up the `parent_conversation_id`\nchain \u2014 the session may not name itself as the source. Each source\nfile is read and re-stored as a new child-scoped row owned by\n`session_id` \u2014 this preserves the session-scoping invariant (the\nchild reads its OWN copy; no cross-session read grant is created).\nValidation is all-or-nothing: an unauthorized source, a missing\nfile, or a request past the copy limits copies nothing.\n\nThe request is bounded before any blob is read: the file count and\nthe summed `StoredFile.bytes` are checked against the copy limits\nduring metadata validation, so an over-limit request is rejected\nwithout buffering a single blob. Within the limits, files are copied\none at a time (read \u2192 create \u2192 put) so peak memory is a single blob,\nnot the whole batch.\n\n**Parameters**\n\n- `body` \u2014 Source session id plus the file ids to copy.\n\n**Returns:** A `session.files.copied` object carrying the `{source_file_id: new_file_id}` mapping.", "operationId": "copy_session_files_v1_sessions__session_id__resources_files_copy_post", "parameters": [ { "description": "Destination (child) session/conversation id.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CopyFilesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Copy Session Files", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/terminals": { "get": { "description": "Return only terminal resources for a session.\n\nThe runner endpoint's pagination params (`limit` / `after` /\n`before` / `order`) are forwarded from the incoming query\nstring \u2014 without this, a client-requested `order=asc` (the web\nterminal tabs rely on creation order to keep the session's own\nterminal first) would be silently dropped and the runner's\n`desc` default would apply.\n\n**Returns:** `PaginatedList` of terminal resources.", "operationId": "list_session_terminals_v1_sessions__session_id__resources_terminals_get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "List Session Terminals", "tags": [ "session_resources" ] }, "post": { "description": "Launch or return an existing terminal resource.\n\nPreserves `sys_terminal_launch` idempotency: an\nalready-running `(terminal, session_key)` returns the\nexisting resource.\n\nUser-initiated creates are gated on the agent's terminal\naccess: the requested `terminal` must be one of the names\ndeclared in the agent spec's `terminals:` block. Native\nharness bootstrap requests (marked `ensure_native_terminal`\nor `bridge_inject_dir` \u2014 the `omnigent claude` / `codex`\nwrappers launching the session's own CLI terminal) are exempt:\nthey launch undeclared names via the runner's\nsynthesize-from-body path and predate the gate. The markers\nare client-controlled, so the exemption is narrowed to the\nexact shape those wrappers send \u2014 a registered native terminal\nname with `session_key` `\"main\"` \u2014 anything else carrying a\nmarker still goes through the declared-name gate (it would\notherwise be an arbitrary-terminal bypass).\n\n**Returns:** The terminal resource object.\n\n**Raises**\n\n- `OmnigentError` \u2014 400 when the requested terminal is not declared by the agent spec (or the agent has no `terminals:` block at all).", "operationId": "create_session_terminal_v1_sessions__session_id__resources_terminals_post", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Create Session Terminal", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/terminals/{terminal_id}": { "delete": { "description": "Close a terminal resource.\n\nDelegates to `TerminalRegistry.close()` on the runner.\nReturns 404 for unknown terminals.\n\n**Returns:** Deletion confirmation object.", "operationId": "delete_session_terminal_v1_sessions__session_id__resources_terminals__terminal_id__delete", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Opaque terminal resource id.", "in": "path", "name": "terminal_id", "required": true, "schema": { "title": "Terminal Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Delete Session Terminal", "tags": [ "session_resources" ] }, "get": { "description": "Return a single terminal resource by id.\n\n**Returns:** The terminal resource object.", "operationId": "get_session_terminal_v1_sessions__session_id__resources_terminals__terminal_id__get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Opaque terminal resource id.", "in": "path", "name": "terminal_id", "required": true, "schema": { "title": "Terminal Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Terminal", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/resources/{resource_id}": { "get": { "description": "Return a single resource by id from the unified inventory.\n\n**Returns:** The resource object regardless of type.", "operationId": "get_session_resource_v1_sessions__session_id__resources__resource_id__get", "parameters": [ { "description": "Session/conversation identifier.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Opaque resource id.", "in": "path", "name": "resource_id", "required": true, "schema": { "title": "Resource Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Get Session Resource", "tags": [ "session_resources" ] } }, "/v1/sessions/{session_id}/stream": { "get": { "description": "Subscribe to the session's live SSE event stream.\n\nDoes NOT replay history; clients reconcile via the snapshot\nendpoint. The generator handles disconnects via a\n`try/finally` that emits the `[DONE]` sentinel in all\nexit paths \u2014 see `_stream_live_events`.\n\nHolding this stream open registers the caller as a session\n*viewer* (presence): co-viewers' streams receive\n`session.presence` events on join/leave/idle edges, and\nthis stream's snapshot-on-connect includes the current\nviewer list. Presence is scoped to the session tree's root\nconversation, so viewers of different agents/sub-agents in\none session see each other. See\n`omnigent/server/presence.py`.\n\n**Returns:** An SSE `StreamingResponse`.\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if no session exists.", "operationId": "stream_session_v1_sessions__session_id__stream_get", "parameters": [ { "description": "Session/conversation identifier, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } }, { "description": "Presence idle flag computed by the web client at connect time (tab backgrounded \u2265 its debounce). An idle *flip* mid-view arrives as a reconnect carrying the new value \u2014 there is no separate update endpoint.", "in": "query", "name": "idle", "required": false, "schema": { "default": false, "title": "Idle", "type": "boolean" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} }, "text/event-stream": { "itemSchema": { "$ref": "#/components/schemas/ServerStreamEvent" } } }, "description": "SSE stream of `ServerStreamEvent` frames for the session." }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Stream Session", "tags": [ "sessions" ] } }, "/v1/sessions/{session_id}/switch-agent": { "post": { "description": "Switch an existing session in place to a different agent/harness.\n\nUnlike fork, this keeps the SAME session \u2014 transcript, comments,\nfiles, host, and workspace are untouched; only the agent/harness\nchanges. The current session-scoped agent is replaced by a clone\nof the target built-in, model settings carry over only within the\nsame provider family (a model id is provider-bound), the native\nruntime session id is cleared, and the harness-presentation labels\nare recomputed for the target. The next turn cold-starts the new\nharness (rebuilding the native transcript from this session's own\nitems for a same-family native target). Only built-in agents are\nbindable, and only while the session is idle.\n\n**Parameters**\n\n- `body` \u2014 The validated `SessionSwitchAgentRequest`.\n\n**Returns:** A `SessionResponse` describing the session after the switch (status `\"idle\"`).\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if the session or target agent does not exist or the target is not a bindable built-in; 403 if the caller lacks edit access; 400 if the session is a sub-agent, has no agent binding, or the target bundle can't be loaded; 409 if a turn is currently running.", "operationId": "switch_session_agent_v1_sessions__session_id__switch_agent_post", "parameters": [ { "description": "Session/conversation identifier to switch, e.g. `\"conv_abc123\"`.", "in": "path", "name": "session_id", "required": true, "schema": { "title": "Session Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionSwitchAgentRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Switch Session Agent", "tags": [ "sessions" ] } }, "/v1/sessions/{source_id}/fork": { "post": { "description": "Fork an existing session into a new session.\n\nDeep-copies the source session's conversation items and\nclones the agent into a new session. When `body.agent_id`\nis set, the fork binds that built-in agent instead of the\nsource's \u2014 switching harness (e.g. Claude-SDK \u2192 Claude Code,\nor Claude \u2192 Codex). The source's model settings carry over\nonly within the same provider family; a same-family native\ntarget also carries conversation history (the runner rebuilds\nits transcript). The REPL/CLI binds the fork to its runner via\n`PATCH /v1/sessions/{id}` after creation.\n\nWhen `body.up_to_response_id` is set, only history up to and\nincluding that response is copied into the fork (a \"fork from\nthis response\"); a native target then rebuilds its transcript\nfrom the truncated items instead of resuming the source's full\nnative transcript.\n\n**Parameters**\n\n- `body` \u2014 The validated `SessionForkRequest`.\n\n**Returns:** A `SessionResponse` describing the newly created fork (status `\"idle\"`).\n\n**Raises**\n\n- `OmnigentError` \u2014 404 if *source_id* does not exist or `body.agent_id` is not a bindable built-in agent; 403 if the caller lacks read access; 400 if the source is a sub-agent session, has no agent binding, or `body.up_to_response_id` names no response in the source session.", "operationId": "fork_session_v1_sessions__source_id__fork_post", "parameters": [ { "description": "Session/conversation identifier of the source session to fork, e.g. `\"conv_abc123\"`.", "in": "path", "name": "source_id", "required": true, "schema": { "title": "Source Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionForkRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Fork Session", "tags": [ "sessions" ] } } }, "servers": [ { "description": "Self-hosted Omnigent server (default local port).", "url": "http://127.0.0.1:6767" } ], "tags": [ { "description": "Create, inspect, fork, and drive agent sessions \u2014 the core unit of work. Covers session items and events, agent binding, permissions, labels, and child sessions. The files, terminals, and sandboxed environments attached to a session live under Session Resources.", "name": "sessions", "x-displayName": "Sessions" }, { "description": "Files, terminals, and sandboxed environments attached to a session: upload and read files, create and manage terminals, and read, write, edit, and search the environment filesystem.", "name": "session_resources", "x-displayName": "Session Resources" }, { "description": "Manage the MCP server declarations on a session's bound agent: list the configured servers and create, update, and remove them on session-scoped agents.", "name": "session_mcp_servers", "x-displayName": "Session MCP Servers" }, { "description": "Discover the built-in agents available to bind to a session.", "name": "agents", "x-displayName": "Agents" }, { "description": "Hosts that can launch runners. Browse the host filesystem and create directories.", "name": "hosts", "x-displayName": "Hosts" }, { "description": "Launch runners on a host and check their status.", "name": "runners", "x-displayName": "Runners" }, { "description": "Contextual policies scoped to a single session \u2014 list, create, update, and remove.", "name": "session_policies", "x-displayName": "Session Policies" }, { "description": "Server-level default policies applied to new sessions.", "name": "default_policies", "x-displayName": "Default Policies" }, { "description": "The catalog of policy types available to instantiate.", "name": "policy_registry", "x-displayName": "Policy Registry" }, { "description": "Threaded comments on a session, including sending a comment to the agent.", "name": "comments", "x-displayName": "Comments" }, { "description": "Health, version, and identity endpoints for the running server.", "name": "system", "x-displayName": "System" } ] }