From a47c7e797d1fc9603744e62152ba0847846335a4 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Fri, 19 Jun 2026 17:19:33 +0200 Subject: [PATCH 01/12] =?UTF-8?q?feat(ci):=20endpoint-audit=20gate=20?= =?UTF-8?q?=E2=80=94=20client=20vs=20agent-server=20OpenAPI=20spec?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adds scripts/endpoint-audit.mjs which diffs the client's HTTP surface against the agent-server OpenAPI spec (live from the running container, or the committed specs/agent-server.openapi.json fallback) and reports: - mismatch: client calls an endpoint the server does not expose (gated) - missing API: server exposes an endpoint the client does not implement Runs as a release gate in release.yml (boots the 1.29.0 image for the live spec). Today's 3 known drifts (cloud-proxy, generate_title, skills /update -> /refresh) are baselined in endpoint-audit.config.json so the gate fails only on new drift. Run locally with: npm run audit:endpoints --- .github/workflows/release.yml | 50 ++++++++++- .gitignore | 3 + endpoint-audit.config.json | 33 +++++++ package.json | 1 + scripts/endpoint-audit.mjs | 148 ++++++++++++++++++++++++++++++++ specs/agent-server.openapi.json | 1 + 6 files changed, 235 insertions(+), 1 deletion(-) create mode 100644 endpoint-audit.config.json create mode 100644 scripts/endpoint-audit.mjs create mode 100644 specs/agent-server.openapi.json diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0a6a717..3c82912 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,9 +10,57 @@ permissions: packages: write jobs: + # Gate the release on the endpoint audit: the client must not call endpoints + # the released agent-server no longer exposes. The audit diffs the client's + # HTTP surface against the live server's OpenAPI spec. See + # scripts/endpoint-audit.mjs. + endpoint-audit: + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + AGENT_SERVER_PORT: 8010 + AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:1.29.0-python + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Start agent-server (ground-truth OpenAPI spec) + run: | + docker pull "${AGENT_SERVER_IMAGE}" + docker run -d --name agent-server -p ${AGENT_SERVER_PORT}:8000 \ + -e LOG_JSON=true "${AGENT_SERVER_IMAGE}" + for i in $(seq 1 30); do + curl -sf http://localhost:${AGENT_SERVER_PORT}/health && break + echo "waiting for agent-server ($i)..."; sleep 2 + done + + - name: Endpoint audit (gates on client/server mismatch) + run: npm run audit:endpoints + + - name: Upload audit report + if: always() + uses: actions/upload-artifact@v4 + with: + name: endpoint-audit + path: .audit/ + + - name: Stop agent-server + if: always() + run: docker rm -f agent-server || true + release: runs-on: ubuntu-latest - + needs: endpoint-audit + steps: - name: Checkout code uses: actions/checkout@v4 diff --git a/.gitignore b/.gitignore index cf3977d..e5e4da9 100644 --- a/.gitignore +++ b/.gitignore @@ -93,3 +93,6 @@ jspm_packages/ # TernJS port file .tern-port + +# endpoint-audit runtime coverage logs +.audit/ diff --git a/endpoint-audit.config.json b/endpoint-audit.config.json new file mode 100644 index 0000000..9cb8714 --- /dev/null +++ b/endpoint-audit.config.json @@ -0,0 +1,33 @@ +{ + "specs": [ + { + "name": "agent-server", + "url": "http://localhost:8010/openapi.json", + "file": "specs/agent-server.openapi.json" + } + ], + "clientGlobs": ["src/client", "src/conversation", "src/workspace"], + + "externalPrefixes": [ + "/api/security/", + "/api/meta-profiles", + "/api/keys", + "/api/shared-", + "/api/accept_tos", + "/api/unset-provider-tokens" + ], + + "ignoreServerOnly": ["/v1/"], + + "_comment_allowClientOnly": "Baselined drift against agent-server 1.29.0. Each entry is the client calling an endpoint the server no longer exposes (a TODO to fix in the client), not an endorsement. Remove entries as they are fixed; new drift is NOT allowlisted and will fail the gate. cloud-proxy + generate_title were dropped server-side; skills uses /update but the server now exposes /refresh.", + "allowClientOnly": [ + "POST /api/cloud-proxy", + "POST /api/conversations/{}/generate_title", + "POST /api/skills/installed/{}/update" + ], + + "gate": { + "mismatch": true, + "missingApi": false + } +} diff --git a/package.json b/package.json index 1649d11..3f7808d 100644 --- a/package.json +++ b/package.json @@ -56,6 +56,7 @@ "test:integration:llm": "jest --config jest.integration.config.cjs --runInBand --testPathIgnorePatterns=\"deterministic-api.integration.test.ts|bash.integration.test.ts\"", "test:git-dependency": "node ./scripts/smoke-test-git-dependency.mjs", "test:all": "npm run test && npm run test:integration && npm run test:git-dependency", + "audit:endpoints": "node ./scripts/endpoint-audit.mjs", "dev": "tsc --watch", "clean": "rimraf dist", "prepare": "npm run clean && npm run build", diff --git a/scripts/endpoint-audit.mjs b/scripts/endpoint-audit.mjs new file mode 100644 index 0000000..445f0b6 --- /dev/null +++ b/scripts/endpoint-audit.mjs @@ -0,0 +1,148 @@ +#!/usr/bin/env node +/** + * Endpoint audit — reconciles the client's HTTP surface against the + * agent-server OpenAPI spec and reports API drift: + * + * 1. mismatch — client calls an endpoint the server does NOT expose + * (a breakage, unless it lives on a known external backend + * listed in `externalPrefixes`) + * 2. missing API — server exposes an endpoint the client does NOT implement + * + * Ground truth is the server's own OpenAPI spec, fetched live from a running + * container (preferred) or read from the committed fallback file. + * + * Exit code is non-zero on gating violations (see config.gate), so the script + * can act as a release gate. + */ +import fs from 'node:fs'; +import path from 'node:path'; + +const ROOT = process.cwd(); +const cfg = JSON.parse(fs.readFileSync(path.join(ROOT, 'endpoint-audit.config.json'), 'utf8')); + +const VERBS = ['get', 'post', 'put', 'patch', 'delete']; + +// "/api/x/${id}" or "/api/x/{name}" -> "/api/x/{}", strip query + trailing slash +const norm = (verb, p) => + `${verb.toUpperCase()} ${ + p + .split('?')[0] + .replace(/\$?\{[^{}]*\}/g, '{}') + .replace(/\/+$/, '') || '/' + }`; + +// --------------------------------------------------------------------------- +// 1. Ground truth: union of all configured backend specs +// --------------------------------------------------------------------------- +async function loadSpec(spec) { + if (spec.url) { + try { + const res = await fetch(spec.url, { signal: AbortSignal.timeout(5000) }); + if (res.ok) return await res.json(); + console.warn(` ! ${spec.name}: ${spec.url} -> HTTP ${res.status}, falling back to file`); + } catch (e) { + console.warn( + ` ! ${spec.name}: ${spec.url} unreachable (${e.message}), falling back to file` + ); + } + } + if (spec.file && fs.existsSync(path.join(ROOT, spec.file))) + return JSON.parse(fs.readFileSync(path.join(ROOT, spec.file), 'utf8')); + throw new Error(`spec "${spec.name}": no reachable url and no fallback file`); +} + +const server = new Set(); // normalized "VERB /path" +for (const spec of cfg.specs) { + const doc = await loadSpec(spec); + for (const [p, methods] of Object.entries(doc.paths ?? {})) + for (const verb of Object.keys(methods)) if (VERBS.includes(verb)) server.add(norm(verb, p)); +} + +// --------------------------------------------------------------------------- +// 2. Client surface: static extraction of every endpoint the client can call +// --------------------------------------------------------------------------- +function walk(dir) { + const out = []; + for (const e of fs.readdirSync(dir, { withFileTypes: true })) { + const full = path.join(dir, e.name); + if (e.isDirectory()) { + if (e.name === '__tests__' || e.name === 'node_modules') continue; + out.push(...walk(full)); + } else if (e.name.endsWith('.ts')) out.push(full); + } + return out; +} + +const VERB_CALL = /\.(get|post|put|patch|delete)\s*(<[^>]*>)?\(/; +const PATH_LIT = /[`'"](\/(?:api|server_info|alive|health|ready)[^`'"]*)[`'"]/; + +const client = new Set(); +for (const glob of cfg.clientGlobs) { + for (const file of walk(path.join(ROOT, glob))) { + const lines = fs.readFileSync(file, 'utf8').split('\n'); + lines.forEach((ln, i) => { + // direct `.get/post/...(` calls, plus generic `.request({ method, url })` + let verb = ln.match(VERB_CALL)?.[1]; + let win = 3; + if (!verb && /\.request\s*\(/.test(ln)) { + const block = lines.slice(i, i + 6).join('\n'); + verb = block.match(/method:\s*['"`](GET|POST|PUT|PATCH|DELETE)['"`]/i)?.[1]; + win = 6; + } + if (!verb) return; + const p = lines + .slice(i, i + win) + .join('\n') + .match(PATH_LIT)?.[1]; + if (p) client.add(norm(verb, p)); + }); + } +} + +// --------------------------------------------------------------------------- +// 3. Diff +// --------------------------------------------------------------------------- +const sorted = (it) => [...it].sort(); +const isExternal = (k) => cfg.externalPrefixes.some((pre) => k.includes(pre)); +const ignoredApi = (k) => (cfg.ignoreServerOnly ?? []).some((pre) => k.includes(pre)); + +const clientOnly = sorted([...client].filter((k) => !server.has(k))); +const mismatch = clientOnly.filter((k) => !isExternal(k) && !cfg.allowClientOnly.includes(k)); +const external = clientOnly.filter(isExternal); +const missingApi = sorted([...server].filter((k) => !client.has(k) && !ignoredApi(k))); + +// --------------------------------------------------------------------------- +// 4. Report +// --------------------------------------------------------------------------- +const section = (title, items) => { + console.log(`\n${title} (${items.length})`); + for (const k of items) console.log(` ${k}`); +}; +console.log(`\n=== Endpoint audit — server=${server.size} client=${client.size} ===`); +section('❌ MISMATCH — client calls an endpoint not on the server', mismatch); +section('ℹ️ external backend (not gated)', external); +section('➕ MISSING API — server has it, client does not implement', missingApi); + +fs.mkdirSync(path.join(ROOT, '.audit'), { recursive: true }); +fs.writeFileSync( + path.join(ROOT, '.audit/endpoint-audit.json'), + JSON.stringify( + { server: server.size, client: client.size, mismatch, external, missingApi }, + null, + 2 + ) +); + +// --------------------------------------------------------------------------- +// 5. Gate +// --------------------------------------------------------------------------- +const g = cfg.gate ?? {}; +const violations = []; +if (g.mismatch !== false && mismatch.length) violations.push(`${mismatch.length} mismatch`); +if (g.missingApi && missingApi.length) violations.push(`${missingApi.length} missing API`); + +if (violations.length) { + console.error(`\n❌ endpoint audit failed: ${violations.join(', ')}`); + process.exit(1); +} +console.log('\n✅ endpoint audit passed'); diff --git a/specs/agent-server.openapi.json b/specs/agent-server.openapi.json new file mode 100644 index 0000000..45ac8d4 --- /dev/null +++ b/specs/agent-server.openapi.json @@ -0,0 +1 @@ +{"openapi":"3.1.0","info":{"title":"OpenHands Agent Server","description":"OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent","version":"0.1.0"},"paths":{"/alive":{"get":{"tags":["Server Details"],"summary":"Alive","description":"Basic liveness check - returns OK if the server process is running.","operationId":"alive_alive_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}}}}},"/health":{"get":{"tags":["Server Details"],"summary":"Health","description":"Basic health check - returns OK if the server process is running.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}}}}},"/ready":{"get":{"tags":["Server Details"],"summary":"Ready","description":"Readiness check - returns OK only if the server has completed initialization.\n\nThis endpoint should be used by Kubernetes readiness probes to determine\nwhen the pod is ready to receive traffic. Returns 503 during initialization.","operationId":"ready_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Ready Ready Get"}}}}}}},"/server_info":{"get":{"tags":["Server Details"],"summary":"Get Server Info","operationId":"get_server_info_server_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerInfo"}}}}}}},"/api/init":{"get":{"tags":["Init"],"summary":"Get Init Status","description":"Report the current init state.\n\nAuthentication is intentionally not required on this endpoint so a warm\npool controller can poll it without holding the init key. The payload\ncontains no sensitive data.","operationId":"get_init_status_api_init_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitStatus"}}}}}},"post":{"tags":["Init"],"summary":"Initialize Server","description":"Initialize a dormant server with runtime configuration.\n\nReturns 400 if the server has already been initialized (state != dormant).\nReturns 500 if initialization fails; in that case the state rolls back to\n``dormant`` so the orchestrator can retry.","operationId":"initialize_server_api_init_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/conversations/{conversation_id}/events/search":{"get":{"tags":["Events"],"summary":"Search Conversation Events","description":"Search / List local events","operationId":"search_conversation_events_api_conversations__conversation_id__events_search_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event kind/type (e.g., ActionEvent, MessageEvent)"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event source (e.g., agent, user, environment)"}},{"name":"body","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by message content (case-insensitive)"}},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/EventSortOrder","title":"Sort order for events","default":"TIMESTAMP"}},{"name":"timestamp__gte","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp >= this datetime"}},{"name":"timestamp__lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp < this datetime"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventPage"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events/count":{"get":{"tags":["Events"],"summary":"Count Conversation Events","description":"Count local events matching the given filters","operationId":"count_conversation_events_api_conversations__conversation_id__events_count_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event kind/type (e.g., ActionEvent, MessageEvent)"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event source (e.g., agent, user, environment)"}},{"name":"body","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by message content (case-insensitive)"}},{"name":"timestamp__gte","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp >= this datetime"}},{"name":"timestamp__lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp < this datetime"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"integer","title":"Response Count Conversation Events Api Conversations Conversation Id Events Count Get"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events/{event_id}":{"get":{"tags":["Events"],"summary":"Get Conversation Event","description":"Get a local event given an id","operationId":"get_conversation_event_api_conversations__conversation_id__events__event_id__get","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"}},{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events":{"get":{"tags":["Events"],"summary":"Batch Get Conversation Events","description":"Get a batch of local events given their ids, returning null for any\nmissing item.","operationId":"batch_get_conversation_events_api_conversations__conversation_id__events_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Event Ids"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Event"},{"type":"null"}]},"title":"Response Batch Get Conversation Events Api Conversations Conversation Id Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Events"],"summary":"Send Message","description":"Send a message to a conversation","operationId":"send_message_api_conversations__conversation_id__events_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events/respond_to_confirmation":{"post":{"tags":["Events"],"summary":"Respond To Confirmation","description":"Accept or reject a pending action in confirmation mode.","operationId":"respond_to_confirmation_api_conversations__conversation_id__events_respond_to_confirmation_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationResponseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/search":{"get":{"tags":["Conversations"],"summary":"Search Conversations","description":"Search / List conversations","operationId":"search_conversations_api_conversations_search_get","parameters":[{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ConversationExecutionStatus"},{"type":"null"}],"title":"Optional filter by conversation execution status"}},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ConversationSortOrder","title":"Sort order for conversations","default":"CREATED_AT_DESC"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/count":{"get":{"tags":["Conversations"],"summary":"Count Conversations","description":"Count conversations matching the given filters","operationId":"count_conversations_api_conversations_count_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ConversationExecutionStatus"},{"type":"null"}],"title":"Optional filter by conversation execution status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"integer","title":"Response Count Conversations Api Conversations Count Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}":{"get":{"tags":["Conversations"],"summary":"Get Conversation","description":"Given an id, get a conversation","operationId":"get_conversation_api_conversations__conversation_id__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationInfo"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Conversations"],"summary":"Delete Conversation","description":"Permanently delete a conversation.","operationId":"delete_conversation_api_conversations__conversation_id__delete","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Conversations"],"summary":"Update Conversation","description":"Update conversation metadata.\n\nThis endpoint allows updating conversation details like title.","operationId":"update_conversation_api_conversations__conversation_id__patch","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConversationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/agent_final_response":{"get":{"tags":["Conversations"],"summary":"Get Conversation Agent Final Response","description":"Get the agent's final response for a conversation.\n\nReturns the text of the last agent finish message (FinishAction) or\nthe last agent text response (MessageEvent). Returns an empty string\nif the agent has not produced a final response yet.","operationId":"get_conversation_agent_final_response_api_conversations__conversation_id__agent_final_response_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponseResult"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations":{"get":{"tags":["Conversations"],"summary":"Batch Get Conversations","description":"Get a batch of conversations given their ids, returning null for\nany missing item","operationId":"batch_get_conversations_api_conversations_get","parameters":[{"name":"ids","in":"query","required":true,"schema":{"type":"array","items":{"type":"string","format":"uuid"},"title":"Ids"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/ConversationInfo"},{"type":"null"}]},"title":"Response Batch Get Conversations Api Conversations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Conversations"],"summary":"Start Conversation","description":"Start a conversation in the local environment.","operationId":"start_conversation_api_conversations_post","parameters":[{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartConversationRequest","examples":[{"workspace":{"working_dir":"workspace/project","kind":"LocalWorkspace"},"initial_message":{"content":[{"text":"Flip a coin!"}]},"agent":{"llm":{"model":"your-model-provider/your-model-name","api_key":"**********","usage_id":"your-llm-service"},"tools":[{"name":"terminal"},{"name":"file_editor"},{"name":"task_tracker"},{"name":"browser_tool_set"}],"system_prompt_kwargs":{"llm_security_analyzer":true},"kind":"Agent"}}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/pause":{"post":{"tags":["Conversations"],"summary":"Pause Conversation","description":"Pause a conversation, allowing it to be resumed later.","operationId":"pause_conversation_api_conversations__conversation_id__pause_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/interrupt":{"post":{"tags":["Conversations"],"summary":"Interrupt Conversation","description":"Immediately interrupt a running conversation.\n\nUnlike ``/pause``, which waits for the current LLM call to finish,\n``/interrupt`` cancels the in-flight request so the effect is instant.\nThe conversation transitions to *paused* and can be resumed later.","operationId":"interrupt_conversation_api_conversations__conversation_id__interrupt_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/run":{"post":{"tags":["Conversations"],"summary":"Run Conversation","description":"Start running the conversation in the background.","operationId":"run_conversation_api_conversations__conversation_id__run_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"409":{"description":"Conversation is already running"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/goal":{"post":{"tags":["Conversations"],"summary":"Start Goal In Conversation","description":"Start a ``/goal`` loop inside an existing conversation.\n\nThe loop appends messages and starts agent runs in the same conversation\nhistory and event stream as the main chat. It does not create a separate\nconversation for the goal or fork the existing one.","operationId":"start_goal_in_conversation_api_conversations__conversation_id__goal_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartGoalRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"409":{"description":"Conversation run or goal loop is already running"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/goal/stop":{"post":{"tags":["Conversations"],"summary":"Stop Goal In Conversation","description":"Stop the active ``/goal`` loop inside this conversation.\n\nThis cancels only the background goal loop, not the conversation itself, and\nrecords an ``interrupted`` goal status so ``/goal/resume`` can continue it.","operationId":"stop_goal_in_conversation_api_conversations__conversation_id__goal_stop_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/goal/resume":{"post":{"tags":["Conversations"],"summary":"Resume Goal In Conversation","description":"Resume the last interrupted ``/goal`` loop inside this conversation.","operationId":"resume_goal_in_conversation_api_conversations__conversation_id__goal_resume_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"409":{"description":"Conversation run or goal loop is already running"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/secrets":{"post":{"tags":["Conversations"],"summary":"Update Conversation Secrets","description":"Update secrets for a conversation.","operationId":"update_conversation_secrets_api_conversations__conversation_id__secrets_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/confirmation_policy":{"post":{"tags":["Conversations"],"summary":"Set Conversation Confirmation Policy","description":"Set the confirmation policy for a conversation.","operationId":"set_conversation_confirmation_policy_api_conversations__conversation_id__confirmation_policy_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetConfirmationPolicyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/security_analyzer":{"post":{"tags":["Conversations"],"summary":"Set Conversation Security Analyzer","description":"Set the security analyzer for a conversation.","operationId":"set_conversation_security_analyzer_api_conversations__conversation_id__security_analyzer_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSecurityAnalyzerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/switch_profile":{"post":{"tags":["Conversations"],"summary":"Switch Conversation Profile","description":"Switch the conversation's LLM profile to a named profile.","operationId":"switch_conversation_profile_api_conversations__conversation_id__switch_profile_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_switch_conversation_profile_api_conversations__conversation_id__switch_profile_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Invalid or corrupted profile"},"404":{"description":"Conversation or profile not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/switch_llm":{"post":{"tags":["Conversations"],"summary":"Switch Conversation Llm","description":"Swap the conversation's LLM to a caller-supplied object.\n\nUsed by app-servers that own the LLM directly and don't push profiles\nto the agent-server's filesystem (see #3017).","operationId":"switch_conversation_llm_api_conversations__conversation_id__switch_llm_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_switch_conversation_llm_api_conversations__conversation_id__switch_llm_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/switch_acp_model":{"post":{"tags":["Conversations"],"summary":"Switch Conversation Acp Model","description":"Switch the model of an ACP conversation.\n\nFor a conversation that has already started, issues a protocol-level\n``session/set_model`` call to the ACP subprocess so the new model applies to\nsubsequent turns without losing context. For one created but not yet run,\nthe value is persisted and applied when the first session starts (returns\n``200`` either way). Only valid for ACP conversations whose provider\nsupports model switching.","operationId":"switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Agent is not ACP, or provider can't switch models"},"404":{"description":"Conversation not found"},"504":{"description":"ACP server did not answer the model switch in time"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/ask_agent":{"post":{"tags":["Conversations"],"summary":"Ask Agent","description":"Ask the agent a simple question without affecting conversation state.","operationId":"ask_agent_api_conversations__conversation_id__ask_agent_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskAgentRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskAgentResponse"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/condense":{"post":{"tags":["Conversations"],"summary":"Condense Conversation","description":"Force condensation of the conversation history.","operationId":"condense_conversation_api_conversations__conversation_id__condense_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/fork":{"post":{"tags":["Conversations"],"summary":"Fork Conversation","description":"Fork a conversation, deep-copying its event history.\n\nThe fork starts in ``idle`` status with a fresh event loop.\nCalling ``run`` on the fork resumes from the copied state, meaning\nthe agent has full event memory of the source conversation.","operationId":"fork_conversation_api_conversations__conversation_id__fork_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForkConversationRequest","default":{"reset_metrics":true}}}}},"responses":{"201":{"description":"Forked conversation created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationInfo"}}}},"404":{"description":"Source conversation not found"},"409":{"description":"Fork ID already in use"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/":{"get":{"tags":["Tools"],"summary":"List Available Tools","description":"List all available tools.","operationId":"list_available_tools_api_tools__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Response List Available Tools Api Tools Get"}}}}}}},"/api/bash/bash_events/search":{"get":{"tags":["Bash"],"summary":"Search Bash Events","description":"Search / List bash event events","operationId":"search_bash_events_api_bash_bash_events_search_get","parameters":[{"name":"kind__eq","in":"query","required":false,"schema":{"anyOf":[{"enum":["BashCommand","BashOutput"],"type":"string"},{"type":"null"}],"title":"Kind Eq"}},{"name":"command_id__eq","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Command Id Eq"}},{"name":"timestamp__gte","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp Gte"}},{"name":"timestamp__lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp Lt"}},{"name":"order__gt","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Filter to events with order greater than this value","description":"Only returns BashOutput events with order > this value. Useful for polling to fetch only new events since the last poll."},"description":"Only returns BashOutput events with order > this value. Useful for polling to fetch only new events since the last poll."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/BashEventSortOrder","default":"TIMESTAMP"}},{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashEventPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/bash_events/{event_id}":{"get":{"tags":["Bash"],"summary":"Get Bash Event","description":"Get a bash event event given an id","operationId":"get_bash_event_api_bash_bash_events__event_id__get","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashEventBase"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/bash_events/":{"get":{"tags":["Bash"],"summary":"Batch Get Bash Events","description":"Get a batch of bash event events given their ids, returning null for any\nmissing item.","operationId":"batch_get_bash_events_api_bash_bash_events__get","requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Event Ids"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"anyOf":[{"$ref":"#/components/schemas/BashEventBase"},{"type":"null"}]},"type":"array","title":"Response Batch Get Bash Events Api Bash Bash Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/start_bash_command":{"post":{"tags":["Bash"],"summary":"Start Bash Command","description":"Execute a bash command in the background","operationId":"start_bash_command_api_bash_start_bash_command_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteBashRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashCommand"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/execute_bash_command":{"post":{"tags":["Bash"],"summary":"Execute Bash Command","description":"Execute a bash command and wait for a result","operationId":"execute_bash_command_api_bash_execute_bash_command_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteBashRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashOutput"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/bash_events":{"delete":{"tags":["Bash"],"summary":"Clear All Bash Events","description":"Clear all bash events from storage","operationId":"clear_all_bash_events_api_bash_bash_events_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"integer"},"type":"object","title":"Response Clear All Bash Events Api Bash Bash Events Delete"}}}}}}},"/api/git/changes":{"get":{"tags":["Git"],"summary":"Git Changes Query","description":"Get git changes using query parameter (preferred method).","operationId":"git_changes_query_api_git_changes_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"The git repository path","title":"Path"},"description":"The git repository path"},{"name":"ref","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected.","title":"Ref"},"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GitChange"},"title":"Response Git Changes Query Api Git Changes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/diff":{"get":{"tags":["Git"],"summary":"Git Diff Query","description":"Get git diff using query parameter (preferred method).","operationId":"git_diff_query_api_git_diff_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"The file path to get diff for","title":"Path"},"description":"The file path to get diff for"},{"name":"ref","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected.","title":"Ref"},"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitDiff"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/upload":{"post":{"tags":["Files"],"summary":"Upload File Query","description":"Upload a file to the workspace using query parameter (preferred method).","operationId":"upload_file_query_api_file_upload_post","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute file path","title":"Path"},"description":"Absolute file path"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_query_api_file_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/download":{"get":{"tags":["Files"],"summary":"Download File Query","description":"Download a file from the workspace using query parameter (preferred method).","operationId":"download_file_query_api_file_download_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute file path","title":"Path"},"description":"Absolute file path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/home":{"get":{"tags":["Files"],"summary":"Get Home Directory","description":"Return the agent-server user's home directory and dynamic sidebar lists.\n\n``favorites`` is the set of visible top-level directories actually present\nin the user's home (so it reflects the real environment instead of a\nhardcoded list of names that may not exist). ``locations`` is the set of\nfilesystem roots — '/' on POSIX or available drive letters on Windows.","operationId":"get_home_directory_api_file_home_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HomeResponse"}}}}}}},"/api/file/search_subdirs":{"get":{"tags":["Files"],"summary":"Search Subdirs","description":"Search / List immediate subdirectories of `path`.\n\nUsed by the GUI's workspace picker. Hidden entries (names starting with '.')\nand symlinks are skipped. Files are skipped. Returns absolute paths so the\nGUI can use a result directly as ``workspace.working_dir``.\n\nResults are sorted case-insensitively by name and paginated. ``page_id`` is\nthe ``next_page_id`` returned by the previous page (the lowercase name of\nthe first item to include on the next page).","operationId":"search_subdirs_api_file_search_subdirs_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute directory path to list subdirectories of","title":"Path"},"description":"Absolute directory path to list subdirectories of"},{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubdirectoryPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/download-trajectory/{conversation_id}":{"get":{"tags":["Files"],"summary":"Download Trajectory","description":"Download a zip archive of a conversation trajectory.","operationId":"download_trajectory_api_file_download_trajectory__conversation_id__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/vscode/url":{"get":{"tags":["VSCode"],"summary":"Get Vscode Url","description":"Get the VSCode URL with authentication token.\n\nArgs:\n base_url: Base URL for the VSCode server (default: http://localhost:8001)\n workspace_dir: Path to workspace directory\n\nReturns:\n VSCode URL with token if available, None otherwise","operationId":"get_vscode_url_api_vscode_url_get","parameters":[{"name":"base_url","in":"query","required":false,"schema":{"type":"string","default":"http://localhost:8001","title":"Base Url"}},{"name":"workspace_dir","in":"query","required":false,"schema":{"type":"string","default":"workspace","title":"Workspace Dir"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VSCodeUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/vscode/status":{"get":{"tags":["VSCode"],"summary":"Get Vscode Status","description":"Get the VSCode server status.\n\nReturns:\n Dictionary with running status and enabled status","operationId":"get_vscode_status_api_vscode_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"string"}]},"type":"object","title":"Response Get Vscode Status Api Vscode Status Get"}}}}}}},"/api/desktop/url":{"get":{"tags":["Desktop"],"summary":"Get Desktop Url","description":"Get the noVNC URL for desktop access.\n\nArgs:\n base_url: Base URL for the noVNC server (default: http://localhost:8002)\n\nReturns:\n noVNC URL if available, None otherwise","operationId":"get_desktop_url_api_desktop_url_get","parameters":[{"name":"base_url","in":"query","required":false,"schema":{"type":"string","default":"http://localhost:8002","title":"Base Url"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesktopUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills":{"post":{"tags":["Skills"],"summary":"Get Skills","description":"Load and merge skills from all configured sources.\n\nSkills are loaded from multiple sources and merged with the following\nprecedence (later overrides earlier for duplicate names):\n1. Sandbox skills (lowest) - Exposed URLs from sandbox\n2. Public skills - From GitHub OpenHands/extensions repository\n3. User skills - From ~/.openhands/skills/\n4. Organization skills - From {org}/.openhands or equivalent\n5. Project skills (highest) - From {workspace}/.openhands/skills/\n\nArgs:\n request: SkillsRequest containing configuration for which sources to load.\n\nReturns:\n SkillsResponse containing merged skills and source counts.","operationId":"get_skills_api_skills_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/sync":{"post":{"tags":["Skills"],"summary":"Sync Skills","description":"Force refresh of public skills from GitHub repository.\n\nThis triggers a git pull on the cached skills repository to get\nthe latest skills from the OpenHands/extensions repository.\n\nReturns:\n SyncResponse indicating success or failure.","operationId":"sync_skills_api_skills_sync_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResponse"}}}}}}},"/api/skills/install":{"post":{"tags":["Skills"],"summary":"Install Skill Endpoint","description":"Install a skill from a source.\n\nInstalls a skill from a git URL, GitHub shorthand, or local path into\nthe user's installed skills directory (~/.openhands/skills/installed/).\n\nArgs:\n request: InstallSkillRequest containing source and options.\n\nReturns:\n InstalledSkillResponse with details about the installation.\n\nRaises:\n HTTPException 409: If skill is already installed and force=False.\n HTTPException 400: If fetching the skill source fails.\n HTTPException 422: If the skill is invalid.","operationId":"install_skill_endpoint_api_skills_install_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallSkillRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstalledSkillResponse"}}}},"400":{"description":"Failed to fetch skill source"},"409":{"description":"Skill already installed (use force=true)"},"422":{"description":"Invalid skill (missing SKILL.md, etc.)"}}}},"/api/skills/installed":{"get":{"tags":["Skills"],"summary":"List Installed Skills Endpoint","description":"List all installed skills.\n\nReturns a list of all skills installed in the user's installed skills\ndirectory (~/.openhands/skills/installed/).\n\nReturns:\n InstalledSkillsListResponse containing list of installed skills.","operationId":"list_installed_skills_endpoint_api_skills_installed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstalledSkillsListResponse"}}}}}}},"/api/skills/installed/{skill_name}":{"get":{"tags":["Skills"],"summary":"Get Installed Skill Endpoint","description":"Get information about a specific installed skill.\n\nArgs:\n skill_name: Name of the skill to get.\n\nReturns:\n InstalledSkillResponse with skill details.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"get_installed_skill_endpoint_api_skills_installed__skill_name__get","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstalledSkillResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Skills"],"summary":"Set Skill Enabled Endpoint","description":"Enable or disable an installed skill.\n\nArgs:\n skill_name: Name of the skill to update.\n request: UpdateSkillStateRequest with enabled state.\n\nReturns:\n UpdateSkillStateResponse indicating new state.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"set_skill_enabled_endpoint_api_skills_installed__skill_name__patch","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillStateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillStateResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Skills"],"summary":"Uninstall Skill Endpoint","description":"Uninstall a skill by name.\n\nRemoves a skill from the user's installed skills directory.\n\nArgs:\n skill_name: Name of the skill to uninstall.\n\nReturns:\n UninstallSkillResponse with uninstall message.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"uninstall_skill_endpoint_api_skills_installed__skill_name__delete","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UninstallSkillResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/installed/{skill_name}/refresh":{"post":{"tags":["Skills"],"summary":"Refresh Skill Endpoint","description":"Refresh an installed skill to the latest version.\n\nRe-fetches the skill from its original source and updates the installation.\n\nArgs:\n skill_name: Name of the skill to refresh.\n\nReturns:\n UpdateSkillResponse with updated skill information.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"refresh_skill_endpoint_api_skills_installed__skill_name__refresh_post","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/marketplace":{"get":{"tags":["Skills"],"summary":"Get Marketplace Catalog","description":"Get the marketplace catalog with installation status.\n\nReturns a list of available skills from the OpenHands extensions\nrepository marketplace, along with their installation status.\n\nThis enables frontend applications to display a \"Marketplace\" tab\nwith installable skills.\n\nReturns:\n MarketplaceCatalogResponse containing list of available skills.","operationId":"get_marketplace_catalog_api_skills_marketplace_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceCatalogResponse"}}}}}}},"/api/hooks":{"post":{"tags":["Hooks"],"summary":"Get Hooks","description":"Load hooks from the workspace .openhands/hooks.json file.\n\nThis endpoint reads the hooks configuration from the project's\n.openhands/hooks.json file if it exists.\n\nArgs:\n request: HooksRequest containing the project directory path.\n\nReturns:\n HooksResponse containing the hook configuration or None.","operationId":"get_hooks_api_hooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HooksRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HooksResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/llm/providers":{"get":{"tags":["LLM"],"summary":"List Providers","description":"List all available LLM providers supported by LiteLLM.","operationId":"list_providers_api_llm_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvidersResponse"}}}}}}},"/api/llm/models":{"get":{"tags":["LLM"],"summary":"List Models","description":"List all available LLM models supported by LiteLLM.\n\nArgs:\n provider: Optional provider name to filter models by.\n\nNote: Bedrock models are excluded unless AWS credentials are configured.","operationId":"list_models_api_llm_models_get","parameters":[{"name":"provider","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter models by provider (e.g., 'openai', 'anthropic')","title":"Provider"},"description":"Filter models by provider (e.g., 'openai', 'anthropic')"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/llm/models/verified":{"get":{"tags":["LLM"],"summary":"List Verified Models","description":"List all verified LLM models organized by provider.\n\nVerified models are those that have been tested and confirmed to work well\nwith OpenHands.","operationId":"list_verified_models_api_llm_models_verified_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifiedModelsResponse"}}}}}}},"/api/llm/subscription/openai/models":{"get":{"tags":["LLM"],"summary":"List Openai Subscription Models","description":"List models available through ChatGPT subscription authentication.","operationId":"list_openai_subscription_models_api_llm_subscription_openai_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionModelsResponse"}}}}}}},"/api/llm/subscription/openai/status":{"get":{"tags":["LLM"],"summary":"Get Openai Subscription Status","description":"Return safe ChatGPT subscription connection state without tokens.","operationId":"get_openai_subscription_status_api_llm_subscription_openai_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"}}}}}}},"/api/llm/subscription/openai/device/start":{"post":{"tags":["LLM"],"summary":"Start Openai Subscription Device Login","description":"Start ChatGPT device-code sign-in without returning tokens.","operationId":"start_openai_subscription_device_login_api_llm_subscription_openai_device_start_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDeviceStartResponse"}}}}}}},"/api/llm/subscription/openai/device/poll":{"post":{"tags":["LLM"],"summary":"Poll Openai Subscription Device Login","description":"Poll a ChatGPT device-code sign-in without returning tokens.","operationId":"poll_openai_subscription_device_login_api_llm_subscription_openai_device_poll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/llm/subscription/openai/logout":{"post":{"tags":["LLM"],"summary":"Logout Openai Subscription","description":"Remove stored ChatGPT subscription credentials.","operationId":"logout_openai_subscription_api_llm_subscription_openai_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"}}}}}}},"/api/mcp/test":{"post":{"tags":["MCP"],"summary":"Test an MCP server configuration","description":"Attempt to connect to a candidate MCP server and list its tools, without persisting any settings. Useful for validating user input in 'add MCP server' flows before storing the config. Optionally invokes one caller-chosen (read-only) tool via `tool_call` and reports its outcome in `tool_result`, so callers can verify credentials that are only exercised on tool invocation. Encrypted `env`/`headers` values round-tripped from settings are decrypted before the connection is attempted. Returns 200 with `ok=false` for connection / timeout failures (those are expected during validation, not server errors).","operationId":"test_mcp_server_api_mcp_test_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPTestRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MCPTestSuccess"},{"$ref":"#/components/schemas/MCPTestFailure"}],"title":"Response Test Mcp Server Api Mcp Test Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings/agent-schema":{"get":{"tags":["Settings"],"summary":"Get Agent Settings Schema","description":"Return the schema used to render AgentSettings-based settings forms.","operationId":"get_agent_settings_schema_api_settings_agent_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsSchema"}}}}}}},"/api/settings/conversation-schema":{"get":{"tags":["Settings"],"summary":"Get Conversation Settings Schema","description":"Return the schema used to render ConversationSettings-based forms.","operationId":"get_conversation_settings_schema_api_settings_conversation_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsSchema"}}}}}}},"/api/settings":{"get":{"tags":["Settings"],"summary":"Get Settings","description":"Get current settings.\n\nReturns the persisted settings including agent configuration,\nconversation settings, and whether an LLM API key is configured.\n\nUse the ``X-Expose-Secrets`` header to control secret exposure:\n- ``encrypted``: Returns cipher-encrypted values (safe for frontend clients)\n- ``plaintext``: Returns raw secret values (backend clients only!)\n- (absent): Returns redacted values (\"**********\")\n\nSecurity:\n When the server is configured with ``session_api_keys``, all endpoints\n under ``/api`` (including this one) require the ``X-Session-API-Key``\n header. When no session API keys are configured, endpoints are open.\n\n **Trust model:** All authenticated clients are treated as equally\n trusted. There is no role-based authorization for ``X-Expose-Secrets``\n modes—any authenticated client can request ``plaintext`` or\n ``encrypted`` exposure. This design assumes:\n\n - All clients sharing session API keys operate in the same trust domain\n - Network-level controls (firewalls, VPCs) restrict access to trusted\n clients only\n - Production deployments use session API keys to prevent anonymous access\n\n The ``plaintext`` mode exists for backend-to-backend communication\n (e.g., RemoteWorkspace). Frontend clients should prefer ``encrypted``\n mode for round-tripping secrets, or omit the header to receive redacted\n values.","operationId":"get_settings_api_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}}}},"patch":{"tags":["Settings"],"summary":"Update Settings","description":"Update settings with partial changes.\n\nAccepts ``agent_settings_diff``, ``conversation_settings_diff``,\n``misc_settings_diff``, and/or ``active_profile`` for incremental updates.\nThe three ``*_settings_diff`` fields are deep-merged; nested objects merge\nrecursively, and a ``null`` value **inside a nested map deletes that entry**\n— the \"unset\" primitive that lets a client remove a single map key without\nround-tripping the whole map. To remove one MCP server's header::\n\n PATCH /api/settings\n {\"agent_settings_diff\":\n {\"mcp_config\": {\"mcpServers\": {\"svc\": {\"headers\": {\"X-Old\": null}}}}}}\n\nA ``null`` on a top-level *field* (e.g. ``{\"confirmation_mode\": null}``)\nis **not** an unset — it flows to model validation as before, so it still\nfails loudly rather than silently resetting the field to its default.\n\n``misc_settings_diff`` is deep-merged into the persisted ``misc_settings``\nblock. The agent-server treats ``misc_settings`` as opaque frontend-owned\ndata: nested dicts are merged recursively, lists are replaced wholesale,\nand the contents are never read or validated server-side.\n\nUses file locking to prevent concurrent updates from overwriting each other.\n\nRaises:\n HTTPException: 400 if the update payload contains invalid values.","operationId":"update_settings_api_settings_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings/secrets":{"get":{"tags":["Settings"],"summary":"List Secrets","description":"List all available secrets (names and descriptions only, no values).","operationId":"list_secrets_api_settings_secrets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretsListResponse"}}}}}},"put":{"tags":["Settings"],"summary":"Create Secret","description":"Create or update a custom secret (upsert).\n\nRaises:\n HTTPException: 400 if secret name format is invalid, 500 if file is corrupted.","operationId":"create_secret_api_settings_secrets_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretCreateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretItemResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings/secrets/{name}":{"get":{"tags":["Settings"],"summary":"Get Secret Value","description":"Get a single secret value by name.\n\nReturns the raw secret value as plain text. This endpoint is designed\nto be used with LookupSecret for lazy secret resolution.\n\nRaises:\n HTTPException: 400 if name format is invalid, 404 if secret not found.","operationId":"get_secret_value_api_settings_secrets__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Settings"],"summary":"Delete Secret","description":"Delete a custom secret by name.\n\nRaises:\n HTTPException: 400 if name format is invalid, 404 if secret not found,\n 500 if file is corrupted.","operationId":"delete_secret_api_settings_secrets__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Delete Secret Api Settings Secrets Name Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspaces":{"get":{"tags":["Workspaces"],"summary":"List Workspaces","description":"Return the saved workspaces and workspace parents.","operationId":"list_workspaces_api_workspaces_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacesListResponse"}}}}}},"post":{"tags":["Workspaces"],"summary":"Add Workspaces","description":"Append workspaces to the saved list. Idempotent — dedupes by ``path``.","operationId":"add_workspaces_api_workspaces_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddWorkspacesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacesListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Workspaces"],"summary":"Delete Workspace","description":"Remove a workspace by its absolute path.","operationId":"delete_workspace_api_workspaces_delete","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute workspace path to remove","title":"Path"},"description":"Absolute workspace path to remove"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspaces/parents":{"post":{"tags":["Workspaces"],"summary":"Add Workspace Parents","description":"Append workspace parents. Idempotent — dedupes by ``path``.","operationId":"add_workspace_parents_api_workspaces_parents_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddWorkspaceParentsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacesListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Workspaces"],"summary":"Delete Workspace Parent","description":"Remove a workspace parent by its absolute path.","operationId":"delete_workspace_parent_api_workspaces_parents_delete","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute workspace parent path to remove","title":"Path"},"description":"Absolute workspace parent path to remove"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles":{"get":{"tags":["Profiles"],"summary":"List Profiles","description":"List all saved LLM profiles.\n\nReturns the list of profiles along with the currently active profile name,\nif one has been activated. The active_profile tracks which LLM profile\nconfiguration is currently in use.","operationId":"list_profiles_api_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileListResponse"}}}}}}},"/api/profiles/{name}":{"get":{"tags":["Profiles"],"summary":"Get Profile","description":"Get a profile's configuration.\n\nUse the ``X-Expose-Secrets`` header to control secret exposure:\n- ``encrypted``: Returns cipher-encrypted values (safe for frontend clients)\n- ``plaintext``: Returns raw secret values (backend clients only!)\n- (absent): Returns nulled ``api_key`` with ``api_key_set`` indicator","operationId":"get_profile_api_profiles__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Profiles"],"summary":"Save Profile","description":"Save an LLM configuration as a named profile.\n\nOverwrites an existing profile of the same name. Returns 409 if creating\na new profile would exceed ``MAX_PROFILES``.\n\nWhen ``OH_SECRET_KEY`` is configured, secrets are encrypted at rest.\nClients can submit cipher-encrypted secrets which will be decrypted\nserver-side before re-encrypting with the storage cipher.","operationId":"save_profile_api_profiles__name__post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveProfileRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Profiles"],"summary":"Delete Profile","description":"Delete a saved profile (idempotent).\n\nGuarded by the agent-profile FK: returns 409 naming the referrers if any\n``AgentProfile`` still cites this LLM profile via ``llm_profile_ref``.","operationId":"delete_profile_api_profiles__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/rename":{"post":{"tags":["Profiles"],"summary":"Rename Profile","description":"Rename a saved profile atomically.\n\nReturns 404 if the source does not exist, or 409 if ``new_name`` already\nexists. A same-name rename is a verified no-op (still 404s if missing).\n\nIf the renamed profile is the currently active profile, the active_profile\nsetting is updated to the new name. Any ``AgentProfile.llm_profile_ref``\nciting the old name is cascaded to the new name in lock-step.","operationId":"rename_profile_api_profiles__name__rename_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameProfileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/activate":{"post":{"tags":["Profiles"],"summary":"Activate Profile","description":"Activate a saved LLM profile.\n\nThis endpoint:\n1. Loads the named profile's LLM configuration\n2. Applies it to the current agent settings (updates ``agent_settings.llm``)\n3. Records the profile name as the active profile for frontend tracking\n\nReturns 404 if the profile does not exist.\n\nUse ``GET /api/profiles`` to see which profile is currently active via\nthe ``active_profile`` field.","operationId":"activate_profile_api_profiles__name__activate_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles":{"get":{"tags":["Agent Profiles"],"summary":"List Agent Profiles","description":"List all stored agent profiles and the active pointer.\n\nOn the first call against an empty store with no active pointer, lazily\nseeds one default profile from the current ``agent_settings`` and activates\nit (the one-time migration that replaces a dedicated seed step).","operationId":"list_agent_profiles_api_agent_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileListResponse"}}}}}}},"/api/agent-profiles/{name}":{"get":{"tags":["Agent Profiles"],"summary":"Get Agent Profile","description":"Get a stored profile.\n\nUse the ``X-Expose-Secrets`` header to control ``skills[].mcp_tools`` secret\nexposure (``encrypted`` / ``plaintext``); absent, those values are masked.","operationId":"get_agent_profile_api_agent_profiles__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Agent Profiles"],"summary":"Save Agent Profile","description":"Save an ``AgentProfile`` under ``name`` (overwriting a namesake).\n\nThe path ``name`` is authoritative — it overrides any ``name`` in the body.\nWith ``OH_SECRET_KEY`` configured, ``skills[].mcp_tools`` secrets are\nencrypted at rest; otherwise they are redacted. Returns 409 if creating a\nnew profile would exceed ``MAX_AGENT_PROFILES``.","operationId":"save_agent_profile_api_agent_profiles__name__post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Agent Profiles"],"summary":"Delete Agent Profile","description":"Delete a stored profile (idempotent).\n\nIf the deleted profile was the active one, ``active_agent_profile_id`` is\ncleared.","operationId":"delete_agent_profile_api_agent_profiles__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles/{name}/rename":{"post":{"tags":["Agent Profiles"],"summary":"Rename Agent Profile","description":"Rename a stored profile atomically.\n\nThe stable ``id`` is preserved, so an active pointer (keyed on ``id``)\nsurvives the rename untouched. Returns 404 if the source is missing, 409 if\n``new_name`` is taken.","operationId":"rename_agent_profile_api_agent_profiles__name__rename_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameAgentProfileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles/{profile_id}/activate":{"post":{"tags":["Agent Profiles"],"summary":"Activate Agent Profile","description":"Activate a profile by its stable ``id`` — pointer only.\n\nSets ``active_agent_profile_id`` and nothing else: unlike the LLM\n``/activate``, this does **not** write ``agent_settings`` (the\ncreation-time-only contract). Returns 404 if no stored profile has that id.","operationId":"activate_agent_profile_api_agent_profiles__profile_id__activate_post","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateAgentProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles/{name}/materialize":{"post":{"tags":["Agent Profiles"],"summary":"Materialize Agent Profile","description":"Dry-run resolve a profile's LLM/MCP references; return a diagnostics report.\n\nDangling LLM/MCP references are reported in the body (valid=False) rather\nthan raising — the only error status is 404 (unknown profile name).\nresolved_settings is redacted (api_key_set booleans; no raw secrets).","operationId":"materialize_agent_profile_api_agent_profiles__name__materialize_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileDiagnostics"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/workspace-session":{"post":{"tags":["Auth"],"summary":"Create Workspace Session","description":"Mint a workspace-scoped session cookie.\n\nCaller must already be authenticated by the ``X-Session-API-Key``\nheader (enforced by the parent router's dependency). The cookie value\nis the validated session API key itself; it is HttpOnly so JS in\nworkspace HTML cannot read it back.","operationId":"create_workspace_session_api_auth_workspace_session_post","responses":{"204":{"description":"Cookie set"},"401":{"description":"Missing or invalid X-Session-API-Key header"}}},"delete":{"tags":["Auth"],"summary":"Delete Workspace Session","description":"Clear the workspace session cookie.\n\nBrowsers identify cookies by ``(name, domain, path)``; the deletion\ncookie must therefore share the original cookie's attributes. We\noverwrite with an empty value and ``max_age=0`` so the browser drops\nit immediately.","operationId":"delete_workspace_session_api_auth_workspace_session_delete","responses":{"204":{"description":"Cookie cleared"}}}},"/v1/models":{"get":{"tags":["OpenAI Compatibility"],"summary":"Get Openai Models","operationId":"get_openai_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAIModelListResponse"}}}}}}},"/v1/chat/completions":{"post":{"tags":["OpenAI Compatibility"],"summary":"Create Chat Completion","operationId":"create_chat_completion_v1_chat_completions_post","parameters":[{"name":"X-OpenHands-ServerConversation-ID","in":"header","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"X-Openhands-Serverconversation-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAIChatCompletionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletion"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/workspace":{"get":{"tags":["Workspace"],"summary":"Serve Workspace Root","description":"Serve ``index.html`` from the conversation's workspace root.","operationId":"serve_workspace_root_api_conversations__conversation_id__workspace_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"File or conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/workspace/{file_path}":{"get":{"tags":["Workspace"],"summary":"Serve Workspace File","description":"Serve a file (or directory ``index.html``) from the workspace.","operationId":"serve_workspace_file_api_conversations__conversation_id__workspace__file_path__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"file_path","in":"path","required":true,"schema":{"type":"string","title":"File Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"File or conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"tags":["Server Details"],"summary":"Get Server Info","operationId":"get_server_info__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerInfo"}}}}}}}},"components":{"schemas":{"ACPAgent-Input":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"},"tools":{"items":{"$ref":"#/components/schemas/Tool-Input"},"type":"array","title":"Tools"},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools"},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Input"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Input"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Input"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"acp_command":{"items":{"type":"string"},"type":"array","title":"Acp Command","description":"Command to start the ACP server, e.g. ['npx', '-y', '@agentclientprotocol/claude-agent-acp']"},"acp_server":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Server","description":"Provider registry key identifying which ACP CLI this agent runs ('claude-code', 'codex', 'gemini-cli', or 'custom'); None when the agent is built directly rather than via ACPAgentSettings. Set by ACPAgentSettings.create_agent() from ACPAgentSettings.acp_server so the authoritative key survives onto the agent — and thus onto ConversationInfo.agent — because the launch command in acp_command does not reliably reverse-map to a provider. Informational only: consumers use it to resolve a provider brand label / model list; the subprocess is still launched from acp_command."},"acp_args":{"items":{"type":"string"},"type":"array","title":"Acp Args","description":"Additional arguments for the ACP server command"},"acp_session_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Session Mode","description":"Session mode ID to set after creating a session. If None (default), auto-detected from the ACP server type: 'bypassPermissions' for claude-agent-acp, 'full-access' for codex-acp."},"acp_prompt_timeout":{"type":"number","title":"Acp Prompt Timeout","description":"Inactivity timeout in seconds for a single ACP prompt() call. The deadline resets on every update from the ACP server (token, thought, tool-call progress, usage), so a steadily-progressing agent runs as long as it keeps making progress; the prompt is only aborted after this many seconds with no activity at all. Prevents indefinite hangs when the ACP server stops responding without killing legitimately long-running work.","default":1800.0},"acp_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Model","description":"Model for the ACP server to use (e.g. 'sonnet' or 'gpt-5.5'). Applied via the protocol — set_config_option(model) for configOptions-based servers (codex, claude), else set_session_model. If None, the server picks its default."},"acp_resume_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Resume Session Id","description":"Optional explicit ACP session id to resume. When set, takes precedence over the id persisted in ``state.agent_state`` and is used to call ``session/load`` on the ACP server. Designed for environments where the per-conversation filesystem (and therefore ``base_state.json``) does not survive across restarts (e.g. cloud sandbox recycles), but the id has been mirrored into durable storage elsewhere. Falls back to a fresh session if the server cannot load the id. Treated as a secret on the wire — possession of the id is enough to resume the underlying ACP session, so default serialization redacts it; pass ``expose_secrets='plaintext'`` (trusted backend) or ``expose_secrets='encrypted'`` plus a cipher (frontend round-trip) when the value must cross a serialization boundary."},"acp_file_secrets":{"items":{"$ref":"#/components/schemas/ACPFileSecretSpec"},"type":"array","title":"Acp File Secrets","description":"Reserved 'file-content' credential secrets to materialise to disk before launching the subprocess (e.g. Codex auth.json, Gemini Vertex SA JSON). The SDK owns the mechanism (write the file in the runtime pod, set the env var, seed-if-absent); these specs are the policy. Defaults to the built-in supported providers; a downstream application may override or extend this to support other ACP servers with different file-auth schemes."},"acp_isolate_data_dir":{"type":"boolean","title":"Acp Isolate Data Dir","description":"Give the ACP subprocess a per-conversation CLI data/config root instead of the shared user ``HOME``. When True and the provider is recognised, point its data-dir env var (``CODEX_HOME`` / ``CLAUDE_CONFIG_DIR`` / ``HOME``; see ``ACPProviderInfo.data_dir_env_var``) at ``/acp/`` — the same per-conversation tree materialised file-secrets use. Required for correctness when several of a user's conversations share one sandbox (``SandboxGroupingStrategy != NO_GROUPING``), where they would otherwise race on one set of CLI auth/config/cache/lock files (see #1019). Off by default: with one sandbox per conversation the shared HOME is already private, and relocating it would hide a pre-existing interactive login. Downstream policy decides when to enable it; the SDK owns where the root lives.","default":false},"kind":{"type":"string","const":"ACPAgent","title":"Kind"}},"type":"object","required":["acp_command"],"title":"ACPAgent","description":"Agent that delegates to an ACP-compatible subprocess server."},"ACPAgent-Output":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Output"},"tools":{"items":{"$ref":"#/components/schemas/openhands__sdk__tool__spec__Tool"},"type":"array","title":"Tools"},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools"},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Output"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Output"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Output"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"acp_command":{"items":{"type":"string"},"type":"array","title":"Acp Command","description":"Command to start the ACP server, e.g. ['npx', '-y', '@agentclientprotocol/claude-agent-acp']"},"acp_server":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Server","description":"Provider registry key identifying which ACP CLI this agent runs ('claude-code', 'codex', 'gemini-cli', or 'custom'); None when the agent is built directly rather than via ACPAgentSettings. Set by ACPAgentSettings.create_agent() from ACPAgentSettings.acp_server so the authoritative key survives onto the agent — and thus onto ConversationInfo.agent — because the launch command in acp_command does not reliably reverse-map to a provider. Informational only: consumers use it to resolve a provider brand label / model list; the subprocess is still launched from acp_command."},"acp_args":{"items":{"type":"string"},"type":"array","title":"Acp Args","description":"Additional arguments for the ACP server command"},"acp_session_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Session Mode","description":"Session mode ID to set after creating a session. If None (default), auto-detected from the ACP server type: 'bypassPermissions' for claude-agent-acp, 'full-access' for codex-acp."},"acp_prompt_timeout":{"type":"number","title":"Acp Prompt Timeout","description":"Inactivity timeout in seconds for a single ACP prompt() call. The deadline resets on every update from the ACP server (token, thought, tool-call progress, usage), so a steadily-progressing agent runs as long as it keeps making progress; the prompt is only aborted after this many seconds with no activity at all. Prevents indefinite hangs when the ACP server stops responding without killing legitimately long-running work.","default":1800.0},"acp_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Model","description":"Model for the ACP server to use (e.g. 'sonnet' or 'gpt-5.5'). Applied via the protocol — set_config_option(model) for configOptions-based servers (codex, claude), else set_session_model. If None, the server picks its default."},"acp_resume_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Resume Session Id","description":"Optional explicit ACP session id to resume. When set, takes precedence over the id persisted in ``state.agent_state`` and is used to call ``session/load`` on the ACP server. Designed for environments where the per-conversation filesystem (and therefore ``base_state.json``) does not survive across restarts (e.g. cloud sandbox recycles), but the id has been mirrored into durable storage elsewhere. Falls back to a fresh session if the server cannot load the id. Treated as a secret on the wire — possession of the id is enough to resume the underlying ACP session, so default serialization redacts it; pass ``expose_secrets='plaintext'`` (trusted backend) or ``expose_secrets='encrypted'`` plus a cipher (frontend round-trip) when the value must cross a serialization boundary."},"acp_file_secrets":{"items":{"$ref":"#/components/schemas/ACPFileSecretSpec"},"type":"array","title":"Acp File Secrets","description":"Reserved 'file-content' credential secrets to materialise to disk before launching the subprocess (e.g. Codex auth.json, Gemini Vertex SA JSON). The SDK owns the mechanism (write the file in the runtime pod, set the env var, seed-if-absent); these specs are the policy. Defaults to the built-in supported providers; a downstream application may override or extend this to support other ACP servers with different file-auth schemes."},"acp_isolate_data_dir":{"type":"boolean","title":"Acp Isolate Data Dir","description":"Give the ACP subprocess a per-conversation CLI data/config root instead of the shared user ``HOME``. When True and the provider is recognised, point its data-dir env var (``CODEX_HOME`` / ``CLAUDE_CONFIG_DIR`` / ``HOME``; see ``ACPProviderInfo.data_dir_env_var``) at ``/acp/`` — the same per-conversation tree materialised file-secrets use. Required for correctness when several of a user's conversations share one sandbox (``SandboxGroupingStrategy != NO_GROUPING``), where they would otherwise race on one set of CLI auth/config/cache/lock files (see #1019). Off by default: with one sandbox per conversation the shared HOME is already private, and relocating it would hide a pre-existing interactive login. Downstream policy decides when to enable it; the SDK owns where the root lives.","default":false},"kind":{"type":"string","const":"ACPAgent","title":"Kind"}},"type":"object","required":["acp_command","kind"],"title":"ACPAgent","description":"Agent that delegates to an ACP-compatible subprocess server."},"ACPFileSecretSpec":{"properties":{"secret_name":{"type":"string","minLength":1,"title":"Secret Name"},"filename":{"type":"string","minLength":1,"title":"Filename"},"env_var":{"type":"string","minLength":1,"title":"Env Var"},"subdir":{"type":"string","minLength":1,"title":"Subdir"},"env_points_to":{"type":"string","enum":["dir","file"],"title":"Env Points To","default":"file"},"warn_if_unset":{"items":{"type":"string"},"type":"array","title":"Warn If Unset","default":[]}},"type":"object","required":["secret_name","filename","env_var","subdir"],"title":"ACPFileSecretSpec","description":"Declarative mapping from a reserved \"file-content\" secret to a credential\nfile the ACP subprocess authenticates from.\n\nSome providers read their credential from a *file on disk* rather than an\nenv var: Codex reads ``$CODEX_HOME/auth.json``; Gemini (Vertex AI) reads a\nservice-account JSON pointed at by ``GOOGLE_APPLICATION_CREDENTIALS``. The\nuser supplies that credential as a pasted blob — a reserved secret named\n:attr:`secret_name` — and :class:`~openhands.sdk.agent.ACPAgent` materialises\nit to :attr:`filename` under the conversation's durable per-conversation root\n(seed-if-absent), then sets :attr:`env_var` so the CLI can find it.\n\nMaterialisation is keyed off :attr:`secret_name` (not the launch command),\nso a custom or aliased ``acp_command`` still works as long as the reserved\nsecret is supplied.\n\nThe SDK owns the *mechanism* (writing the file in the runtime pod, setting\nthe env var, seed-if-absent, permissions); the *policy* — which secrets map\nto which files for which CLIs — lives in these specs. Built-in defaults\ncover the supported providers, but downstream applications can override\n:attr:`~openhands.sdk.agent.ACPAgent.acp_file_secrets` to support other ACP\nservers with different file-auth schemes without an SDK change."},"ACPModelInfo":{"properties":{"model_id":{"type":"string","title":"Model Id","description":"Server-assigned model identifier. May be concrete (e.g. ``\"gpt-5.5\"``) or an opaque alias (e.g. ``\"default\"``, ``\"auto\"``). This is the value to pass back to the server to switch to this model."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable label, e.g. ``\"GPT-5.5\"``."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional longer description supplied by the server."}},"type":"object","required":["model_id"],"title":"ACPModelInfo","description":"One model an ACP server offers for a session.\n\nA normalized, stable mirror of the ACP protocol's ``ModelInfo``. The\nprotocol ``models`` capability is flagged **UNSTABLE**, so we re-map it\ninto our own type at the SDK boundary rather than re-serializing the\nvendored ``acp.schema`` type onto the agent-server's public API — clients\nget a stable shape regardless of upstream protocol churn.\n\nCarries everything a client needs to render a picker and resolve a\n``current_model_id`` to a display label *itself*; the SDK deliberately\ndoes no name curation."},"ACPToolCallEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"tool_call_id":{"type":"string","title":"Tool Call Id"},"title":{"type":"string","title":"Title"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"tool_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Kind"},"raw_input":{"anyOf":[{},{"type":"null"}],"title":"Raw Input"},"raw_output":{"anyOf":[{},{"type":"null"}],"title":"Raw Output"},"content":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Content"},"is_error":{"type":"boolean","title":"Is Error","default":false},"kind":{"type":"string","const":"ACPToolCallEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_call_id","title","kind"],"title":"ACPToolCallEvent","description":"Event representing a tool call executed by an ACP server.\n\nCaptures the tool name, inputs, outputs, and status from ACP\n``ToolCallStart`` / ``ToolCallProgress`` notifications so they can\nbe surfaced in the OpenHands event stream and visualizer.\n\nThis is *not* an ``LLMConvertibleEvent`` — ACP tool calls do not\nparticipate in LLM message conversion."},"APIBasedCritic-Input":{"properties":{"server_url":{"type":"string","title":"Server Url","description":"Base URL of the vLLM classification service","default":"https://llm-proxy.app.all-hands.dev/vllm"},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true}],"title":"Api Key","description":"API key for authenticating with the vLLM service"},"model_name":{"type":"string","title":"Model Name","description":"Name of the model to use","default":"critic"},"tokenizer_name":{"type":"string","title":"Tokenizer Name","description":"HuggingFace tokenizer name for loading chat template","default":"Qwen/Qwen3-4B-Instruct-2507"},"pass_tools_definitions":{"type":"boolean","title":"Pass Tools Definitions","description":"Whether to pass tool definitions to the model","default":true},"timeout_seconds":{"type":"number","title":"Timeout Seconds","description":"Timeout for requests to the model","default":300.0},"has_success_label":{"type":"boolean","title":"Has Success Label","description":"Whether the model predicts success label at index 0","default":true},"sentiment_labels":{"items":{"type":"string"},"type":"array","title":"Sentiment Labels","default":["sentiment_positive","sentiment_neutral","sentiment_negative"]},"agent_issue_labels":{"items":{"type":"string"},"type":"array","title":"Agent Issue Labels","default":["misunderstood_intention","did_not_follow_instruction","insufficient_analysis","insufficient_clarification","improper_tool_use_or_setup","loop_behavior","insufficient_testing","insufficient_debugging","incomplete_implementation","file_management_errors","scope_creep","risky_actions_or_permission","other_agent_issue"]},"infra_labels":{"items":{"type":"string"},"type":"array","title":"Infra Labels","default":["infrastructure_external_issue","infrastructure_agent_caused_issue"]},"user_followup_labels":{"items":{"type":"string"},"type":"array","title":"User Followup Labels","default":["clarification_or_restatement","correction","direction_change","vcs_update_requests","progress_or_scope_concern","frustration_or_complaint","removal_or_reversion_request","other_user_issue"]},"sentiment_map":{"additionalProperties":{"type":"string"},"type":"object","title":"Sentiment Map","default":{"Positive":"sentiment_positive","Neutral":"sentiment_neutral","Negative":"sentiment_negative"}},"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"issue_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issue Threshold","description":"APIBasedCritic-specific probability threshold for agent issue labels that should trigger iterative refinement.","default":0.75},"kind":{"type":"string","const":"APIBasedCritic","title":"Kind"}},"type":"object","required":["api_key"],"title":"APIBasedCritic"},"APIBasedCritic-Output":{"properties":{"server_url":{"type":"string","title":"Server Url","description":"Base URL of the vLLM classification service","default":"https://llm-proxy.app.all-hands.dev/vllm"},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true}],"title":"Api Key","description":"API key for authenticating with the vLLM service"},"model_name":{"type":"string","title":"Model Name","description":"Name of the model to use","default":"critic"},"tokenizer_name":{"type":"string","title":"Tokenizer Name","description":"HuggingFace tokenizer name for loading chat template","default":"Qwen/Qwen3-4B-Instruct-2507"},"pass_tools_definitions":{"type":"boolean","title":"Pass Tools Definitions","description":"Whether to pass tool definitions to the model","default":true},"timeout_seconds":{"type":"number","title":"Timeout Seconds","description":"Timeout for requests to the model","default":300.0},"has_success_label":{"type":"boolean","title":"Has Success Label","description":"Whether the model predicts success label at index 0","default":true},"sentiment_labels":{"items":{"type":"string"},"type":"array","title":"Sentiment Labels","default":["sentiment_positive","sentiment_neutral","sentiment_negative"]},"agent_issue_labels":{"items":{"type":"string"},"type":"array","title":"Agent Issue Labels","default":["misunderstood_intention","did_not_follow_instruction","insufficient_analysis","insufficient_clarification","improper_tool_use_or_setup","loop_behavior","insufficient_testing","insufficient_debugging","incomplete_implementation","file_management_errors","scope_creep","risky_actions_or_permission","other_agent_issue"]},"infra_labels":{"items":{"type":"string"},"type":"array","title":"Infra Labels","default":["infrastructure_external_issue","infrastructure_agent_caused_issue"]},"user_followup_labels":{"items":{"type":"string"},"type":"array","title":"User Followup Labels","default":["clarification_or_restatement","correction","direction_change","vcs_update_requests","progress_or_scope_concern","frustration_or_complaint","removal_or_reversion_request","other_user_issue"]},"sentiment_map":{"additionalProperties":{"type":"string"},"type":"object","title":"Sentiment Map","default":{"Positive":"sentiment_positive","Neutral":"sentiment_neutral","Negative":"sentiment_negative"}},"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"issue_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issue Threshold","description":"APIBasedCritic-specific probability threshold for agent issue labels that should trigger iterative refinement.","default":0.75},"kind":{"type":"string","const":"APIBasedCritic","title":"Kind"}},"type":"object","required":["api_key","kind"],"title":"APIBasedCritic"},"Action":{"oneOf":[{"$ref":"#/components/schemas/BrowserActionWithRisk"},{"$ref":"#/components/schemas/BrowserClickActionWithRisk"},{"$ref":"#/components/schemas/BrowserCloseTabActionWithRisk"},{"$ref":"#/components/schemas/BrowserGetContentActionWithRisk"},{"$ref":"#/components/schemas/BrowserGetStateActionWithRisk"},{"$ref":"#/components/schemas/BrowserGetStorageActionWithRisk"},{"$ref":"#/components/schemas/BrowserGoBackActionWithRisk"},{"$ref":"#/components/schemas/BrowserListTabsActionWithRisk"},{"$ref":"#/components/schemas/BrowserNavigateActionWithRisk"},{"$ref":"#/components/schemas/BrowserScrollActionWithRisk"},{"$ref":"#/components/schemas/BrowserSetStorageActionWithRisk"},{"$ref":"#/components/schemas/BrowserStartRecordingActionWithRisk"},{"$ref":"#/components/schemas/BrowserStopRecordingActionWithRisk"},{"$ref":"#/components/schemas/BrowserSwitchTabActionWithRisk"},{"$ref":"#/components/schemas/BrowserTypeActionWithRisk"},{"$ref":"#/components/schemas/DelegateActionWithRisk"},{"$ref":"#/components/schemas/EditActionWithRisk"},{"$ref":"#/components/schemas/FileEditorActionWithRisk"},{"$ref":"#/components/schemas/FinishActionWithRisk"},{"$ref":"#/components/schemas/GlobActionWithRisk"},{"$ref":"#/components/schemas/GrepActionWithRisk"},{"$ref":"#/components/schemas/InvokeSkillActionWithRisk"},{"$ref":"#/components/schemas/ListDirectoryActionWithRisk"},{"$ref":"#/components/schemas/MCPToolActionWithRisk"},{"$ref":"#/components/schemas/PlanningFileEditorActionWithRisk"},{"$ref":"#/components/schemas/ReadFileActionWithRisk"},{"$ref":"#/components/schemas/SwitchLLMActionWithRisk"},{"$ref":"#/components/schemas/TaskActionWithRisk"},{"$ref":"#/components/schemas/TaskTrackerActionWithRisk"},{"$ref":"#/components/schemas/TerminalActionWithRisk"},{"$ref":"#/components/schemas/ThinkActionWithRisk"},{"$ref":"#/components/schemas/WorkflowActionWithRisk"},{"$ref":"#/components/schemas/WriteFileActionWithRisk"},{"$ref":"#/components/schemas/MCPToolAction"},{"$ref":"#/components/schemas/FinishAction"},{"$ref":"#/components/schemas/InvokeSkillAction"},{"$ref":"#/components/schemas/SwitchLLMAction"},{"$ref":"#/components/schemas/ThinkAction"},{"$ref":"#/components/schemas/BrowserAction"},{"$ref":"#/components/schemas/BrowserClickAction"},{"$ref":"#/components/schemas/BrowserCloseTabAction"},{"$ref":"#/components/schemas/BrowserGetContentAction"},{"$ref":"#/components/schemas/BrowserGetStateAction"},{"$ref":"#/components/schemas/BrowserGetStorageAction"},{"$ref":"#/components/schemas/BrowserGoBackAction"},{"$ref":"#/components/schemas/BrowserListTabsAction"},{"$ref":"#/components/schemas/BrowserNavigateAction"},{"$ref":"#/components/schemas/BrowserScrollAction"},{"$ref":"#/components/schemas/BrowserSetStorageAction"},{"$ref":"#/components/schemas/BrowserStartRecordingAction"},{"$ref":"#/components/schemas/BrowserStopRecordingAction"},{"$ref":"#/components/schemas/BrowserSwitchTabAction"},{"$ref":"#/components/schemas/BrowserTypeAction"},{"$ref":"#/components/schemas/DelegateAction"},{"$ref":"#/components/schemas/FileEditorAction"},{"$ref":"#/components/schemas/EditAction"},{"$ref":"#/components/schemas/ListDirectoryAction"},{"$ref":"#/components/schemas/ReadFileAction"},{"$ref":"#/components/schemas/WriteFileAction"},{"$ref":"#/components/schemas/GlobAction"},{"$ref":"#/components/schemas/GrepAction"},{"$ref":"#/components/schemas/PlanningFileEditorAction"},{"$ref":"#/components/schemas/TaskAction"},{"$ref":"#/components/schemas/TaskTrackerAction"},{"$ref":"#/components/schemas/TerminalAction"},{"$ref":"#/components/schemas/WorkflowAction"}],"discriminator":{"propertyName":"kind","mapping":{"abc__BrowserActionWithRisk-Output__1":"#/components/schemas/BrowserActionWithRisk","abc__BrowserClickActionWithRisk-Output__1":"#/components/schemas/BrowserClickActionWithRisk","abc__BrowserCloseTabActionWithRisk-Output__1":"#/components/schemas/BrowserCloseTabActionWithRisk","abc__BrowserGetContentActionWithRisk-Output__1":"#/components/schemas/BrowserGetContentActionWithRisk","abc__BrowserGetStateActionWithRisk-Output__1":"#/components/schemas/BrowserGetStateActionWithRisk","abc__BrowserGetStorageActionWithRisk-Output__1":"#/components/schemas/BrowserGetStorageActionWithRisk","abc__BrowserGoBackActionWithRisk-Output__1":"#/components/schemas/BrowserGoBackActionWithRisk","abc__BrowserListTabsActionWithRisk-Output__1":"#/components/schemas/BrowserListTabsActionWithRisk","abc__BrowserNavigateActionWithRisk-Output__1":"#/components/schemas/BrowserNavigateActionWithRisk","abc__BrowserScrollActionWithRisk-Output__1":"#/components/schemas/BrowserScrollActionWithRisk","abc__BrowserSetStorageActionWithRisk-Output__1":"#/components/schemas/BrowserSetStorageActionWithRisk","abc__BrowserStartRecordingActionWithRisk-Output__1":"#/components/schemas/BrowserStartRecordingActionWithRisk","abc__BrowserStopRecordingActionWithRisk-Output__1":"#/components/schemas/BrowserStopRecordingActionWithRisk","abc__BrowserSwitchTabActionWithRisk-Output__1":"#/components/schemas/BrowserSwitchTabActionWithRisk","abc__BrowserTypeActionWithRisk-Output__1":"#/components/schemas/BrowserTypeActionWithRisk","abc__DelegateActionWithRisk-Output__1":"#/components/schemas/DelegateActionWithRisk","abc__EditActionWithRisk-Output__1":"#/components/schemas/EditActionWithRisk","abc__FileEditorActionWithRisk-Output__1":"#/components/schemas/FileEditorActionWithRisk","abc__FinishActionWithRisk-Output__1":"#/components/schemas/FinishActionWithRisk","abc__GlobActionWithRisk-Output__1":"#/components/schemas/GlobActionWithRisk","abc__GrepActionWithRisk-Output__1":"#/components/schemas/GrepActionWithRisk","abc__InvokeSkillActionWithRisk-Output__1":"#/components/schemas/InvokeSkillActionWithRisk","abc__ListDirectoryActionWithRisk-Output__1":"#/components/schemas/ListDirectoryActionWithRisk","abc__MCPToolActionWithRisk-Output__1":"#/components/schemas/MCPToolActionWithRisk","abc__PlanningFileEditorActionWithRisk-Output__1":"#/components/schemas/PlanningFileEditorActionWithRisk","abc__ReadFileActionWithRisk-Output__1":"#/components/schemas/ReadFileActionWithRisk","abc__SwitchLLMActionWithRisk-Output__1":"#/components/schemas/SwitchLLMActionWithRisk","abc__TaskActionWithRisk-Output__1":"#/components/schemas/TaskActionWithRisk","abc__TaskTrackerActionWithRisk-Output__1":"#/components/schemas/TaskTrackerActionWithRisk","abc__TerminalActionWithRisk-Output__1":"#/components/schemas/TerminalActionWithRisk","abc__ThinkActionWithRisk-Output__1":"#/components/schemas/ThinkActionWithRisk","abc__WorkflowActionWithRisk-Output__1":"#/components/schemas/WorkflowActionWithRisk","abc__WriteFileActionWithRisk-Output__1":"#/components/schemas/WriteFileActionWithRisk","openhands__sdk__mcp__definition__MCPToolAction-Output__1":"#/components/schemas/MCPToolAction","openhands__sdk__tool__builtins__finish__FinishAction-Output__1":"#/components/schemas/FinishAction","openhands__sdk__tool__builtins__invoke_skill__InvokeSkillAction-Output__1":"#/components/schemas/InvokeSkillAction","openhands__sdk__tool__builtins__switch_llm__SwitchLLMAction-Output__1":"#/components/schemas/SwitchLLMAction","openhands__sdk__tool__builtins__think__ThinkAction-Output__1":"#/components/schemas/ThinkAction","openhands__tools__browser_use__definition__BrowserAction-Output__1":"#/components/schemas/BrowserAction","openhands__tools__browser_use__definition__BrowserClickAction-Output__1":"#/components/schemas/BrowserClickAction","openhands__tools__browser_use__definition__BrowserCloseTabAction-Output__1":"#/components/schemas/BrowserCloseTabAction","openhands__tools__browser_use__definition__BrowserGetContentAction-Output__1":"#/components/schemas/BrowserGetContentAction","openhands__tools__browser_use__definition__BrowserGetStateAction-Output__1":"#/components/schemas/BrowserGetStateAction","openhands__tools__browser_use__definition__BrowserGetStorageAction-Output__1":"#/components/schemas/BrowserGetStorageAction","openhands__tools__browser_use__definition__BrowserGoBackAction-Output__1":"#/components/schemas/BrowserGoBackAction","openhands__tools__browser_use__definition__BrowserListTabsAction-Output__1":"#/components/schemas/BrowserListTabsAction","openhands__tools__browser_use__definition__BrowserNavigateAction-Output__1":"#/components/schemas/BrowserNavigateAction","openhands__tools__browser_use__definition__BrowserScrollAction-Output__1":"#/components/schemas/BrowserScrollAction","openhands__tools__browser_use__definition__BrowserSetStorageAction-Output__1":"#/components/schemas/BrowserSetStorageAction","openhands__tools__browser_use__definition__BrowserStartRecordingAction-Output__1":"#/components/schemas/BrowserStartRecordingAction","openhands__tools__browser_use__definition__BrowserStopRecordingAction-Output__1":"#/components/schemas/BrowserStopRecordingAction","openhands__tools__browser_use__definition__BrowserSwitchTabAction-Output__1":"#/components/schemas/BrowserSwitchTabAction","openhands__tools__browser_use__definition__BrowserTypeAction-Output__1":"#/components/schemas/BrowserTypeAction","openhands__tools__delegate__definition__DelegateAction-Output__1":"#/components/schemas/DelegateAction","openhands__tools__file_editor__definition__FileEditorAction-Output__1":"#/components/schemas/FileEditorAction","openhands__tools__gemini__edit__definition__EditAction-Output__1":"#/components/schemas/EditAction","openhands__tools__gemini__list_directory__definition__ListDirectoryAction-Output__1":"#/components/schemas/ListDirectoryAction","openhands__tools__gemini__read_file__definition__ReadFileAction-Output__1":"#/components/schemas/ReadFileAction","openhands__tools__gemini__write_file__definition__WriteFileAction-Output__1":"#/components/schemas/WriteFileAction","openhands__tools__glob__definition__GlobAction-Output__1":"#/components/schemas/GlobAction","openhands__tools__grep__definition__GrepAction-Output__1":"#/components/schemas/GrepAction","openhands__tools__planning_file_editor__definition__PlanningFileEditorAction-Output__1":"#/components/schemas/PlanningFileEditorAction","openhands__tools__task__definition__TaskAction-Output__1":"#/components/schemas/TaskAction","openhands__tools__task_tracker__definition__TaskTrackerAction-Output__1":"#/components/schemas/TaskTrackerAction","openhands__tools__terminal__definition__TerminalAction-Output__1":"#/components/schemas/TerminalAction","openhands__tools__workflow__definition__WorkflowAction-Output__1":"#/components/schemas/WorkflowAction"}}},"ActionEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"thought":{"items":{"$ref":"#/components/schemas/TextContent"},"type":"array","title":"Thought","description":"The thought process of the agent before taking this action"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content","description":"Intermediate reasoning/thinking content from reasoning models"},"thinking_blocks":{"items":{"anyOf":[{"$ref":"#/components/schemas/ThinkingBlock"},{"$ref":"#/components/schemas/RedactedThinkingBlock"}]},"type":"array","title":"Thinking Blocks","description":"Anthropic thinking blocks from the LLM response"},"responses_reasoning_item":{"anyOf":[{"$ref":"#/components/schemas/ReasoningItemModel"},{"type":"null"}],"description":"OpenAI Responses reasoning item from model output"},"action":{"anyOf":[{"$ref":"#/components/schemas/Action"},{"type":"null"}],"description":"Single tool call returned by LLM (None when non-executable)"},"tool_name":{"type":"string","title":"Tool Name","description":"The name of the tool being called"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The unique id returned by LLM API for this tool call"},"tool_call":{"$ref":"#/components/schemas/MessageToolCall","description":"The tool call received from the LLM response. We keep a copy of it so it is easier to construct it into LLM messageThis could be different from `action`: e.g., `tool_call` may contain `security_risk` field predicted by LLM when LLM risk analyzer is enabled, while `action` does not."},"llm_response_id":{"type":"string","title":"Llm Response Id","description":"Completion or Response ID of the LLM response that generated this eventE.g., Can be used to group related actions from same LLM response. This helps in tracking and managing results of parallel function calling from the same LLM response."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"critic_result":{"anyOf":[{"$ref":"#/components/schemas/CriticResult"},{"type":"null"}],"description":"Optional critic evaluation of this action and preceding history."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"A concise summary (approximately 10 words) of what this action does, provided by the LLM for explainability and debugging. Examples of good summaries: 'editing configuration file for deployment settings' | 'searching codebase for authentication function definitions' | 'installing required dependencies from package manifest' | 'running tests to verify bug fix' | 'viewing directory structure to locate source files'"},"kind":{"type":"string","const":"ActionEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["thought","tool_name","tool_call_id","tool_call","llm_response_id","kind"],"title":"ActionEvent"},"ActivateAgentProfileResponse":{"properties":{"id":{"type":"string","title":"Id"},"message":{"type":"string","title":"Message"},"agent_settings_applied":{"type":"boolean","title":"Agent Settings Applied","default":false}},"type":"object","required":["id","message"],"title":"ActivateAgentProfileResponse"},"ActivateProfileResponse":{"properties":{"name":{"type":"string","title":"Name"},"message":{"type":"string","title":"Message"},"llm_applied":{"type":"boolean","title":"Llm Applied","default":true}},"type":"object","required":["name","message"],"title":"ActivateProfileResponse","description":"Response model for profile activation."},"AddWorkspaceParentsRequest":{"properties":{"parents":{"items":{"$ref":"#/components/schemas/WorkspaceParentItem"},"type":"array","title":"Parents"}},"type":"object","required":["parents"],"title":"AddWorkspaceParentsRequest"},"AddWorkspacesRequest":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/WorkspaceItem"},"type":"array","title":"Workspaces"}},"type":"object","required":["workspaces"],"title":"AddWorkspacesRequest"},"Agent-Input":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input","description":"LLM configuration for the agent.","examples":[{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"}]},"tools":{"items":{"$ref":"#/components/schemas/Tool-Input"},"type":"array","title":"Tools","description":"List of tools to initialize for the agent.","examples":[{"name":"TerminalTool","params":{}},{"name":"FileEditorTool","params":{}},{"name":"TaskTrackerTool","params":{}}]},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools","description":"List of default tool class names to include. By default, the agent includes 'FinishTool' and 'ThinkTool'. Set to an empty list to disable all default tools, or provide a subset to include only specific ones. Example: include_default_tools=['FinishTool'] to only include FinishTool, or include_default_tools=[] to disable all default tools.","examples":[["FinishTool","ThinkTool"],["FinishTool"],[]]},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Input"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Input"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Input"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"kind":{"type":"string","const":"Agent","title":"Kind"}},"type":"object","required":["llm"],"title":"Agent","description":"Main agent implementation for OpenHands.\n\nThe Agent class provides the core functionality for running AI agents that can\ninteract with tools, process messages, and execute actions. It inherits from\nAgentBase and implements the agent execution logic. Critic-related functionality\nis provided by CriticMixin.\n\nAttributes:\n llm: The language model instance used for reasoning.\n tools: List of tools available to the agent.\n system_prompt: Inline system prompt string. When provided the agent\n uses this text verbatim instead of rendering from a template.\n Mutually exclusive with a non-default ``system_prompt_filename``.\n **Not recommended** unless you know what you are doing (e.g.\n customising agent behaviour for a completely different task) —\n this will override OpenHands' built-in system instructions.\n system_prompt_filename: Jinja2 template filename resolved relative to\n the agent's prompts directory, or an absolute path. Defaults to\n ``\"system_prompt.j2\"``.\n system_prompt_kwargs: Extra kwargs forwarded to the Jinja2 template.\n\nExample:\n ```python\n from openhands.sdk import LLM, Agent, Tool\n from pydantic import SecretStr\n\n llm = LLM(model=\"gpt-5.5\", api_key=SecretStr(\"key\"))\n tools = [Tool(name=\"TerminalTool\"), Tool(name=\"FileEditorTool\")]\n agent = Agent(llm=llm, tools=tools)\n ```\n\n To override the system prompt entirely::\n\n agent = Agent(\n llm=llm,\n tools=tools,\n system_prompt=\"You are a helpful coding assistant.\",\n )"},"Agent-Output":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Output","description":"LLM configuration for the agent.","examples":[{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"}]},"tools":{"items":{"$ref":"#/components/schemas/openhands__sdk__tool__spec__Tool"},"type":"array","title":"Tools","description":"List of tools to initialize for the agent.","examples":[{"name":"TerminalTool","params":{}},{"name":"FileEditorTool","params":{}},{"name":"TaskTrackerTool","params":{}}]},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools","description":"List of default tool class names to include. By default, the agent includes 'FinishTool' and 'ThinkTool'. Set to an empty list to disable all default tools, or provide a subset to include only specific ones. Example: include_default_tools=['FinishTool'] to only include FinishTool, or include_default_tools=[] to disable all default tools.","examples":[["FinishTool","ThinkTool"],["FinishTool"],[]]},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Output"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Output"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Output"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"kind":{"type":"string","const":"Agent","title":"Kind"}},"type":"object","required":["llm","kind"],"title":"Agent","description":"Main agent implementation for OpenHands.\n\nThe Agent class provides the core functionality for running AI agents that can\ninteract with tools, process messages, and execute actions. It inherits from\nAgentBase and implements the agent execution logic. Critic-related functionality\nis provided by CriticMixin.\n\nAttributes:\n llm: The language model instance used for reasoning.\n tools: List of tools available to the agent.\n system_prompt: Inline system prompt string. When provided the agent\n uses this text verbatim instead of rendering from a template.\n Mutually exclusive with a non-default ``system_prompt_filename``.\n **Not recommended** unless you know what you are doing (e.g.\n customising agent behaviour for a completely different task) —\n this will override OpenHands' built-in system instructions.\n system_prompt_filename: Jinja2 template filename resolved relative to\n the agent's prompts directory, or an absolute path. Defaults to\n ``\"system_prompt.j2\"``.\n system_prompt_kwargs: Extra kwargs forwarded to the Jinja2 template.\n\nExample:\n ```python\n from openhands.sdk import LLM, Agent, Tool\n from pydantic import SecretStr\n\n llm = LLM(model=\"gpt-5.5\", api_key=SecretStr(\"key\"))\n tools = [Tool(name=\"TerminalTool\"), Tool(name=\"FileEditorTool\")]\n agent = Agent(llm=llm, tools=tools)\n ```\n\n To override the system prompt entirely::\n\n agent = Agent(\n llm=llm,\n tools=tools,\n system_prompt=\"You are a helpful coding assistant.\",\n )"},"AgentBase-Input":{"oneOf":[{"$ref":"#/components/schemas/ACPAgent-Input"},{"$ref":"#/components/schemas/Agent-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__agent__acp_agent__ACPAgent-Input__1":"#/components/schemas/ACPAgent-Input","openhands__sdk__agent__agent__Agent-Input__1":"#/components/schemas/Agent-Input"}}},"AgentBase-Output":{"oneOf":[{"$ref":"#/components/schemas/ACPAgent-Output"},{"$ref":"#/components/schemas/Agent-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__agent__acp_agent__ACPAgent-Output__1":"#/components/schemas/ACPAgent-Output","openhands__sdk__agent__agent__Agent-Output__1":"#/components/schemas/Agent-Output"}}},"AgentContext-Input":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/Skill-Input"},"type":"array","title":"Skills","description":"List of available skills that can extend the user's input.","acp_compatible":true},"system_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Message Suffix","description":"Optional suffix to append to the system prompt.","acp_compatible":true},"user_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Message Suffix","description":"Optional suffix to append to the user's message.","acp_compatible":true},"load_user_skills":{"type":"boolean","title":"Load User Skills","description":"Whether to automatically load user skills from ~/.openhands/skills/ and ~/.openhands/microagents/ (for backward compatibility). ","default":false,"acp_compatible":true},"load_public_skills":{"type":"boolean","title":"Load Public Skills","description":"Whether to automatically load skills from the public OpenHands skills repository at https://github.com/OpenHands/extensions. This allows you to get the latest skills without SDK updates.","default":false,"acp_compatible":true},"marketplace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace Path","description":"Relative marketplace JSON path within the public skills repository. Set to None to load all public skills without marketplace filtering.","default":"marketplaces/default.json","acp_compatible":true},"load_project_skills":{"type":"boolean","title":"Load Project Skills","description":"Whether to automatically load project skills from the conversation workspace (e.g. .openhands/skills/, AGENTS.md). Unlike load_user_skills / load_public_skills, this flag is not resolved by AgentContext itself (the workspace path is unknown at validation time); LocalConversation resolves it lazily on the first send_message() / run(), when the workspace is known. Also unlike load_user_skills / load_public_skills (which yield to explicit skills on a name conflict), resolved project skills are authoritative: a project skill overrides a same-named skill already present in `skills`.","default":false,"acp_compatible":true},"secrets":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/SecretSource-Input"}]},"type":"object"},{"type":"null"}],"title":"Secrets","description":"Dictionary mapping secret keys to values or secret sources. Secrets are used for authentication and sensitive data handling. Values can be either strings or SecretSource instances (str | SecretSource).","acp_compatible":true},"current_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}],"title":"Current Datetime","description":"Current date and time information to provide to the agent. Can be a datetime object (which will be formatted as ISO 8601) or a pre-formatted string. When provided, this information is included in the system prompt to give the agent awareness of the current time context. Defaults to the current (timezone-aware) datetime.","acp_compatible":true}},"type":"object","title":"AgentContext","description":"Central structure for managing prompt extension.\n\nAgentContext unifies all the contextual inputs that shape how the system\nextends and interprets user prompts. It combines both static environment\ndetails and dynamic, user-activated extensions from skills.\n\nSpecifically, it provides:\n- **Repository context / Repo Skills**: Information about the active codebase,\n branches, and repo-specific instructions contributed by repo skills.\n- **Runtime context**: Current execution environment (hosts, working\n directory, secrets, date, etc.).\n- **Conversation instructions**: Optional task- or channel-specific rules\n that constrain or guide the agent’s behavior across the session.\n- **Knowledge Skills**: Extensible components that can be triggered by user input\n to inject knowledge or domain-specific guidance.\n\nTogether, these elements make AgentContext the primary container responsible\nfor assembling, formatting, and injecting all prompt-relevant context into\nLLM interactions."},"AgentContext-Output":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/Skill-Output"},"type":"array","title":"Skills","description":"List of available skills that can extend the user's input.","acp_compatible":true},"system_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Message Suffix","description":"Optional suffix to append to the system prompt.","acp_compatible":true},"user_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Message Suffix","description":"Optional suffix to append to the user's message.","acp_compatible":true},"load_user_skills":{"type":"boolean","title":"Load User Skills","description":"Whether to automatically load user skills from ~/.openhands/skills/ and ~/.openhands/microagents/ (for backward compatibility). ","default":false,"acp_compatible":true},"load_public_skills":{"type":"boolean","title":"Load Public Skills","description":"Whether to automatically load skills from the public OpenHands skills repository at https://github.com/OpenHands/extensions. This allows you to get the latest skills without SDK updates.","default":false,"acp_compatible":true},"marketplace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace Path","description":"Relative marketplace JSON path within the public skills repository. Set to None to load all public skills without marketplace filtering.","default":"marketplaces/default.json","acp_compatible":true},"load_project_skills":{"type":"boolean","title":"Load Project Skills","description":"Whether to automatically load project skills from the conversation workspace (e.g. .openhands/skills/, AGENTS.md). Unlike load_user_skills / load_public_skills, this flag is not resolved by AgentContext itself (the workspace path is unknown at validation time); LocalConversation resolves it lazily on the first send_message() / run(), when the workspace is known. Also unlike load_user_skills / load_public_skills (which yield to explicit skills on a name conflict), resolved project skills are authoritative: a project skill overrides a same-named skill already present in `skills`.","default":false,"acp_compatible":true},"secrets":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Secrets","description":"Dictionary mapping secret keys to values or secret sources. Secrets are used for authentication and sensitive data handling. Values can be either strings or SecretSource instances (str | SecretSource).","acp_compatible":true},"current_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}],"title":"Current Datetime","description":"Current date and time information to provide to the agent. Can be a datetime object (which will be formatted as ISO 8601) or a pre-formatted string. When provided, this information is included in the system prompt to give the agent awareness of the current time context. Defaults to the current (timezone-aware) datetime.","acp_compatible":true}},"type":"object","title":"AgentContext","description":"Central structure for managing prompt extension.\n\nAgentContext unifies all the contextual inputs that shape how the system\nextends and interprets user prompts. It combines both static environment\ndetails and dynamic, user-activated extensions from skills.\n\nSpecifically, it provides:\n- **Repository context / Repo Skills**: Information about the active codebase,\n branches, and repo-specific instructions contributed by repo skills.\n- **Runtime context**: Current execution environment (hosts, working\n directory, secrets, date, etc.).\n- **Conversation instructions**: Optional task- or channel-specific rules\n that constrain or guide the agent’s behavior across the session.\n- **Knowledge Skills**: Extensible components that can be triggered by user input\n to inject knowledge or domain-specific guidance.\n\nTogether, these elements make AgentContext the primary container responsible\nfor assembling, formatting, and injecting all prompt-relevant context into\nLLM interactions."},"AgentDefinition":{"properties":{"name":{"type":"string","title":"Name","description":"Agent name (from frontmatter or filename)"},"description":{"type":"string","title":"Description","description":"Agent description","default":""},"model":{"type":"string","title":"Model","description":"Model to use ('inherit' uses parent model)","default":"inherit"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color","description":"Display color for the agent"},"tools":{"items":{"type":"string"},"type":"array","title":"Tools","description":"List of allowed tools for this agent"},"skills":{"items":{"type":"string"},"type":"array","title":"Skills","description":"List of skill names for this agent. Resolved from project/user directories."},"system_prompt":{"type":"string","title":"System Prompt","description":"System prompt content","default":""},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Source file path for this agent"},"when_to_use_examples":{"items":{"type":"string"},"type":"array","title":"When To Use Examples","description":"Examples of when to use this agent (for triggering)"},"hooks":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Input"},{"type":"null"}],"description":"Hook configuration for this agent"},"permission_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Permission Mode","description":"How the subagent handles permissions. None inherits the parent policy, 'always_confirm' requires confirmation for every action, 'never_confirm' skips all confirmations, 'confirm_risky' only confirms actions above a risk threshold."},"max_iteration_per_run":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Iteration Per Run","description":"Maximum iterations per run. It must be strictly positive, or None for default."},"max_budget_per_run":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Budget Per Run","description":"Maximum accumulated cost (USD) per run for this sub-agent. Must be strictly positive, or None for no budget."},"mcp_servers":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mcp Servers","description":"MCP server configurations for this agent. Keys are server names, values are server configs with 'command', 'args', etc.","examples":[{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}]},"profile_store_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Store Dir","description":"Path to the directory where LLM profiles are stored. If None, the default profile store directory is used."},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Input"},{"type":"null"}],"description":"Context condenser for the sub-agent. None applies a default summarizing condenser; set a NoOpCondenser to disable condensation."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Additional metadata from frontmatter"}},"type":"object","required":["name"],"title":"AgentDefinition","description":"Agent definition loaded from Markdown file.\n\nAgents are specialized configurations that can be triggered based on\nuser input patterns. They define custom system prompts and tool access."},"AgentErrorEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"tool_name":{"type":"string","title":"Tool Name","description":"The tool name that this observation is responding to"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The tool call id that this observation is responding to"},"error":{"type":"string","title":"Error","description":"The error message from the scaffold"},"kind":{"type":"string","const":"AgentErrorEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","tool_call_id","error","kind"],"title":"AgentErrorEvent","description":"Error triggered by the agent.\n\nNote: This event should not contain model \"thought\" or \"reasoning_content\". It\nrepresents an error produced by the agent/scaffold, not model output."},"AgentFinishedCritic-Input":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"AgentFinishedCritic","title":"Kind"}},"type":"object","title":"AgentFinishedCritic","description":"Critic that evaluates whether an agent properly finished a task.\n\nThis critic checks two main criteria:\n1. The agent's last action was a FinishAction (proper completion)\n2. The generated git patch is non-empty (actual changes were made)"},"AgentFinishedCritic-Output":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"AgentFinishedCritic","title":"Kind"}},"type":"object","required":["kind"],"title":"AgentFinishedCritic","description":"Critic that evaluates whether an agent properly finished a task.\n\nThis critic checks two main criteria:\n1. The agent's last action was a FinishAction (proper completion)\n2. The generated git patch is non-empty (actual changes were made)"},"AgentProfileDetailResponse":{"properties":{"name":{"type":"string","title":"Name"},"profile":{"additionalProperties":true,"type":"object","title":"Profile"}},"type":"object","required":["name","profile"],"title":"AgentProfileDetailResponse"},"AgentProfileDiagnostics":{"properties":{"agent_kind":{"type":"string","title":"Agent Kind"},"valid":{"type":"boolean","title":"Valid","default":false},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"llm_profile_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Profile Ref"},"llm_profile_resolved":{"type":"boolean","title":"Llm Profile Resolved","default":false},"llm_api_key_set":{"type":"boolean","title":"Llm Api Key Set","default":false},"mcp_server_refs":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mcp Server Refs"},"resolved_mcp_servers":{"items":{"type":"string"},"type":"array","title":"Resolved Mcp Servers"},"dangling_mcp_server_refs":{"items":{"type":"string"},"type":"array","title":"Dangling Mcp Server Refs"},"acp_api_key_secret_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Api Key Secret Name"},"acp_base_url_secret_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Base Url Secret Name"},"acp_file_secret_names":{"items":{"type":"string"},"type":"array","title":"Acp File Secret Names"},"resolved_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Resolved Settings"}},"type":"object","required":["agent_kind"],"title":"AgentProfileDiagnostics","description":"Side-effect-free report of what :func:`resolve_agent_profile` would do.\n\nConsumed by ``POST /{id}/materialize`` (#3719) and the canvas editor. The\nverdict (:attr:`valid`) and the dangling-ref lists match exactly what a real\nresolve produces; :attr:`resolved_settings` is the redacted settings dump\n(present only when :attr:`valid`)."},"AgentProfileInfo":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"type":"string","title":"Name"},"agent_kind":{"type":"string","title":"Agent Kind","default":"openhands"},"revision":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Revision"},"llm_profile_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Profile Ref"},"mcp_server_refs":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mcp Server Refs"}},"type":"object","required":["name"],"title":"AgentProfileInfo","description":"Summary projection of a stored profile (no secret instantiation)."},"AgentProfileListResponse":{"properties":{"profiles":{"items":{"$ref":"#/components/schemas/AgentProfileInfo"},"type":"array","title":"Profiles"},"active_agent_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Agent Profile Id"}},"type":"object","required":["profiles"],"title":"AgentProfileListResponse"},"AgentProfileMutationResponse":{"properties":{"name":{"type":"string","title":"Name"},"message":{"type":"string","title":"Message"}},"type":"object","required":["name","message"],"title":"AgentProfileMutationResponse"},"AgentResponseResult":{"properties":{"response":{"type":"string","title":"Response","description":"The agent's final response text. Extracted from either a FinishAction message or the last agent MessageEvent. Empty string if no final response is available."}},"type":"object","required":["response"],"title":"AgentResponseResult","description":"The agent's final response for a conversation.\n\nContains the text of the last agent finish message or text response.\nEmpty string if the agent has not produced a final response yet."},"AlwaysConfirm-Input":{"properties":{"kind":{"type":"string","const":"AlwaysConfirm","title":"Kind"}},"type":"object","title":"AlwaysConfirm"},"AlwaysConfirm-Output":{"properties":{"kind":{"type":"string","const":"AlwaysConfirm","title":"Kind"}},"type":"object","required":["kind"],"title":"AlwaysConfirm"},"Annotation":{"properties":{"type":{"type":"string","const":"url_citation","title":"Type"},"url_citation":{"$ref":"#/components/schemas/AnnotationURLCitation"}},"additionalProperties":true,"type":"object","required":["type","url_citation"],"title":"Annotation","description":"A URL citation when using web search."},"AnnotationURLCitation":{"properties":{"end_index":{"type":"integer","title":"End Index"},"start_index":{"type":"integer","title":"Start Index"},"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"}},"additionalProperties":true,"type":"object","required":["end_index","start_index","title","url"],"title":"AnnotationURLCitation","description":"A URL citation when using web search."},"AskAgentRequest":{"properties":{"question":{"type":"string","title":"Question","description":"The question to ask the agent"}},"type":"object","required":["question"],"title":"AskAgentRequest","description":"Payload to ask the agent a simple question."},"AskAgentResponse":{"properties":{"response":{"type":"string","title":"Response","description":"The agent's response to the question"}},"type":"object","required":["response"],"title":"AskAgentResponse","description":"Response containing the agent's answer."},"BaseWorkspace":{"oneOf":[{"$ref":"#/components/schemas/LocalWorkspace-Output"},{"$ref":"#/components/schemas/RemoteWorkspace"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__workspace__local__LocalWorkspace-Output__1":"#/components/schemas/LocalWorkspace-Output","openhands__sdk__workspace__remote__base__RemoteWorkspace-Output__1":"#/components/schemas/RemoteWorkspace"}}},"BashCommand":{"properties":{"command":{"type":"string","title":"Command","description":"The bash command to execute"},"cwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd","description":"The current working directory"},"timeout":{"type":"integer","title":"Timeout","description":"The max number of seconds a command may be permitted to run.","default":300},"id":{"type":"string","title":"Id"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"kind":{"type":"string","const":"BashCommand","title":"Kind"}},"type":"object","required":["command","kind"],"title":"BashCommand"},"BashError":{"properties":{"id":{"type":"string","title":"Id"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"code":{"type":"string","title":"Code","description":"Code for the error - typically an error type"},"detail":{"type":"string","title":"Detail","description":"Details about the error"},"kind":{"type":"string","const":"BashError","title":"Kind"}},"type":"object","required":["code","detail","kind"],"title":"BashError"},"BashEventBase":{"oneOf":[{"$ref":"#/components/schemas/BashCommand"},{"$ref":"#/components/schemas/BashError"},{"$ref":"#/components/schemas/BashOutput"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__agent_server__models__BashCommand-Output__1":"#/components/schemas/BashCommand","openhands__agent_server__models__BashError-Output__1":"#/components/schemas/BashError","openhands__agent_server__models__BashOutput-Output__1":"#/components/schemas/BashOutput"}}},"BashEventPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/BashEventBase"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"BashEventPage"},"BashEventSortOrder":{"type":"string","enum":["TIMESTAMP","TIMESTAMP_DESC"],"title":"BashEventSortOrder"},"BashOutput":{"properties":{"id":{"type":"string","title":"Id"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"command_id":{"type":"string","title":"Command Id"},"order":{"type":"integer","title":"Order","description":"The order for this output, sequentially starting with 0","default":0},"exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exit Code","description":"Exit code None implies the command is still running."},"stdout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stdout","description":"The standard output from the command"},"stderr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stderr","description":"The error output from the command"},"kind":{"type":"string","const":"BashOutput","title":"Kind"}},"type":"object","required":["command_id","kind"],"title":"BashOutput","description":"Output of a bash command. A single command may have multiple pieces of output\ndepending on how large the output is."},"Body_switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post":{"properties":{"model":{"type":"string","title":"Model"}},"type":"object","required":["model"],"title":"Body_switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post"},"Body_switch_conversation_llm_api_conversations__conversation_id__switch_llm_post":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"}},"type":"object","required":["llm"],"title":"Body_switch_conversation_llm_api_conversations__conversation_id__switch_llm_post"},"Body_switch_conversation_profile_api_conversations__conversation_id__switch_profile_post":{"properties":{"profile_name":{"type":"string","title":"Profile Name"}},"type":"object","required":["profile_name"],"title":"Body_switch_conversation_profile_api_conversations__conversation_id__switch_profile_post"},"Body_upload_file_query_api_file_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_file_query_api_file_upload_post"},"BrowserAction":{"properties":{"kind":{"type":"string","const":"BrowserAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserAction","description":"Base class for all browser actions.\n\nThis base class serves as the parent for all browser-related actions,\nenabling proper type hierarchy and eliminating the need for union types."},"BrowserActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserActionWithRisk"},"BrowserClickAction":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the element to click (from browser_get_state)"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open any resulting navigation in a new tab. Default: False","default":false},"kind":{"type":"string","const":"BrowserClickAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","kind"],"title":"BrowserClickAction","description":"Schema for clicking elements."},"BrowserClickActionWithRisk":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the element to click (from browser_get_state)"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open any resulting navigation in a new tab. Default: False","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserClickActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","kind"],"title":"BrowserClickActionWithRisk"},"BrowserClickTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserClickTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserClickTool","description":"Tool for clicking browser elements."},"BrowserCloseTabAction":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to close (from browser_list_tabs)"},"kind":{"type":"string","const":"BrowserCloseTabAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserCloseTabAction","description":"Schema for closing browser tabs."},"BrowserCloseTabActionWithRisk":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to close (from browser_list_tabs)"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserCloseTabActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserCloseTabActionWithRisk"},"BrowserCloseTabTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserCloseTabTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserCloseTabTool","description":"Tool for closing browser tabs."},"BrowserGetContentAction":{"properties":{"extract_links":{"type":"boolean","title":"Extract Links","description":"Whether to include links in the content (default: False)","default":false},"start_from_char":{"type":"integer","minimum":0.0,"title":"Start From Char","description":"Character index to start from in the page content (default: 0)","default":0},"kind":{"type":"string","const":"BrowserGetContentAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetContentAction","description":"Schema for getting page content in markdown."},"BrowserGetContentActionWithRisk":{"properties":{"extract_links":{"type":"boolean","title":"Extract Links","description":"Whether to include links in the content (default: False)","default":false},"start_from_char":{"type":"integer","minimum":0.0,"title":"Start From Char","description":"Character index to start from in the page content (default: 0)","default":0},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGetContentActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetContentActionWithRisk"},"BrowserGetContentTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGetContentTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGetContentTool","description":"Tool for getting page content in markdown."},"BrowserGetStateAction":{"properties":{"include_screenshot":{"type":"boolean","title":"Include Screenshot","description":"Whether to include a screenshot of the current page. Default: False","default":false},"kind":{"type":"string","const":"BrowserGetStateAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStateAction","description":"Schema for getting browser state."},"BrowserGetStateActionWithRisk":{"properties":{"include_screenshot":{"type":"boolean","title":"Include Screenshot","description":"Whether to include a screenshot of the current page. Default: False","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGetStateActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStateActionWithRisk"},"BrowserGetStateTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGetStateTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGetStateTool","description":"Tool for getting browser state."},"BrowserGetStorageAction":{"properties":{"kind":{"type":"string","const":"BrowserGetStorageAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStorageAction","description":"Schema for getting browser storage (cookies, local storage, session storage)."},"BrowserGetStorageActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGetStorageActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStorageActionWithRisk"},"BrowserGetStorageTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGetStorageTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGetStorageTool","description":"Tool for getting browser storage."},"BrowserGoBackAction":{"properties":{"kind":{"type":"string","const":"BrowserGoBackAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGoBackAction","description":"Schema for going back in browser history."},"BrowserGoBackActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGoBackActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGoBackActionWithRisk"},"BrowserGoBackTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGoBackTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGoBackTool","description":"Tool for going back in browser history."},"BrowserListTabsAction":{"properties":{"kind":{"type":"string","const":"BrowserListTabsAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserListTabsAction","description":"Schema for listing browser tabs."},"BrowserListTabsActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserListTabsActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserListTabsActionWithRisk"},"BrowserListTabsTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserListTabsTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserListTabsTool","description":"Tool for listing browser tabs."},"BrowserNavigateAction":{"properties":{"url":{"type":"string","title":"Url","description":"The URL to navigate to"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open in a new tab. Default: False","default":false},"kind":{"type":"string","const":"BrowserNavigateAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["url","kind"],"title":"BrowserNavigateAction","description":"Schema for browser navigation."},"BrowserNavigateActionWithRisk":{"properties":{"url":{"type":"string","title":"Url","description":"The URL to navigate to"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open in a new tab. Default: False","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserNavigateActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["url","kind"],"title":"BrowserNavigateActionWithRisk"},"BrowserNavigateTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserNavigateTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserNavigateTool","description":"Tool for browser navigation."},"BrowserObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"screenshot_data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screenshot Data","description":"Base64 screenshot data if available"},"full_output_save_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Output Save Dir","description":"Directory where full output files are saved"},"kind":{"type":"string","const":"BrowserObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserObservation","description":"Base observation for browser operations."},"BrowserScrollAction":{"properties":{"direction":{"type":"string","enum":["up","down"],"title":"Direction","description":"Direction to scroll. Options: 'up', 'down'. Default: 'down'","default":"down"},"kind":{"type":"string","const":"BrowserScrollAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserScrollAction","description":"Schema for scrolling the page."},"BrowserScrollActionWithRisk":{"properties":{"direction":{"type":"string","enum":["up","down"],"title":"Direction","description":"Direction to scroll. Options: 'up', 'down'. Default: 'down'","default":"down"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserScrollActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserScrollActionWithRisk"},"BrowserScrollTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserScrollTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserScrollTool","description":"Tool for scrolling the browser page."},"BrowserSetStorageAction":{"properties":{"storage_state":{"additionalProperties":true,"type":"object","title":"Storage State","description":"Storage state dictionary containing 'cookies' and 'origins' (from browser_get_storage)"},"kind":{"type":"string","const":"BrowserSetStorageAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["storage_state","kind"],"title":"BrowserSetStorageAction","description":"Schema for setting browser storage (cookies, local storage, session storage)."},"BrowserSetStorageActionWithRisk":{"properties":{"storage_state":{"additionalProperties":true,"type":"object","title":"Storage State","description":"Storage state dictionary containing 'cookies' and 'origins' (from browser_get_storage)"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserSetStorageActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["storage_state","kind"],"title":"BrowserSetStorageActionWithRisk"},"BrowserSetStorageTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserSetStorageTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserSetStorageTool","description":"Tool for setting browser storage."},"BrowserStartRecordingAction":{"properties":{"kind":{"type":"string","const":"BrowserStartRecordingAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStartRecordingAction","description":"Schema for starting browser session recording."},"BrowserStartRecordingActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserStartRecordingActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStartRecordingActionWithRisk"},"BrowserStartRecordingTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserStartRecordingTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserStartRecordingTool","description":"Tool for starting browser session recording."},"BrowserStopRecordingAction":{"properties":{"kind":{"type":"string","const":"BrowserStopRecordingAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStopRecordingAction","description":"Schema for stopping browser session recording."},"BrowserStopRecordingActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserStopRecordingActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStopRecordingActionWithRisk"},"BrowserStopRecordingTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserStopRecordingTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserStopRecordingTool","description":"Tool for stopping browser session recording."},"BrowserSwitchTabAction":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to switch to (from browser_list_tabs)"},"kind":{"type":"string","const":"BrowserSwitchTabAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserSwitchTabAction","description":"Schema for switching browser tabs."},"BrowserSwitchTabActionWithRisk":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to switch to (from browser_list_tabs)"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserSwitchTabActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserSwitchTabActionWithRisk"},"BrowserSwitchTabTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserSwitchTabTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserSwitchTabTool","description":"Tool for switching browser tabs."},"BrowserToolSet":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserToolSet","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserToolSet","description":"A set of all browser tools.\n\nThis tool set includes all available browser-related tools\n for interacting with web pages.\n\nThe toolset automatically checks for Chromium availability\nwhen created and automatically installs it if missing."},"BrowserTypeAction":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the input element (from browser_get_state)"},"text":{"type":"string","title":"Text","description":"The text to type"},"kind":{"type":"string","const":"BrowserTypeAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","text","kind"],"title":"BrowserTypeAction","description":"Schema for typing text into elements."},"BrowserTypeActionWithRisk":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the input element (from browser_get_state)"},"text":{"type":"string","title":"Text","description":"The text to type"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserTypeActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","text","kind"],"title":"BrowserTypeActionWithRisk"},"BrowserTypeTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserTypeTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserTypeTool","description":"Tool for typing text into browser elements."},"ChatCompletion":{"properties":{"id":{"type":"string","title":"Id"},"choices":{"items":{"$ref":"#/components/schemas/Choice"},"type":"array","title":"Choices"},"created":{"type":"integer","title":"Created"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"chat.completion","title":"Object"},"service_tier":{"anyOf":[{"type":"string","enum":["auto","default","flex","scale","priority"]},{"type":"null"}],"title":"Service Tier"},"system_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Fingerprint"},"usage":{"anyOf":[{"$ref":"#/components/schemas/CompletionUsage"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["id","choices","created","model","object"],"title":"ChatCompletion","description":"Represents a chat completion response returned by model, based on the provided input."},"ChatCompletionAudio":{"properties":{"id":{"type":"string","title":"Id"},"data":{"type":"string","title":"Data"},"expires_at":{"type":"integer","title":"Expires At"},"transcript":{"type":"string","title":"Transcript"}},"additionalProperties":true,"type":"object","required":["id","data","expires_at","transcript"],"title":"ChatCompletionAudio","description":"If the audio output modality is requested, this object contains data\nabout the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio)."},"ChatCompletionMessage":{"properties":{"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"role":{"type":"string","const":"assistant","title":"Role"},"annotations":{"anyOf":[{"items":{"$ref":"#/components/schemas/Annotation"},"type":"array"},{"type":"null"}],"title":"Annotations"},"audio":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionAudio"},{"type":"null"}]},"function_call":{"anyOf":[{"$ref":"#/components/schemas/FunctionCall"},{"type":"null"}]},"tool_calls":{"anyOf":[{"items":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionMessageFunctionToolCall"},{"$ref":"#/components/schemas/ChatCompletionMessageCustomToolCall"}]},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"additionalProperties":true,"type":"object","required":["role"],"title":"ChatCompletionMessage","description":"A chat completion message generated by the model."},"ChatCompletionMessageCustomToolCall":{"properties":{"id":{"type":"string","title":"Id"},"custom":{"$ref":"#/components/schemas/Custom"},"type":{"type":"string","const":"custom","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","custom","type"],"title":"ChatCompletionMessageCustomToolCall","description":"A call to a custom tool created by the model."},"ChatCompletionMessageFunctionToolCall":{"properties":{"id":{"type":"string","title":"Id"},"function":{"$ref":"#/components/schemas/Function"},"type":{"type":"string","const":"function","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","function","type"],"title":"ChatCompletionMessageFunctionToolCall","description":"A call to a function tool created by the model."},"ChatCompletionTokenLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"},"top_logprobs":{"items":{"$ref":"#/components/schemas/TopLogprob"},"type":"array","title":"Top Logprobs"}},"additionalProperties":true,"type":"object","required":["token","logprob","top_logprobs"],"title":"ChatCompletionTokenLogprob"},"Choice":{"properties":{"finish_reason":{"type":"string","enum":["stop","length","tool_calls","content_filter","function_call"],"title":"Finish Reason"},"index":{"type":"integer","title":"Index"},"logprobs":{"anyOf":[{"$ref":"#/components/schemas/ChoiceLogprobs"},{"type":"null"}]},"message":{"$ref":"#/components/schemas/ChatCompletionMessage"}},"additionalProperties":true,"type":"object","required":["finish_reason","index","message"],"title":"Choice"},"ChoiceLogprobs":{"properties":{"content":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Refusal"}},"additionalProperties":true,"type":"object","title":"ChoiceLogprobs","description":"Log probability information for the choice."},"ClientTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"client_tool_name":{"type":"string","title":"Client Tool Name","description":"Per-instance tool name from the ClientToolSpec."},"input_schema":{"additionalProperties":true,"type":"object","title":"Input Schema","description":"The original JSON Schema for the tool's parameters, as provided by the client. Used verbatim when exporting the tool to the LLM so client-defined constraints (enum, nested objects, bounds, additionalProperties, ...) are preserved."},"kind":{"type":"string","const":"ClientTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","client_tool_name","input_schema","kind","title"],"title":"ClientTool","description":"A tool whose execution is deferred to the external client.\n\nCreated from a :class:`ClientToolSpec` at conversation start. The agent\nsees it as a normal tool and can call it; the ActionEvent is emitted\nover WebSocket for the client to handle."},"ClientToolObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"kind":{"type":"string","const":"ClientToolObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ClientToolObservation","description":"Observation returned when a client tool is called.\n\nThe actual execution happens on the client side; the SDK returns\nthis acknowledgment so the agent loop can continue."},"ClientToolSpec-Input":{"properties":{"name":{"type":"string","title":"Name","description":"Unique tool name the agent will use to call this tool."},"description":{"type":"string","title":"Description","description":"Description shown to the LLM explaining when and how to use this tool."},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters","description":"JSON Schema describing the tool's input parameters. Must be an object schema."},"annotations":{"anyOf":[{"$ref":"#/components/schemas/ToolAnnotations-Input"},{"type":"null"}],"description":"Optional MCP-style annotations for the tool. When omitted, the tool is treated conservatively (not read-only), so the agent is asked to predict a security risk before calling it."}},"type":"object","required":["name","description"],"title":"ClientToolSpec","description":"A tool defined by the client, executed externally (not by the SDK).\n\nClients pass these specs in ``POST /conversations`` to register tools\nwhose execution is handled outside the SDK (e.g., by a frontend\nlistening for ActionEvents over WebSocket)."},"ClientToolSpec-Output":{"properties":{"name":{"type":"string","title":"Name","description":"Unique tool name the agent will use to call this tool."},"description":{"type":"string","title":"Description","description":"Description shown to the LLM explaining when and how to use this tool."},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters","description":"JSON Schema describing the tool's input parameters. Must be an object schema."},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}],"description":"Optional MCP-style annotations for the tool. When omitted, the tool is treated conservatively (not read-only), so the agent is asked to predict a security risk before calling it."}},"type":"object","required":["name","description"],"title":"ClientToolSpec","description":"A tool defined by the client, executed externally (not by the SDK).\n\nClients pass these specs in ``POST /conversations`` to register tools\nwhose execution is handled outside the SDK (e.g., by a frontend\nlistening for ActionEvents over WebSocket)."},"CmdOutputMetadata":{"properties":{"exit_code":{"type":"integer","title":"Exit Code","description":"The exit code of the last executed command.","default":-1},"pid":{"type":"integer","title":"Pid","description":"The process ID of the last executed command.","default":-1},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username","description":"The username of the current user."},"hostname":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hostname","description":"The hostname of the machine."},"working_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Working Dir","description":"The current working directory."},"py_interpreter_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Py Interpreter Path","description":"The path to the current Python interpreter, if any."},"prefix":{"type":"string","title":"Prefix","description":"Prefix to add to command output","default":""},"suffix":{"type":"string","title":"Suffix","description":"Suffix to add to command output","default":""}},"type":"object","title":"CmdOutputMetadata","description":"Additional metadata captured from PS1"},"CompletionTokensDetails":{"properties":{"accepted_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Accepted Prediction Tokens"},"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"reasoning_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reasoning Tokens"},"rejected_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rejected Prediction Tokens"}},"additionalProperties":true,"type":"object","title":"CompletionTokensDetails","description":"Breakdown of tokens used in a completion."},"CompletionUsage":{"properties":{"completion_tokens":{"type":"integer","title":"Completion Tokens"},"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"total_tokens":{"type":"integer","title":"Total Tokens"},"completion_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/CompletionTokensDetails"},{"type":"null"}]},"prompt_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/PromptTokensDetails"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["completion_tokens","prompt_tokens","total_tokens"],"title":"CompletionUsage","description":"Usage statistics for the completion request."},"Condensation":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"forgotten_event_ids":{"items":{"type":"string"},"type":"array","uniqueItems":true,"title":"Forgotten Event Ids","description":"The IDs of the events that are being forgotten (removed from the `View` given to the LLM)."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"An optional summary of the events being forgotten."},"summary_offset":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Summary Offset","description":"An optional offset to the start of the resulting view (after forgotten events have been removed) indicating where the summary should be inserted. If not provided, the summary will not be inserted into the view."},"llm_response_id":{"type":"string","title":"Llm Response Id","description":"Completion or Response ID of the LLM response that generated this event"},"kind":{"type":"string","const":"Condensation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["llm_response_id","kind"],"title":"Condensation","description":"This action indicates a condensation of the conversation history is happening."},"CondensationRequest":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"kind":{"type":"string","const":"CondensationRequest","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"CondensationRequest","description":"This action is used to request a condensation of the conversation history.\n\nAttributes:\n action (str): The action type, namely ActionType.CONDENSATION_REQUEST."},"CondensationSummaryEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"summary":{"type":"string","title":"Summary"},"kind":{"type":"string","const":"CondensationSummaryEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["summary","kind"],"title":"CondensationSummaryEvent","description":"This event represents a summary generated by a condenser."},"CondenserBase-Input":{"oneOf":[{"$ref":"#/components/schemas/LLMSummarizingCondenser-Input"},{"$ref":"#/components/schemas/NoOpCondenser-Input"},{"$ref":"#/components/schemas/PipelineCondenser-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__context__condenser__llm_summarizing_condenser__LLMSummarizingCondenser-Input__1":"#/components/schemas/LLMSummarizingCondenser-Input","openhands__sdk__context__condenser__no_op_condenser__NoOpCondenser-Input__1":"#/components/schemas/NoOpCondenser-Input","openhands__sdk__context__condenser__pipeline_condenser__PipelineCondenser-Input__1":"#/components/schemas/PipelineCondenser-Input"}}},"CondenserBase-Output":{"oneOf":[{"$ref":"#/components/schemas/LLMSummarizingCondenser-Output"},{"$ref":"#/components/schemas/NoOpCondenser-Output"},{"$ref":"#/components/schemas/PipelineCondenser-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__context__condenser__llm_summarizing_condenser__LLMSummarizingCondenser-Output__1":"#/components/schemas/LLMSummarizingCondenser-Output","openhands__sdk__context__condenser__no_op_condenser__NoOpCondenser-Output__1":"#/components/schemas/NoOpCondenser-Output","openhands__sdk__context__condenser__pipeline_condenser__PipelineCondenser-Output__1":"#/components/schemas/PipelineCondenser-Output"}}},"ConfirmRisky-Input":{"properties":{"threshold":{"$ref":"#/components/schemas/SecurityRisk","default":"HIGH"},"confirm_unknown":{"type":"boolean","title":"Confirm Unknown","default":true},"kind":{"type":"string","const":"ConfirmRisky","title":"Kind"}},"type":"object","title":"ConfirmRisky"},"ConfirmRisky-Output":{"properties":{"threshold":{"$ref":"#/components/schemas/SecurityRisk","default":"HIGH"},"confirm_unknown":{"type":"boolean","title":"Confirm Unknown","default":true},"kind":{"type":"string","const":"ConfirmRisky","title":"Kind"}},"type":"object","required":["kind"],"title":"ConfirmRisky"},"ConfirmationPolicyBase-Input":{"oneOf":[{"$ref":"#/components/schemas/AlwaysConfirm-Input"},{"$ref":"#/components/schemas/ConfirmRisky-Input"},{"$ref":"#/components/schemas/NeverConfirm-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__confirmation_policy__AlwaysConfirm-Input__1":"#/components/schemas/AlwaysConfirm-Input","openhands__sdk__security__confirmation_policy__ConfirmRisky-Input__1":"#/components/schemas/ConfirmRisky-Input","openhands__sdk__security__confirmation_policy__NeverConfirm-Input__1":"#/components/schemas/NeverConfirm-Input"}}},"ConfirmationPolicyBase-Output":{"oneOf":[{"$ref":"#/components/schemas/AlwaysConfirm-Output"},{"$ref":"#/components/schemas/ConfirmRisky-Output"},{"$ref":"#/components/schemas/NeverConfirm-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__confirmation_policy__AlwaysConfirm-Output__1":"#/components/schemas/AlwaysConfirm-Output","openhands__sdk__security__confirmation_policy__ConfirmRisky-Output__1":"#/components/schemas/ConfirmRisky-Output","openhands__sdk__security__confirmation_policy__NeverConfirm-Output__1":"#/components/schemas/NeverConfirm-Output"}}},"ConfirmationResponseRequest":{"properties":{"accept":{"type":"boolean","title":"Accept"},"reason":{"type":"string","title":"Reason","default":"User rejected the action."}},"type":"object","required":["accept"],"title":"ConfirmationResponseRequest","description":"Payload to accept or reject a pending action."},"ConversationErrorEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","description":"The source of this event"},"code":{"type":"string","title":"Code","description":"Code for the error - typically a type"},"detail":{"type":"string","title":"Detail","description":"Details about the error"},"kind":{"type":"string","const":"ConversationErrorEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","code","detail","kind"],"title":"ConversationErrorEvent","description":"Conversation-level failure that is NOT sent back to the LLM.\n\nThis event is emitted by the conversation runtime when an unexpected\nexception bubbles up and prevents the run loop from continuing. It is\nintended for client applications (e.g., UIs) to present a top-level error\nstate, and for orchestration to react. It is not an observation and it is\nnot LLM-convertible.\n\nDifferences from AgentErrorEvent:\n- Not tied to any tool_name/tool_call_id (AgentErrorEvent is a tool\n observation).\n- Typically source='environment' and the run loop moves to an ERROR state,\n while AgentErrorEvent has source='agent' and the conversation can\n continue."},"ConversationExecutionStatus":{"type":"string","enum":["idle","running","paused","waiting_for_confirmation","finished","error","stuck","deleting"],"title":"ConversationExecutionStatus","description":"Enum representing the current execution state of the conversation."},"ConversationInfo":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique conversation ID"},"workspace":{"$ref":"#/components/schemas/BaseWorkspace","description":"Workspace used by the agent to execute commands and read/write files. Not the process working directory."},"persistence_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Persistence Dir","description":"Directory for persisting conversation state and events. If None, conversation will not be persisted.","default":"workspace/conversations"},"max_iterations":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Iterations","description":"Maximum number of iterations the agent can perform in a single run.","default":500},"stuck_detection":{"type":"boolean","title":"Stuck Detection","description":"Whether to enable stuck detection for the agent.","default":true},"execution_status":{"$ref":"#/components/schemas/ConversationExecutionStatus","default":"idle"},"confirmation_policy":{"$ref":"#/components/schemas/ConfirmationPolicyBase-Output","default":{"kind":"NeverConfirm"}},"security_analyzer":{"anyOf":[{"$ref":"#/components/schemas/SecurityAnalyzerBase-Output"},{"type":"null"}],"description":"Optional security analyzer to evaluate action risks."},"activated_knowledge_skills":{"items":{"type":"string"},"type":"array","title":"Activated Knowledge Skills","description":"List of activated knowledge skills name"},"invoked_skills":{"items":{"type":"string"},"type":"array","title":"Invoked Skills","description":"Names of progressive-disclosure skills explicitly invoked via the `invoke_skill` tool."},"blocked_actions":{"additionalProperties":{"type":"string"},"type":"object","title":"Blocked Actions","description":"Actions blocked by PreToolUse hooks, keyed by action ID"},"blocked_messages":{"additionalProperties":{"type":"string"},"type":"object","title":"Blocked Messages","description":"Messages blocked by UserPromptSubmit hooks, keyed by message ID"},"last_user_message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last User Message Id","description":"Most recent user MessageEvent id for hook block checks. Updated when user messages are emitted so Agent.step can pop blocked_messages without scanning the event log. If None, hook-blocked checks are skipped (legacy conversations)."},"stats":{"$ref":"#/components/schemas/ConversationStats","description":"Conversation statistics for tracking LLM metrics"},"secret_registry":{"$ref":"#/components/schemas/SecretRegistry","description":"Registry for handling secrets and sensitive data"},"agent_state":{"additionalProperties":true,"type":"object","title":"Agent State","description":"Dictionary for agent-specific runtime state that persists across iterations."},"hook_config":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Output"},{"type":"null"}],"description":"Hook configuration for this conversation. Includes definitions for PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, and Stop hooks."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"User-defined title for the conversation"},"metrics":{"anyOf":[{"$ref":"#/components/schemas/MetricsSnapshot"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"tags":{"additionalProperties":{"type":"string"},"type":"object","title":"Tags","description":"Key-value tags for the conversation. Keys must be lowercase alphanumeric. Values are arbitrary strings up to 256 characters."},"current_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Model Id","description":"Model the agent is actually using for this session. For ACP agents, this is lifted off ``ACPAgent.current_model_id`` (populated from the ``models.currentModelId`` field on the ACP session response, or from ``acp_model`` when the caller forced an override). May be an opaque alias (e.g. claude-agent-acp's ``\"default\"``); match it against ``available_models`` to get a display label. ``None`` for older ACP servers that don't surface the field, or while the agent is still initializing. Native OpenHands agents leave this ``None`` — consumers should read ``agent.llm.model`` for those."},"available_models":{"items":{"$ref":"#/components/schemas/ACPModelInfo"},"type":"array","title":"Available Models","description":"Models the ACP server offers for this session, lifted off ``ACPAgent.available_models`` (the ``models.availableModels`` field on the ACP session response). Each entry carries a ``model_id`` plus an optional ``name``/``description``. Surfaced verbatim so clients can render a model picker and resolve ``current_model_id`` to a display label themselves — the server does no name curation. Empty for ACP servers that don't surface the (UNSTABLE) capability and for native OpenHands agents. Client contract: ``current_model_id`` is NOT guaranteed to be a member — a forced ``acp_model`` override may name a model absent from the list — so treat a miss as 'show the raw id'. Some entries are opaque aliases whose human identity lives in ``description`` (e.g. claude-agent-acp's ``\"default\"`` -> ``\"Opus 4.7 with 1M context · ...\"``)."},"supports_runtime_model_switch":{"type":"boolean","title":"Supports Runtime Model Switch","description":"Whether a live, mid-conversation model switch will be attempted for this conversation — tells the inline picker whether to offer a live-switch control. Mirrors the SDK's switch gate: ``True`` for known switch-capable providers; ``False`` for unknown/custom ACP servers because their generic config writes are not guaranteed live-switch primitives. ``False`` for native OpenHands agents, for a known provider that declares no support, and before the conversation has started a session.","default":false},"launched_agent_profile":{"anyOf":[{"$ref":"#/components/schemas/LaunchedAgentProfile"},{"type":"null"}],"description":"Provenance snapshot of the agent profile that launched this conversation. Set at creation when the conversation was started via ``agent_profile_id``; ``None`` for conversations started directly with ``agent`` or ``agent_settings``. Clients use this to identify which agent profile is current without fragile settings-comparison."},"agent":{"$ref":"#/components/schemas/AgentBase-Output","description":"The agent running in the conversation."},"client_tools":{"items":{"$ref":"#/components/schemas/ClientToolSpec-Output"},"type":"array","title":"Client Tools","description":"Client-defined tool specs registered for this conversation. Surfaced so that a client re-attaching by conversation id can register the dynamic ClientAction_* action types before syncing persisted events, avoiding 'Unknown kind' deserialization errors."}},"type":"object","required":["id","workspace","agent"],"title":"ConversationInfo","description":"Information about a conversation running locally without a Runtime sandbox."},"ConversationPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ConversationInfo"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"ConversationPage"},"ConversationSortOrder":{"type":"string","enum":["CREATED_AT","UPDATED_AT","CREATED_AT_DESC","UPDATED_AT_DESC"],"title":"ConversationSortOrder","description":"Enum for conversation sorting options."},"ConversationStateUpdateEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"key":{"type":"string","title":"Key","description":"Unique key for this state update event"},"value":{"title":"Value","description":"Serialized conversation state updates"},"kind":{"type":"string","const":"ConversationStateUpdateEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ConversationStateUpdateEvent","description":"Event that contains conversation state updates.\n\nThis event is sent via websocket whenever the conversation state changes,\nallowing remote clients to stay in sync without making REST API calls.\n\nAll fields are serialized versions of the corresponding ConversationState fields\nto ensure compatibility with websocket transmission."},"ConversationStats":{"additionalProperties":true,"type":"object"},"Cost":{"properties":{"model":{"type":"string","title":"Model"},"cost":{"type":"number","minimum":0.0,"title":"Cost","description":"Cost must be non-negative"},"timestamp":{"type":"number","title":"Timestamp"}},"type":"object","required":["model","cost"],"title":"Cost"},"CriticBase-Input":{"oneOf":[{"$ref":"#/components/schemas/AgentFinishedCritic-Input"},{"$ref":"#/components/schemas/APIBasedCritic-Input"},{"$ref":"#/components/schemas/EmptyPatchCritic-Input"},{"$ref":"#/components/schemas/PassCritic-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__critic__impl__agent_finished__AgentFinishedCritic-Input__1":"#/components/schemas/AgentFinishedCritic-Input","openhands__sdk__critic__impl__api__critic__APIBasedCritic-Input__1":"#/components/schemas/APIBasedCritic-Input","openhands__sdk__critic__impl__empty_patch__EmptyPatchCritic-Input__1":"#/components/schemas/EmptyPatchCritic-Input","openhands__sdk__critic__impl__pass_critic__PassCritic-Input__1":"#/components/schemas/PassCritic-Input"}}},"CriticBase-Output":{"oneOf":[{"$ref":"#/components/schemas/AgentFinishedCritic-Output"},{"$ref":"#/components/schemas/APIBasedCritic-Output"},{"$ref":"#/components/schemas/EmptyPatchCritic-Output"},{"$ref":"#/components/schemas/PassCritic-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__critic__impl__agent_finished__AgentFinishedCritic-Output__1":"#/components/schemas/AgentFinishedCritic-Output","openhands__sdk__critic__impl__api__critic__APIBasedCritic-Output__1":"#/components/schemas/APIBasedCritic-Output","openhands__sdk__critic__impl__empty_patch__EmptyPatchCritic-Output__1":"#/components/schemas/EmptyPatchCritic-Output","openhands__sdk__critic__impl__pass_critic__PassCritic-Output__1":"#/components/schemas/PassCritic-Output"}}},"CriticResult":{"properties":{"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score","description":"A predicted probability of success between 0 and 1."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"An optional message explaining the score."},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata","description":"Optional metadata about the critic evaluation. Can include event_ids and categorized_features for visualization."}},"type":"object","required":["score","message"],"title":"CriticResult","description":"A critic result is a score and a message."},"Custom":{"properties":{"input":{"type":"string","title":"Input"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["input","name"],"title":"Custom","description":"The custom tool that the model called."},"DelegateAction":{"properties":{"command":{"type":"string","enum":["spawn","delegate"],"title":"Command","description":"The commands to run. Allowed options are: `spawn`, `delegate`."},"ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Ids","description":"Required parameter of `spawn` command. List of identifiers to initialize sub-agents with."},"agent_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Agent Types","description":"Optional parameter of `spawn` command. List of agent types for each ID (e.g., ['researcher', 'programmer']). If omitted or blank for an ID, the default general-purpose agent is used."},"tasks":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tasks","description":"Required parameter of `delegate` command. Dictionary mapping sub-agent identifiers to task descriptions."},"kind":{"type":"string","const":"DelegateAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"DelegateAction","description":"Schema for delegation operations."},"DelegateActionWithRisk":{"properties":{"command":{"type":"string","enum":["spawn","delegate"],"title":"Command","description":"The commands to run. Allowed options are: `spawn`, `delegate`."},"ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Ids","description":"Required parameter of `spawn` command. List of identifiers to initialize sub-agents with."},"agent_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Agent Types","description":"Optional parameter of `spawn` command. List of agent types for each ID (e.g., ['researcher', 'programmer']). If omitted or blank for an ID, the default general-purpose agent is used."},"tasks":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tasks","description":"Required parameter of `delegate` command. Dictionary mapping sub-agent identifiers to task descriptions."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"DelegateActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"DelegateActionWithRisk"},"DelegateObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["spawn","delegate"],"title":"Command","description":"The command that was executed"},"kind":{"type":"string","const":"DelegateObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"DelegateObservation","description":"Observation from delegation operations."},"DeleteResponse":{"properties":{"deleted":{"type":"boolean","title":"Deleted","default":true}},"type":"object","title":"DeleteResponse"},"DesktopUrlResponse":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"}},"type":"object","required":["url"],"title":"DesktopUrlResponse","description":"Response model for Desktop URL."},"EditAction":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to modify."},"old_string":{"type":"string","title":"Old String","description":"The text to replace. To create a new file, use an empty string. Must match the exact text in the file including whitespace."},"new_string":{"type":"string","title":"New String","description":"The text to replace it with."},"expected_replacements":{"type":"integer","minimum":0.0,"title":"Expected Replacements","description":"Number of replacements expected. Defaults to 1. Use when you want to replace multiple occurrences. The edit will fail if the actual count doesn't match.","default":1},"kind":{"type":"string","const":"EditAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","old_string","new_string","kind"],"title":"EditAction","description":"Schema for edit operation."},"EditActionWithRisk":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to modify."},"old_string":{"type":"string","title":"Old String","description":"The text to replace. To create a new file, use an empty string. Must match the exact text in the file including whitespace."},"new_string":{"type":"string","title":"New String","description":"The text to replace it with."},"expected_replacements":{"type":"integer","minimum":0.0,"title":"Expected Replacements","description":"Number of replacements expected. Defaults to 1. Use when you want to replace multiple occurrences. The edit will fail if the actual count doesn't match.","default":1},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"EditActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","old_string","new_string","kind"],"title":"EditActionWithRisk"},"EditObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path","description":"The file path that was edited."},"is_new_file":{"type":"boolean","title":"Is New File","description":"Whether a new file was created.","default":false},"replacements_made":{"type":"integer","title":"Replacements Made","description":"Number of replacements actually made.","default":0},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The content before the edit."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The content after the edit."},"kind":{"type":"string","const":"EditObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"EditObservation","description":"Observation from editing a file."},"EditTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"EditTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"EditTool","description":"Tool for editing files via find/replace."},"EmptyPatchCritic-Input":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"EmptyPatchCritic","title":"Kind"}},"type":"object","title":"EmptyPatchCritic","description":"Critic that only evaluates whether a git patch is non-empty.\n\nThis critic checks only one criterion:\n- The generated git patch is non-empty (actual changes were made)\n\nUnlike AgentFinishedCritic, this critic does not check for proper\nagent completion with FinishAction."},"EmptyPatchCritic-Output":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"EmptyPatchCritic","title":"Kind"}},"type":"object","required":["kind"],"title":"EmptyPatchCritic","description":"Critic that only evaluates whether a git patch is non-empty.\n\nThis critic checks only one criterion:\n- The generated git patch is non-empty (actual changes were made)\n\nUnlike AgentFinishedCritic, this critic does not check for proper\nagent completion with FinishAction."},"EnsembleSecurityAnalyzer-Input":{"properties":{"analyzers":{"items":{"$ref":"#/components/schemas/SecurityAnalyzerBase-Input"},"type":"array","minItems":1,"title":"Analyzers","description":"Analyzers whose assessments are combined via max-severity"},"propagate_unknown":{"type":"boolean","title":"Propagate Unknown","description":"When True, any child returning UNKNOWN causes the ensemble to return UNKNOWN. When False (default), UNKNOWN is filtered out if any child returns a concrete level.","default":false},"kind":{"type":"string","const":"EnsembleSecurityAnalyzer","title":"Kind"}},"type":"object","required":["analyzers"],"title":"EnsembleSecurityAnalyzer","description":"Wire multiple analyzers together and take the worst-case risk.\n\nUse this as the top-level analyzer you set on a conversation. It\ncalls each child analyzer, collects their risk assessments, and\nreturns the highest concrete risk. It does not perform any detection,\nextraction, or normalization of its own.\n\nHow UNKNOWN works (default, ``propagate_unknown=False``): if *all*\nchildren return UNKNOWN, the ensemble returns UNKNOWN (which\n``ConfirmRisky`` confirms by default). If any child returns a\nconcrete level, UNKNOWN results are filtered out and the highest\nconcrete level wins.\n\nWith ``propagate_unknown=True``: if *any* child returns UNKNOWN, the\nensemble returns UNKNOWN regardless of other results. Use this in\nstricter environments where incomplete assessment should trigger\nconfirmation.\n\nIf a child analyzer raises an exception, it contributes HIGH\n(fail-closed, logged). This prevents a broken analyzer from silently\ndegrading safety.\n\nExample::\n\n from openhands.sdk.security import (\n EnsembleSecurityAnalyzer,\n PatternSecurityAnalyzer,\n PolicyRailSecurityAnalyzer,\n ConfirmRisky,\n SecurityRisk,\n )\n\n analyzer = EnsembleSecurityAnalyzer(\n analyzers=[\n PolicyRailSecurityAnalyzer(),\n PatternSecurityAnalyzer(),\n ]\n )\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"EnsembleSecurityAnalyzer-Output":{"properties":{"analyzers":{"items":{"$ref":"#/components/schemas/SecurityAnalyzerBase-Output"},"type":"array","minItems":1,"title":"Analyzers","description":"Analyzers whose assessments are combined via max-severity"},"propagate_unknown":{"type":"boolean","title":"Propagate Unknown","description":"When True, any child returning UNKNOWN causes the ensemble to return UNKNOWN. When False (default), UNKNOWN is filtered out if any child returns a concrete level.","default":false},"kind":{"type":"string","const":"EnsembleSecurityAnalyzer","title":"Kind"}},"type":"object","required":["analyzers","kind"],"title":"EnsembleSecurityAnalyzer","description":"Wire multiple analyzers together and take the worst-case risk.\n\nUse this as the top-level analyzer you set on a conversation. It\ncalls each child analyzer, collects their risk assessments, and\nreturns the highest concrete risk. It does not perform any detection,\nextraction, or normalization of its own.\n\nHow UNKNOWN works (default, ``propagate_unknown=False``): if *all*\nchildren return UNKNOWN, the ensemble returns UNKNOWN (which\n``ConfirmRisky`` confirms by default). If any child returns a\nconcrete level, UNKNOWN results are filtered out and the highest\nconcrete level wins.\n\nWith ``propagate_unknown=True``: if *any* child returns UNKNOWN, the\nensemble returns UNKNOWN regardless of other results. Use this in\nstricter environments where incomplete assessment should trigger\nconfirmation.\n\nIf a child analyzer raises an exception, it contributes HIGH\n(fail-closed, logged). This prevents a broken analyzer from silently\ndegrading safety.\n\nExample::\n\n from openhands.sdk.security import (\n EnsembleSecurityAnalyzer,\n PatternSecurityAnalyzer,\n PolicyRailSecurityAnalyzer,\n ConfirmRisky,\n SecurityRisk,\n )\n\n analyzer = EnsembleSecurityAnalyzer(\n analyzers=[\n PolicyRailSecurityAnalyzer(),\n PatternSecurityAnalyzer(),\n ]\n )\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"Event":{"oneOf":[{"$ref":"#/components/schemas/ServerErrorEvent"},{"$ref":"#/components/schemas/ACPToolCallEvent"},{"$ref":"#/components/schemas/Condensation"},{"$ref":"#/components/schemas/CondensationRequest"},{"$ref":"#/components/schemas/CondensationSummaryEvent"},{"$ref":"#/components/schemas/ConversationErrorEvent"},{"$ref":"#/components/schemas/ConversationStateUpdateEvent"},{"$ref":"#/components/schemas/HookExecutionEvent"},{"$ref":"#/components/schemas/LLMCompletionLogEvent"},{"$ref":"#/components/schemas/ActionEvent"},{"$ref":"#/components/schemas/MessageEvent"},{"$ref":"#/components/schemas/AgentErrorEvent"},{"$ref":"#/components/schemas/ObservationEvent"},{"$ref":"#/components/schemas/UserRejectObservation"},{"$ref":"#/components/schemas/SystemPromptEvent"},{"$ref":"#/components/schemas/StreamingDeltaEvent"},{"$ref":"#/components/schemas/TokenEvent"},{"$ref":"#/components/schemas/InterruptEvent"},{"$ref":"#/components/schemas/PauseEvent"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__agent_server__models__ServerErrorEvent-Output__1":"#/components/schemas/ServerErrorEvent","openhands__sdk__event__acp_tool_call__ACPToolCallEvent-Output__1":"#/components/schemas/ACPToolCallEvent","openhands__sdk__event__condenser__Condensation-Output__1":"#/components/schemas/Condensation","openhands__sdk__event__condenser__CondensationRequest-Output__1":"#/components/schemas/CondensationRequest","openhands__sdk__event__condenser__CondensationSummaryEvent-Output__1":"#/components/schemas/CondensationSummaryEvent","openhands__sdk__event__conversation_error__ConversationErrorEvent-Output__1":"#/components/schemas/ConversationErrorEvent","openhands__sdk__event__conversation_state__ConversationStateUpdateEvent-Output__1":"#/components/schemas/ConversationStateUpdateEvent","openhands__sdk__event__hook_execution__HookExecutionEvent-Output__1":"#/components/schemas/HookExecutionEvent","openhands__sdk__event__llm_completion_log__LLMCompletionLogEvent-Output__1":"#/components/schemas/LLMCompletionLogEvent","openhands__sdk__event__llm_convertible__action__ActionEvent-Output__1":"#/components/schemas/ActionEvent","openhands__sdk__event__llm_convertible__message__MessageEvent-Output__1":"#/components/schemas/MessageEvent","openhands__sdk__event__llm_convertible__observation__AgentErrorEvent-Output__1":"#/components/schemas/AgentErrorEvent","openhands__sdk__event__llm_convertible__observation__ObservationEvent-Output__1":"#/components/schemas/ObservationEvent","openhands__sdk__event__llm_convertible__observation__UserRejectObservation-Output__1":"#/components/schemas/UserRejectObservation","openhands__sdk__event__llm_convertible__system__SystemPromptEvent-Output__1":"#/components/schemas/SystemPromptEvent","openhands__sdk__event__streaming_delta__StreamingDeltaEvent-Output__1":"#/components/schemas/StreamingDeltaEvent","openhands__sdk__event__token__TokenEvent-Output__1":"#/components/schemas/TokenEvent","openhands__sdk__event__user_action__InterruptEvent-Output__1":"#/components/schemas/InterruptEvent","openhands__sdk__event__user_action__PauseEvent-Output__1":"#/components/schemas/PauseEvent"}}},"EventPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Event"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"EventPage"},"EventSortOrder":{"type":"string","enum":["TIMESTAMP","TIMESTAMP_DESC"],"title":"EventSortOrder","description":"Enum for event sorting options."},"ExecuteBashRequest":{"properties":{"command":{"type":"string","title":"Command","description":"The bash command to execute"},"cwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd","description":"The current working directory"},"timeout":{"type":"integer","title":"Timeout","description":"The max number of seconds a command may be permitted to run.","default":300}},"type":"object","required":["command"],"title":"ExecuteBashRequest"},"ExposedUrl":{"properties":{"name":{"type":"string","title":"Name"},"url":{"type":"string","title":"Url"},"port":{"type":"integer","title":"Port"}},"type":"object","required":["name","url","port"],"title":"ExposedUrl","description":"Represents an exposed URL from the sandbox."},"FallbackStrategy":{"properties":{"fallback_llms":{"items":{"type":"string"},"type":"array","title":"Fallback Llms","description":"Ordered list of LLM profile names to try on transient failure."},"profile_store_dir":{"anyOf":[{"type":"string"},{"type":"string","format":"path"},{"type":"null"}],"title":"Profile Store Dir","description":"Path to directory containing profiles. If not specified, defaults to `.openhands/profiles`."}},"type":"object","required":["fallback_llms"],"title":"FallbackStrategy","description":"Encapsulates fallback behavior for LLM calls.\n\nWhen the primary LLM fails with a transient error (after retries),\nthis strategy tries alternate LLMs loaded from LLMProfileStore profiles.\nFallback is per-call: each new request starts with the primary model."},"FileBrowserEntry":{"properties":{"label":{"type":"string","title":"Label"},"path":{"type":"string","title":"Path"}},"type":"object","required":["label","path"],"title":"FileBrowserEntry"},"FileEditorAction":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"kind":{"type":"string","const":"FileEditorAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"FileEditorAction","description":"Schema for file editor operations."},"FileEditorActionWithRisk":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"FileEditorActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"FileEditorActionWithRisk"},"FileEditorObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The command that was run: `view`, `create`, `str_replace`, `insert`, or `undo_edit`."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The file path that was edited."},"prev_exist":{"type":"boolean","title":"Prev Exist","description":"Indicates if the file previously existed. If not, it was created.","default":true},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The content of the file before the edit."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The content of the file after the edit."},"kind":{"type":"string","const":"FileEditorObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"FileEditorObservation","description":"A ToolResult that can be rendered as a CLI output."},"FileEditorTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"FileEditorTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"FileEditorTool","description":"A ToolDefinition subclass that automatically initializes a FileEditorExecutor."},"FileEntry":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the file or directory"},"path":{"type":"string","title":"Path","description":"Absolute path to the file or directory"},"is_directory":{"type":"boolean","title":"Is Directory","description":"Whether this entry is a directory"},"size":{"type":"integer","title":"Size","description":"Size of the file in bytes (0 for directories)"},"modified_time":{"type":"string","format":"date-time","title":"Modified Time","description":"Last modified timestamp"}},"type":"object","required":["name","path","is_directory","size","modified_time"],"title":"FileEntry","description":"Information about a file or directory."},"FinishAction":{"properties":{"message":{"type":"string","title":"Message","description":"Final message to send to the user."},"kind":{"type":"string","const":"FinishAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["message","kind"],"title":"FinishAction"},"FinishActionWithRisk":{"properties":{"message":{"type":"string","title":"Message","description":"Final message to send to the user."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"FinishActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["message","kind"],"title":"FinishActionWithRisk"},"FinishObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"kind":{"type":"string","const":"FinishObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"FinishObservation","description":"Observation returned after finishing a task.\nThe FinishAction itself contains the message sent to the user so no\nextra fields are needed here."},"FinishTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"FinishTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"FinishTool","description":"Tool for signaling the completion of a task or conversation."},"ForkConversationRequest":{"properties":{"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id","description":"ID for the forked conversation (auto-generated if null)"},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Title","description":"Optional title for the forked conversation"},"tags":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tags","description":"Optional tags for the forked conversation. Keys must be lowercase alphanumeric."},"reset_metrics":{"type":"boolean","title":"Reset Metrics","description":"If true, cost/token stats start fresh on the fork. If false, metrics are copied from the source.","default":true}},"type":"object","title":"ForkConversationRequest","description":"Payload to fork a conversation."},"Function":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"Function","description":"The function that the model called."},"FunctionCall":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"FunctionCall","description":"Deprecated and replaced by `tool_calls`.\n\nThe name and arguments of a function that should be called, as generated by the model."},"GitChange":{"properties":{"status":{"$ref":"#/components/schemas/GitChangeStatus"},"path":{"type":"string","format":"path","title":"Path"}},"type":"object","required":["status","path"],"title":"GitChange"},"GitChangeStatus":{"type":"string","enum":["MOVED","ADDED","DELETED","UPDATED"],"title":"GitChangeStatus"},"GitDiff":{"properties":{"modified":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Modified"},"original":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original"}},"type":"object","required":["modified","original"],"title":"GitDiff"},"GlobAction":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The glob pattern to match files (e.g., \"**/*.js\", \"src/**/*.ts\")"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"kind":{"type":"string","const":"GlobAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GlobAction","description":"Schema for glob pattern matching operations."},"GlobActionWithRisk":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The glob pattern to match files (e.g., \"**/*.js\", \"src/**/*.ts\")"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"GlobActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GlobActionWithRisk"},"GlobObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"files":{"items":{"type":"string"},"type":"array","title":"Files","description":"List of matching file paths sorted by modification time"},"pattern":{"type":"string","title":"Pattern","description":"The glob pattern that was used"},"search_path":{"type":"string","title":"Search Path","description":"The directory that was searched"},"truncated":{"type":"boolean","title":"Truncated","description":"Whether results were truncated to 100 files","default":false},"kind":{"type":"string","const":"GlobObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["files","pattern","search_path","kind"],"title":"GlobObservation","description":"Observation from glob pattern matching operations."},"GlobTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"GlobTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"GlobTool","description":"A ToolDefinition subclass that automatically initializes a GlobExecutor."},"GraySwanAnalyzer-Input":{"properties":{"history_limit":{"type":"integer","title":"History Limit","description":"Number of recent events to include as context","default":20},"max_message_chars":{"type":"integer","title":"Max Message Chars","description":"Max characters for conversation processing","default":30000},"timeout":{"type":"number","title":"Timeout","description":"Request timeout in seconds","default":30.0},"low_threshold":{"type":"number","title":"Low Threshold","description":"Risk threshold for LOW classification (score <= threshold)","default":0.3},"medium_threshold":{"type":"number","title":"Medium Threshold","description":"Risk threshold for MEDIUM classification (score <= threshold)","default":0.7},"api_url":{"type":"string","title":"Api Url","description":"GraySwan Cygnal API endpoint","default":"https://api.grayswan.ai/cygnal/monitor"},"api_key":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"GraySwan API key (via GRAYSWAN_API_KEY env var)"},"policy_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy Id","description":"GraySwan policy ID (via GRAYSWAN_POLICY_ID env var)"},"kind":{"type":"string","const":"GraySwanAnalyzer","title":"Kind"}},"type":"object","title":"GraySwanAnalyzer","description":"Security analyzer using GraySwan's Cygnal API for AI safety monitoring.\n\nThis analyzer sends conversation history and pending actions to the GraySwan\nCygnal API for security analysis. The API returns a violation score which is\nmapped to SecurityRisk levels.\n\nEnvironment Variables:\n GRAYSWAN_API_KEY: Required API key for GraySwan authentication\n GRAYSWAN_POLICY_ID: Optional policy ID for custom GraySwan policy\n\nExample:\n >>> from openhands.sdk.security.grayswan import GraySwanAnalyzer\n >>> analyzer = GraySwanAnalyzer()\n >>> risk = analyzer.security_risk(action_event)"},"GraySwanAnalyzer-Output":{"properties":{"history_limit":{"type":"integer","title":"History Limit","description":"Number of recent events to include as context","default":20},"max_message_chars":{"type":"integer","title":"Max Message Chars","description":"Max characters for conversation processing","default":30000},"timeout":{"type":"number","title":"Timeout","description":"Request timeout in seconds","default":30.0},"low_threshold":{"type":"number","title":"Low Threshold","description":"Risk threshold for LOW classification (score <= threshold)","default":0.3},"medium_threshold":{"type":"number","title":"Medium Threshold","description":"Risk threshold for MEDIUM classification (score <= threshold)","default":0.7},"api_url":{"type":"string","title":"Api Url","description":"GraySwan Cygnal API endpoint","default":"https://api.grayswan.ai/cygnal/monitor"},"api_key":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"GraySwan API key (via GRAYSWAN_API_KEY env var)"},"policy_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy Id","description":"GraySwan policy ID (via GRAYSWAN_POLICY_ID env var)"},"kind":{"type":"string","const":"GraySwanAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"GraySwanAnalyzer","description":"Security analyzer using GraySwan's Cygnal API for AI safety monitoring.\n\nThis analyzer sends conversation history and pending actions to the GraySwan\nCygnal API for security analysis. The API returns a violation score which is\nmapped to SecurityRisk levels.\n\nEnvironment Variables:\n GRAYSWAN_API_KEY: Required API key for GraySwan authentication\n GRAYSWAN_POLICY_ID: Optional policy ID for custom GraySwan policy\n\nExample:\n >>> from openhands.sdk.security.grayswan import GraySwanAnalyzer\n >>> analyzer = GraySwanAnalyzer()\n >>> risk = analyzer.security_risk(action_event)"},"GrepAction":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The regex pattern to search for in file contents"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"include":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include","description":"Optional file pattern to filter which files to search (e.g., \"*.js\", \"*.{ts,tsx}\")"},"kind":{"type":"string","const":"GrepAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GrepAction","description":"Schema for grep content search operations."},"GrepActionWithRisk":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The regex pattern to search for in file contents"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"include":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include","description":"Optional file pattern to filter which files to search (e.g., \"*.js\", \"*.{ts,tsx}\")"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"GrepActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GrepActionWithRisk"},"GrepObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"matches":{"items":{"type":"string"},"type":"array","title":"Matches","description":"List of file paths containing the pattern"},"pattern":{"type":"string","title":"Pattern","description":"The regex pattern that was used"},"search_path":{"type":"string","title":"Search Path","description":"The directory that was searched"},"include_pattern":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include Pattern","description":"The file pattern filter that was used"},"truncated":{"type":"boolean","title":"Truncated","description":"Whether results were truncated to 100 files","default":false},"kind":{"type":"string","const":"GrepObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["matches","pattern","search_path","kind"],"title":"GrepObservation","description":"Observation from grep content search operations."},"GrepTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"GrepTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"GrepTool","description":"A ToolDefinition subclass that automatically initializes a GrepExecutor."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthStatus":{"properties":{"status":{"type":"string","title":"Status"}},"type":"object","required":["status"],"title":"HealthStatus"},"HomeResponse":{"properties":{"home":{"type":"string","title":"Home"},"favorites":{"items":{"$ref":"#/components/schemas/FileBrowserEntry"},"type":"array","title":"Favorites","default":[]},"locations":{"items":{"$ref":"#/components/schemas/FileBrowserEntry"},"type":"array","title":"Locations","default":[]}},"type":"object","required":["home"],"title":"HomeResponse"},"HookConfig-Input":{"properties":{"pre_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Pre Tool Use","description":"Hooks that run before tool execution"},"post_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Post Tool Use","description":"Hooks that run after tool execution"},"user_prompt_submit":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"User Prompt Submit","description":"Hooks that run when user submits a prompt"},"session_start":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Session Start","description":"Hooks that run when a session starts"},"session_end":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Session End","description":"Hooks that run when a session ends"},"stop":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Stop","description":"Hooks that run when the agent attempts to stop"}},"additionalProperties":false,"type":"object","title":"HookConfig","description":"Configuration for all hooks.\n\nHooks can be configured either by loading from `.openhands/hooks.json` or\nby directly instantiating with typed fields:\n\n # Direct instantiation with typed fields (recommended):\n config = HookConfig(\n pre_tool_use=[\n HookMatcher(\n matcher=\"terminal\",\n hooks=[HookDefinition(command=\"block_dangerous.sh\")]\n )\n ]\n )\n\n # Load from JSON file:\n config = HookConfig.load(\".openhands/hooks.json\")"},"HookConfig-Output":{"properties":{"pre_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Pre Tool Use","description":"Hooks that run before tool execution"},"post_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Post Tool Use","description":"Hooks that run after tool execution"},"user_prompt_submit":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"User Prompt Submit","description":"Hooks that run when user submits a prompt"},"session_start":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Session Start","description":"Hooks that run when a session starts"},"session_end":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Session End","description":"Hooks that run when a session ends"},"stop":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Stop","description":"Hooks that run when the agent attempts to stop"}},"additionalProperties":false,"type":"object","title":"HookConfig","description":"Configuration for all hooks.\n\nHooks can be configured either by loading from `.openhands/hooks.json` or\nby directly instantiating with typed fields:\n\n # Direct instantiation with typed fields (recommended):\n config = HookConfig(\n pre_tool_use=[\n HookMatcher(\n matcher=\"terminal\",\n hooks=[HookDefinition(command=\"block_dangerous.sh\")]\n )\n ]\n )\n\n # Load from JSON file:\n config = HookConfig.load(\".openhands/hooks.json\")"},"HookDefinition":{"properties":{"type":{"$ref":"#/components/schemas/HookType","default":"command"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"command":{"type":"string","title":"Command"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt"},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"tools":{"items":{"type":"string"},"type":"array","title":"Tools"},"timeout":{"type":"integer","title":"Timeout","default":60},"max_iterations":{"type":"integer","title":"Max Iterations","default":3},"async":{"type":"boolean","title":"Async","default":false}},"type":"object","required":["command"],"title":"HookDefinition","description":"A single hook definition."},"HookExecutionEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","description":"Source is always 'hook' for hook execution events","default":"hook"},"hook_event_type":{"type":"string","enum":["PreToolUse","PostToolUse","UserPromptSubmit","SessionStart","SessionEnd","Stop"],"title":"Hook Event Type","description":"The type of hook event that triggered this execution"},"hook_command":{"type":"string","title":"Hook Command","description":"The hook command that was executed"},"tool_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Name","description":"Tool name for PreToolUse/PostToolUse hooks"},"success":{"type":"boolean","title":"Success","description":"Whether the hook executed successfully"},"blocked":{"type":"boolean","title":"Blocked","description":"Whether the hook blocked the operation (exit code 2 or deny)","default":false},"exit_code":{"type":"integer","title":"Exit Code","description":"Exit code from the hook command"},"stdout":{"type":"string","title":"Stdout","description":"Standard output from the hook","default":""},"stderr":{"type":"string","title":"Stderr","description":"Standard error from the hook","default":""},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Reason provided by hook (for blocking)"},"additional_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Additional Context","description":"Additional context injected by hook (e.g., for UserPromptSubmit)"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if hook execution failed"},"action_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action Id","description":"ID of the action this hook is associated with (PreToolUse/PostToolUse)"},"message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message Id","description":"ID of the message this hook is associated with (UserPromptSubmit)"},"hook_input":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Hook Input","description":"The input data that was passed to the hook"},"kind":{"type":"string","const":"HookExecutionEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["hook_event_type","hook_command","success","exit_code","kind"],"title":"HookExecutionEvent","description":"Event emitted when a hook is executed.\n\nThis event provides observability into hook execution, including:\n- Which hook type was triggered\n- The command that was run\n- The result (success/blocked/error)\n- Any output from the hook\n\nThis allows clients to track hook execution via the event stream."},"HookMatcher-Input":{"properties":{"matcher":{"type":"string","title":"Matcher","default":"*"},"hooks":{"items":{"$ref":"#/components/schemas/HookDefinition"},"type":"array","title":"Hooks"}},"type":"object","title":"HookMatcher","description":"Matches events to hooks based on patterns.\n\nSupports exact match, wildcard (*), and regex (auto-detected or /pattern/)."},"HookMatcher-Output":{"properties":{"matcher":{"type":"string","title":"Matcher","default":"*"},"hooks":{"items":{"$ref":"#/components/schemas/HookDefinition"},"type":"array","title":"Hooks"}},"type":"object","title":"HookMatcher","description":"Matches events to hooks based on patterns.\n\nSupports exact match, wildcard (*), and regex (auto-detected or /pattern/)."},"HookType":{"type":"string","enum":["command","prompt","agent"],"title":"HookType","description":"Types of hooks that can be executed."},"HooksRequest":{"properties":{"project_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Dir","description":"Workspace directory path for project hooks"}},"type":"object","title":"HooksRequest","description":"Request body for loading hooks."},"HooksResponse":{"properties":{"hook_config":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Output"},{"type":"null"}],"description":"Hook configuration loaded from the workspace, or None if not found"}},"type":"object","title":"HooksResponse","description":"Response containing hooks configuration."},"Icon":{"properties":{"src":{"type":"string","title":"Src"},"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"sizes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sizes"}},"additionalProperties":true,"type":"object","required":["src"],"title":"Icon","description":"An icon for display in user interfaces."},"ImageContent":{"properties":{"cache_prompt":{"type":"boolean","title":"Cache Prompt","default":false},"type":{"type":"string","const":"image","title":"Type","default":"image"},"image_urls":{"items":{"type":"string"},"type":"array","title":"Image Urls"}},"type":"object","required":["image_urls"],"title":"ImageContent"},"InitRequest":{"properties":{"session_api_keys":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Session Api Keys","description":"Per-user session API keys. If provided, all subsequent /api/* requests must authenticate with one of these keys via the X-Session-API-Key header."},"secret_key":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Secret Key","description":"Symmetric secret used to encrypt persisted secrets. If not provided, falls back to the first session_api_key (matching the default Config behavior)."},"conversations_path":{"anyOf":[{"type":"string","format":"path"},{"type":"null"}],"title":"Conversations Path","description":"Directory where conversations are persisted. Override this to point at the mounted user workspace."},"bash_events_dir":{"anyOf":[{"type":"string","format":"path"},{"type":"null"}],"title":"Bash Events Dir","description":"Directory where bash events are persisted. Typically located inside the mounted user workspace."},"webhooks":{"anyOf":[{"items":{"$ref":"#/components/schemas/WebhookSpec"},"type":"array"},{"type":"null"}],"title":"Webhooks","description":"Per-user webhooks (e.g. for streaming events back)."},"web_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Web Url","description":"External URL where this server is reachable, used for root-path calculation. Only honored when not already set in dormant config."},"allow_cors_origins":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allow Cors Origins","description":"CORS origins to add to the existing localhost allowlist."},"max_concurrent_runs":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Concurrent Runs","description":"Override the conversation-step concurrency limit."},"env":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Env","description":"Process environment variables to set before conversation services start. Useful for credentials consumed by tools (e.g. GITHUB_TOKEN). These are applied with ``os.environ.update``; existing values are overwritten."}},"additionalProperties":false,"type":"object","title":"InitRequest","description":"Runtime configuration delivered at /api/init time.\n\nEach field is optional and overrides the equivalent field on the dormant\n``Config``. Fields not provided keep the value the server was constructed\nwith (typically from env vars at pod startup). The set of overridable\nfields is intentionally narrow — it covers the values that today are\n\"env-var shaped\" and must change per-user, not image-build-time\nconfiguration (Python deps, plugin set, etc.) which stays bound to the\nwarm-pool flavor."},"InitStatus":{"properties":{"state":{"type":"string","enum":["dormant","initializing","ready"],"title":"State","description":"``dormant`` — server is up but waiting for /api/init. ``initializing`` — /api/init has been received and services are starting. ``ready`` — initialization complete; all /api/* routes are live."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"If a previous /api/init attempt failed, the error message. The state rolls back to ``dormant`` so /api/init can be retried."}},"type":"object","required":["state"],"title":"InitStatus"},"InputMetadata":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the input parameter"},"description":{"type":"string","title":"Description","description":"Description of the input parameter"}},"type":"object","required":["name","description"],"title":"InputMetadata","description":"Metadata for task skill inputs."},"InstallSkillRequest":{"properties":{"source":{"type":"string","minLength":1,"title":"Source","description":"Skill source - git URL, GitHub shorthand, or local path. Examples: 'https://github.com/OpenHands/extensions/tree/main/skills/github', 'github:OpenHands/extensions/skills/github', '/path/to/skill'"},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref","description":"Optional branch, tag, or commit to install"},"repo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Path","description":"Subdirectory path within the repository (for monorepos)"},"force":{"type":"boolean","title":"Force","description":"If true, overwrite existing installation","default":false}},"type":"object","required":["source"],"title":"InstallSkillRequest","description":"Request body for installing a skill."},"InstalledSkillResponse":{"properties":{"name":{"type":"string","title":"Name","description":"Skill name"},"version":{"type":"string","title":"Version","description":"Skill version","default":""},"description":{"type":"string","title":"Description","description":"Skill description","default":""},"enabled":{"type":"boolean","title":"Enabled","description":"Whether the skill is enabled","default":true},"source":{"type":"string","title":"Source","description":"Original source (e.g., 'github:owner/repo')"},"resolved_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved Ref","description":"Resolved git commit SHA"},"repo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Path","description":"Subdirectory path within the repository"},"installed_at":{"type":"string","title":"Installed At","description":"ISO 8601 timestamp of installation"},"install_path":{"type":"string","title":"Install Path","description":"Path where the skill is installed"}},"type":"object","required":["name","source","installed_at","install_path"],"title":"InstalledSkillResponse","description":"Response containing installed skill information."},"InstalledSkillsListResponse":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/InstalledSkillResponse"},"type":"array","title":"Skills"}},"type":"object","required":["skills"],"title":"InstalledSkillsListResponse","description":"Response containing list of installed skills."},"InterruptEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"user"},"kind":{"type":"string","const":"InterruptEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"InterruptEvent","description":"Event indicating the agent was interrupted mid-operation.\n\nUnlike :class:`PauseEvent` which takes effect between agent steps,\nan interrupt cancels the in-flight LLM call immediately. The\nconversation state is set to PAUSED so it can be resumed later."},"InvokeSkillAction":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the loaded skill to invoke."},"kind":{"type":"string","const":"InvokeSkillAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","kind"],"title":"InvokeSkillAction"},"InvokeSkillActionWithRisk":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the loaded skill to invoke."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"InvokeSkillActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","kind"],"title":"InvokeSkillActionWithRisk"},"InvokeSkillObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"skill_name":{"type":"string","title":"Skill Name","description":"Name of the skill this observation corresponds to."},"kind":{"type":"string","const":"InvokeSkillObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["skill_name","kind"],"title":"InvokeSkillObservation"},"InvokeSkillTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"InvokeSkillTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"InvokeSkillTool","description":"Built-in tool for explicit invocation of progressive-disclosure skills."},"IterativeRefinementConfig":{"properties":{"success_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Success Threshold","description":"Score threshold (0-1) to consider task successful.","default":0.6},"max_iterations":{"type":"integer","minimum":1.0,"title":"Max Iterations","description":"Maximum number of iterations before giving up.","default":3}},"type":"object","title":"IterativeRefinementConfig","description":"Configuration for iterative refinement based on critic feedback.\n\nWhen attached to a CriticBase, the Conversation.run() method will\nautomatically retry the task if the critic score is below the threshold.\n\nExample:\n critic = APIBasedCritic(\n server_url=\"...\",\n api_key=\"...\",\n model_name=\"critic\",\n iterative_refinement=IterativeRefinementConfig(\n success_threshold=0.7,\n max_iterations=3,\n ),\n )\n agent = Agent(llm=llm, tools=tools, critic=critic)\n conversation = Conversation(agent=agent, workspace=workspace)\n conversation.send_message(\"Create a calculator module...\")\n conversation.run() # Will automatically retry if critic score < 0.7"},"KeywordTrigger":{"properties":{"type":{"type":"string","const":"keyword","title":"Type","default":"keyword"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"}},"type":"object","required":["keywords"],"title":"KeywordTrigger","description":"Trigger for keyword-based skills.\n\nThese skills are activated when specific keywords appear in the user's query."},"LLM-Input":{"properties":{"model":{"type":"string","title":"Model","description":"Model name.","default":"gpt-5.5","openhands_settings":{"depends_on":[],"prominence":"critical"}},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"API key.","openhands_settings":{"depends_on":[],"label":"API Key","prominence":"critical"}},"auth_type":{"type":"string","enum":["api_key","subscription"],"title":"Auth Type","description":"Authentication mode for the LLM.","default":"api_key","openhands_settings":{"depends_on":[],"label":"Authentication","prominence":"critical"}},"subscription_vendor":{"anyOf":[{"type":"string","const":"openai"},{"type":"null"}],"title":"Subscription Vendor","description":"Subscription provider for subscription-backed LLM access.","openhands_settings":{"depends_on":["auth_type"],"label":"Subscription provider","prominence":"critical"}},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"Custom base URL.","openhands_settings":{"depends_on":[],"prominence":"major"}},"api_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Version","description":"API version (e.g., Azure)."},"aws_access_key_id":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Access Key Id"},"aws_secret_access_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Secret Access Key"},"aws_session_token":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Session Token"},"aws_region_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Region Name"},"aws_profile_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Profile Name"},"aws_role_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Role Name"},"aws_session_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Session Name"},"aws_bedrock_runtime_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Bedrock Runtime Endpoint"},"openrouter_site_url":{"type":"string","title":"Openrouter Site Url","default":"https://docs.all-hands.dev/"},"openrouter_app_name":{"type":"string","title":"Openrouter App Name","default":"OpenHands"},"num_retries":{"type":"integer","minimum":0.0,"title":"Num Retries","default":5},"retry_multiplier":{"type":"number","minimum":0.0,"title":"Retry Multiplier","default":8.0},"retry_min_wait":{"type":"integer","minimum":0.0,"title":"Retry Min Wait","default":8},"retry_max_wait":{"type":"integer","minimum":0.0,"title":"Retry Max Wait","default":64},"timeout":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"HTTP timeout in seconds. Default is 300s (5 minutes). Set to None to disable timeout (not recommended for production).","default":300},"max_message_chars":{"type":"integer","minimum":1.0,"title":"Max Message Chars","description":"Approx max chars in each event/content sent to the LLM.","default":30000},"temperature":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Temperature","description":"Sampling temperature for response generation. Defaults to None (uses provider default temperature). Set to 0.0 for deterministic outputs, or higher values (0.7-1.0) for more creative responses."},"top_p":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Top P","description":"Nucleus sampling parameter. Defaults to None (uses provider default). Set to a value between 0 and 1 to control diversity of outputs."},"top_k":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Top K"},"max_input_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Input Tokens","description":"The maximum number of input tokens. Note that this is currently unused, and the value at runtime is actually the total tokens in OpenAI (e.g. 128,000 tokens for GPT-4)."},"max_output_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Output Tokens","description":"The maximum number of output tokens. This is sent to the LLM."},"model_canonical_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Canonical Name","description":"Optional canonical model name for feature registry lookups. The OpenHands SDK maintains a model feature registry that maps model names to capabilities (e.g., vision support, prompt caching, responses API support). When using proxied or aliased model identifiers, set this field to the canonical model name (e.g., 'openai/gpt-4o') to ensure correct capability detection. If not provided, the 'model' field will be used for capability lookups."},"extra_headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Extra Headers","description":"Optional HTTP headers to forward to LiteLLM requests."},"input_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Input Cost Per Token","description":"The cost per input token. This will available in logs for user."},"output_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Output Cost Per Token","description":"The cost per output token. This will available in logs for user."},"ollama_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ollama Base Url"},"stream":{"type":"boolean","title":"Stream","description":"Enable streaming responses from the LLM. When enabled, the provided `on_token` callback in .completions and .responses will be invoked for each chunk of tokens.","default":false},"drop_params":{"type":"boolean","title":"Drop Params","default":true},"modify_params":{"type":"boolean","title":"Modify Params","description":"Modify params allows litellm to do transformations like adding a default message, when a message is empty.","default":true},"disable_vision":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Vision","description":"If model is vision capable, this option allows to disable image processing (useful for cost reduction)."},"disable_stop_word":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Stop Word","description":"Disable using of stop word.","default":false},"caching_prompt":{"type":"boolean","title":"Caching Prompt","description":"Enable caching of prompts.","default":true},"log_completions":{"type":"boolean","title":"Log Completions","description":"Enable logging of completions.","default":false},"log_completions_folder":{"type":"string","title":"Log Completions Folder","description":"The folder to log LLM completions to. Required if log_completions is True.","default":"logs/completions"},"custom_tokenizer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Tokenizer","description":"A custom tokenizer to use for token counting."},"native_tool_calling":{"type":"boolean","title":"Native Tool Calling","description":"Whether to use native tool calling.","default":true},"force_string_serializer":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force String Serializer","description":"Force using string content serializer when sending to LLM API. If None (default), auto-detect based on model. Useful for providers that do not support list content, like HuggingFace and Groq."},"inline_image_urls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Inline Image Urls","description":"If True, fetch any http(s) image URL in outgoing messages and inline it as a base64 ``data:`` URL before sending. If None (default), auto-detect based on model (some APIs such as Moonshot's public Kimi endpoint reject URL-formatted images and require base64). Set this explicitly when the model is reached through a proxy alias that hides the underlying provider (e.g. ``litellm_proxy/``). Note: inlining only runs when ``vision_is_active()`` is True, so the alias must still be recognised as vision-capable by litellm — otherwise images are not sent at all and there is nothing to inline."},"reasoning_effort":{"anyOf":[{"type":"string","enum":["low","medium","high","xhigh","none"]},{"type":"null"}],"title":"Reasoning Effort","description":"The effort to put into reasoning. This is a string that can be one of 'low', 'medium', 'high', 'xhigh', or 'none'. Can apply to all reasoning models.","default":"high"},"reasoning_summary":{"anyOf":[{"type":"string","enum":["auto","concise","detailed"]},{"type":"null"}],"title":"Reasoning Summary","description":"The level of detail for reasoning summaries. This is a string that can be one of 'auto', 'concise', or 'detailed'. Requires verified OpenAI organization. Only sent when explicitly set."},"enable_encrypted_reasoning":{"type":"boolean","title":"Enable Encrypted Reasoning","description":"If True, ask for ['reasoning.encrypted_content'] in Responses API include.","default":true},"prompt_cache_retention":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Cache Retention","description":"Retention policy for prompt cache. Only sent for supported models (GPT-5+ and GPT-4.1, excluding Azure deployments); explicitly stripped for all others.","default":"24h"},"extended_thinking_budget":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Extended Thinking Budget","description":"The budget tokens for extended thinking, supported by Anthropic models.","default":200000},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"The seed to use for random number generation."},"usage_id":{"type":"string","title":"Usage Id","description":"Unique usage identifier for the LLM. Used for registry lookups, telemetry, and spend tracking.","default":"default"},"litellm_extra_body":{"additionalProperties":true,"type":"object","title":"Litellm Extra Body","description":"Additional key-value pairs to pass to litellm's extra_body parameter. This is useful for custom inference endpoints that need additional parameters for configuration, routing, or advanced features. NOTE: Not all LLM providers support extra_body parameters. Some providers (e.g., OpenAI) may reject requests with unrecognized options. This is commonly supported by: - LiteLLM proxy servers (routing metadata, tracing) - vLLM endpoints (return_token_ids, etc.) - Custom inference clusters Examples: - Proxy routing: {'trace_version': '1.0.0', 'tags': ['agent:my-agent']} - vLLM features: {'return_token_ids': True}"},"fallback_strategy":{"anyOf":[{"$ref":"#/components/schemas/FallbackStrategy"},{"type":"null"}],"description":"Optional fallback strategy for trying alternate LLMs on transient failure. Construct with FallbackStrategy(fallback_llms=[...]).Excluded from serialization; must be reconfigured after load."}},"type":"object","title":"LLM","description":"Language model interface for OpenHands agents.\n\nThe LLM class provides a unified interface for interacting with various\nlanguage models through the litellm library. It handles model configuration,\nAPI authentication, retry logic, and tool calling capabilities.\n\nAttributes:\n model: Model name (e.g., \"gpt-5.5\").\n api_key: API key for authentication.\n base_url: Custom API base URL.\n num_retries: Number of retry attempts for failed requests.\n timeout: Request timeout in seconds.\n\nExample:\n ```python\n from openhands.sdk import LLM\n from pydantic import SecretStr\n\n llm = LLM(\n model=\"gpt-5.5\",\n api_key=SecretStr(\"your-api-key\"),\n usage_id=\"my-agent\"\n )\n # Use with agent or conversation\n ```"},"LLM-Output":{"properties":{"model":{"type":"string","title":"Model","description":"Model name.","default":"gpt-5.5","openhands_settings":{"depends_on":[],"prominence":"critical"}},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"API key.","openhands_settings":{"depends_on":[],"label":"API Key","prominence":"critical"}},"auth_type":{"type":"string","enum":["api_key","subscription"],"title":"Auth Type","description":"Authentication mode for the LLM.","default":"api_key","openhands_settings":{"depends_on":[],"label":"Authentication","prominence":"critical"}},"subscription_vendor":{"anyOf":[{"type":"string","const":"openai"},{"type":"null"}],"title":"Subscription Vendor","description":"Subscription provider for subscription-backed LLM access.","openhands_settings":{"depends_on":["auth_type"],"label":"Subscription provider","prominence":"critical"}},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"Custom base URL.","openhands_settings":{"depends_on":[],"prominence":"major"}},"api_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Version","description":"API version (e.g., Azure)."},"aws_access_key_id":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Access Key Id"},"aws_secret_access_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Secret Access Key"},"aws_session_token":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Session Token"},"aws_region_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Region Name"},"aws_profile_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Profile Name"},"aws_role_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Role Name"},"aws_session_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Session Name"},"aws_bedrock_runtime_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Bedrock Runtime Endpoint"},"openrouter_site_url":{"type":"string","title":"Openrouter Site Url","default":"https://docs.all-hands.dev/"},"openrouter_app_name":{"type":"string","title":"Openrouter App Name","default":"OpenHands"},"num_retries":{"type":"integer","minimum":0.0,"title":"Num Retries","default":5},"retry_multiplier":{"type":"number","minimum":0.0,"title":"Retry Multiplier","default":8.0},"retry_min_wait":{"type":"integer","minimum":0.0,"title":"Retry Min Wait","default":8},"retry_max_wait":{"type":"integer","minimum":0.0,"title":"Retry Max Wait","default":64},"timeout":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"HTTP timeout in seconds. Default is 300s (5 minutes). Set to None to disable timeout (not recommended for production).","default":300},"max_message_chars":{"type":"integer","minimum":1.0,"title":"Max Message Chars","description":"Approx max chars in each event/content sent to the LLM.","default":30000},"temperature":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Temperature","description":"Sampling temperature for response generation. Defaults to None (uses provider default temperature). Set to 0.0 for deterministic outputs, or higher values (0.7-1.0) for more creative responses."},"top_p":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Top P","description":"Nucleus sampling parameter. Defaults to None (uses provider default). Set to a value between 0 and 1 to control diversity of outputs."},"top_k":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Top K"},"max_input_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Input Tokens","description":"The maximum number of input tokens. Note that this is currently unused, and the value at runtime is actually the total tokens in OpenAI (e.g. 128,000 tokens for GPT-4)."},"max_output_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Output Tokens","description":"The maximum number of output tokens. This is sent to the LLM."},"model_canonical_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Canonical Name","description":"Optional canonical model name for feature registry lookups. The OpenHands SDK maintains a model feature registry that maps model names to capabilities (e.g., vision support, prompt caching, responses API support). When using proxied or aliased model identifiers, set this field to the canonical model name (e.g., 'openai/gpt-4o') to ensure correct capability detection. If not provided, the 'model' field will be used for capability lookups."},"extra_headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Extra Headers","description":"Optional HTTP headers to forward to LiteLLM requests."},"input_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Input Cost Per Token","description":"The cost per input token. This will available in logs for user."},"output_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Output Cost Per Token","description":"The cost per output token. This will available in logs for user."},"ollama_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ollama Base Url"},"stream":{"type":"boolean","title":"Stream","description":"Enable streaming responses from the LLM. When enabled, the provided `on_token` callback in .completions and .responses will be invoked for each chunk of tokens.","default":false},"drop_params":{"type":"boolean","title":"Drop Params","default":true},"modify_params":{"type":"boolean","title":"Modify Params","description":"Modify params allows litellm to do transformations like adding a default message, when a message is empty.","default":true},"disable_vision":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Vision","description":"If model is vision capable, this option allows to disable image processing (useful for cost reduction)."},"disable_stop_word":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Stop Word","description":"Disable using of stop word.","default":false},"caching_prompt":{"type":"boolean","title":"Caching Prompt","description":"Enable caching of prompts.","default":true},"log_completions":{"type":"boolean","title":"Log Completions","description":"Enable logging of completions.","default":false},"log_completions_folder":{"type":"string","title":"Log Completions Folder","description":"The folder to log LLM completions to. Required if log_completions is True.","default":"logs/completions"},"custom_tokenizer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Tokenizer","description":"A custom tokenizer to use for token counting."},"native_tool_calling":{"type":"boolean","title":"Native Tool Calling","description":"Whether to use native tool calling.","default":true},"force_string_serializer":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force String Serializer","description":"Force using string content serializer when sending to LLM API. If None (default), auto-detect based on model. Useful for providers that do not support list content, like HuggingFace and Groq."},"inline_image_urls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Inline Image Urls","description":"If True, fetch any http(s) image URL in outgoing messages and inline it as a base64 ``data:`` URL before sending. If None (default), auto-detect based on model (some APIs such as Moonshot's public Kimi endpoint reject URL-formatted images and require base64). Set this explicitly when the model is reached through a proxy alias that hides the underlying provider (e.g. ``litellm_proxy/``). Note: inlining only runs when ``vision_is_active()`` is True, so the alias must still be recognised as vision-capable by litellm — otherwise images are not sent at all and there is nothing to inline."},"reasoning_effort":{"anyOf":[{"type":"string","enum":["low","medium","high","xhigh","none"]},{"type":"null"}],"title":"Reasoning Effort","description":"The effort to put into reasoning. This is a string that can be one of 'low', 'medium', 'high', 'xhigh', or 'none'. Can apply to all reasoning models.","default":"high"},"reasoning_summary":{"anyOf":[{"type":"string","enum":["auto","concise","detailed"]},{"type":"null"}],"title":"Reasoning Summary","description":"The level of detail for reasoning summaries. This is a string that can be one of 'auto', 'concise', or 'detailed'. Requires verified OpenAI organization. Only sent when explicitly set."},"enable_encrypted_reasoning":{"type":"boolean","title":"Enable Encrypted Reasoning","description":"If True, ask for ['reasoning.encrypted_content'] in Responses API include.","default":true},"prompt_cache_retention":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Cache Retention","description":"Retention policy for prompt cache. Only sent for supported models (GPT-5+ and GPT-4.1, excluding Azure deployments); explicitly stripped for all others.","default":"24h"},"extended_thinking_budget":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Extended Thinking Budget","description":"The budget tokens for extended thinking, supported by Anthropic models.","default":200000},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"The seed to use for random number generation."},"usage_id":{"type":"string","title":"Usage Id","description":"Unique usage identifier for the LLM. Used for registry lookups, telemetry, and spend tracking.","default":"default"},"litellm_extra_body":{"additionalProperties":true,"type":"object","title":"Litellm Extra Body","description":"Additional key-value pairs to pass to litellm's extra_body parameter. This is useful for custom inference endpoints that need additional parameters for configuration, routing, or advanced features. NOTE: Not all LLM providers support extra_body parameters. Some providers (e.g., OpenAI) may reject requests with unrecognized options. This is commonly supported by: - LiteLLM proxy servers (routing metadata, tracing) - vLLM endpoints (return_token_ids, etc.) - Custom inference clusters Examples: - Proxy routing: {'trace_version': '1.0.0', 'tags': ['agent:my-agent']} - vLLM features: {'return_token_ids': True}"}},"type":"object","title":"LLM","description":"Language model interface for OpenHands agents.\n\nThe LLM class provides a unified interface for interacting with various\nlanguage models through the litellm library. It handles model configuration,\nAPI authentication, retry logic, and tool calling capabilities.\n\nAttributes:\n model: Model name (e.g., \"gpt-5.5\").\n api_key: API key for authentication.\n base_url: Custom API base URL.\n num_retries: Number of retry attempts for failed requests.\n timeout: Request timeout in seconds.\n\nExample:\n ```python\n from openhands.sdk import LLM\n from pydantic import SecretStr\n\n llm = LLM(\n model=\"gpt-5.5\",\n api_key=SecretStr(\"your-api-key\"),\n usage_id=\"my-agent\"\n )\n # Use with agent or conversation\n ```"},"LLMCompletionLogEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"filename":{"type":"string","title":"Filename","description":"The intended filename for this log (relative to log directory)"},"log_data":{"type":"string","title":"Log Data","description":"The JSON-encoded log data to be written to the file"},"model_name":{"type":"string","title":"Model Name","description":"The model name for context","default":"unknown"},"usage_id":{"type":"string","title":"Usage Id","description":"The LLM usage_id that produced this log","default":"default"},"kind":{"type":"string","const":"LLMCompletionLogEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["filename","log_data","kind"],"title":"LLMCompletionLogEvent","description":"Event containing LLM completion log data.\n\nWhen an LLM is configured with log_completions=True in a remote conversation,\nthis event streams the completion log data back to the client through WebSocket\ninstead of writing it to a file inside the Docker container."},"LLMSecurityAnalyzer-Input":{"properties":{"kind":{"type":"string","const":"LLMSecurityAnalyzer","title":"Kind"}},"type":"object","title":"LLMSecurityAnalyzer","description":"LLM-based security analyzer.\n\nThis analyzer respects the security_risk attribute that can be set by the LLM\nwhen generating actions, similar to OpenHands' LLMRiskAnalyzer.\n\nIt provides a lightweight security analysis approach that leverages the LLM's\nunderstanding of action context and potential risks."},"LLMSecurityAnalyzer-Output":{"properties":{"kind":{"type":"string","const":"LLMSecurityAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"LLMSecurityAnalyzer","description":"LLM-based security analyzer.\n\nThis analyzer respects the security_risk attribute that can be set by the LLM\nwhen generating actions, similar to OpenHands' LLMRiskAnalyzer.\n\nIt provides a lightweight security analysis approach that leverages the LLM's\nunderstanding of action context and potential risks."},"LLMSummarizingCondenser-Input":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"},"max_size":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Size","default":240},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"keep_first":{"type":"integer","minimum":0.0,"title":"Keep First","default":2},"minimum_progress":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Minimum Progress","default":0.1},"hard_context_reset_max_retries":{"type":"integer","exclusiveMinimum":0.0,"title":"Hard Context Reset Max Retries","default":5},"hard_context_reset_context_scaling":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Hard Context Reset Context Scaling","default":0.8},"kind":{"type":"string","const":"LLMSummarizingCondenser","title":"Kind"}},"type":"object","required":["llm"],"title":"LLMSummarizingCondenser","description":"LLM-based condenser that summarizes forgotten events.\n\nUses an independent LLM (stored in the `llm` attribute) for generating summaries\nof forgotten events. The optional `agent_llm` parameter passed to condense() is\nthe LLM used by the agent for token counting purposes, and you should not assume\nit is the same as the one defined in this condenser."},"LLMSummarizingCondenser-Output":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Output"},"max_size":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Size","default":240},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"keep_first":{"type":"integer","minimum":0.0,"title":"Keep First","default":2},"minimum_progress":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Minimum Progress","default":0.1},"hard_context_reset_max_retries":{"type":"integer","exclusiveMinimum":0.0,"title":"Hard Context Reset Max Retries","default":5},"hard_context_reset_context_scaling":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Hard Context Reset Context Scaling","default":0.8},"kind":{"type":"string","const":"LLMSummarizingCondenser","title":"Kind"}},"type":"object","required":["llm","kind"],"title":"LLMSummarizingCondenser","description":"LLM-based condenser that summarizes forgotten events.\n\nUses an independent LLM (stored in the `llm` attribute) for generating summaries\nof forgotten events. The optional `agent_llm` parameter passed to condense() is\nthe LLM used by the agent for token counting purposes, and you should not assume\nit is the same as the one defined in this condenser."},"LaunchedAgentProfile":{"properties":{"agent_profile_id":{"type":"string","format":"uuid","title":"Agent Profile Id","description":"Stable id of the agent profile that launched the conversation."},"revision":{"type":"integer","minimum":0.0,"title":"Revision","description":"Revision of the agent profile at launch time."}},"type":"object","required":["agent_profile_id","revision"],"title":"LaunchedAgentProfile","description":"Provenance snapshot recorded when an agent profile launches a conversation.\n\nStored on ``StoredConversation`` and projected onto ``ConversationInfo`` so\nts-client ``deriveSwitchPlan`` can identify which agent profile is current\nwithout fragile settings-comparison. See #3720."},"ListDirectoryAction":{"properties":{"dir_path":{"type":"string","title":"Dir Path","description":"The path to the directory to list. Defaults to current directory.","default":"."},"recursive":{"type":"boolean","title":"Recursive","description":"Whether to list subdirectories recursively (up to 2 levels).","default":false},"kind":{"type":"string","const":"ListDirectoryAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ListDirectoryAction","description":"Schema for list directory operation."},"ListDirectoryActionWithRisk":{"properties":{"dir_path":{"type":"string","title":"Dir Path","description":"The path to the directory to list. Defaults to current directory.","default":"."},"recursive":{"type":"boolean","title":"Recursive","description":"Whether to list subdirectories recursively (up to 2 levels).","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"ListDirectoryActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ListDirectoryActionWithRisk"},"ListDirectoryObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"dir_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dir Path","description":"The directory path that was listed."},"entries":{"items":{"$ref":"#/components/schemas/FileEntry"},"type":"array","title":"Entries","description":"List of files and directories found."},"total_count":{"type":"integer","title":"Total Count","description":"Total number of entries found.","default":0},"is_truncated":{"type":"boolean","title":"Is Truncated","description":"Whether the listing was truncated due to too many entries.","default":false},"kind":{"type":"string","const":"ListDirectoryObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ListDirectoryObservation","description":"Observation from listing a directory."},"ListDirectoryTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"ListDirectoryTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"ListDirectoryTool","description":"Tool for listing directory contents with metadata."},"LocalWorkspace-Input":{"properties":{"working_dir":{"type":"string","title":"Working Dir","description":"The working directory for agent operations and tool execution. Accepts both string paths and Path objects. Path objects are automatically converted to strings."},"kind":{"type":"string","const":"LocalWorkspace","title":"Kind"}},"type":"object","required":["working_dir"],"title":"LocalWorkspace","description":"Local workspace implementation that operates on the host filesystem.\n\nLocalWorkspace provides direct access to the local filesystem and command execution\nenvironment. It's suitable for development and testing scenarios where the agent\nshould operate directly on the host system.\n\nExample:\n >>> workspace = LocalWorkspace(working_dir=\"/path/to/project\")\n >>> with workspace:\n ... result = workspace.execute_command(\"ls -la\")\n ... content = workspace.read_file(\"README.md\")"},"LocalWorkspace-Output":{"properties":{"working_dir":{"type":"string","title":"Working Dir","description":"The working directory for agent operations and tool execution. Accepts both string paths and Path objects. Path objects are automatically converted to strings."},"kind":{"type":"string","const":"LocalWorkspace","title":"Kind"}},"type":"object","required":["working_dir","kind"],"title":"LocalWorkspace","description":"Local workspace implementation that operates on the host filesystem.\n\nLocalWorkspace provides direct access to the local filesystem and command execution\nenvironment. It's suitable for development and testing scenarios where the agent\nshould operate directly on the host system.\n\nExample:\n >>> workspace = LocalWorkspace(working_dir=\"/path/to/project\")\n >>> with workspace:\n ... result = workspace.execute_command(\"ls -la\")\n ... content = workspace.read_file(\"README.md\")"},"LookupSecret-Input":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"url":{"type":"string","title":"Url"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"kind":{"type":"string","const":"LookupSecret","title":"Kind"}},"type":"object","required":["url"],"title":"LookupSecret","description":"A secret looked up from some external url"},"LookupSecret-Output":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"url":{"type":"string","title":"Url"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"kind":{"type":"string","const":"LookupSecret","title":"Kind"}},"type":"object","required":["url","kind"],"title":"LookupSecret","description":"A secret looked up from some external url"},"MCPTestFailure":{"properties":{"ok":{"type":"boolean","const":false,"title":"Ok","default":false},"error":{"type":"string","title":"Error","description":"Human-readable error message."},"error_kind":{"type":"string","enum":["timeout","connection","unknown"],"title":"Error Kind","description":"Coarse error classification, useful for branching UI."}},"type":"object","required":["error","error_kind"],"title":"MCPTestFailure","description":"Response when the candidate server fails to connect or list tools.\n\nThe endpoint returns HTTP 200 in both success and failure cases: a\nfailure here is the *expected* outcome of validating a user-supplied\nconfig, not a server-side error. The structured shape makes it easy\nfor the UI to render an actionable message."},"MCPTestRequest":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name","description":"Name to use for the server inside the temporary MCPConfig. Only affects error messages -- does not need to match any persisted setting.","default":"test-server"},"server":{"oneOf":[{"$ref":"#/components/schemas/_StdioMCPServerSpec"},{"$ref":"#/components/schemas/_RemoteMCPServerSpec"}],"title":"Server","discriminator":{"propertyName":"type","mapping":{"http":"#/components/schemas/_RemoteMCPServerSpec","shttp":"#/components/schemas/_RemoteMCPServerSpec","sse":"#/components/schemas/_RemoteMCPServerSpec","stdio":"#/components/schemas/_StdioMCPServerSpec","streamable-http":"#/components/schemas/_RemoteMCPServerSpec"}}},"timeout":{"type":"number","maximum":120.0,"exclusiveMinimum":0.0,"title":"Timeout","description":"Seconds to wait for connection + tools/list to complete.","default":15.0},"tool_call":{"anyOf":[{"$ref":"#/components/schemas/MCPToolCallSpec"},{"type":"null"}],"description":"Optional read-only tool to invoke after listing succeeds, so callers can verify credentials the server only exercises on tool invocation. Its outcome is reported verbatim in `tool_result` without affecting `ok`."}},"type":"object","required":["server"],"title":"MCPTestRequest","description":"Body for ``POST /api/mcp/test``."},"MCPTestSuccess":{"properties":{"ok":{"type":"boolean","const":true,"title":"Ok","default":true},"tools":{"items":{"type":"string"},"type":"array","title":"Tools","description":"Names of tools advertised by the MCP server."},"tool_result":{"anyOf":[{"$ref":"#/components/schemas/MCPToolCallResult"},{"type":"null"}],"description":"Outcome of the requested `tool_call`, when one was supplied."}},"type":"object","title":"MCPTestSuccess","description":"Response when the candidate server connects and lists its tools."},"MCPToolAction":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data","description":"Dynamic data fields from the tool call"},"kind":{"type":"string","const":"MCPToolAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"MCPToolAction","description":"Schema for MCP input action.\n\nIt is just a thin wrapper around raw JSON and does\nnot do any validation.\n\nValidation will be performed by MCPTool.__call__\nby constructing dynamically created Pydantic model\nfrom the MCP tool input schema."},"MCPToolActionWithRisk":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data","description":"Dynamic data fields from the tool call"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"MCPToolActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"MCPToolActionWithRisk"},"MCPToolCallResult":{"properties":{"is_error":{"type":"boolean","title":"Is Error","description":"The MCP-level isError flag of the result."},"text":{"type":"string","title":"Text","description":"Concatenated text content of the result."}},"type":"object","required":["is_error","text"],"title":"MCPToolCallResult","description":"Verbatim outcome of the requested ``tool_call``.\n\nThe endpoint stays provider-neutral: many servers report upstream\nfailures (e.g. Slack's ``{\"ok\": false, \"error\": \"invalid_auth\"}``)\nas ordinary text content with ``isError`` unset, so interpreting the\npayload is the caller's job."},"MCPToolCallSpec":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Name of the tool to invoke"},"arguments":{"additionalProperties":true,"type":"object","title":"Arguments","description":"Arguments passed to the tool unchanged."}},"type":"object","required":["name"],"title":"MCPToolCallSpec","description":"A single tool invocation to run as part of the connection test.\n\nListing tools does not exercise the credentials many servers only use\ninside tool handlers, so callers can name one tool to invoke after the\nlisting succeeds. Callers are responsible for choosing a read-only tool;\nthe endpoint executes it verbatim."},"MCPToolDefinition":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"mcp_tool":{"$ref":"#/components/schemas/mcp__types__Tool","description":"The MCP tool definition."},"kind":{"type":"string","const":"MCPToolDefinition","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","mcp_tool","kind","title"],"title":"MCPToolDefinition","description":"MCP Tool that wraps an MCP client and provides tool functionality."},"MCPToolObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"tool_name":{"type":"string","title":"Tool Name","description":"Name of the tool that was called"},"kind":{"type":"string","const":"MCPToolObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","kind"],"title":"MCPToolObservation","description":"Observation from MCP tool execution."},"MarketplaceCatalogResponse":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/MarketplaceSkillInfo"},"type":"array","title":"Skills"}},"type":"object","required":["skills"],"title":"MarketplaceCatalogResponse","description":"Response containing the marketplace catalog."},"MarketplaceSkillInfo":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"source":{"type":"string","title":"Source"},"installed":{"type":"boolean","title":"Installed"}},"type":"object","required":["name","description","source","installed"],"title":"MarketplaceSkillInfo","description":"Information about a skill in the marketplace catalog."},"Message":{"properties":{"role":{"type":"string","enum":["user","system","assistant","tool"],"title":"Role"},"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content"},"tool_calls":{"anyOf":[{"items":{"$ref":"#/components/schemas/MessageToolCall"},"type":"array"},{"type":"null"}],"title":"Tool Calls"},"tool_call_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Call Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content","description":"Intermediate reasoning/thinking content from reasoning models"},"thinking_blocks":{"items":{"anyOf":[{"$ref":"#/components/schemas/ThinkingBlock"},{"$ref":"#/components/schemas/RedactedThinkingBlock"}]},"type":"array","title":"Thinking Blocks","description":"Raw Anthropic thinking blocks for extended thinking feature"},"responses_reasoning_item":{"anyOf":[{"$ref":"#/components/schemas/ReasoningItemModel"},{"type":"null"}],"description":"OpenAI Responses reasoning item from model output"}},"type":"object","required":["role"],"title":"Message"},"MessageEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source"},"llm_message":{"$ref":"#/components/schemas/Message","description":"The exact LLM message for this message event"},"llm_response_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Response Id","description":"Completion or Response ID of the LLM response that generated this eventIf the source != 'agent', this field is None"},"activated_skills":{"items":{"type":"string"},"type":"array","title":"Activated Skills","description":"List of activated skill name"},"extended_content":{"items":{"$ref":"#/components/schemas/TextContent"},"type":"array","title":"Extended Content","description":"List of content added by agent context"},"sender":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sender","description":"Optional identifier of the sender. Can be used to track message origin in multi-agent scenarios."},"critic_result":{"anyOf":[{"$ref":"#/components/schemas/CriticResult"},{"type":"null"}],"description":"Optional critic evaluation of this message and preceding history."},"kind":{"type":"string","const":"MessageEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","llm_message","kind"],"title":"MessageEvent","description":"Message from either agent or user.\n\nThis is originally the \"MessageAction\", but it suppose not to be tool call."},"MessageToolCall":{"properties":{"id":{"type":"string","title":"Id","description":"Canonical tool call id"},"responses_item_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Responses Item Id","description":"Original Responses function_call.id, echoed verbatim on replay"},"name":{"type":"string","title":"Name","description":"Tool/function name"},"arguments":{"type":"string","title":"Arguments","description":"JSON string of arguments"},"origin":{"type":"string","enum":["completion","responses"],"title":"Origin","description":"Originating API family"}},"type":"object","required":["id","name","arguments","origin"],"title":"MessageToolCall","description":"Transport-agnostic tool call representation.\n\nOne canonical id is used for linking across actions/observations and\nfor Responses function_call_output call_id."},"Metrics":{"properties":{"model_name":{"type":"string","title":"Model Name","description":"Name of the model","default":"default"},"accumulated_cost":{"type":"number","minimum":0.0,"title":"Accumulated Cost","description":"Total accumulated cost, must be non-negative","default":0.0},"max_budget_per_task":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Budget Per Task","description":"Maximum budget per task"},"accumulated_token_usage":{"anyOf":[{"$ref":"#/components/schemas/TokenUsage"},{"type":"null"}],"description":"Accumulated token usage across all calls"},"costs":{"items":{"$ref":"#/components/schemas/Cost"},"type":"array","title":"Costs","description":"List of individual costs"},"response_latencies":{"items":{"$ref":"#/components/schemas/ResponseLatency"},"type":"array","title":"Response Latencies","description":"List of response latencies"},"token_usages":{"items":{"$ref":"#/components/schemas/TokenUsage"},"type":"array","title":"Token Usages","description":"List of token usage records"}},"type":"object","title":"Metrics","description":"Metrics class can record various metrics during running and evaluation.\nWe track:\n - accumulated_cost and costs\n - max_budget_per_task (budget limit)\n - A list of ResponseLatency\n - A list of TokenUsage (one per call)."},"MetricsSnapshot":{"properties":{"model_name":{"type":"string","title":"Model Name","description":"Name of the model","default":"default"},"accumulated_cost":{"type":"number","minimum":0.0,"title":"Accumulated Cost","description":"Total accumulated cost, must be non-negative","default":0.0},"max_budget_per_task":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Budget Per Task","description":"Maximum budget per task"},"accumulated_token_usage":{"anyOf":[{"$ref":"#/components/schemas/TokenUsage"},{"type":"null"}],"description":"Accumulated token usage across all calls"}},"type":"object","title":"MetricsSnapshot","description":"A snapshot of metrics at a point in time.\n\nDoes not include lists of individual costs, latencies, or token usages."},"Model":{"properties":{"id":{"type":"string","title":"Id"},"created":{"type":"integer","title":"Created"},"object":{"type":"string","const":"model","title":"Object"},"owned_by":{"type":"string","title":"Owned By"}},"additionalProperties":true,"type":"object","required":["id","created","object","owned_by"],"title":"Model","description":"Describes an OpenAI model offering that can be used with the API."},"ModelsResponse":{"properties":{"models":{"items":{"type":"string"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"ModelsResponse","description":"Response containing the list of available LLM models."},"NeverConfirm-Input":{"properties":{"kind":{"type":"string","const":"NeverConfirm","title":"Kind"}},"type":"object","title":"NeverConfirm"},"NeverConfirm-Output":{"properties":{"kind":{"type":"string","const":"NeverConfirm","title":"Kind"}},"type":"object","required":["kind"],"title":"NeverConfirm"},"NoOpCondenser-Input":{"properties":{"kind":{"type":"string","const":"NoOpCondenser","title":"Kind"}},"type":"object","title":"NoOpCondenser","description":"Simple condenser that returns a view un-manipulated.\n\nPrimarily intended for testing purposes."},"NoOpCondenser-Output":{"properties":{"kind":{"type":"string","const":"NoOpCondenser","title":"Kind"}},"type":"object","required":["kind"],"title":"NoOpCondenser","description":"Simple condenser that returns a view un-manipulated.\n\nPrimarily intended for testing purposes."},"Observation":{"oneOf":[{"$ref":"#/components/schemas/MCPToolObservation"},{"$ref":"#/components/schemas/FinishObservation"},{"$ref":"#/components/schemas/InvokeSkillObservation"},{"$ref":"#/components/schemas/SwitchLLMObservation"},{"$ref":"#/components/schemas/ThinkObservation"},{"$ref":"#/components/schemas/ClientToolObservation"},{"$ref":"#/components/schemas/BrowserObservation"},{"$ref":"#/components/schemas/DelegateObservation"},{"$ref":"#/components/schemas/FileEditorObservation"},{"$ref":"#/components/schemas/EditObservation"},{"$ref":"#/components/schemas/ListDirectoryObservation"},{"$ref":"#/components/schemas/ReadFileObservation"},{"$ref":"#/components/schemas/WriteFileObservation"},{"$ref":"#/components/schemas/GlobObservation"},{"$ref":"#/components/schemas/GrepObservation"},{"$ref":"#/components/schemas/PlanningFileEditorObservation"},{"$ref":"#/components/schemas/TaskObservation"},{"$ref":"#/components/schemas/TaskTrackerObservation"},{"$ref":"#/components/schemas/TerminalObservation"},{"$ref":"#/components/schemas/WorkflowObservation"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__mcp__definition__MCPToolObservation-Output__1":"#/components/schemas/MCPToolObservation","openhands__sdk__tool__builtins__finish__FinishObservation-Output__1":"#/components/schemas/FinishObservation","openhands__sdk__tool__builtins__invoke_skill__InvokeSkillObservation-Output__1":"#/components/schemas/InvokeSkillObservation","openhands__sdk__tool__builtins__switch_llm__SwitchLLMObservation-Output__1":"#/components/schemas/SwitchLLMObservation","openhands__sdk__tool__builtins__think__ThinkObservation-Output__1":"#/components/schemas/ThinkObservation","openhands__sdk__tool__client_tool__ClientToolObservation-Output__1":"#/components/schemas/ClientToolObservation","openhands__tools__browser_use__definition__BrowserObservation-Output__1":"#/components/schemas/BrowserObservation","openhands__tools__delegate__definition__DelegateObservation-Output__1":"#/components/schemas/DelegateObservation","openhands__tools__file_editor__definition__FileEditorObservation-Output__1":"#/components/schemas/FileEditorObservation","openhands__tools__gemini__edit__definition__EditObservation-Output__1":"#/components/schemas/EditObservation","openhands__tools__gemini__list_directory__definition__ListDirectoryObservation-Output__1":"#/components/schemas/ListDirectoryObservation","openhands__tools__gemini__read_file__definition__ReadFileObservation-Output__1":"#/components/schemas/ReadFileObservation","openhands__tools__gemini__write_file__definition__WriteFileObservation-Output__1":"#/components/schemas/WriteFileObservation","openhands__tools__glob__definition__GlobObservation-Output__1":"#/components/schemas/GlobObservation","openhands__tools__grep__definition__GrepObservation-Output__1":"#/components/schemas/GrepObservation","openhands__tools__planning_file_editor__definition__PlanningFileEditorObservation-Output__1":"#/components/schemas/PlanningFileEditorObservation","openhands__tools__task__definition__TaskObservation-Output__1":"#/components/schemas/TaskObservation","openhands__tools__task_tracker__definition__TaskTrackerObservation-Output__1":"#/components/schemas/TaskTrackerObservation","openhands__tools__terminal__definition__TerminalObservation-Output__1":"#/components/schemas/TerminalObservation","openhands__tools__workflow__definition__WorkflowObservation-Output__1":"#/components/schemas/WorkflowObservation"}}},"ObservationEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"tool_name":{"type":"string","title":"Tool Name","description":"The tool name that this observation is responding to"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The tool call id that this observation is responding to"},"observation":{"$ref":"#/components/schemas/Observation","description":"The observation (tool call) sent to LLM"},"action_id":{"type":"string","title":"Action Id","description":"The action id that this observation is responding to"},"kind":{"type":"string","const":"ObservationEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","tool_call_id","observation","action_id","kind"],"title":"ObservationEvent"},"OpenAIChatCompletionRequest":{"properties":{"model":{"type":"string","title":"Model"},"messages":{"items":{"$ref":"#/components/schemas/OpenAIChatMessage"},"type":"array","title":"Messages"},"stream":{"type":"boolean","title":"Stream","default":false},"stream_options":{"anyOf":[{"$ref":"#/components/schemas/OpenAIStreamOptions"},{"type":"null"}]}},"type":"object","required":["model","messages"],"title":"OpenAIChatCompletionRequest"},"OpenAIChatMessage":{"properties":{"role":{"type":"string","enum":["system","developer","user","assistant","tool"],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"items":{"$ref":"#/components/schemas/OpenAIContentPart"},"type":"array"},{"type":"null"}],"title":"Content"}},"type":"object","required":["role"],"title":"OpenAIChatMessage"},"OpenAIContentPart":{"properties":{"type":{"type":"string","title":"Type"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"image_url":{"anyOf":[{"$ref":"#/components/schemas/OpenAIImageURL"},{"type":"string"},{"type":"null"}],"title":"Image Url"}},"type":"object","required":["type"],"title":"OpenAIContentPart"},"OpenAIImageURL":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"OpenAIImageURL"},"OpenAIModelListResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Model"},"type":"array","title":"Data"}},"type":"object","required":["data"],"title":"OpenAIModelListResponse"},"OpenAIStreamOptions":{"properties":{"include_usage":{"type":"boolean","title":"Include Usage","default":false}},"type":"object","title":"OpenAIStreamOptions"},"OrgConfig":{"properties":{"repository":{"type":"string","title":"Repository","description":"Selected repository (e.g., 'owner/repo')"},"provider":{"type":"string","title":"Provider","description":"Git provider type: github, gitlab, azure, bitbucket"},"org_repo_url":{"type":"string","title":"Org Repo Url","description":"Pre-authenticated Git URL for the organization repository. Contains sensitive credentials - handle with care and avoid logging."},"org_name":{"type":"string","title":"Org Name","description":"Organization name"}},"type":"object","required":["repository","provider","org_repo_url","org_name"],"title":"OrgConfig","description":"Configuration for loading organization-level skills."},"PassCritic-Input":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"PassCritic","title":"Kind"}},"type":"object","title":"PassCritic","description":"Critic that always returns success.\n\nThis critic can be used when no evaluation is needed or when\nall instances should be considered successful regardless of their output."},"PassCritic-Output":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"PassCritic","title":"Kind"}},"type":"object","required":["kind"],"title":"PassCritic","description":"Critic that always returns success.\n\nThis critic can be used when no evaluation is needed or when\nall instances should be considered successful regardless of their output."},"PatternSecurityAnalyzer-Input":{"properties":{"high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"High Patterns","description":"HIGH patterns scanned against executable fields only"},"medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Medium Patterns","description":"MEDIUM patterns scanned against executable fields only"},"injection_high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection High Patterns","description":"HIGH patterns scanned against all fields"},"injection_medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection Medium Patterns","description":"MEDIUM patterns scanned against all fields"},"kind":{"type":"string","const":"PatternSecurityAnalyzer","title":"Kind"}},"type":"object","title":"PatternSecurityAnalyzer","description":"Catch dangerous agent actions through deterministic signature scanning.\n\nUse this when you want fast, local, no-network threat detection at the\naction boundary. It returns ``SecurityRisk.HIGH``, ``MEDIUM``, or ``LOW``\n-- pair it with ``ConfirmRisky`` to decide what gets confirmed.\n\nThe key design choice: shell-destructive patterns only scan what the\nagent will *execute* (tool arguments), never what it *thought about*\n(reasoning text). Injection patterns scan everything, because\n\"ignore all previous instructions\" is dangerous wherever it appears.\n\nNormalization is always on -- invisible characters and fullwidth\nsubstitutions are collapsed before matching.\n\nExample::\n\n from openhands.sdk.security import PatternSecurityAnalyzer, ConfirmRisky\n\n analyzer = PatternSecurityAnalyzer()\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"PatternSecurityAnalyzer-Output":{"properties":{"high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"High Patterns","description":"HIGH patterns scanned against executable fields only"},"medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Medium Patterns","description":"MEDIUM patterns scanned against executable fields only"},"injection_high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection High Patterns","description":"HIGH patterns scanned against all fields"},"injection_medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection Medium Patterns","description":"MEDIUM patterns scanned against all fields"},"kind":{"type":"string","const":"PatternSecurityAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"PatternSecurityAnalyzer","description":"Catch dangerous agent actions through deterministic signature scanning.\n\nUse this when you want fast, local, no-network threat detection at the\naction boundary. It returns ``SecurityRisk.HIGH``, ``MEDIUM``, or ``LOW``\n-- pair it with ``ConfirmRisky`` to decide what gets confirmed.\n\nThe key design choice: shell-destructive patterns only scan what the\nagent will *execute* (tool arguments), never what it *thought about*\n(reasoning text). Injection patterns scan everything, because\n\"ignore all previous instructions\" is dangerous wherever it appears.\n\nNormalization is always on -- invisible characters and fullwidth\nsubstitutions are collapsed before matching.\n\nExample::\n\n from openhands.sdk.security import PatternSecurityAnalyzer, ConfirmRisky\n\n analyzer = PatternSecurityAnalyzer()\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"PauseEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"user"},"kind":{"type":"string","const":"PauseEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"PauseEvent","description":"Event indicating that the agent execution was paused by user request."},"PipelineCondenser-Input":{"properties":{"condensers":{"items":{"$ref":"#/components/schemas/CondenserBase-Input"},"type":"array","title":"Condensers"},"kind":{"type":"string","const":"PipelineCondenser","title":"Kind"}},"type":"object","required":["condensers"],"title":"PipelineCondenser","description":"A condenser that applies a sequence of condensers in order.\n\nAll condensers are defined primarily by their `condense` method, which takes a\n`View` and an optional `agent_llm` parameter, returning either a new `View` or a\n`Condensation` event. That means we can chain multiple condensers together by\npassing `View`s along and exiting early if any condenser returns a `Condensation`.\n\nFor example:\n\n # Use the pipeline condenser to chain multiple other condensers together\n condenser = PipelineCondenser(condensers=[\n CondenserA(...),\n CondenserB(...),\n CondenserC(...),\n ])\n\n result = condenser.condense(view, agent_llm=agent_llm)\n\n # Doing the same thing without the pipeline condenser requires more boilerplate\n # for the monadic chaining\n other_result = view\n\n if isinstance(other_result, View):\n other_result = CondenserA(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserB(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserC(...).condense(other_result, agent_llm=agent_llm)\n\n assert result == other_result"},"PipelineCondenser-Output":{"properties":{"condensers":{"items":{"$ref":"#/components/schemas/CondenserBase-Output"},"type":"array","title":"Condensers"},"kind":{"type":"string","const":"PipelineCondenser","title":"Kind"}},"type":"object","required":["condensers","kind"],"title":"PipelineCondenser","description":"A condenser that applies a sequence of condensers in order.\n\nAll condensers are defined primarily by their `condense` method, which takes a\n`View` and an optional `agent_llm` parameter, returning either a new `View` or a\n`Condensation` event. That means we can chain multiple condensers together by\npassing `View`s along and exiting early if any condenser returns a `Condensation`.\n\nFor example:\n\n # Use the pipeline condenser to chain multiple other condensers together\n condenser = PipelineCondenser(condensers=[\n CondenserA(...),\n CondenserB(...),\n CondenserC(...),\n ])\n\n result = condenser.condense(view, agent_llm=agent_llm)\n\n # Doing the same thing without the pipeline condenser requires more boilerplate\n # for the monadic chaining\n other_result = view\n\n if isinstance(other_result, View):\n other_result = CondenserA(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserB(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserC(...).condense(other_result, agent_llm=agent_llm)\n\n assert result == other_result"},"PlanningFileEditorAction":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"kind":{"type":"string","const":"PlanningFileEditorAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"PlanningFileEditorAction","description":"Schema for planning file editor operations.\n\nInherits from FileEditorAction but restricts editing to PLAN.md only.\nAllows viewing any file but only editing PLAN.md."},"PlanningFileEditorActionWithRisk":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"PlanningFileEditorActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"PlanningFileEditorActionWithRisk"},"PlanningFileEditorObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The command that was run: `view`, `create`, `str_replace`, `insert`, or `undo_edit`."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The file path that was edited."},"prev_exist":{"type":"boolean","title":"Prev Exist","description":"Indicates if the file previously existed. If not, it was created.","default":true},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The content of the file before the edit."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The content of the file after the edit."},"kind":{"type":"string","const":"PlanningFileEditorObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"PlanningFileEditorObservation","description":"Observation from planning file editor operations.\n\nInherits from FileEditorObservation - same structure, just different type."},"PlanningFileEditorTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"PlanningFileEditorTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"PlanningFileEditorTool","description":"A planning file editor tool with read-all, edit-PLAN.md-only access."},"PluginSource":{"properties":{"source":{"type":"string","title":"Source","description":"Plugin source: 'github:owner/repo', any git URL, or local path"},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref","description":"Optional branch, tag, or commit (only for git sources)"},"repo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Path","description":"Subdirectory path within the git repository (e.g., 'plugins/my-plugin' for monorepos). Only relevant for git sources, not local paths."}},"type":"object","required":["source"],"title":"PluginSource","description":"Specification for a plugin to load.\n\nThis model describes where to find a plugin and is used by load_plugins()\nto fetch and load plugins from various sources.\n\nExamples:\n >>> # GitHub repository\n >>> PluginSource(source=\"github:owner/repo\", ref=\"v1.0.0\")\n\n >>> # Plugin from monorepo subdirectory\n >>> PluginSource(\n ... source=\"github:owner/monorepo\",\n ... repo_path=\"plugins/my-plugin\"\n ... )\n\n >>> # Local path\n >>> PluginSource(source=\"/path/to/plugin\")"},"PolicyRailSecurityAnalyzer-Input":{"properties":{"kind":{"type":"string","const":"PolicyRailSecurityAnalyzer","title":"Kind"}},"type":"object","title":"PolicyRailSecurityAnalyzer","description":"Catch composed threats that plain regex signatures would miss.\n\nUse this when you need to detect threats defined by *combinations*\nof tokens (e.g., ``curl`` piped to ``bash``) rather than individual\nsignatures. While these rails *could* each be expressed as a single\nregex, keeping them as named rules with per-segment evaluation makes\nthe threat model more interpretable, the rules easier to maintain,\nand the audit trail clearer than a flat pattern list.\n\nEvaluates normalized executable segments only -- reasoning text is\nnever scanned.\n\nReturns ``SecurityRisk.HIGH`` when a rail fires, ``LOW`` otherwise.\nPair with ``ConfirmRisky`` and compose via ``EnsembleSecurityAnalyzer``.\n\nv1 rails: fetch-to-exec, raw-disk-op, catastrophic-delete.\n\nExample::\n\n from openhands.sdk.security import PolicyRailSecurityAnalyzer\n\n analyzer = PolicyRailSecurityAnalyzer()\n # risk = analyzer.security_risk(action)"},"PolicyRailSecurityAnalyzer-Output":{"properties":{"kind":{"type":"string","const":"PolicyRailSecurityAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"PolicyRailSecurityAnalyzer","description":"Catch composed threats that plain regex signatures would miss.\n\nUse this when you need to detect threats defined by *combinations*\nof tokens (e.g., ``curl`` piped to ``bash``) rather than individual\nsignatures. While these rails *could* each be expressed as a single\nregex, keeping them as named rules with per-segment evaluation makes\nthe threat model more interpretable, the rules easier to maintain,\nand the audit trail clearer than a flat pattern list.\n\nEvaluates normalized executable segments only -- reasoning text is\nnever scanned.\n\nReturns ``SecurityRisk.HIGH`` when a rail fires, ``LOW`` otherwise.\nPair with ``ConfirmRisky`` and compose via ``EnsembleSecurityAnalyzer``.\n\nv1 rails: fetch-to-exec, raw-disk-op, catastrophic-delete.\n\nExample::\n\n from openhands.sdk.security import PolicyRailSecurityAnalyzer\n\n analyzer = PolicyRailSecurityAnalyzer()\n # risk = analyzer.security_risk(action)"},"ProfileDetailResponse":{"properties":{"name":{"type":"string","title":"Name"},"config":{"additionalProperties":true,"type":"object","title":"Config"},"api_key_set":{"type":"boolean","title":"Api Key Set","default":false}},"type":"object","required":["name","config"],"title":"ProfileDetailResponse","description":"``config.api_key`` is always nulled; use ``api_key_set`` instead."},"ProfileInfo":{"properties":{"name":{"type":"string","title":"Name"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url"},"api_key_set":{"type":"boolean","title":"Api Key Set","default":false}},"type":"object","required":["name"],"title":"ProfileInfo"},"ProfileListResponse":{"properties":{"profiles":{"items":{"$ref":"#/components/schemas/ProfileInfo"},"type":"array","title":"Profiles"},"active_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Profile"}},"type":"object","required":["profiles"],"title":"ProfileListResponse"},"ProfileMutationResponse":{"properties":{"name":{"type":"string","title":"Name"},"message":{"type":"string","title":"Message"}},"type":"object","required":["name","message"],"title":"ProfileMutationResponse"},"PromptTokensDetails":{"properties":{"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"cached_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cached Tokens"}},"additionalProperties":true,"type":"object","title":"PromptTokensDetails","description":"Breakdown of tokens used in the prompt."},"ProvidersResponse":{"properties":{"providers":{"items":{"type":"string"},"type":"array","title":"Providers"}},"type":"object","required":["providers"],"title":"ProvidersResponse","description":"Response containing the list of available LLM providers."},"ReadFileAction":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to read."},"offset":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Offset","description":"Optional: The 0-based line number to start reading from. Use for paginating through large files."},"limit":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Limit","description":"Optional: Maximum number of lines to read. Use with 'offset' to paginate through large files."},"kind":{"type":"string","const":"ReadFileAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","kind"],"title":"ReadFileAction","description":"Schema for read file operation."},"ReadFileActionWithRisk":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to read."},"offset":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Offset","description":"Optional: The 0-based line number to start reading from. Use for paginating through large files."},"limit":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Limit","description":"Optional: Maximum number of lines to read. Use with 'offset' to paginate through large files."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"ReadFileActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","kind"],"title":"ReadFileActionWithRisk"},"ReadFileObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"file_path":{"type":"string","title":"File Path","description":"The file path that was read."},"file_content":{"type":"string","title":"File Content","description":"The content read from the file.","default":""},"is_truncated":{"type":"boolean","title":"Is Truncated","description":"Whether the content was truncated due to size limits.","default":false},"lines_shown":{"anyOf":[{"prefixItems":[{"type":"integer"},{"type":"integer"}],"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Lines Shown","description":"If truncated, the range of lines shown (start, end) - 1-indexed."},"total_lines":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Lines","description":"Total number of lines in the file."},"kind":{"type":"string","const":"ReadFileObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","kind"],"title":"ReadFileObservation","description":"Observation from reading a file."},"ReadFileTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"ReadFileTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"ReadFileTool","description":"Tool for reading file contents with pagination support."},"ReasoningItemModel":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"summary":{"items":{"type":"string"},"type":"array","title":"Summary"},"content":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Content"},"encrypted_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Encrypted Content"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},"type":"object","title":"ReasoningItemModel","description":"OpenAI Responses reasoning item (non-stream, subset we consume).\n\nDo not log or render encrypted_content."},"RedactedThinkingBlock":{"properties":{"type":{"type":"string","const":"redacted_thinking","title":"Type","default":"redacted_thinking"},"data":{"type":"string","title":"Data","description":"The redacted thinking content"}},"type":"object","required":["data"],"title":"RedactedThinkingBlock","description":"Redacted thinking block for previous responses without extended thinking.\n\nThis is used as a placeholder for assistant messages that were generated\nbefore extended thinking was enabled."},"RemoteWorkspace":{"properties":{"working_dir":{"type":"string","title":"Working Dir","description":"The working directory for agent operations and tool execution."},"host":{"type":"string","title":"Host","description":"The remote host URL for the workspace."},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"API key for authenticating with the remote host."},"read_timeout":{"type":"number","title":"Read Timeout","description":"Timeout in seconds for reading operations of httpx.Client.","default":600.0},"max_connections":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Connections","description":"Maximum number of connections for httpx.Client. None means no limit, useful for running many conversations in parallel."},"kind":{"type":"string","const":"RemoteWorkspace","title":"Kind"}},"type":"object","required":["working_dir","host","kind"],"title":"RemoteWorkspace","description":"Remote workspace implementation that connects to an OpenHands agent server.\n\nRemoteWorkspace provides access to a sandboxed environment running on a remote\nOpenHands agent server. This is the recommended approach for production deployments\nas it provides better isolation and security.\n\nSupports optional completion callbacks on exit via environment variables:\n - ``AUTOMATION_CALLBACK_URL`` — URL to POST completion status to\n - ``AUTOMATION_CALLBACK_API_KEY`` — Bearer token for callback auth (optional)\n - ``AUTOMATION_RUN_ID`` — Run ID to include in callback payload (optional)\n\nExample:\n >>> workspace = RemoteWorkspace(\n ... host=\"https://agent-server.example.com\",\n ... working_dir=\"/workspace\"\n ... )\n >>> with workspace:\n ... result = workspace.execute_command(\"ls -la\")\n ... content = workspace.read_file(\"README.md\")"},"RenameAgentProfileRequest":{"properties":{"new_name":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"New Name"}},"type":"object","required":["new_name"],"title":"RenameAgentProfileRequest"},"RenameProfileRequest":{"properties":{"new_name":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"New Name"}},"type":"object","required":["new_name"],"title":"RenameProfileRequest"},"ResponseLatency":{"properties":{"model":{"type":"string","title":"Model"},"latency":{"type":"number","minimum":0.0,"title":"Latency","description":"Latency must be non-negative"},"response_id":{"type":"string","title":"Response Id"}},"type":"object","required":["model","latency","response_id"],"title":"ResponseLatency","description":"Metric tracking the round-trip time per completion call."},"SandboxConfig":{"properties":{"exposed_urls":{"items":{"$ref":"#/components/schemas/ExposedUrl"},"type":"array","title":"Exposed Urls","description":"List of exposed URLs from the sandbox"}},"type":"object","title":"SandboxConfig","description":"Configuration for loading sandbox-specific skills."},"SaveProfileRequest":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"},"include_secrets":{"type":"boolean","title":"Include Secrets","description":"Whether to persist the API key with the profile.","default":true}},"type":"object","required":["llm"],"title":"SaveProfileRequest"},"SecretCreateRequest":{"properties":{"name":{"type":"string","title":"Name"},"value":{"type":"string","format":"password","title":"Value","writeOnly":true},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name","value"],"title":"SecretCreateRequest","description":"Request model for PUT /api/settings/secrets.\n\nCreates or updates a secret with the given name and value."},"SecretItemResponse":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"SecretItemResponse","description":"Response model for a secret item (without value).\n\nUsed in list responses and as the response for create/update operations."},"SecretRegistry":{"properties":{"secret_sources":{"additionalProperties":{"$ref":"#/components/schemas/SecretSource-Output"},"type":"object","title":"Secret Sources"}},"type":"object","title":"SecretRegistry","description":"Manages secrets and injects them into bash commands when needed.\n\nThe secret registry stores a mapping of secret keys to SecretSources\nthat retrieve the actual secret values. When a bash command is about to be\nexecuted, it scans the command for any secret keys and injects the corresponding\nenvironment variables.\n\nSecret sources will redact / encrypt their sensitive values as appropriate when\nserializing, depending on the content of the context. If a context is present\nand contains a 'cipher' object, this is used for encryption. If it contains a\nboolean 'expose_secrets' flag set to True, secrets are dunped in plain text.\nOtherwise secrets are redacted.\n\nAdditionally, it tracks the latest exported values to enable consistent masking\neven when callable secrets fail on subsequent calls."},"SecretSource-Input":{"oneOf":[{"$ref":"#/components/schemas/LookupSecret-Input"},{"$ref":"#/components/schemas/StaticSecret-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__secret__secrets__LookupSecret-Input__1":"#/components/schemas/LookupSecret-Input","openhands__sdk__secret__secrets__StaticSecret-Input__1":"#/components/schemas/StaticSecret-Input"}}},"SecretSource-Output":{"oneOf":[{"$ref":"#/components/schemas/LookupSecret-Output"},{"$ref":"#/components/schemas/StaticSecret-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__secret__secrets__LookupSecret-Output__1":"#/components/schemas/LookupSecret-Output","openhands__sdk__secret__secrets__StaticSecret-Output__1":"#/components/schemas/StaticSecret-Output"}}},"SecretsListResponse":{"properties":{"secrets":{"items":{"$ref":"#/components/schemas/SecretItemResponse"},"type":"array","title":"Secrets"}},"type":"object","required":["secrets"],"title":"SecretsListResponse","description":"Response model for GET /api/settings/secrets.\n\nLists all available secrets with their names and descriptions.\nValues are never included in list responses."},"SecurityAnalyzerBase-Input":{"oneOf":[{"$ref":"#/components/schemas/PatternSecurityAnalyzer-Input"},{"$ref":"#/components/schemas/PolicyRailSecurityAnalyzer-Input"},{"$ref":"#/components/schemas/EnsembleSecurityAnalyzer-Input"},{"$ref":"#/components/schemas/GraySwanAnalyzer-Input"},{"$ref":"#/components/schemas/LLMSecurityAnalyzer-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__defense_in_depth__pattern__PatternSecurityAnalyzer-Input__1":"#/components/schemas/PatternSecurityAnalyzer-Input","openhands__sdk__security__defense_in_depth__policy_rails__PolicyRailSecurityAnalyzer-Input__1":"#/components/schemas/PolicyRailSecurityAnalyzer-Input","openhands__sdk__security__ensemble__EnsembleSecurityAnalyzer-Input__1":"#/components/schemas/EnsembleSecurityAnalyzer-Input","openhands__sdk__security__grayswan__analyzer__GraySwanAnalyzer-Input__1":"#/components/schemas/GraySwanAnalyzer-Input","openhands__sdk__security__llm_analyzer__LLMSecurityAnalyzer-Input__1":"#/components/schemas/LLMSecurityAnalyzer-Input"}}},"SecurityAnalyzerBase-Output":{"oneOf":[{"$ref":"#/components/schemas/PatternSecurityAnalyzer-Output"},{"$ref":"#/components/schemas/PolicyRailSecurityAnalyzer-Output"},{"$ref":"#/components/schemas/EnsembleSecurityAnalyzer-Output"},{"$ref":"#/components/schemas/GraySwanAnalyzer-Output"},{"$ref":"#/components/schemas/LLMSecurityAnalyzer-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__defense_in_depth__pattern__PatternSecurityAnalyzer-Output__1":"#/components/schemas/PatternSecurityAnalyzer-Output","openhands__sdk__security__defense_in_depth__policy_rails__PolicyRailSecurityAnalyzer-Output__1":"#/components/schemas/PolicyRailSecurityAnalyzer-Output","openhands__sdk__security__ensemble__EnsembleSecurityAnalyzer-Output__1":"#/components/schemas/EnsembleSecurityAnalyzer-Output","openhands__sdk__security__grayswan__analyzer__GraySwanAnalyzer-Output__1":"#/components/schemas/GraySwanAnalyzer-Output","openhands__sdk__security__llm_analyzer__LLMSecurityAnalyzer-Output__1":"#/components/schemas/LLMSecurityAnalyzer-Output"}}},"SecurityRisk":{"type":"string","enum":["UNKNOWN","LOW","MEDIUM","HIGH"],"title":"SecurityRisk","description":"Security risk levels for actions.\n\nBased on OpenHands security risk levels but adapted for agent-sdk.\nInteger values allow for easy comparison and ordering."},"SendMessageRequest":{"properties":{"role":{"type":"string","enum":["user","system","assistant","tool"],"title":"Role","default":"user"},"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content"},"run":{"type":"boolean","title":"Run","description":"Whether the agent loop should automatically run if not running","default":false}},"type":"object","title":"SendMessageRequest","description":"Payload to send a message to the agent."},"ServerErrorEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","description":"The source of this event"},"code":{"type":"string","title":"Code","description":"Code for the error - typically an error type"},"detail":{"type":"string","title":"Detail","description":"Details about the error"},"kind":{"type":"string","const":"ServerErrorEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","code","detail","kind"],"title":"ServerErrorEvent","description":"Event emitted by the agent server when a server-level error occurs.\n\nThis event is used for errors that originate from the agent server itself,\nsuch as MCP connection failures, WebSocket errors, or other infrastructure\nissues. Unlike ConversationErrorEvent which is for conversation-level failures,\nthis event indicates a problem with the server environment."},"ServerInfo":{"properties":{"uptime":{"type":"number","title":"Uptime"},"idle_time":{"type":"number","title":"Idle Time"},"title":{"type":"string","title":"Title","default":"OpenHands Agent Server"},"version":{"type":"string","title":"Version"},"sdk_version":{"type":"string","title":"Sdk Version"},"tools_version":{"type":"string","title":"Tools Version"},"workspace_version":{"type":"string","title":"Workspace Version"},"build_git_sha":{"type":"string","title":"Build Git Sha"},"build_git_ref":{"type":"string","title":"Build Git Ref"},"python_version":{"type":"string","title":"Python Version"},"usable_tools":{"items":{"type":"string"},"type":"array","title":"Usable Tools"},"runtime_idle_timeout_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Runtime Idle Timeout Seconds"},"max_foreground_terminal_timeout_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Foreground Terminal Timeout Seconds"},"docs":{"type":"string","title":"Docs","default":"/docs"},"redoc":{"type":"string","title":"Redoc","default":"/redoc"}},"type":"object","required":["uptime","idle_time"],"title":"ServerInfo"},"SetConfirmationPolicyRequest":{"properties":{"policy":{"$ref":"#/components/schemas/ConfirmationPolicyBase-Input","description":"The confirmation policy to set"}},"type":"object","required":["policy"],"title":"SetConfirmationPolicyRequest","description":"Payload to set confirmation policy for a conversation."},"SetSecurityAnalyzerRequest":{"properties":{"security_analyzer":{"anyOf":[{"$ref":"#/components/schemas/SecurityAnalyzerBase-Input"},{"type":"null"}],"description":"The security analyzer to set"}},"type":"object","required":["security_analyzer"],"title":"SetSecurityAnalyzerRequest","description":"Payload to set security analyzer for a conversation"},"SettingProminence":{"type":"string","enum":["critical","major","minor"],"title":"SettingProminence"},"SettingsChoice":{"properties":{"value":{"anyOf":[{"type":"boolean"},{"type":"integer"},{"type":"number"},{"type":"string"}],"title":"Value"},"label":{"type":"string","title":"Label"}},"type":"object","required":["value","label"],"title":"SettingsChoice"},"SettingsFieldSchema":{"properties":{"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"section":{"type":"string","title":"Section"},"section_label":{"type":"string","title":"Section Label"},"value_type":{"type":"string","enum":["string","integer","number","boolean","array","object"],"title":"Value Type"},"default":{"title":"Default"},"prominence":{"$ref":"#/components/schemas/SettingProminence","default":"minor"},"depends_on":{"items":{"type":"string"},"type":"array","title":"Depends On"},"secret":{"type":"boolean","title":"Secret","default":false},"choices":{"items":{"$ref":"#/components/schemas/SettingsChoice"},"type":"array","title":"Choices"},"variant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Variant","description":"When set, the field only applies to the named ``AgentSettings`` variant (``'openhands'`` or ``'acp'``). The GUI filters fields by the user's current variant; fields with ``variant=None`` are shown regardless."}},"type":"object","required":["key","label","section","section_label","value_type"],"title":"SettingsFieldSchema"},"SettingsResponse":{"properties":{"agent_settings":{"additionalProperties":true,"type":"object","title":"Agent Settings"},"conversation_settings":{"additionalProperties":true,"type":"object","title":"Conversation Settings"},"llm_api_key_is_set":{"type":"boolean","title":"Llm Api Key Is Set"},"active_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Profile","description":"Name of the currently active LLM profile, if one is selected."},"active_agent_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Agent Profile Id","description":"Stable id of the currently active AgentProfile, if one is set."},"misc_settings":{"additionalProperties":true,"type":"object","title":"Misc Settings"}},"type":"object","required":["agent_settings","conversation_settings","llm_api_key_is_set"],"title":"SettingsResponse","description":"Response model for GET /api/settings.\n\nContains the full settings payload including agent configuration,\nconversation settings, active LLM profile, miscellaneous frontend-owned\nsettings, and a flag indicating whether an LLM API key is set.\n\nThe ``agent_settings`` and ``conversation_settings`` fields are raw dicts\nbecause the server controls secret serialization via context. Use the\ntyped accessor methods for validation:\n\nExample::\n\n response = SettingsResponse.model_validate(api_response.json())\n agent = response.get_agent_settings() # Returns AgentSettingsConfig\n conv = response.get_conversation_settings() # Returns ConversationSettings\n\n``misc_settings`` is an opaque container for frontend-owned data that the\nagent-server persists but does not interpret — see the docstring of\n:class:`PersistedSettings.misc_settings`."},"SettingsSchema":{"properties":{"model_name":{"type":"string","title":"Model Name"},"sections":{"items":{"$ref":"#/components/schemas/SettingsSectionSchema"},"type":"array","title":"Sections"}},"type":"object","required":["model_name","sections"],"title":"SettingsSchema"},"SettingsSectionSchema":{"properties":{"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"fields":{"items":{"$ref":"#/components/schemas/SettingsFieldSchema"},"type":"array","title":"Fields"},"variant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Variant","description":"When set, this section only applies to the named ``AgentSettings`` variant (e.g. ``'openhands'`` or ``'acp'``). The GUI filters sections by the current ``agent_kind`` value; sections with ``variant=None`` are always shown."}},"type":"object","required":["key","label","fields"],"title":"SettingsSectionSchema"},"SettingsUpdateRequest":{"properties":{"agent_settings_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Agent Settings Diff"},"conversation_settings_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Conversation Settings Diff"},"misc_settings_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Misc Settings Diff"},"active_profile":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"},{"type":"null"}],"title":"Active Profile","description":"Name of the active LLM profile to persist; null clears it."},"active_agent_profile_id":{"anyOf":[{"type":"string","pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"},{"type":"null"}],"title":"Active Agent Profile Id","description":"Stable id of the active AgentProfile to persist; null clears it."}},"type":"object","title":"SettingsUpdateRequest","description":"Request model for PATCH /api/settings.\n\nSupports partial updates via diff objects that are deep-merged with\nexisting settings. ``misc_settings_diff`` is deep-merged into the\npersisted ``misc_settings`` block with the same semantics as\n``agent_settings_diff`` and ``conversation_settings_diff``: nested dicts\nmerge recursively, and lists are replaced wholesale rather than merged.\nBecause ``misc_settings`` is opaque to the agent-server, callers are\nresponsible for the shape of what they store there."},"Skill-Input":{"properties":{"name":{"type":"string","title":"Name"},"content":{"type":"string","title":"Content"},"trigger":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/KeywordTrigger"},{"$ref":"#/components/schemas/TaskTrigger"}],"discriminator":{"propertyName":"type","mapping":{"keyword":"#/components/schemas/KeywordTrigger","task":"#/components/schemas/TaskTrigger"}}},{"type":"null"}],"title":"Trigger","description":"Trigger determines when skill content is auto-injected. None = no auto-injection (for AgentSkills: agent reads on demand; for legacy: full content always in system prompt). KeywordTrigger = auto-inject when keywords appear in user messages. TaskTrigger = auto-inject for specific tasks, may require user input."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"The source path or identifier of the skill. When it is None, it is treated as a programmatically defined skill."},"mcp_tools":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mcp Tools","description":"MCP tools configuration for the skill (repo skills only). It should conform to the MCPConfig schema: https://gofastmcp.com/clients/client#configuration-format"},"inputs":{"items":{"$ref":"#/components/schemas/InputMetadata"},"type":"array","title":"Inputs","description":"Input metadata for the skill (task skills only)"},"is_agentskills_format":{"type":"boolean","title":"Is Agentskills Format","description":"Whether this skill was loaded from a SKILL.md file following the AgentSkills standard. AgentSkills-format skills use progressive disclosure: always listed in with name, description, and location. If the skill also has triggers, content is auto-injected when triggered AND agent can read file anytime.","default":false},"version":{"type":"string","title":"Version","description":"Skill version (AgentSkills standard field).","default":"1.0.0"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A brief description of what the skill does and when to use it. Descriptions exceeding MAX_DESCRIPTION_LENGTH are truncated with a notice pointing to the skill's source path."},"license":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"License","description":"The license under which the skill is distributed. AgentSkills standard field (e.g., 'Apache-2.0', 'MIT')."},"compatibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compatibility","description":"Environment requirements or compatibility notes for the skill. AgentSkills standard field (e.g., 'Requires git and docker')."},"metadata":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Metadata","description":"Arbitrary key-value metadata for the skill. AgentSkills standard field for extensibility."},"allowed_tools":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tools","description":"List of pre-approved tools for this skill. AgentSkills standard field (parsed from space-delimited string)."},"disable_model_invocation":{"type":"boolean","title":"Disable Model Invocation","description":"Whether this skill can only be activated by trigger matching and should not be advertised to the model for direct invocation.","default":false},"resources":{"anyOf":[{"$ref":"#/components/schemas/SkillResources"},{"type":"null"}],"description":"Resource directories for the skill (scripts/, references/, assets/). AgentSkills standard field. Only populated for SKILL.md directory format."}},"type":"object","required":["name","content"],"title":"Skill","description":"A skill provides specialized knowledge or functionality.\n\nSkill behavior depends on format (is_agentskills_format) and trigger:\n\nAgentSkills format (SKILL.md files):\n- Always listed in with name, description, location\n- Agent reads full content on demand (progressive disclosure)\n- If has triggers: content is ALSO auto-injected when triggered\n\nLegacy OpenHands format:\n- With triggers: Listed in , content injected on trigger\n- Without triggers (None): Full content in , always active\n\nThis model supports both OpenHands-specific fields and AgentSkills standard\nfields (https://agentskills.io/specification) for cross-platform compatibility."},"Skill-Output":{"properties":{"name":{"type":"string","title":"Name"},"content":{"type":"string","title":"Content"},"trigger":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/KeywordTrigger"},{"$ref":"#/components/schemas/TaskTrigger"}],"discriminator":{"propertyName":"type","mapping":{"keyword":"#/components/schemas/KeywordTrigger","task":"#/components/schemas/TaskTrigger"}}},{"type":"null"}],"title":"Trigger","description":"Trigger determines when skill content is auto-injected. None = no auto-injection (for AgentSkills: agent reads on demand; for legacy: full content always in system prompt). KeywordTrigger = auto-inject when keywords appear in user messages. TaskTrigger = auto-inject for specific tasks, may require user input."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"The source path or identifier of the skill. When it is None, it is treated as a programmatically defined skill."},"mcp_tools":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mcp Tools","description":"MCP tools configuration for the skill (repo skills only). It should conform to the MCPConfig schema: https://gofastmcp.com/clients/client#configuration-format"},"inputs":{"items":{"$ref":"#/components/schemas/InputMetadata"},"type":"array","title":"Inputs","description":"Input metadata for the skill (task skills only)"},"is_agentskills_format":{"type":"boolean","title":"Is Agentskills Format","description":"Whether this skill was loaded from a SKILL.md file following the AgentSkills standard. AgentSkills-format skills use progressive disclosure: always listed in with name, description, and location. If the skill also has triggers, content is auto-injected when triggered AND agent can read file anytime.","default":false},"version":{"type":"string","title":"Version","description":"Skill version (AgentSkills standard field).","default":"1.0.0"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A brief description of what the skill does and when to use it. Descriptions exceeding MAX_DESCRIPTION_LENGTH are truncated with a notice pointing to the skill's source path."},"license":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"License","description":"The license under which the skill is distributed. AgentSkills standard field (e.g., 'Apache-2.0', 'MIT')."},"compatibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compatibility","description":"Environment requirements or compatibility notes for the skill. AgentSkills standard field (e.g., 'Requires git and docker')."},"metadata":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Metadata","description":"Arbitrary key-value metadata for the skill. AgentSkills standard field for extensibility."},"allowed_tools":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tools","description":"List of pre-approved tools for this skill. AgentSkills standard field (parsed from space-delimited string)."},"disable_model_invocation":{"type":"boolean","title":"Disable Model Invocation","description":"Whether this skill can only be activated by trigger matching and should not be advertised to the model for direct invocation.","default":false},"resources":{"anyOf":[{"$ref":"#/components/schemas/SkillResources"},{"type":"null"}],"description":"Resource directories for the skill (scripts/, references/, assets/). AgentSkills standard field. Only populated for SKILL.md directory format."}},"type":"object","required":["name","content"],"title":"Skill","description":"A skill provides specialized knowledge or functionality.\n\nSkill behavior depends on format (is_agentskills_format) and trigger:\n\nAgentSkills format (SKILL.md files):\n- Always listed in with name, description, location\n- Agent reads full content on demand (progressive disclosure)\n- If has triggers: content is ALSO auto-injected when triggered\n\nLegacy OpenHands format:\n- With triggers: Listed in , content injected on trigger\n- Without triggers (None): Full content in , always active\n\nThis model supports both OpenHands-specific fields and AgentSkills standard\nfields (https://agentskills.io/specification) for cross-platform compatibility."},"SkillInfo":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","enum":["repo","knowledge","agentskills"],"title":"Type"},"content":{"type":"string","title":"Content"},"triggers":{"items":{"type":"string"},"type":"array","title":"Triggers"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_agentskills_format":{"type":"boolean","title":"Is Agentskills Format","default":false},"disable_model_invocation":{"type":"boolean","title":"Disable Model Invocation","default":false}},"type":"object","required":["name","type","content"],"title":"SkillInfo","description":"Skill information returned by the API."},"SkillResources":{"properties":{"skill_root":{"type":"string","title":"Skill Root","description":"Root directory of the skill (absolute path)"},"scripts":{"items":{"type":"string"},"type":"array","title":"Scripts","description":"List of script files in scripts/ directory (relative paths)"},"references":{"items":{"type":"string"},"type":"array","title":"References","description":"List of reference files in references/ directory (relative paths)"},"assets":{"items":{"type":"string"},"type":"array","title":"Assets","description":"List of asset files in assets/ directory (relative paths)"}},"type":"object","required":["skill_root"],"title":"SkillResources","description":"Resource directories for a skill (AgentSkills standard).\n\nPer the AgentSkills specification, skills can include:\n- scripts/: Executable scripts the agent can run\n- references/: Reference documentation and examples\n- assets/: Static assets (images, data files, etc.)"},"SkillsRequest":{"properties":{"load_public":{"type":"boolean","title":"Load Public","description":"Load public skills from OpenHands/extensions repo","default":true},"load_user":{"type":"boolean","title":"Load User","description":"Load user skills from ~/.openhands/skills/","default":true},"load_project":{"type":"boolean","title":"Load Project","description":"Load project skills from workspace","default":true},"load_org":{"type":"boolean","title":"Load Org","description":"Load organization-level skills","default":true},"marketplace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace Path","description":"Relative marketplace JSON path for public skills. Set to null to load all public skills.","default":"marketplaces/default.json"},"project_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Dir","description":"Workspace directory path for project skills"},"org_configs":{"anyOf":[{"items":{"$ref":"#/components/schemas/OrgConfig"},"type":"array"},{"type":"null"}],"title":"Org Configs","description":"Organization/user skill repositories to load concurrently"},"org_config":{"anyOf":[{"$ref":"#/components/schemas/OrgConfig"},{"type":"null"}],"description":"Deprecated since v1.28.0 and scheduled for removal in v1.33.0. Single organization skills configuration; prefer org_configs.","deprecated":true},"sandbox_config":{"anyOf":[{"$ref":"#/components/schemas/SandboxConfig"},{"type":"null"}],"description":"Sandbox skills configuration"}},"type":"object","title":"SkillsRequest","description":"Request body for loading skills."},"SkillsResponse":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/SkillInfo"},"type":"array","title":"Skills"},"sources":{"additionalProperties":{"type":"integer"},"type":"object","title":"Sources","description":"Count of skills loaded from each source"}},"type":"object","required":["skills"],"title":"SkillsResponse","description":"Response containing all available skills."},"StartConversationRequest":{"properties":{"workspace":{"$ref":"#/components/schemas/LocalWorkspace-Input","description":"Working directory for agent operations and tool execution."},"worktree":{"type":"boolean","title":"Worktree","description":"If true and the workspace is already inside a git repository, create a dedicated git worktree for this conversation under `/tmp/conversation-worktrees//`.","default":false},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id","description":"Optional conversation ID. If not provided, a random UUID will be generated."},"confirmation_policy":{"$ref":"#/components/schemas/ConfirmationPolicyBase-Input","description":"Controls when the conversation will prompt the user before continuing. Defaults to never.","default":{"kind":"NeverConfirm"}},"security_analyzer":{"anyOf":[{"$ref":"#/components/schemas/SecurityAnalyzerBase-Input"},{"type":"null"}],"description":"Optional security analyzer to evaluate action risks."},"initial_message":{"anyOf":[{"$ref":"#/components/schemas/SendMessageRequest"},{"type":"null"}],"description":"Initial message to pass to the LLM"},"max_iterations":{"type":"integer","minimum":1.0,"title":"Max Iterations","description":"If set, the max number of iterations the agent will run before stopping. This is useful to prevent infinite loops.","default":500},"stuck_detection":{"type":"boolean","title":"Stuck Detection","description":"If true, the conversation will use stuck detection to prevent infinite loops.","default":true},"secrets":{"additionalProperties":{"$ref":"#/components/schemas/SecretSource-Input"},"type":"object","title":"Secrets","description":"Secrets available in the conversation"},"secrets_encrypted":{"type":"boolean","title":"Secrets Encrypted","description":"If true, indicates that secret values in the agent configuration are cipher-encrypted and should be decrypted by the server before use. This enables secure round-tripping of settings through untrusted clients (e.g., frontend) that received encrypted values via the X-Expose-Secrets header. Flow: client calls GET /api/settings with X-Expose-Secrets: encrypted to receive cipher-encrypted secrets, then passes them in the agent config with secrets_encrypted=True so the server can decrypt them.","default":false},"tool_module_qualnames":{"additionalProperties":{"type":"string"},"type":"object","title":"Tool Module Qualnames","description":"Mapping of tool names to their module qualnames from the client's registry. These modules will be dynamically imported on the server to register the tools for this conversation."},"client_tools":{"items":{"$ref":"#/components/schemas/ClientToolSpec-Input"},"type":"array","title":"Client Tools","description":"Tools defined by the client via JSON spec. These tools have no server-side executor — when the agent calls them, an ActionEvent is emitted over the WebSocket and the client handles execution. The SDK returns an acknowledgment observation immediately."},"agent_definitions":{"items":{"$ref":"#/components/schemas/AgentDefinition"},"type":"array","title":"Agent Definitions","description":"Agent definitions from the client's registry. These are registered on the server so that task tools can see user-registered subagents."},"plugins":{"anyOf":[{"items":{"$ref":"#/components/schemas/PluginSource"},"type":"array"},{"type":"null"}],"title":"Plugins","description":"List of plugins to load for this conversation. Plugins are loaded and their skills/MCP config are merged into the agent. Hooks are extracted and stored for runtime execution."},"hook_config":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Input"},{"type":"null"}],"description":"Optional hook configuration for this conversation. Hooks are shell scripts that run at key lifecycle events (PreToolUse, PostToolUse, UserPromptSubmit, Stop, etc.). If both hook_config and plugins are provided, they are merged with explicit hooks running before plugin hooks."},"tags":{"additionalProperties":{"type":"string"},"type":"object","title":"Tags","description":"Key-value tags for the conversation. Keys must be lowercase alphanumeric. Values are arbitrary strings up to 256 characters."},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"Optional user ID to associate with observability traces. When set, this is passed to Laminar.set_trace_user_id() so traces can be queried by user."},"observability_metadata":{"additionalProperties":{"$ref":"#/components/schemas/TraceMetadataValue"},"type":"object","title":"Observability Metadata","description":"Trace-level metadata to attach to observability backends. Values must be scalars or homogeneous scalar lists supported by OpenTelemetry."},"observability_tags":{"items":{"type":"string"},"type":"array","title":"Observability Tags","description":"Tags to attach to the conversation root observability span."},"autotitle":{"type":"boolean","title":"Autotitle","description":"If true, automatically generate a title for the conversation from the first user message. Precedence: title_llm_profile (if set and loads) → agent.llm → message truncation.","default":true},"title_llm_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title Llm Profile","description":"Optional LLM profile name for title generation. If set, the LLM is loaded from LLMProfileStore (~/.openhands/profiles/) and used for LLM-based title generation. This enables using a fast/cheap model for titles regardless of the agent's main model. If not set (or profile loading fails), title generation falls back to the agent's LLM."},"agent_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Agent Settings","description":"Optional agent settings payload. If `agent` is omitted, this is validated with the AgentSettingsBase `agent_kind` discriminator and used to construct the concrete agent."},"agent_profile_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Agent Profile Id","description":"Optional agent profile ID. When set, the agent-server resolves the referenced profile server-side (stores + cipher are required) and builds the agent from it. Mutually exclusive with `agent` and `agent_settings`. The SDK validator enforces exclusivity only — resolution happens in conversation_service, not here."},"agent":{"$ref":"#/components/schemas/AgentBase-Input"}},"type":"object","required":["workspace"],"title":"StartConversationRequest","description":"Payload to create a new conversation.\n\nSupports any concrete :class:`AgentBase` implementation, including regular\nOpenHands agents and ACP agents. Clients may provide either a concrete\n``agent`` payload or an ``agent_settings`` payload; when ``agent_settings``\nis provided without ``agent``, the settings are validated with the\n``agent_kind`` discriminator and converted to the appropriate agent type."},"StartGoalRequest":{"properties":{"objective":{"type":"string","title":"Objective","description":"The goal objective to pursue and audit."},"max_iterations":{"type":"integer","minimum":1.0,"title":"Max Iterations","description":"Maximum audit rounds before giving up.","default":10}},"type":"object","required":["objective"],"title":"StartGoalRequest","description":"Payload to start a ``/goal`` loop inside a conversation."},"StaticSecret-Input":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"value":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Value"},"kind":{"type":"string","const":"StaticSecret","title":"Kind"}},"type":"object","title":"StaticSecret","description":"A secret stored locally"},"StaticSecret-Output":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"value":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Value"},"kind":{"type":"string","const":"StaticSecret","title":"Kind"}},"type":"object","required":["kind"],"title":"StaticSecret","description":"A secret stored locally"},"StreamingDeltaEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content"},"kind":{"type":"string","const":"StreamingDeltaEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"StreamingDeltaEvent","description":"Transient LLM token delta for real-time WebSocket delivery.\n\nNot persisted to the conversation event log: these events are published\ndirectly to PubSub, bypassing the callback chain that writes to\nConversationState.events. Clients reconnecting mid-stream will receive\nthe final MessageEvent from history but none of the deltas that produced\nit — deltas are a UX affordance, not part of the durable conversation\nrecord."},"SubdirectoryEntry":{"properties":{"name":{"type":"string","title":"Name"},"path":{"type":"string","title":"Path"}},"type":"object","required":["name","path"],"title":"SubdirectoryEntry"},"SubdirectoryPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SubdirectoryEntry"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"SubdirectoryPage"},"SubscriptionDevicePollRequest":{"properties":{"device_code":{"type":"string","title":"Device Code"}},"type":"object","required":["device_code"],"title":"SubscriptionDevicePollRequest","description":"Poll request for a previously-started subscription device login."},"SubscriptionDeviceStartResponse":{"properties":{"device_code":{"type":"string","title":"Device Code","description":"Opaque server-side polling token."},"user_code":{"type":"string","title":"User Code"},"verification_uri":{"type":"string","title":"Verification Uri"},"verification_uri_complete":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verification Uri Complete"},"expires_at":{"type":"integer","title":"Expires At"},"interval_seconds":{"type":"integer","title":"Interval Seconds"}},"type":"object","required":["device_code","user_code","verification_uri","expires_at","interval_seconds"],"title":"SubscriptionDeviceStartResponse","description":"Device-code challenge details for browser sign-in."},"SubscriptionModelsResponse":{"properties":{"vendor":{"type":"string","title":"Vendor","default":"openai"},"models":{"items":{"type":"string"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"SubscriptionModelsResponse","description":"Models available through a subscription provider."},"SubscriptionStatusResponse":{"properties":{"vendor":{"type":"string","title":"Vendor","default":"openai"},"connected":{"type":"boolean","title":"Connected"},"account_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Email"},"expires_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["connected"],"title":"SubscriptionStatusResponse","description":"Safe subscription authentication status."},"Success":{"properties":{"success":{"type":"boolean","title":"Success","default":true}},"type":"object","title":"Success"},"SwitchLLMAction":{"properties":{"profile_name":{"type":"string","title":"Profile Name","description":"Name of the saved LLM profile to use for future agent steps."},"reason":{"type":"string","title":"Reason","description":"Brief reason why this profile is a better fit for the next step."},"kind":{"type":"string","const":"SwitchLLMAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["profile_name","reason","kind"],"title":"SwitchLLMAction","description":"Action for switching this conversation to a saved LLM profile."},"SwitchLLMActionWithRisk":{"properties":{"profile_name":{"type":"string","title":"Profile Name","description":"Name of the saved LLM profile to use for future agent steps."},"reason":{"type":"string","title":"Reason","description":"Brief reason why this profile is a better fit for the next step."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"SwitchLLMActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["profile_name","reason","kind"],"title":"SwitchLLMActionWithRisk"},"SwitchLLMObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"profile_name":{"type":"string","title":"Profile Name","description":"Name of the profile that the tool attempted to activate."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Reason the agent gave for attempting this LLM profile switch."},"active_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Model","description":"Model configured by the activated profile, when available."},"kind":{"type":"string","const":"SwitchLLMObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["profile_name","kind"],"title":"SwitchLLMObservation","description":"Observation returned after switching this conversation's LLM profile."},"SwitchLLMTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"SwitchLLMTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"SwitchLLMTool","description":"Tool for switching a conversation to a saved LLM profile."},"SyncResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status"},"message":{"type":"string","title":"Message"}},"type":"object","required":["status","message"],"title":"SyncResponse","description":"Response from skill sync operation."},"SystemPromptEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"system_prompt":{"$ref":"#/components/schemas/TextContent","description":"The system prompt text"},"tools":{"items":{"$ref":"#/components/schemas/ToolDefinition"},"type":"array","title":"Tools","description":"List of tools as ToolDefinition objects"},"dynamic_context":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"type":"null"}],"description":"Optional dynamic per-conversation context (runtime info, repo context, secrets). When provided, this is included as a second content block in the system message (not cached)."},"kind":{"type":"string","const":"SystemPromptEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["system_prompt","tools","kind"],"title":"SystemPromptEvent","description":"System prompt added by the agent.\n\nThe system prompt can optionally include dynamic context that varies between\nconversations. When ``dynamic_context`` is provided, it is included as a\nsecond content block in the same system message. Cache markers are NOT\napplied here - they are applied by ``LLM._apply_prompt_caching()`` when\ncaching is enabled, ensuring provider-specific cache control is only added\nwhen appropriate.\n\nAttributes:\n system_prompt: The static system prompt text (cacheable across conversations)\n tools: List of available tools\n dynamic_context: Optional per-conversation context (hosts, repo info, etc.)\n Sent as a second TextContent block inside the system message."},"TaskAction":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A short (3-5 word) description of the task."},"prompt":{"type":"string","title":"Prompt","description":"The task for the agent to perform."},"subagent_type":{"type":"string","title":"Subagent Type","description":"The type of specialized agent to use for this task.","default":"general-purpose"},"resume":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resume","description":"Task ID of the task to resume from."},"kind":{"type":"string","const":"TaskAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["prompt","kind"],"title":"TaskAction","description":"Schema for launching a sub-agent task."},"TaskActionWithRisk":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A short (3-5 word) description of the task."},"prompt":{"type":"string","title":"Prompt","description":"The task for the agent to perform."},"subagent_type":{"type":"string","title":"Subagent Type","description":"The type of specialized agent to use for this task.","default":"general-purpose"},"resume":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resume","description":"Task ID of the task to resume from."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"TaskActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["prompt","kind"],"title":"TaskActionWithRisk"},"TaskItem":{"properties":{"title":{"type":"string","title":"Title","description":"A brief title for the task."},"notes":{"type":"string","title":"Notes","description":"Additional details or notes about the task.","default":""},"status":{"type":"string","enum":["todo","in_progress","done"],"title":"Status","description":"The current status of the task. One of 'todo', 'in_progress', or 'done'.","default":"todo"}},"type":"object","required":["title"],"title":"TaskItem"},"TaskObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"task_id":{"type":"string","title":"Task Id","description":"The unique identifier of the task."},"subagent":{"type":"string","title":"Subagent","description":"The subagent of the task."},"status":{"type":"string","title":"Status","description":"The status of the task."},"kind":{"type":"string","const":"TaskObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["task_id","subagent","status","kind"],"title":"TaskObservation","description":"Observation from a task execution."},"TaskTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TaskTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TaskTool","description":"Tool for launching (blocking) sub-agent tasks."},"TaskToolSet":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TaskToolSet","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TaskToolSet","description":"Task tool set.\n\nCreates the Task tool backed by a shared TaskManager.\n\nUsage:\n from openhands.tools.task import TaskToolSet\n\n agent = Agent(\n llm=llm,\n tools=[\n Tool(name=TerminalTool.name),\n Tool(name=FileEditorTool.name),\n Tool(name=TaskToolSet.name),\n ],\n )"},"TaskTrackerAction":{"properties":{"command":{"type":"string","enum":["view","plan"],"title":"Command","description":"The command to execute. `view` shows the current task list. `plan` creates or updates the task list based on provided requirements and progress. Always `view` the current list before making changes.","default":"view"},"task_list":{"items":{"$ref":"#/components/schemas/TaskItem"},"type":"array","title":"Task List","description":"The full task list. Required parameter of `plan` command."},"kind":{"type":"string","const":"TaskTrackerAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"TaskTrackerAction","description":"An action where the agent writes or updates a task list for task management."},"TaskTrackerActionWithRisk":{"properties":{"command":{"type":"string","enum":["view","plan"],"title":"Command","description":"The command to execute. `view` shows the current task list. `plan` creates or updates the task list based on provided requirements and progress. Always `view` the current list before making changes.","default":"view"},"task_list":{"items":{"$ref":"#/components/schemas/TaskItem"},"type":"array","title":"Task List","description":"The full task list. Required parameter of `plan` command."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"TaskTrackerActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"TaskTrackerActionWithRisk"},"TaskTrackerObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["view","plan"],"title":"Command","description":"The command that was executed: \"view\" or \"plan\"."},"task_list":{"items":{"$ref":"#/components/schemas/TaskItem"},"type":"array","title":"Task List","description":"The current task list"},"kind":{"type":"string","const":"TaskTrackerObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TaskTrackerObservation","description":"This data class represents the result of a task tracking operation."},"TaskTrackerTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TaskTrackerTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TaskTrackerTool","description":"A ToolDefinition subclass that automatically initializes a TaskTrackerExecutor."},"TaskTrigger":{"properties":{"type":{"type":"string","const":"task","title":"Type","default":"task"},"triggers":{"items":{"type":"string"},"type":"array","title":"Triggers"}},"type":"object","required":["triggers"],"title":"TaskTrigger","description":"Trigger for task-specific skills.\n\nThese skills are activated for specific task types and can modify prompts."},"TerminalAction":{"properties":{"command":{"type":"string","title":"Command","description":"The shell command to execute. Can be empty string to view additional logs when the previous exit code is `-1`. Can be a special key name when `is_input` is True: `C-c` (Ctrl+C), `C-d` (Ctrl+D/EOF), `C-z` (Ctrl+Z), or any `C-` for Ctrl sequences; navigation keys `UP`, `DOWN`, `LEFT`, `RIGHT`, `HOME`, `END`, `PGUP`, `PGDN`; and `TAB`, `ESC`, `BS` (Backspace), `ENTER`. You can only execute one command at a time. Use the platform-appropriate shell syntax described in the tool description when chaining commands."},"is_input":{"type":"boolean","title":"Is Input","description":"If True, the command is an input to the running process. If False, the command is executed in the terminal session. Default is False.","default":false},"timeout":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"Optional. Sets a maximum time limit (in seconds) for running the command. If the command takes longer than this limit, you’ll be asked whether to continue or stop it. If you don’t set a value, the command will instead pause and ask for confirmation when it produces no new output for 30 seconds. Use a higher value if the command is expected to take a long time (like installation or testing), or if it has a known fixed duration (like sleep)."},"reset":{"type":"boolean","title":"Reset","description":"If True, reset the terminal by creating a new session. Use this only when the terminal becomes unresponsive. Note that all previously set environment variables and session state will be lost after reset. Cannot be used with is_input=True.","default":false},"kind":{"type":"string","const":"TerminalAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TerminalAction","description":"Schema for terminal command execution."},"TerminalActionWithRisk":{"properties":{"command":{"type":"string","title":"Command","description":"The shell command to execute. Can be empty string to view additional logs when the previous exit code is `-1`. Can be a special key name when `is_input` is True: `C-c` (Ctrl+C), `C-d` (Ctrl+D/EOF), `C-z` (Ctrl+Z), or any `C-` for Ctrl sequences; navigation keys `UP`, `DOWN`, `LEFT`, `RIGHT`, `HOME`, `END`, `PGUP`, `PGDN`; and `TAB`, `ESC`, `BS` (Backspace), `ENTER`. You can only execute one command at a time. Use the platform-appropriate shell syntax described in the tool description when chaining commands."},"is_input":{"type":"boolean","title":"Is Input","description":"If True, the command is an input to the running process. If False, the command is executed in the terminal session. Default is False.","default":false},"timeout":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"Optional. Sets a maximum time limit (in seconds) for running the command. If the command takes longer than this limit, you’ll be asked whether to continue or stop it. If you don’t set a value, the command will instead pause and ask for confirmation when it produces no new output for 30 seconds. Use a higher value if the command is expected to take a long time (like installation or testing), or if it has a known fixed duration (like sleep)."},"reset":{"type":"boolean","title":"Reset","description":"If True, reset the terminal by creating a new session. Use this only when the terminal becomes unresponsive. Note that all previously set environment variables and session state will be lost after reset. Cannot be used with is_input=True.","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"TerminalActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TerminalActionWithRisk"},"TerminalObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command","description":"The shell command that was executed. Can be empty string if the observation is from a previous command that hit soft timeout and is not yet finished."},"exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exit Code","description":"The exit code of the command. -1 indicates the process hit the soft timeout and is not yet finished."},"timeout":{"type":"boolean","title":"Timeout","description":"Whether the command execution timed out.","default":false},"metadata":{"$ref":"#/components/schemas/CmdOutputMetadata","description":"Additional metadata captured from PS1 after command execution."},"full_output_save_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Output Save Dir","description":"Directory where full output files are saved"},"kind":{"type":"string","const":"TerminalObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TerminalObservation","description":"A ToolResult that can be rendered as a CLI output."},"TerminalTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TerminalTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TerminalTool","description":"A ToolDefinition subclass that automatically initializes a TerminalExecutor with auto-detection."},"TextContent":{"properties":{"cache_prompt":{"type":"boolean","title":"Cache Prompt","default":false},"type":{"type":"string","const":"text","title":"Type","default":"text"},"text":{"type":"string","title":"Text"}},"additionalProperties":false,"type":"object","required":["text"],"title":"TextContent"},"ThinkAction":{"properties":{"thought":{"type":"string","title":"Thought","description":"The thought to log."},"kind":{"type":"string","const":"ThinkAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["thought","kind"],"title":"ThinkAction","description":"Action for logging a thought without making any changes."},"ThinkActionWithRisk":{"properties":{"thought":{"type":"string","title":"Thought","description":"The thought to log."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"ThinkActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["thought","kind"],"title":"ThinkActionWithRisk"},"ThinkObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"kind":{"type":"string","const":"ThinkObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ThinkObservation","description":"Observation returned after logging a thought.\nThe ThinkAction itself contains the thought logged so no extra\nfields are needed here."},"ThinkTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"ThinkTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"ThinkTool","description":"Tool for logging thoughts without making changes."},"ThinkingBlock":{"properties":{"type":{"type":"string","const":"thinking","title":"Type","default":"thinking"},"thinking":{"type":"string","title":"Thinking","description":"The thinking content"},"signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signature","description":"Cryptographic signature for the thinking block"}},"type":"object","required":["thinking"],"title":"ThinkingBlock","description":"Anthropic thinking block for extended thinking feature.\n\nThis represents the raw thinking blocks returned by Anthropic models\nwhen extended thinking is enabled. These blocks must be preserved\nand passed back to the API for tool use scenarios."},"TokenEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source"},"prompt_token_ids":{"items":{"type":"integer"},"type":"array","title":"Prompt Token Ids","description":"The exact prompt token IDs for this message event"},"response_token_ids":{"items":{"type":"integer"},"type":"array","title":"Response Token Ids","description":"The exact response token IDs for this message event"},"kind":{"type":"string","const":"TokenEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","prompt_token_ids","response_token_ids","kind"],"title":"TokenEvent","description":"Event from VLLM representing token IDs used in LLM interaction."},"TokenUsage":{"properties":{"model":{"type":"string","title":"Model","default":""},"prompt_tokens":{"type":"integer","minimum":0.0,"title":"Prompt Tokens","description":"Prompt tokens must be non-negative","default":0},"completion_tokens":{"type":"integer","minimum":0.0,"title":"Completion Tokens","description":"Completion tokens must be non-negative","default":0},"cache_read_tokens":{"type":"integer","minimum":0.0,"title":"Cache Read Tokens","description":"Cache read tokens must be non-negative","default":0},"cache_write_tokens":{"type":"integer","minimum":0.0,"title":"Cache Write Tokens","description":"Cache write tokens must be non-negative","default":0},"reasoning_tokens":{"type":"integer","minimum":0.0,"title":"Reasoning Tokens","description":"Reasoning tokens must be non-negative","default":0},"context_window":{"type":"integer","minimum":0.0,"title":"Context Window","description":"Context window must be non-negative","default":0},"per_turn_token":{"type":"integer","minimum":0.0,"title":"Per Turn Token","description":"Per turn tokens must be non-negative","default":0},"response_id":{"type":"string","title":"Response Id","default":""}},"type":"object","title":"TokenUsage","description":"Metric tracking detailed token usage per completion call."},"Tool-Input":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the tool class, e.g., 'TerminalTool'. Import it from an `openhands.tools.` subpackage.","examples":["TerminalTool","FileEditorTool","TaskTrackerTool"]},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"Parameters for the tool's .create() method, e.g., {'working_dir': '/app'}","examples":[{"working_dir":"/workspace"}]}},"type":"object","required":["name"],"title":"Tool","description":"Defines a tool to be initialized for the agent.\n\nThis is only used in agent-sdk for type schema for server use."},"ToolAnnotations-Input":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"A human-readable title for the tool."},"readOnlyHint":{"type":"boolean","title":"Readonlyhint","description":"If true, the tool does not modify its environment. Default: false","default":false},"destructiveHint":{"type":"boolean","title":"Destructivehint","description":"If true, the tool may perform destructive updates to its environment. If false, the tool performs only additive updates. (This property is meaningful only when `readOnlyHint == false`) Default: true","default":true},"idempotentHint":{"type":"boolean","title":"Idempotenthint","description":"If true, calling the tool repeatedly with the same arguments will have no additional effect on the its environment. (This property is meaningful only when `readOnlyHint == false`) Default: false","default":false},"openWorldHint":{"type":"boolean","title":"Openworldhint","description":"If true, this tool may interact with an 'open world' of external entities. If false, the tool's domain of interaction is closed. For example, the world of a web search tool is open, whereas that of a memory tool is not. Default: true","default":true}},"type":"object","title":"openhands.sdk.tool.tool.ToolAnnotations","description":"Annotations to provide hints about the tool's behavior.\n\nBased on Model Context Protocol (MCP) spec:\nhttps://github.com/modelcontextprotocol/modelcontextprotocol/blob/caf3424488b10b4a7b1f8cb634244a450a1f4400/schema/2025-06-18/schema.ts#L838"},"ToolDefinition":{"oneOf":[{"$ref":"#/components/schemas/MCPToolDefinition"},{"$ref":"#/components/schemas/FinishTool"},{"$ref":"#/components/schemas/InvokeSkillTool"},{"$ref":"#/components/schemas/SwitchLLMTool"},{"$ref":"#/components/schemas/ThinkTool"},{"$ref":"#/components/schemas/ClientTool"},{"$ref":"#/components/schemas/BrowserClickTool"},{"$ref":"#/components/schemas/BrowserCloseTabTool"},{"$ref":"#/components/schemas/BrowserGetContentTool"},{"$ref":"#/components/schemas/BrowserGetStateTool"},{"$ref":"#/components/schemas/BrowserGetStorageTool"},{"$ref":"#/components/schemas/BrowserGoBackTool"},{"$ref":"#/components/schemas/BrowserListTabsTool"},{"$ref":"#/components/schemas/BrowserNavigateTool"},{"$ref":"#/components/schemas/BrowserScrollTool"},{"$ref":"#/components/schemas/BrowserSetStorageTool"},{"$ref":"#/components/schemas/BrowserStartRecordingTool"},{"$ref":"#/components/schemas/BrowserStopRecordingTool"},{"$ref":"#/components/schemas/BrowserSwitchTabTool"},{"$ref":"#/components/schemas/BrowserToolSet"},{"$ref":"#/components/schemas/BrowserTypeTool"},{"$ref":"#/components/schemas/FileEditorTool"},{"$ref":"#/components/schemas/EditTool"},{"$ref":"#/components/schemas/ListDirectoryTool"},{"$ref":"#/components/schemas/ReadFileTool"},{"$ref":"#/components/schemas/WriteFileTool"},{"$ref":"#/components/schemas/GlobTool"},{"$ref":"#/components/schemas/GrepTool"},{"$ref":"#/components/schemas/PlanningFileEditorTool"},{"$ref":"#/components/schemas/TaskTool"},{"$ref":"#/components/schemas/TaskToolSet"},{"$ref":"#/components/schemas/TaskTrackerTool"},{"$ref":"#/components/schemas/TerminalTool"},{"$ref":"#/components/schemas/WorkflowTool"},{"$ref":"#/components/schemas/WorkflowToolSet"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__mcp__tool__MCPToolDefinition-Output__1":"#/components/schemas/MCPToolDefinition","openhands__sdk__tool__builtins__finish__FinishTool-Output__1":"#/components/schemas/FinishTool","openhands__sdk__tool__builtins__invoke_skill__InvokeSkillTool-Output__1":"#/components/schemas/InvokeSkillTool","openhands__sdk__tool__builtins__switch_llm__SwitchLLMTool-Output__1":"#/components/schemas/SwitchLLMTool","openhands__sdk__tool__builtins__think__ThinkTool-Output__1":"#/components/schemas/ThinkTool","openhands__sdk__tool__client_tool__ClientTool-Output__1":"#/components/schemas/ClientTool","openhands__tools__browser_use__definition__BrowserClickTool-Output__1":"#/components/schemas/BrowserClickTool","openhands__tools__browser_use__definition__BrowserCloseTabTool-Output__1":"#/components/schemas/BrowserCloseTabTool","openhands__tools__browser_use__definition__BrowserGetContentTool-Output__1":"#/components/schemas/BrowserGetContentTool","openhands__tools__browser_use__definition__BrowserGetStateTool-Output__1":"#/components/schemas/BrowserGetStateTool","openhands__tools__browser_use__definition__BrowserGetStorageTool-Output__1":"#/components/schemas/BrowserGetStorageTool","openhands__tools__browser_use__definition__BrowserGoBackTool-Output__1":"#/components/schemas/BrowserGoBackTool","openhands__tools__browser_use__definition__BrowserListTabsTool-Output__1":"#/components/schemas/BrowserListTabsTool","openhands__tools__browser_use__definition__BrowserNavigateTool-Output__1":"#/components/schemas/BrowserNavigateTool","openhands__tools__browser_use__definition__BrowserScrollTool-Output__1":"#/components/schemas/BrowserScrollTool","openhands__tools__browser_use__definition__BrowserSetStorageTool-Output__1":"#/components/schemas/BrowserSetStorageTool","openhands__tools__browser_use__definition__BrowserStartRecordingTool-Output__1":"#/components/schemas/BrowserStartRecordingTool","openhands__tools__browser_use__definition__BrowserStopRecordingTool-Output__1":"#/components/schemas/BrowserStopRecordingTool","openhands__tools__browser_use__definition__BrowserSwitchTabTool-Output__1":"#/components/schemas/BrowserSwitchTabTool","openhands__tools__browser_use__definition__BrowserToolSet-Output__1":"#/components/schemas/BrowserToolSet","openhands__tools__browser_use__definition__BrowserTypeTool-Output__1":"#/components/schemas/BrowserTypeTool","openhands__tools__file_editor__definition__FileEditorTool-Output__1":"#/components/schemas/FileEditorTool","openhands__tools__gemini__edit__definition__EditTool-Output__1":"#/components/schemas/EditTool","openhands__tools__gemini__list_directory__definition__ListDirectoryTool-Output__1":"#/components/schemas/ListDirectoryTool","openhands__tools__gemini__read_file__definition__ReadFileTool-Output__1":"#/components/schemas/ReadFileTool","openhands__tools__gemini__write_file__definition__WriteFileTool-Output__1":"#/components/schemas/WriteFileTool","openhands__tools__glob__definition__GlobTool-Output__1":"#/components/schemas/GlobTool","openhands__tools__grep__definition__GrepTool-Output__1":"#/components/schemas/GrepTool","openhands__tools__planning_file_editor__definition__PlanningFileEditorTool-Output__1":"#/components/schemas/PlanningFileEditorTool","openhands__tools__task__definition__TaskTool-Output__1":"#/components/schemas/TaskTool","openhands__tools__task__definition__TaskToolSet-Output__1":"#/components/schemas/TaskToolSet","openhands__tools__task_tracker__definition__TaskTrackerTool-Output__1":"#/components/schemas/TaskTrackerTool","openhands__tools__terminal__definition__TerminalTool-Output__1":"#/components/schemas/TerminalTool","openhands__tools__workflow__definition__WorkflowTool-Output__1":"#/components/schemas/WorkflowTool","openhands__tools__workflow__definition__WorkflowToolSet-Output__1":"#/components/schemas/WorkflowToolSet"}}},"ToolExecution":{"properties":{"taskSupport":{"anyOf":[{"type":"string","enum":["forbidden","optional","required"]},{"type":"null"}],"title":"Tasksupport"}},"additionalProperties":true,"type":"object","title":"ToolExecution","description":"Execution-related properties for a tool."},"TopLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"}},"additionalProperties":true,"type":"object","required":["token","logprob"],"title":"TopLogprob"},"TraceMetadataValue":{"anyOf":[{"type":"string"},{"type":"boolean"},{"type":"integer"},{"type":"number"},{"items":{"type":"string"},"type":"array"},{"items":{"type":"boolean"},"type":"array"},{"items":{"type":"integer"},"type":"array"},{"items":{"type":"number"},"type":"array"}]},"UninstallSkillResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"UninstallSkillResponse","description":"Response from skill uninstall operation."},"UpdateConversationRequest":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Title","description":"New conversation title"},"tags":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tags","description":"Key-value tags to set on the conversation. Keys must be lowercase alphanumeric. Values are arbitrary strings up to 256 characters. Replaces all existing tags when provided."}},"type":"object","title":"UpdateConversationRequest","description":"Payload to update conversation metadata."},"UpdateSecretsRequest":{"properties":{"secrets":{"additionalProperties":{"$ref":"#/components/schemas/SecretSource-Input"},"type":"object","title":"Secrets","description":"Dictionary mapping secret keys to values"}},"type":"object","required":["secrets"],"title":"UpdateSecretsRequest","description":"Payload to update secrets in a conversation."},"UpdateSkillResponse":{"properties":{"message":{"type":"string","title":"Message"},"skill":{"$ref":"#/components/schemas/InstalledSkillResponse"}},"type":"object","required":["message","skill"],"title":"UpdateSkillResponse","description":"Response from skill update operation."},"UpdateSkillStateRequest":{"properties":{"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["enabled"],"title":"UpdateSkillStateRequest","description":"Request body for updating skill state (enable/disable)."},"UpdateSkillStateResponse":{"properties":{"name":{"type":"string","title":"Name"},"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["name","enabled"],"title":"UpdateSkillStateResponse","description":"Response from skill state update operation."},"UserRejectObservation":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"tool_name":{"type":"string","title":"Tool Name","description":"The tool name that this observation is responding to"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The tool call id that this observation is responding to"},"rejection_reason":{"type":"string","title":"Rejection Reason","description":"Reason for rejecting the action","default":"User rejected the action"},"rejection_source":{"type":"string","enum":["user","hook"],"title":"Rejection Source","description":"Source of the rejection: 'user' for confirmation mode rejections, 'hook' for PreToolUse hook blocks","default":"user"},"action_id":{"type":"string","title":"Action Id","description":"The action id that this observation is responding to"},"kind":{"type":"string","const":"UserRejectObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","tool_call_id","action_id","kind"],"title":"UserRejectObservation","description":"Observation when an action is rejected by user or hook.\n\nThis event is emitted when:\n- User rejects an action during confirmation mode (rejection_source=\"user\")\n- A PreToolUse hook blocks an action (rejection_source=\"hook\")"},"VSCodeUrlResponse":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"}},"type":"object","required":["url"],"title":"VSCodeUrlResponse","description":"Response model for VSCode URL."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifiedModelsResponse":{"properties":{"models":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Models"}},"type":"object","required":["models"],"title":"VerifiedModelsResponse","description":"Response containing verified LLM models organized by provider."},"WebhookSpec":{"properties":{"event_buffer_size":{"type":"integer","minimum":1.0,"title":"Event Buffer Size","description":"The number of events to buffer locally before posting to the webhook","default":5},"base_url":{"type":"string","title":"Base Url","description":"The base URL of the webhook service. Events will be sent to {base_url}/events and conversation info to {base_url}/conversations"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"flush_delay":{"type":"number","exclusiveMinimum":0.0,"title":"Flush Delay","description":"The delay in seconds after which buffered events will be flushed to the webhook, even if the buffer is not full. Timer is reset on each new event.","default":30.0},"num_retries":{"type":"integer","minimum":0.0,"title":"Num Retries","description":"The number of times to retry if the post operation fails","default":3},"retry_delay":{"type":"integer","minimum":0.0,"title":"Retry Delay","description":"The delay between retries","default":5},"max_queue_size":{"type":"integer","minimum":1.0,"title":"Max Queue Size","description":"Upper bound on the number of events buffered for delivery. When the downstream is failing and events are re-queued for retry, the oldest events are dropped past this bound to prevent unbounded memory growth.","default":1000}},"type":"object","required":["base_url"],"title":"WebhookSpec","description":"Spec to create a webhook. All webhook requests use POST method."},"WorkflowAction":{"properties":{"name":{"type":"string","title":"Name","description":"A short name for this workflow run."},"script":{"type":"string","title":"Script","description":"Python workflow script to run. It must define `async def main(wf):` and coordinate work only through the provided `wf` object."},"max_concurrency":{"type":"integer","maximum":64.0,"minimum":1.0,"title":"Max Concurrency","description":"Maximum number of sub-agent tasks to run concurrently. Consider 2–4 for LLM-heavy workflows to avoid hitting API rate limits.","default":8},"kind":{"type":"string","const":"WorkflowAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","script","kind"],"title":"WorkflowAction","description":"Schema for running a Python dynamic workflow script."},"WorkflowActionWithRisk":{"properties":{"name":{"type":"string","title":"Name","description":"A short name for this workflow run."},"script":{"type":"string","title":"Script","description":"Python workflow script to run. It must define `async def main(wf):` and coordinate work only through the provided `wf` object."},"max_concurrency":{"type":"integer","maximum":64.0,"minimum":1.0,"title":"Max Concurrency","description":"Maximum number of sub-agent tasks to run concurrently. Consider 2–4 for LLM-heavy workflows to avoid hitting API rate limits.","default":8},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"WorkflowActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","script","kind"],"title":"WorkflowActionWithRisk"},"WorkflowObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"name":{"type":"string","title":"Name","description":"The workflow name that was executed."},"status":{"type":"string","enum":["completed","error"],"title":"Status","description":"The workflow execution status."},"kind":{"type":"string","const":"WorkflowObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","status","kind"],"title":"WorkflowObservation","description":"Observation from a dynamic workflow run."},"WorkflowTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"WorkflowTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"WorkflowTool","description":"Low-level tool for explicit executor injection.\n\nPrefer ``WorkflowToolSet`` for standard SDK auto-create usage.\nUse ``WorkflowTool`` when you need to inject a custom executor\n(e.g., in tests or extensions)."},"WorkflowToolSet":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"WorkflowToolSet","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"WorkflowToolSet","description":"Tool set that creates the dynamic workflow tool."},"WorkspaceItem":{"properties":{"id":{"type":"string","maxLength":4096,"minLength":1,"title":"Id"},"name":{"type":"string","maxLength":256,"minLength":1,"title":"Name"},"path":{"type":"string","maxLength":4096,"minLength":1,"title":"Path"},"parentPath":{"anyOf":[{"type":"string","maxLength":4096},{"type":"null"}],"title":"Parentpath"}},"type":"object","required":["id","name","path"],"title":"WorkspaceItem"},"WorkspaceParentItem":{"properties":{"id":{"type":"string","maxLength":4096,"minLength":1,"title":"Id"},"name":{"type":"string","maxLength":256,"minLength":1,"title":"Name"},"path":{"type":"string","maxLength":4096,"minLength":1,"title":"Path"}},"type":"object","required":["id","name","path"],"title":"WorkspaceParentItem"},"WorkspacesListResponse":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/WorkspaceItem"},"type":"array","title":"Workspaces"},"workspaceParents":{"items":{"$ref":"#/components/schemas/WorkspaceParentItem"},"type":"array","title":"Workspaceparents"}},"type":"object","title":"WorkspacesListResponse"},"WriteFileAction":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to write to."},"content":{"type":"string","title":"Content","description":"The content to write to the file."},"kind":{"type":"string","const":"WriteFileAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","content","kind"],"title":"WriteFileAction","description":"Schema for write file operation."},"WriteFileActionWithRisk":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to write to."},"content":{"type":"string","title":"Content","description":"The content to write to the file."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"WriteFileActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","content","kind"],"title":"WriteFileActionWithRisk"},"WriteFileObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path","description":"The file path that was written."},"is_new_file":{"type":"boolean","title":"Is New File","description":"Whether a new file was created.","default":false},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The previous content of the file (if it existed)."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The new content written to the file."},"kind":{"type":"string","const":"WriteFileObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"WriteFileObservation","description":"Observation from writing a file."},"WriteFileTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"WriteFileTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"WriteFileTool","description":"Tool for writing complete file contents."},"_RemoteMCPServerSpec":{"properties":{"type":{"type":"string","enum":["http","shttp","streamable-http","sse"],"title":"Type"},"url":{"type":"string","minLength":1,"title":"Url"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"Bearer token. If provided, sent as 'Authorization: Bearer '."}},"type":"object","required":["type","url"],"title":"_RemoteMCPServerSpec","description":"Remote (HTTP / SSE) MCP server spec."},"_StdioMCPServerSpec":{"properties":{"type":{"type":"string","const":"stdio","title":"Type","default":"stdio"},"command":{"type":"string","minLength":1,"title":"Command","description":"Executable to invoke"},"args":{"items":{"type":"string"},"type":"array","title":"Args"},"env":{"additionalProperties":{"type":"string"},"type":"object","title":"Env"},"cwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd"}},"type":"object","required":["command"],"title":"_StdioMCPServerSpec","description":"Stdio (subprocess) MCP server spec.\n\nMirrors the subset of ``fastmcp.mcp_config.StdioMCPServer`` fields the\nOpenHands UI exposes today."},"mcp__types__Tool":{"properties":{"name":{"type":"string","title":"Name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"inputSchema":{"additionalProperties":true,"type":"object","title":"Inputschema"},"outputSchema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Outputschema"},"icons":{"anyOf":[{"items":{"$ref":"#/components/schemas/Icon"},"type":"array"},{"type":"null"}],"title":"Icons"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/mcp__types__ToolAnnotations"},{"type":"null"}]},"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"execution":{"anyOf":[{"$ref":"#/components/schemas/ToolExecution"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["name","inputSchema"],"title":"Tool","description":"Definition for a tool the client can call."},"mcp__types__ToolAnnotations":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"readOnlyHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Readonlyhint"},"destructiveHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Destructivehint"},"idempotentHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Idempotenthint"},"openWorldHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Openworldhint"}},"additionalProperties":true,"type":"object","title":"ToolAnnotations","description":"Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**.\nThey are not guaranteed to provide a faithful description of\ntool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations\nreceived from untrusted servers."},"openhands__sdk__tool__spec__Tool":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the tool class, e.g., 'TerminalTool'. Import it from an `openhands.tools.` subpackage.","examples":["TerminalTool","FileEditorTool","TaskTrackerTool"]},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"Parameters for the tool's .create() method, e.g., {'working_dir': '/app'}","examples":[{"working_dir":"/workspace"}]}},"type":"object","required":["name"],"title":"Tool","description":"Defines a tool to be initialized for the agent.\n\nThis is only used in agent-sdk for type schema for server use."},"openhands__sdk__tool__tool__ToolAnnotations":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"A human-readable title for the tool."},"readOnlyHint":{"type":"boolean","title":"Readonlyhint","description":"If true, the tool does not modify its environment. Default: false","default":false},"destructiveHint":{"type":"boolean","title":"Destructivehint","description":"If true, the tool may perform destructive updates to its environment. If false, the tool performs only additive updates. (This property is meaningful only when `readOnlyHint == false`) Default: true","default":true},"idempotentHint":{"type":"boolean","title":"Idempotenthint","description":"If true, calling the tool repeatedly with the same arguments will have no additional effect on the its environment. (This property is meaningful only when `readOnlyHint == false`) Default: false","default":false},"openWorldHint":{"type":"boolean","title":"Openworldhint","description":"If true, this tool may interact with an 'open world' of external entities. If false, the tool's domain of interaction is closed. For example, the world of a web search tool is open, whereas that of a memory tool is not. Default: true","default":true}},"type":"object","title":"openhands.sdk.tool.tool.ToolAnnotations","description":"Annotations to provide hints about the tool's behavior.\n\nBased on Model Context Protocol (MCP) spec:\nhttps://github.com/modelcontextprotocol/modelcontextprotocol/blob/caf3424488b10b4a7b1f8cb634244a450a1f4400/schema/2025-06-18/schema.ts#L838"}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-Init-API-Key"}}}} \ No newline at end of file From 29ec6762aa71d5c2bdc2ddc28fb0a035ba546dd8 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 08:52:19 +0200 Subject: [PATCH 02/12] ci: move endpoint audit to its own workflow Run the endpoint audit as a standalone Endpoint Audit workflow on push and pull_request (main/develop) instead of as a gate inside the release job. Releases no longer depend on the audit. --- .github/workflows/endpoint-audit.yml | 54 ++++++++++++++++++++++++++++ .github/workflows/release.yml | 48 ------------------------- 2 files changed, 54 insertions(+), 48 deletions(-) create mode 100644 .github/workflows/endpoint-audit.yml diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml new file mode 100644 index 0000000..c3e98fd --- /dev/null +++ b/.github/workflows/endpoint-audit.yml @@ -0,0 +1,54 @@ +name: Endpoint Audit + +on: + push: + branches: [ main, develop ] + pull_request: + branches: [ main, develop ] + +jobs: + # Verify the client doesn't call endpoints the agent-server no longer exposes. + # The audit diffs the client's HTTP surface against the live server's OpenAPI + # spec. See scripts/endpoint-audit.mjs. + endpoint-audit: + runs-on: ubuntu-latest + timeout-minutes: 15 + env: + AGENT_SERVER_PORT: 8010 + AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:1.29.0-python + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Use Node.js 20.x + uses: actions/setup-node@v4 + with: + node-version: 20.x + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Start agent-server (ground-truth OpenAPI spec) + run: | + docker pull "${AGENT_SERVER_IMAGE}" + docker run -d --name agent-server -p ${AGENT_SERVER_PORT}:8000 \ + -e LOG_JSON=true "${AGENT_SERVER_IMAGE}" + for i in $(seq 1 30); do + curl -sf http://localhost:${AGENT_SERVER_PORT}/health && break + echo "waiting for agent-server ($i)..."; sleep 2 + done + + - name: Endpoint audit (gates on client/server mismatch) + run: npm run audit:endpoints + + - name: Upload audit report + if: always() + uses: actions/upload-artifact@v4 + with: + name: endpoint-audit + path: .audit/ + + - name: Stop agent-server + if: always() + run: docker rm -f agent-server || true diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3c82912..ca78b6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,56 +10,8 @@ permissions: packages: write jobs: - # Gate the release on the endpoint audit: the client must not call endpoints - # the released agent-server no longer exposes. The audit diffs the client's - # HTTP surface against the live server's OpenAPI spec. See - # scripts/endpoint-audit.mjs. - endpoint-audit: - runs-on: ubuntu-latest - timeout-minutes: 15 - env: - AGENT_SERVER_PORT: 8010 - AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:1.29.0-python - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Use Node.js 20.x - uses: actions/setup-node@v4 - with: - node-version: 20.x - cache: 'npm' - - - name: Install dependencies - run: npm ci - - - name: Start agent-server (ground-truth OpenAPI spec) - run: | - docker pull "${AGENT_SERVER_IMAGE}" - docker run -d --name agent-server -p ${AGENT_SERVER_PORT}:8000 \ - -e LOG_JSON=true "${AGENT_SERVER_IMAGE}" - for i in $(seq 1 30); do - curl -sf http://localhost:${AGENT_SERVER_PORT}/health && break - echo "waiting for agent-server ($i)..."; sleep 2 - done - - - name: Endpoint audit (gates on client/server mismatch) - run: npm run audit:endpoints - - - name: Upload audit report - if: always() - uses: actions/upload-artifact@v4 - with: - name: endpoint-audit - path: .audit/ - - - name: Stop agent-server - if: always() - run: docker rm -f agent-server || true - release: runs-on: ubuntu-latest - needs: endpoint-audit steps: - name: Checkout code From 6b24037af167324a8ab656333c660ebbf70b3b97 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 08:54:20 +0200 Subject: [PATCH 03/12] ci: run endpoint audit on all PRs, push to main only Drop the pull_request branch filter so the audit runs on every PR regardless of target branch, and push only on main (no develop branch). --- .github/workflows/endpoint-audit.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index c3e98fd..4fdd6c7 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -2,9 +2,8 @@ name: Endpoint Audit on: push: - branches: [ main, develop ] + branches: [ main ] pull_request: - branches: [ main, develop ] jobs: # Verify the client doesn't call endpoints the agent-server no longer exposes. From b9cc254ea91e7771f194060776c9f8cc688f1dc8 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 09:01:07 +0200 Subject: [PATCH 04/12] ci: read agent-server image from package.json instead of hardcoding Define the agent-server image once in package.json (config.agentServerImage) and have the endpoint-audit and integration-tests workflows resolve it at runtime into $GITHUB_ENV. Bumping the pinned version is now a single edit. Update README.md and AGENTS.md to point at package.json as the canonical pin. --- .github/workflows/endpoint-audit.yml | 5 ++++- .github/workflows/integration-tests.yml | 9 ++++++++- AGENTS.md | 5 +++-- README.md | 3 ++- package.json | 3 +++ 5 files changed, 20 insertions(+), 5 deletions(-) diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index 4fdd6c7..ba34fd8 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -14,7 +14,6 @@ jobs: timeout-minutes: 15 env: AGENT_SERVER_PORT: 8010 - AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:1.29.0-python steps: - name: Checkout code uses: actions/checkout@v4 @@ -28,6 +27,10 @@ jobs: - name: Install dependencies run: npm ci + # Single source of truth: package.json's config.agentServerImage. + - name: Resolve agent-server image + run: echo "AGENT_SERVER_IMAGE=$(node -p "require('./package.json').config.agentServerImage")" >> "$GITHUB_ENV" + - name: Start agent-server (ground-truth OpenAPI spec) run: | docker pull "${AGENT_SERVER_IMAGE}" diff --git a/.github/workflows/integration-tests.yml b/.github/workflows/integration-tests.yml index e3b0541..e16ab31 100644 --- a/.github/workflows/integration-tests.yml +++ b/.github/workflows/integration-tests.yml @@ -16,7 +16,6 @@ env: AGENT_SERVER_PORT: 8010 HOST_WORKSPACE_DIR: /tmp/agent-workspace AGENT_WORKSPACE_DIR: /workspace - AGENT_SERVER_IMAGE: ghcr.io/openhands/agent-server:1.29.0-python jobs: integration-test: @@ -36,6 +35,10 @@ jobs: - name: Install dependencies run: npm ci + # Single source of truth: package.json's config.agentServerImage. + - name: Resolve agent-server image + run: echo "AGENT_SERVER_IMAGE=$(node -p "require('./package.json').config.agentServerImage")" >> "$GITHUB_ENV" + - name: Build package run: npm run build @@ -162,6 +165,10 @@ jobs: - name: Install dependencies run: npm ci + # Single source of truth: package.json's config.agentServerImage. + - name: Resolve agent-server image + run: echo "AGENT_SERVER_IMAGE=$(node -p "require('./package.json').config.agentServerImage")" >> "$GITHUB_ENV" + - name: Build package run: npm run build diff --git a/AGENTS.md b/AGENTS.md index 4321006..9e8d2c3 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -304,7 +304,8 @@ Integration tests are in `src/__tests__/integration/` and require a running agen export LLM_API_KEY="your-api-key" export LLM_MODEL="anthropic/claude-sonnet-4-5-20250929" -# Start agent-server in Docker (software-agent-sdk v1.29.0) +# Start agent-server in Docker (software-agent-sdk v1.29.0; +# canonical pin: package.json -> config.agentServerImage) docker run -d --name agent-server -p 8010:8000 \ -v /tmp/agent-workspace:/workspace \ ghcr.io/openhands/agent-server:1.29.0-python @@ -336,7 +337,7 @@ Required GitHub secrets: ### CI Image Version -- The integration workflow pins `ghcr.io/openhands/agent-server:1.29.0-python`, which corresponds to the `software-agent-sdk` release `v1.29.0`. +- The agent-server image is defined **once** in `package.json` under `config.agentServerImage` (currently `ghcr.io/openhands/agent-server:1.29.0-python`, corresponding to the `software-agent-sdk` release `v1.29.0`). The `integration-tests.yml` and `endpoint-audit.yml` workflows read it from there at runtime, so bump the version in that single place (and the local-setup snippets above). - Keep the TypeScript client tests strict against that released server image rather than adding compatibility fallbacks for older prerelease builds. ## Agent Behavior Guidelines diff --git a/README.md b/README.md index 17eafc6..fea9fb7 100644 --- a/README.md +++ b/README.md @@ -377,7 +377,8 @@ Integration tests require a running agent-server in Docker with a mounted worksp chmod 777 /tmp/agent-workspace ``` -2. Start the agent-server container (software-agent-sdk v1.29.0): +2. Start the agent-server container (software-agent-sdk v1.29.0; the canonical + image pin lives in `package.json` under `config.agentServerImage`): ```bash docker run -d \ diff --git a/package.json b/package.json index 3f7808d..e02e4bd 100644 --- a/package.json +++ b/package.json @@ -41,6 +41,9 @@ } } }, + "config": { + "agentServerImage": "ghcr.io/openhands/agent-server:1.29.0-python" + }, "scripts": { "build": "tsc && node ./scripts/copy-json-assets.mjs && node ./scripts/rewrite-relative-imports.mjs", "lint": "eslint src/**/*.ts", From cfc3b551ef1d9bf91a9374651d4b9aecca1e9b8f Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 09:01:59 +0200 Subject: [PATCH 05/12] docs: drop stale version literals from CI Image Version note --- AGENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/AGENTS.md b/AGENTS.md index 9e8d2c3..8b84bf8 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -337,7 +337,7 @@ Required GitHub secrets: ### CI Image Version -- The agent-server image is defined **once** in `package.json` under `config.agentServerImage` (currently `ghcr.io/openhands/agent-server:1.29.0-python`, corresponding to the `software-agent-sdk` release `v1.29.0`). The `integration-tests.yml` and `endpoint-audit.yml` workflows read it from there at runtime, so bump the version in that single place (and the local-setup snippets above). +- The agent-server image is defined **once** in `package.json` under `config.agentServerImage`. The `integration-tests.yml` and `endpoint-audit.yml` workflows read it from there at runtime, so bump the version in that single place (and the local-setup snippets above). - Keep the TypeScript client tests strict against that released server image rather than adding compatibility fallbacks for older prerelease builds. ## Agent Behavior Guidelines From 7ad35689c014f265926315c3d1b6f93fcd7fe3de Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 09:09:13 +0200 Subject: [PATCH 06/12] ci: keep release.yml unchanged and fix endpoint-audit artifact upload - Restore release.yml to its original content (no endpoint-audit gate); the audit now runs only as its own workflow. - upload-artifact@v4 skips dot-directories unless include-hidden-files is set, so the .audit/ report was never uploaded ("No files were found"). Enable include-hidden-files so the report uploads. --- .github/workflows/endpoint-audit.yml | 2 ++ .github/workflows/release.yml | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index ba34fd8..52e97e0 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -50,6 +50,8 @@ jobs: with: name: endpoint-audit path: .audit/ + # .audit/ is a dot-directory; upload-artifact@v4 skips hidden paths by default. + include-hidden-files: true - name: Stop agent-server if: always() diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ca78b6a..0a6a717 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,7 +12,7 @@ permissions: jobs: release: runs-on: ubuntu-latest - + steps: - name: Checkout code uses: actions/checkout@v4 From 0723c9abe9c1a7aa16b7a70b7d9bce24d3c4587e Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 09:13:10 +0200 Subject: [PATCH 07/12] ci: run endpoint audit on push to any branch --- .github/workflows/endpoint-audit.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index 52e97e0..3d4a1a3 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -2,7 +2,7 @@ name: Endpoint Audit on: push: - branches: [ main ] + branches: [ '**' ] pull_request: jobs: From 45f5e0a52bcbdfe13bfd4c297b4a5937c9bfe9f0 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 09:17:01 +0200 Subject: [PATCH 08/12] ci: post endpoint-audit report as a PR comment Add a github-script step that renders .audit/endpoint-audit.json into a single self-updating PR comment (matched by a hidden marker). Runs on pull_request events even when the audit gate fails, so reviewers see the mismatches. Grants pull-requests: write for commenting. --- .github/workflows/endpoint-audit.yml | 55 ++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index 3d4a1a3..d36bb98 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -5,6 +5,11 @@ on: branches: [ '**' ] pull_request: +# Needed so the audit can post its report as a comment on the PR. +permissions: + contents: read + pull-requests: write + jobs: # Verify the client doesn't call endpoints the agent-server no longer exposes. # The audit diffs the client's HTTP surface against the live server's OpenAPI @@ -53,6 +58,56 @@ jobs: # .audit/ is a dot-directory; upload-artifact@v4 skips hidden paths by default. include-hidden-files: true + # Post the report as a single, self-updating comment on the PR. Runs even + # when the audit gate fails (the report is written before the gate), so + # reviewers see the mismatches that failed the check. + - name: Comment audit report on PR + if: always() && github.event_name == 'pull_request' + uses: actions/github-script@v7 + with: + script: | + const fs = require('fs'); + const reportPath = '.audit/endpoint-audit.json'; + if (!fs.existsSync(reportPath)) { + core.warning(`No audit report at ${reportPath}; skipping PR comment.`); + return; + } + const r = JSON.parse(fs.readFileSync(reportPath, 'utf8')); + const list = (items) => + items.length ? items.map((i) => `- \`${i}\``).join('\n') : '_none_'; + const marker = ''; + const status = r.mismatch.length ? '❌ Mismatches found' : '✅ No mismatches'; + const body = [ + marker, + '## Endpoint audit', + '', + `**${status}** — server endpoints: ${r.server}, client endpoints: ${r.client}`, + '', + `### ❌ Mismatch — client calls an endpoint the server does not expose (${r.mismatch.length})`, + list(r.mismatch), + '', + `### ➕ Missing API — server exposes it, client does not implement (${r.missingApi.length})`, + list(r.missingApi), + '', + `
ℹ️ External backend, not gated (${r.external.length})`, + '', + list(r.external), + '
', + ].join('\n'); + const { owner, repo } = context.repo; + const issue_number = context.issue.number; + const comments = await github.paginate(github.rest.issues.listComments, { + owner, + repo, + issue_number, + }); + const existing = comments.find((c) => c.body && c.body.includes(marker)); + if (existing) { + await github.rest.issues.updateComment({ owner, repo, comment_id: existing.id, body }); + } else { + await github.rest.issues.createComment({ owner, repo, issue_number, body }); + } + - name: Stop agent-server if: always() run: docker rm -f agent-server || true From dd124a7ee73dac285f8918f4f5d38867c12bd525 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 10:48:05 +0200 Subject: [PATCH 09/12] ci(endpoint-audit): gate strictly on agent-server, classify off-contract calls MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the opaque externalPrefixes/allowClientOnly allowlists with a strict gate: any client call not on the agent-server fails the audit. To explain where each off-contract call actually goes, load extra `classify` specs (the public app.all-hands.dev OpenAPI, live with a committed fallback) and label every gated endpoint with the backend that serves it, or mark it as served by no known backend. Today this surfaces 19 off-contract calls: 5 served by cloud (keys, shared- events, accept_tos) and 14 by no known backend (meta-profiles, security/*, unset-provider-tokens, cloud-proxy, generate_title, skills/update) — previously all hidden behind the allowlists. The PR comment now groups failures by backend. --- .github/workflows/endpoint-audit.yml | 34 ++- endpoint-audit.config.json | 24 +- scripts/endpoint-audit.mjs | 95 ++++-- specs/cloud.openapi.json | 437 +++++++++++++++++++++++++++ 4 files changed, 535 insertions(+), 55 deletions(-) create mode 100644 specs/cloud.openapi.json diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index d36bb98..3a9f742 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -74,24 +74,38 @@ jobs: } const r = JSON.parse(fs.readFileSync(reportPath, 'utf8')); const list = (items) => - items.length ? items.map((i) => `- \`${i}\``).join('\n') : '_none_'; + items && items.length ? items.map((i) => `- \`${i}\``).join('\n') : '_none_'; const marker = ''; - const status = r.mismatch.length ? '❌ Mismatches found' : '✅ No mismatches'; + const NO_BACKEND = '(no known backend)'; + const offContract = r.mismatch || []; + const byBackend = r.byBackend || {}; + const status = offContract.length + ? `❌ ${offContract.length} off-contract call(s) — not on the agent-server` + : '✅ All client calls are on the agent-server'; + const backendSections = Object.keys(byBackend) + .sort() + .map((name) => { + const heading = + name === NO_BACKEND + ? `#### ⛔ ${name} — served by no backend we can see (${byBackend[name].length})` + : `#### ↗️ served by \`${name}\` (${byBackend[name].length})`; + return [heading, '', list(byBackend[name]), ''].join('\n'); + }) + .join('\n'); + const classifiers = + r.classifiers && r.classifiers.length ? ` · classifiers: ${r.classifiers.join(', ')}` : ''; const body = [ marker, '## Endpoint audit', '', - `**${status}** — server endpoints: ${r.server}, client endpoints: ${r.client}`, + `**${status}** — agent-server endpoints: ${r.agentServer}, client endpoints: ${r.client}${classifiers}`, '', - `### ❌ Mismatch — client calls an endpoint the server does not expose (${r.mismatch.length})`, - list(r.mismatch), + `### ❌ Not on agent-server (gated, ${offContract.length})`, '', - `### ➕ Missing API — server exposes it, client does not implement (${r.missingApi.length})`, - list(r.missingApi), - '', - `
ℹ️ External backend, not gated (${r.external.length})`, + offContract.length ? backendSections : '_none_', + `
➕ Missing API — agent-server exposes it, client does not implement (${(r.missingApi || []).length})`, '', - list(r.external), + list(r.missingApi), '
', ].join('\n'); const { owner, repo } = context.repo; diff --git a/endpoint-audit.config.json b/endpoint-audit.config.json index 9cb8714..bab170c 100644 --- a/endpoint-audit.config.json +++ b/endpoint-audit.config.json @@ -1,31 +1,23 @@ { + "_comment": "Endpoint audit config. The client is GATED against the agent-server only: any client call not on the agent-server fails the gate. Additional `classify` specs are fetched (live, with a committed fallback) purely to label each gated call with the backend that actually serves it (cloud) vs no known backend at all. See scripts/endpoint-audit.mjs.", "specs": [ { "name": "agent-server", + "role": "gate", "url": "http://localhost:8010/openapi.json", "file": "specs/agent-server.openapi.json" + }, + { + "name": "cloud", + "role": "classify", + "url": "https://app.all-hands.dev/openapi.json", + "file": "specs/cloud.openapi.json" } ], "clientGlobs": ["src/client", "src/conversation", "src/workspace"], - "externalPrefixes": [ - "/api/security/", - "/api/meta-profiles", - "/api/keys", - "/api/shared-", - "/api/accept_tos", - "/api/unset-provider-tokens" - ], - "ignoreServerOnly": ["/v1/"], - "_comment_allowClientOnly": "Baselined drift against agent-server 1.29.0. Each entry is the client calling an endpoint the server no longer exposes (a TODO to fix in the client), not an endorsement. Remove entries as they are fixed; new drift is NOT allowlisted and will fail the gate. cloud-proxy + generate_title were dropped server-side; skills uses /update but the server now exposes /refresh.", - "allowClientOnly": [ - "POST /api/cloud-proxy", - "POST /api/conversations/{}/generate_title", - "POST /api/skills/installed/{}/update" - ], - "gate": { "mismatch": true, "missingApi": false diff --git a/scripts/endpoint-audit.mjs b/scripts/endpoint-audit.mjs index 445f0b6..3823104 100644 --- a/scripts/endpoint-audit.mjs +++ b/scripts/endpoint-audit.mjs @@ -1,18 +1,24 @@ #!/usr/bin/env node /** * Endpoint audit — reconciles the client's HTTP surface against the - * agent-server OpenAPI spec and reports API drift: + * agent-server OpenAPI spec: * - * 1. mismatch — client calls an endpoint the server does NOT expose - * (a breakage, unless it lives on a known external backend - * listed in `externalPrefixes`) - * 2. missing API — server exposes an endpoint the client does NOT implement + * - The client is GATED against the agent-server spec only. Any endpoint the + * client calls that the agent-server does NOT expose fails the gate — this + * is an agent-server client, so off-contract calls are surfaced as errors + * rather than silently allowlisted. + * - To explain WHERE each off-contract call actually goes, extra `classify` + * specs (e.g. the cloud app at app.all-hands.dev) are loaded and used only + * to label each gated endpoint with the backend that serves it, or to mark + * it as served by NO known backend (genuinely unsupported). + * - missing API — agent-server exposes an endpoint the client does NOT + * implement (informational, not gated). * - * Ground truth is the server's own OpenAPI spec, fetched live from a running - * container (preferred) or read from the committed fallback file. + * Specs are fetched live from each backend (preferred) or read from a committed + * fallback file. A `gate` spec with neither is a hard error; a `classify` spec + * that is unavailable is skipped (its endpoints just go unlabeled). * - * Exit code is non-zero on gating violations (see config.gate), so the script - * can act as a release gate. + * Exit code is non-zero on gating violations (see config.gate). */ import fs from 'node:fs'; import path from 'node:path'; @@ -32,30 +38,42 @@ const norm = (verb, p) => }`; // --------------------------------------------------------------------------- -// 1. Ground truth: union of all configured backend specs +// 1. Backend specs: agent-server (gate) + others (classify) // --------------------------------------------------------------------------- async function loadSpec(spec) { if (spec.url) { try { - const res = await fetch(spec.url, { signal: AbortSignal.timeout(5000) }); + const res = await fetch(spec.url, { signal: AbortSignal.timeout(8000) }); if (res.ok) return await res.json(); console.warn(` ! ${spec.name}: ${spec.url} -> HTTP ${res.status}, falling back to file`); } catch (e) { - console.warn( - ` ! ${spec.name}: ${spec.url} unreachable (${e.message}), falling back to file` - ); + console.warn(` ! ${spec.name}: ${spec.url} unreachable (${e.message}), falling back to file`); } } if (spec.file && fs.existsSync(path.join(ROOT, spec.file))) return JSON.parse(fs.readFileSync(path.join(ROOT, spec.file), 'utf8')); + if (spec.role === 'classify') { + console.warn(` ! ${spec.name}: no reachable url and no fallback file — skipping (classify only)`); + return null; + } throw new Error(`spec "${spec.name}": no reachable url and no fallback file`); } -const server = new Set(); // normalized "VERB /path" +const specToSet = (doc) => { + const set = new Set(); // normalized "VERB /path" + for (const [p, methods] of Object.entries(doc.paths ?? {})) + for (const verb of Object.keys(methods)) if (VERBS.includes(verb)) set.add(norm(verb, p)); + return set; +}; + +const gate = new Set(); // union of all `gate` specs (the agent-server contract) +const classifiers = []; // [{ name, set }] for labelling off-contract calls for (const spec of cfg.specs) { const doc = await loadSpec(spec); - for (const [p, methods] of Object.entries(doc.paths ?? {})) - for (const verb of Object.keys(methods)) if (VERBS.includes(verb)) server.add(norm(verb, p)); + if (!doc) continue; + const set = specToSet(doc); + if (spec.role === 'classify') classifiers.push({ name: spec.name, set }); + else for (const k of set) gate.add(k); } // --------------------------------------------------------------------------- @@ -100,16 +118,20 @@ for (const glob of cfg.clientGlobs) { } // --------------------------------------------------------------------------- -// 3. Diff +// 3. Diff + classify // --------------------------------------------------------------------------- const sorted = (it) => [...it].sort(); -const isExternal = (k) => cfg.externalPrefixes.some((pre) => k.includes(pre)); const ignoredApi = (k) => (cfg.ignoreServerOnly ?? []).some((pre) => k.includes(pre)); -const clientOnly = sorted([...client].filter((k) => !server.has(k))); -const mismatch = clientOnly.filter((k) => !isExternal(k) && !cfg.allowClientOnly.includes(k)); -const external = clientOnly.filter(isExternal); -const missingApi = sorted([...server].filter((k) => !client.has(k) && !ignoredApi(k))); +const NO_BACKEND = '(no known backend)'; +const classify = (k) => classifiers.find((c) => c.set.has(k))?.name ?? NO_BACKEND; + +// Every client call the agent-server does NOT expose is off-contract -> gated. +const mismatch = sorted([...client].filter((k) => !gate.has(k))); +const byBackend = {}; // backend name -> [endpoints] +for (const k of mismatch) (byBackend[classify(k)] ??= []).push(k); + +const missingApi = sorted([...gate].filter((k) => !client.has(k) && !ignoredApi(k))); // --------------------------------------------------------------------------- // 4. Report @@ -118,16 +140,30 @@ const section = (title, items) => { console.log(`\n${title} (${items.length})`); for (const k of items) console.log(` ${k}`); }; -console.log(`\n=== Endpoint audit — server=${server.size} client=${client.size} ===`); -section('❌ MISMATCH — client calls an endpoint not on the server', mismatch); -section('ℹ️ external backend (not gated)', external); -section('➕ MISSING API — server has it, client does not implement', missingApi); +console.log( + `\n=== Endpoint audit — agent-server=${gate.size} client=${client.size}` + + ` classifiers=[${classifiers.map((c) => c.name).join(', ') || 'none'}] ===` +); +console.log(`\n❌ NOT ON AGENT-SERVER — off-contract client calls (${mismatch.length})`); +for (const name of Object.keys(byBackend).sort()) { + const tag = name === NO_BACKEND ? `${name} ⛔` : `served by: ${name}`; + console.log(` ${tag} (${byBackend[name].length})`); + for (const k of byBackend[name]) console.log(` ${k}`); +} +section('➕ MISSING API — agent-server has it, client does not implement', missingApi); fs.mkdirSync(path.join(ROOT, '.audit'), { recursive: true }); fs.writeFileSync( path.join(ROOT, '.audit/endpoint-audit.json'), JSON.stringify( - { server: server.size, client: client.size, mismatch, external, missingApi }, + { + agentServer: gate.size, + client: client.size, + classifiers: classifiers.map((c) => c.name), + mismatch, + byBackend, + missingApi, + }, null, 2 ) @@ -138,7 +174,8 @@ fs.writeFileSync( // --------------------------------------------------------------------------- const g = cfg.gate ?? {}; const violations = []; -if (g.mismatch !== false && mismatch.length) violations.push(`${mismatch.length} mismatch`); +if (g.mismatch !== false && mismatch.length) + violations.push(`${mismatch.length} off-contract (not on agent-server)`); if (g.missingApi && missingApi.length) violations.push(`${missingApi.length} missing API`); if (violations.length) { diff --git a/specs/cloud.openapi.json b/specs/cloud.openapi.json new file mode 100644 index 0000000..f3ead5b --- /dev/null +++ b/specs/cloud.openapi.json @@ -0,0 +1,437 @@ +{ + "info": { + "note": "Path index only (verbs, no schemas). Classification fallback for app.all-hands.dev; refresh via: curl -s https://app.all-hands.dev/openapi.json | (this generator). Not gated.", + "title": "OpenHands" + }, + "paths": { + "/alive": { + "get": {} + }, + "/api/accept_tos": { + "post": {} + }, + "/api/admin/verified-models": { + "get": {}, + "post": {} + }, + "/api/admin/verified-models/{provider}/{model_name}": { + "delete": {}, + "put": {} + }, + "/api/analytics/events": { + "post": {} + }, + "/api/authenticate": { + "post": {} + }, + "/api/billing/cancel": { + "get": {} + }, + "/api/billing/create-checkout-session": { + "post": {} + }, + "/api/billing/create-customer-setup-session": { + "post": {} + }, + "/api/billing/credits": { + "get": {} + }, + "/api/billing/has-payment-method": { + "post": {} + }, + "/api/billing/subscription-access": { + "get": {} + }, + "/api/billing/success": { + "get": {} + }, + "/api/complete_onboarding": { + "post": {} + }, + "/api/email": { + "post": {} + }, + "/api/email/resend": { + "put": {} + }, + "/api/email/verified": { + "get": {} + }, + "/api/keys": { + "get": {}, + "post": {} + }, + "/api/keys/current": { + "get": {} + }, + "/api/keys/llm/byor": { + "get": {} + }, + "/api/keys/llm/byor/permitted": { + "get": {} + }, + "/api/keys/llm/byor/refresh": { + "post": {} + }, + "/api/keys/{key_id}": { + "delete": {} + }, + "/api/logout": { + "post": {} + }, + "/api/onboarding_status": { + "get": {} + }, + "/api/organizations": { + "get": {}, + "post": {} + }, + "/api/organizations/app": { + "get": {}, + "post": {} + }, + "/api/organizations/llm": { + "get": {}, + "post": {} + }, + "/api/organizations/members/invite/accept": { + "get": {}, + "post": {} + }, + "/api/organizations/{org_id}": { + "delete": {}, + "get": {}, + "patch": {} + }, + "/api/organizations/{org_id}/git-claims": { + "get": {}, + "post": {} + }, + "/api/organizations/{org_id}/git-claims/{claim_id}": { + "delete": {} + }, + "/api/organizations/{org_id}/me": { + "get": {} + }, + "/api/organizations/{org_id}/members": { + "get": {} + }, + "/api/organizations/{org_id}/members/count": { + "get": {} + }, + "/api/organizations/{org_id}/members/financial": { + "get": {} + }, + "/api/organizations/{org_id}/members/invite": { + "post": {} + }, + "/api/organizations/{org_id}/members/{user_id}": { + "delete": {}, + "patch": {} + }, + "/api/organizations/{org_id}/profiles": { + "get": {} + }, + "/api/organizations/{org_id}/profiles/{name}": { + "delete": {}, + "get": {}, + "post": {} + }, + "/api/organizations/{org_id}/profiles/{name}/activate": { + "post": {} + }, + "/api/organizations/{org_id}/profiles/{name}/rename": { + "post": {} + }, + "/api/organizations/{org_id}/settings": { + "get": {}, + "patch": {} + }, + "/api/organizations/{org_id}/switch": { + "post": {} + }, + "/api/refresh-tokens": { + "get": {} + }, + "/api/service/health": { + "get": {} + }, + "/api/service/users/{user_id}/orgs/{org_id}/api-keys": { + "post": {} + }, + "/api/service/users/{user_id}/orgs/{org_id}/api-keys/{key_name}": { + "delete": {} + }, + "/api/shared-conversations": { + "get": {} + }, + "/api/shared-events": { + "get": {} + }, + "/api/shared-events/count": { + "get": {} + }, + "/api/shared-events/search": { + "get": {} + }, + "/api/shared-events/{conversation_id}/{event_id}": { + "get": {} + }, + "/api/users/app": { + "get": {}, + "post": {} + }, + "/api/v1/app-conversations": { + "get": {}, + "post": {} + }, + "/api/v1/app-conversations/count": { + "get": {} + }, + "/api/v1/app-conversations/search": { + "get": {} + }, + "/api/v1/app-conversations/start-tasks": { + "get": {} + }, + "/api/v1/app-conversations/start-tasks/count": { + "get": {} + }, + "/api/v1/app-conversations/start-tasks/search": { + "get": {} + }, + "/api/v1/app-conversations/stream-start": { + "post": {} + }, + "/api/v1/app-conversations/{conversation_id}": { + "delete": {}, + "patch": {} + }, + "/api/v1/app-conversations/{conversation_id}/download": { + "get": {} + }, + "/api/v1/app-conversations/{conversation_id}/file": { + "get": {} + }, + "/api/v1/app-conversations/{conversation_id}/git/changes": { + "get": {} + }, + "/api/v1/app-conversations/{conversation_id}/git/diff": { + "get": {} + }, + "/api/v1/app-conversations/{conversation_id}/hooks": { + "get": {} + }, + "/api/v1/app-conversations/{conversation_id}/send-message": { + "post": {} + }, + "/api/v1/app-conversations/{conversation_id}/skills": { + "get": {} + }, + "/api/v1/app-conversations/{conversation_id}/switch_profile": { + "post": {} + }, + "/api/v1/config/models/search": { + "get": {} + }, + "/api/v1/config/providers/search": { + "get": {} + }, + "/api/v1/conversation/{conversation_id}/events": { + "get": {} + }, + "/api/v1/conversation/{conversation_id}/events/count": { + "get": {} + }, + "/api/v1/conversation/{conversation_id}/events/search": { + "get": {} + }, + "/api/v1/conversations/{conversation_id}/pending-messages": { + "post": {} + }, + "/api/v1/git/branches/search": { + "get": {} + }, + "/api/v1/git/installations/search": { + "get": {} + }, + "/api/v1/git/repositories/search": { + "get": {} + }, + "/api/v1/git/suggested-tasks/search": { + "get": {} + }, + "/api/v1/sandbox-specs": { + "get": {} + }, + "/api/v1/sandbox-specs/search": { + "get": {} + }, + "/api/v1/sandboxes": { + "get": {}, + "post": {} + }, + "/api/v1/sandboxes/search": { + "get": {} + }, + "/api/v1/sandboxes/{id}": { + "delete": {} + }, + "/api/v1/sandboxes/{sandbox_id}/pause": { + "post": {} + }, + "/api/v1/sandboxes/{sandbox_id}/resume": { + "post": {} + }, + "/api/v1/sandboxes/{sandbox_id}/settings/secrets": { + "get": {} + }, + "/api/v1/sandboxes/{sandbox_id}/settings/secrets/{secret_name}": { + "get": {} + }, + "/api/v1/secrets": { + "post": {} + }, + "/api/v1/secrets/git-providers": { + "delete": {}, + "post": {} + }, + "/api/v1/secrets/search": { + "get": {} + }, + "/api/v1/secrets/{secret_id}": { + "delete": {}, + "put": {} + }, + "/api/v1/settings": { + "get": {}, + "post": {} + }, + "/api/v1/settings/agent-schema": { + "get": {} + }, + "/api/v1/settings/conversation-schema": { + "get": {} + }, + "/api/v1/settings/profiles": { + "get": {} + }, + "/api/v1/settings/profiles/{name}": { + "delete": {}, + "get": {}, + "post": {} + }, + "/api/v1/settings/profiles/{name}/activate": { + "post": {} + }, + "/api/v1/settings/profiles/{name}/rename": { + "post": {} + }, + "/api/v1/skills/search": { + "get": {} + }, + "/api/v1/users/git-info": { + "get": {} + }, + "/api/v1/users/git-organizations": { + "get": {} + }, + "/api/v1/users/me": { + "get": {} + }, + "/api/v1/web-client/config": { + "get": {} + }, + "/api/v1/webhooks/conversations": { + "post": {} + }, + "/api/v1/webhooks/events/{conversation_id}": { + "post": {} + }, + "/api/v1/webhooks/secrets": { + "get": {} + }, + "/health": { + "get": {} + }, + "/integration/bitbucket/events": { + "post": {} + }, + "/integration/github/events": { + "post": {} + }, + "/integration/gitlab/events": { + "post": {} + }, + "/integration/gitlab/reinstall-webhook": { + "post": {} + }, + "/integration/gitlab/resources": { + "get": {} + }, + "/integration/jira/callback": { + "get": {} + }, + "/integration/jira/events": { + "post": {} + }, + "/integration/jira/workspaces": { + "post": {} + }, + "/integration/jira/workspaces/link": { + "get": {}, + "post": {} + }, + "/integration/jira/workspaces/unlink": { + "post": {} + }, + "/integration/jira/workspaces/validate/{workspace_name}": { + "get": {} + }, + "/oauth/device/authorize": { + "post": {} + }, + "/oauth/device/token": { + "post": {} + }, + "/oauth/device/verify-authenticated": { + "post": {} + }, + "/oauth/github/callback": { + "get": {} + }, + "/oauth/keycloak/callback": { + "get": {} + }, + "/oauth/keycloak/offline/callback": { + "get": {} + }, + "/ready": { + "get": {} + }, + "/saas": { + "get": {} + }, + "/server_info": { + "get": {} + }, + "/slack/install": { + "get": {} + }, + "/slack/install-callback": { + "get": {} + }, + "/slack/keycloak-callback": { + "get": {} + }, + "/slack/on-event": { + "post": {} + }, + "/slack/on-form-interaction": { + "post": {} + }, + "/slack/on-options-load": { + "post": {} + } + } +} \ No newline at end of file From 39829d0ccfa2755049ff97185fd7160b10738299 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 10:51:29 +0200 Subject: [PATCH 10/12] ci(endpoint-audit): add summary table to PR comment, expand Missing API --- .github/workflows/endpoint-audit.yml | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/.github/workflows/endpoint-audit.yml b/.github/workflows/endpoint-audit.yml index 3a9f742..ffefa64 100644 --- a/.github/workflows/endpoint-audit.yml +++ b/.github/workflows/endpoint-audit.yml @@ -94,19 +94,35 @@ jobs: .join('\n'); const classifiers = r.classifiers && r.classifiers.length ? ` · classifiers: ${r.classifiers.join(', ')}` : ''; + const summary = [ + '| Category | Count |', + '| --- | ---: |', + `| ❌ Off-contract (not on agent-server) | ${offContract.length} |`, + ...Object.keys(byBackend) + .sort() + .map((name) => + name === NO_BACKEND + ? `|   ⛔ no known backend | ${byBackend[name].length} |` + : `|   ↗️ served by \`${name}\` | ${byBackend[name].length} |` + ), + `| ➕ Missing API (agent-server has, client lacks) | ${(r.missingApi || []).length} |`, + `| agent-server endpoints | ${r.agentServer} |`, + `| client endpoints | ${r.client} |`, + ].join('\n'); const body = [ marker, '## Endpoint audit', '', - `**${status}** — agent-server endpoints: ${r.agentServer}, client endpoints: ${r.client}${classifiers}`, + `**${status}**${classifiers}`, + '', + summary, '', `### ❌ Not on agent-server (gated, ${offContract.length})`, '', offContract.length ? backendSections : '_none_', - `
➕ Missing API — agent-server exposes it, client does not implement (${(r.missingApi || []).length})`, + `### ➕ Missing API — agent-server exposes it, client does not implement (${(r.missingApi || []).length})`, '', list(r.missingApi), - '
', ].join('\n'); const { owner, repo } = context.repo; const issue_number = context.issue.number; From 4e9f6245abc6ef42b6fcdfaf72ccc75b96bc76d9 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 10:54:54 +0200 Subject: [PATCH 11/12] ci(endpoint-audit): drop vendored cloud spec, classify via live fetch only --- endpoint-audit.config.json | 5 +- specs/cloud.openapi.json | 437 ------------------------------------- 2 files changed, 2 insertions(+), 440 deletions(-) delete mode 100644 specs/cloud.openapi.json diff --git a/endpoint-audit.config.json b/endpoint-audit.config.json index bab170c..00bced9 100644 --- a/endpoint-audit.config.json +++ b/endpoint-audit.config.json @@ -1,5 +1,5 @@ { - "_comment": "Endpoint audit config. The client is GATED against the agent-server only: any client call not on the agent-server fails the gate. Additional `classify` specs are fetched (live, with a committed fallback) purely to label each gated call with the backend that actually serves it (cloud) vs no known backend at all. See scripts/endpoint-audit.mjs.", + "_comment": "Endpoint audit config. The client is GATED against the agent-server only: any client call not on the agent-server fails the gate. Additional `classify` specs are fetched live purely to label each gated call with the backend that actually serves it (cloud) vs no known backend at all; if a classify spec is unreachable its labels just degrade to 'no known backend'. See scripts/endpoint-audit.mjs.", "specs": [ { "name": "agent-server", @@ -10,8 +10,7 @@ { "name": "cloud", "role": "classify", - "url": "https://app.all-hands.dev/openapi.json", - "file": "specs/cloud.openapi.json" + "url": "https://app.all-hands.dev/openapi.json" } ], "clientGlobs": ["src/client", "src/conversation", "src/workspace"], diff --git a/specs/cloud.openapi.json b/specs/cloud.openapi.json deleted file mode 100644 index f3ead5b..0000000 --- a/specs/cloud.openapi.json +++ /dev/null @@ -1,437 +0,0 @@ -{ - "info": { - "note": "Path index only (verbs, no schemas). Classification fallback for app.all-hands.dev; refresh via: curl -s https://app.all-hands.dev/openapi.json | (this generator). Not gated.", - "title": "OpenHands" - }, - "paths": { - "/alive": { - "get": {} - }, - "/api/accept_tos": { - "post": {} - }, - "/api/admin/verified-models": { - "get": {}, - "post": {} - }, - "/api/admin/verified-models/{provider}/{model_name}": { - "delete": {}, - "put": {} - }, - "/api/analytics/events": { - "post": {} - }, - "/api/authenticate": { - "post": {} - }, - "/api/billing/cancel": { - "get": {} - }, - "/api/billing/create-checkout-session": { - "post": {} - }, - "/api/billing/create-customer-setup-session": { - "post": {} - }, - "/api/billing/credits": { - "get": {} - }, - "/api/billing/has-payment-method": { - "post": {} - }, - "/api/billing/subscription-access": { - "get": {} - }, - "/api/billing/success": { - "get": {} - }, - "/api/complete_onboarding": { - "post": {} - }, - "/api/email": { - "post": {} - }, - "/api/email/resend": { - "put": {} - }, - "/api/email/verified": { - "get": {} - }, - "/api/keys": { - "get": {}, - "post": {} - }, - "/api/keys/current": { - "get": {} - }, - "/api/keys/llm/byor": { - "get": {} - }, - "/api/keys/llm/byor/permitted": { - "get": {} - }, - "/api/keys/llm/byor/refresh": { - "post": {} - }, - "/api/keys/{key_id}": { - "delete": {} - }, - "/api/logout": { - "post": {} - }, - "/api/onboarding_status": { - "get": {} - }, - "/api/organizations": { - "get": {}, - "post": {} - }, - "/api/organizations/app": { - "get": {}, - "post": {} - }, - "/api/organizations/llm": { - "get": {}, - "post": {} - }, - "/api/organizations/members/invite/accept": { - "get": {}, - "post": {} - }, - "/api/organizations/{org_id}": { - "delete": {}, - "get": {}, - "patch": {} - }, - "/api/organizations/{org_id}/git-claims": { - "get": {}, - "post": {} - }, - "/api/organizations/{org_id}/git-claims/{claim_id}": { - "delete": {} - }, - "/api/organizations/{org_id}/me": { - "get": {} - }, - "/api/organizations/{org_id}/members": { - "get": {} - }, - "/api/organizations/{org_id}/members/count": { - "get": {} - }, - "/api/organizations/{org_id}/members/financial": { - "get": {} - }, - "/api/organizations/{org_id}/members/invite": { - "post": {} - }, - "/api/organizations/{org_id}/members/{user_id}": { - "delete": {}, - "patch": {} - }, - "/api/organizations/{org_id}/profiles": { - "get": {} - }, - "/api/organizations/{org_id}/profiles/{name}": { - "delete": {}, - "get": {}, - "post": {} - }, - "/api/organizations/{org_id}/profiles/{name}/activate": { - "post": {} - }, - "/api/organizations/{org_id}/profiles/{name}/rename": { - "post": {} - }, - "/api/organizations/{org_id}/settings": { - "get": {}, - "patch": {} - }, - "/api/organizations/{org_id}/switch": { - "post": {} - }, - "/api/refresh-tokens": { - "get": {} - }, - "/api/service/health": { - "get": {} - }, - "/api/service/users/{user_id}/orgs/{org_id}/api-keys": { - "post": {} - }, - "/api/service/users/{user_id}/orgs/{org_id}/api-keys/{key_name}": { - "delete": {} - }, - "/api/shared-conversations": { - "get": {} - }, - "/api/shared-events": { - "get": {} - }, - "/api/shared-events/count": { - "get": {} - }, - "/api/shared-events/search": { - "get": {} - }, - "/api/shared-events/{conversation_id}/{event_id}": { - "get": {} - }, - "/api/users/app": { - "get": {}, - "post": {} - }, - "/api/v1/app-conversations": { - "get": {}, - "post": {} - }, - "/api/v1/app-conversations/count": { - "get": {} - }, - "/api/v1/app-conversations/search": { - "get": {} - }, - "/api/v1/app-conversations/start-tasks": { - "get": {} - }, - "/api/v1/app-conversations/start-tasks/count": { - "get": {} - }, - "/api/v1/app-conversations/start-tasks/search": { - "get": {} - }, - "/api/v1/app-conversations/stream-start": { - "post": {} - }, - "/api/v1/app-conversations/{conversation_id}": { - "delete": {}, - "patch": {} - }, - "/api/v1/app-conversations/{conversation_id}/download": { - "get": {} - }, - "/api/v1/app-conversations/{conversation_id}/file": { - "get": {} - }, - "/api/v1/app-conversations/{conversation_id}/git/changes": { - "get": {} - }, - "/api/v1/app-conversations/{conversation_id}/git/diff": { - "get": {} - }, - "/api/v1/app-conversations/{conversation_id}/hooks": { - "get": {} - }, - "/api/v1/app-conversations/{conversation_id}/send-message": { - "post": {} - }, - "/api/v1/app-conversations/{conversation_id}/skills": { - "get": {} - }, - "/api/v1/app-conversations/{conversation_id}/switch_profile": { - "post": {} - }, - "/api/v1/config/models/search": { - "get": {} - }, - "/api/v1/config/providers/search": { - "get": {} - }, - "/api/v1/conversation/{conversation_id}/events": { - "get": {} - }, - "/api/v1/conversation/{conversation_id}/events/count": { - "get": {} - }, - "/api/v1/conversation/{conversation_id}/events/search": { - "get": {} - }, - "/api/v1/conversations/{conversation_id}/pending-messages": { - "post": {} - }, - "/api/v1/git/branches/search": { - "get": {} - }, - "/api/v1/git/installations/search": { - "get": {} - }, - "/api/v1/git/repositories/search": { - "get": {} - }, - "/api/v1/git/suggested-tasks/search": { - "get": {} - }, - "/api/v1/sandbox-specs": { - "get": {} - }, - "/api/v1/sandbox-specs/search": { - "get": {} - }, - "/api/v1/sandboxes": { - "get": {}, - "post": {} - }, - "/api/v1/sandboxes/search": { - "get": {} - }, - "/api/v1/sandboxes/{id}": { - "delete": {} - }, - "/api/v1/sandboxes/{sandbox_id}/pause": { - "post": {} - }, - "/api/v1/sandboxes/{sandbox_id}/resume": { - "post": {} - }, - "/api/v1/sandboxes/{sandbox_id}/settings/secrets": { - "get": {} - }, - "/api/v1/sandboxes/{sandbox_id}/settings/secrets/{secret_name}": { - "get": {} - }, - "/api/v1/secrets": { - "post": {} - }, - "/api/v1/secrets/git-providers": { - "delete": {}, - "post": {} - }, - "/api/v1/secrets/search": { - "get": {} - }, - "/api/v1/secrets/{secret_id}": { - "delete": {}, - "put": {} - }, - "/api/v1/settings": { - "get": {}, - "post": {} - }, - "/api/v1/settings/agent-schema": { - "get": {} - }, - "/api/v1/settings/conversation-schema": { - "get": {} - }, - "/api/v1/settings/profiles": { - "get": {} - }, - "/api/v1/settings/profiles/{name}": { - "delete": {}, - "get": {}, - "post": {} - }, - "/api/v1/settings/profiles/{name}/activate": { - "post": {} - }, - "/api/v1/settings/profiles/{name}/rename": { - "post": {} - }, - "/api/v1/skills/search": { - "get": {} - }, - "/api/v1/users/git-info": { - "get": {} - }, - "/api/v1/users/git-organizations": { - "get": {} - }, - "/api/v1/users/me": { - "get": {} - }, - "/api/v1/web-client/config": { - "get": {} - }, - "/api/v1/webhooks/conversations": { - "post": {} - }, - "/api/v1/webhooks/events/{conversation_id}": { - "post": {} - }, - "/api/v1/webhooks/secrets": { - "get": {} - }, - "/health": { - "get": {} - }, - "/integration/bitbucket/events": { - "post": {} - }, - "/integration/github/events": { - "post": {} - }, - "/integration/gitlab/events": { - "post": {} - }, - "/integration/gitlab/reinstall-webhook": { - "post": {} - }, - "/integration/gitlab/resources": { - "get": {} - }, - "/integration/jira/callback": { - "get": {} - }, - "/integration/jira/events": { - "post": {} - }, - "/integration/jira/workspaces": { - "post": {} - }, - "/integration/jira/workspaces/link": { - "get": {}, - "post": {} - }, - "/integration/jira/workspaces/unlink": { - "post": {} - }, - "/integration/jira/workspaces/validate/{workspace_name}": { - "get": {} - }, - "/oauth/device/authorize": { - "post": {} - }, - "/oauth/device/token": { - "post": {} - }, - "/oauth/device/verify-authenticated": { - "post": {} - }, - "/oauth/github/callback": { - "get": {} - }, - "/oauth/keycloak/callback": { - "get": {} - }, - "/oauth/keycloak/offline/callback": { - "get": {} - }, - "/ready": { - "get": {} - }, - "/saas": { - "get": {} - }, - "/server_info": { - "get": {} - }, - "/slack/install": { - "get": {} - }, - "/slack/install-callback": { - "get": {} - }, - "/slack/keycloak-callback": { - "get": {} - }, - "/slack/on-event": { - "post": {} - }, - "/slack/on-form-interaction": { - "post": {} - }, - "/slack/on-options-load": { - "post": {} - } - } -} \ No newline at end of file From 95d8d93a9bd0d39821b5a0ad96dd89cb506aa320 Mon Sep 17 00:00:00 2001 From: VascoSch92 Date: Mon, 22 Jun 2026 11:02:21 +0200 Subject: [PATCH 12/12] ci(endpoint-audit): drop committed agent-server spec; gate fetches it live CI boots the pinned agent-server image and fetches /openapi.json live, so the 466KB committed fallback was unused there and only drifted from the image. Remove it (and its config file ref); local runs now require the image running, consistent with the integration tests. --- endpoint-audit.config.json | 3 +-- specs/agent-server.openapi.json | 1 - 2 files changed, 1 insertion(+), 3 deletions(-) delete mode 100644 specs/agent-server.openapi.json diff --git a/endpoint-audit.config.json b/endpoint-audit.config.json index 00bced9..e8d70e4 100644 --- a/endpoint-audit.config.json +++ b/endpoint-audit.config.json @@ -4,8 +4,7 @@ { "name": "agent-server", "role": "gate", - "url": "http://localhost:8010/openapi.json", - "file": "specs/agent-server.openapi.json" + "url": "http://localhost:8010/openapi.json" }, { "name": "cloud", diff --git a/specs/agent-server.openapi.json b/specs/agent-server.openapi.json deleted file mode 100644 index 45ac8d4..0000000 --- a/specs/agent-server.openapi.json +++ /dev/null @@ -1 +0,0 @@ -{"openapi":"3.1.0","info":{"title":"OpenHands Agent Server","description":"OpenHands Agent Server - REST/WebSocket interface for OpenHands AI Agent","version":"0.1.0"},"paths":{"/alive":{"get":{"tags":["Server Details"],"summary":"Alive","description":"Basic liveness check - returns OK if the server process is running.","operationId":"alive_alive_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}}}}},"/health":{"get":{"tags":["Server Details"],"summary":"Health","description":"Basic health check - returns OK if the server process is running.","operationId":"health_health_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HealthStatus"}}}}}}},"/ready":{"get":{"tags":["Server Details"],"summary":"Ready","description":"Readiness check - returns OK only if the server has completed initialization.\n\nThis endpoint should be used by Kubernetes readiness probes to determine\nwhen the pod is ready to receive traffic. Returns 503 during initialization.","operationId":"ready_ready_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"string"},"type":"object","title":"Response Ready Ready Get"}}}}}}},"/server_info":{"get":{"tags":["Server Details"],"summary":"Get Server Info","operationId":"get_server_info_server_info_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerInfo"}}}}}}},"/api/init":{"get":{"tags":["Init"],"summary":"Get Init Status","description":"Report the current init state.\n\nAuthentication is intentionally not required on this endpoint so a warm\npool controller can poll it without holding the init key. The payload\ncontains no sensitive data.","operationId":"get_init_status_api_init_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitStatus"}}}}}},"post":{"tags":["Init"],"summary":"Initialize Server","description":"Initialize a dormant server with runtime configuration.\n\nReturns 400 if the server has already been initialized (state != dormant).\nReturns 500 if initialization fails; in that case the state rolls back to\n``dormant`` so the orchestrator can retry.","operationId":"initialize_server_api_init_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InitStatus"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}},"security":[{"APIKeyHeader":[]}]}},"/api/conversations/{conversation_id}/events/search":{"get":{"tags":["Events"],"summary":"Search Conversation Events","description":"Search / List local events","operationId":"search_conversation_events_api_conversations__conversation_id__events_search_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event kind/type (e.g., ActionEvent, MessageEvent)"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event source (e.g., agent, user, environment)"}},{"name":"body","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by message content (case-insensitive)"}},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/EventSortOrder","title":"Sort order for events","default":"TIMESTAMP"}},{"name":"timestamp__gte","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp >= this datetime"}},{"name":"timestamp__lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp < this datetime"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventPage"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events/count":{"get":{"tags":["Events"],"summary":"Count Conversation Events","description":"Count local events matching the given filters","operationId":"count_conversation_events_api_conversations__conversation_id__events_count_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"kind","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event kind/type (e.g., ActionEvent, MessageEvent)"}},{"name":"source","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by event source (e.g., agent, user, environment)"}},{"name":"body","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional filter by message content (case-insensitive)"}},{"name":"timestamp__gte","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp >= this datetime"}},{"name":"timestamp__lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Filter: event timestamp < this datetime"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"integer","title":"Response Count Conversation Events Api Conversations Conversation Id Events Count Get"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events/{event_id}":{"get":{"tags":["Events"],"summary":"Get Conversation Event","description":"Get a local event given an id","operationId":"get_conversation_event_api_conversations__conversation_id__events__event_id__get","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"}},{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Event"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events":{"get":{"tags":["Events"],"summary":"Batch Get Conversation Events","description":"Get a batch of local events given their ids, returning null for any\nmissing item.","operationId":"batch_get_conversation_events_api_conversations__conversation_id__events_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"array","items":{"type":"string"},"title":"Event Ids"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/Event"},{"type":"null"}]},"title":"Response Batch Get Conversation Events Api Conversations Conversation Id Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Events"],"summary":"Send Message","description":"Send a message to a conversation","operationId":"send_message_api_conversations__conversation_id__events_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SendMessageRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/events/respond_to_confirmation":{"post":{"tags":["Events"],"summary":"Respond To Confirmation","description":"Accept or reject a pending action in confirmation mode.","operationId":"respond_to_confirmation_api_conversations__conversation_id__events_respond_to_confirmation_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConfirmationResponseRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/search":{"get":{"tags":["Conversations"],"summary":"Search Conversations","description":"Search / List conversations","operationId":"search_conversations_api_conversations_search_get","parameters":[{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}},{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ConversationExecutionStatus"},{"type":"null"}],"title":"Optional filter by conversation execution status"}},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/ConversationSortOrder","title":"Sort order for conversations","default":"CREATED_AT_DESC"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/count":{"get":{"tags":["Conversations"],"summary":"Count Conversations","description":"Count conversations matching the given filters","operationId":"count_conversations_api_conversations_count_get","parameters":[{"name":"status","in":"query","required":false,"schema":{"anyOf":[{"$ref":"#/components/schemas/ConversationExecutionStatus"},{"type":"null"}],"title":"Optional filter by conversation execution status"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"integer","title":"Response Count Conversations Api Conversations Count Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}":{"get":{"tags":["Conversations"],"summary":"Get Conversation","description":"Given an id, get a conversation","operationId":"get_conversation_api_conversations__conversation_id__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationInfo"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Conversations"],"summary":"Delete Conversation","description":"Permanently delete a conversation.","operationId":"delete_conversation_api_conversations__conversation_id__delete","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Conversations"],"summary":"Update Conversation","description":"Update conversation metadata.\n\nThis endpoint allows updating conversation details like title.","operationId":"update_conversation_api_conversations__conversation_id__patch","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateConversationRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/agent_final_response":{"get":{"tags":["Conversations"],"summary":"Get Conversation Agent Final Response","description":"Get the agent's final response for a conversation.\n\nReturns the text of the last agent finish message (FinishAction) or\nthe last agent text response (MessageEvent). Returns an empty string\nif the agent has not produced a final response yet.","operationId":"get_conversation_agent_final_response_api_conversations__conversation_id__agent_final_response_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentResponseResult"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations":{"get":{"tags":["Conversations"],"summary":"Batch Get Conversations","description":"Get a batch of conversations given their ids, returning null for\nany missing item","operationId":"batch_get_conversations_api_conversations_get","parameters":[{"name":"ids","in":"query","required":true,"schema":{"type":"array","items":{"type":"string","format":"uuid"},"title":"Ids"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/ConversationInfo"},{"type":"null"}]},"title":"Response Batch Get Conversations Api Conversations Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Conversations"],"summary":"Start Conversation","description":"Start a conversation in the local environment.","operationId":"start_conversation_api_conversations_post","parameters":[{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartConversationRequest","examples":[{"workspace":{"working_dir":"workspace/project","kind":"LocalWorkspace"},"initial_message":{"content":[{"text":"Flip a coin!"}]},"agent":{"llm":{"model":"your-model-provider/your-model-name","api_key":"**********","usage_id":"your-llm-service"},"tools":[{"name":"terminal"},{"name":"file_editor"},{"name":"task_tracker"},{"name":"browser_tool_set"}],"system_prompt_kwargs":{"llm_security_analyzer":true},"kind":"Agent"}}]}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationInfo"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/pause":{"post":{"tags":["Conversations"],"summary":"Pause Conversation","description":"Pause a conversation, allowing it to be resumed later.","operationId":"pause_conversation_api_conversations__conversation_id__pause_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/interrupt":{"post":{"tags":["Conversations"],"summary":"Interrupt Conversation","description":"Immediately interrupt a running conversation.\n\nUnlike ``/pause``, which waits for the current LLM call to finish,\n``/interrupt`` cancels the in-flight request so the effect is instant.\nThe conversation transitions to *paused* and can be resumed later.","operationId":"interrupt_conversation_api_conversations__conversation_id__interrupt_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/run":{"post":{"tags":["Conversations"],"summary":"Run Conversation","description":"Start running the conversation in the background.","operationId":"run_conversation_api_conversations__conversation_id__run_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"409":{"description":"Conversation is already running"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/goal":{"post":{"tags":["Conversations"],"summary":"Start Goal In Conversation","description":"Start a ``/goal`` loop inside an existing conversation.\n\nThe loop appends messages and starts agent runs in the same conversation\nhistory and event stream as the main chat. It does not create a separate\nconversation for the goal or fork the existing one.","operationId":"start_goal_in_conversation_api_conversations__conversation_id__goal_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartGoalRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"409":{"description":"Conversation run or goal loop is already running"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/goal/stop":{"post":{"tags":["Conversations"],"summary":"Stop Goal In Conversation","description":"Stop the active ``/goal`` loop inside this conversation.\n\nThis cancels only the background goal loop, not the conversation itself, and\nrecords an ``interrupted`` goal status so ``/goal/resume`` can continue it.","operationId":"stop_goal_in_conversation_api_conversations__conversation_id__goal_stop_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/goal/resume":{"post":{"tags":["Conversations"],"summary":"Resume Goal In Conversation","description":"Resume the last interrupted ``/goal`` loop inside this conversation.","operationId":"resume_goal_in_conversation_api_conversations__conversation_id__goal_resume_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"409":{"description":"Conversation run or goal loop is already running"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/secrets":{"post":{"tags":["Conversations"],"summary":"Update Conversation Secrets","description":"Update secrets for a conversation.","operationId":"update_conversation_secrets_api_conversations__conversation_id__secrets_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSecretsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/confirmation_policy":{"post":{"tags":["Conversations"],"summary":"Set Conversation Confirmation Policy","description":"Set the confirmation policy for a conversation.","operationId":"set_conversation_confirmation_policy_api_conversations__conversation_id__confirmation_policy_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetConfirmationPolicyRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/security_analyzer":{"post":{"tags":["Conversations"],"summary":"Set Conversation Security Analyzer","description":"Set the security analyzer for a conversation.","operationId":"set_conversation_security_analyzer_api_conversations__conversation_id__security_analyzer_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SetSecurityAnalyzerRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/switch_profile":{"post":{"tags":["Conversations"],"summary":"Switch Conversation Profile","description":"Switch the conversation's LLM profile to a named profile.","operationId":"switch_conversation_profile_api_conversations__conversation_id__switch_profile_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_switch_conversation_profile_api_conversations__conversation_id__switch_profile_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Invalid or corrupted profile"},"404":{"description":"Conversation or profile not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/switch_llm":{"post":{"tags":["Conversations"],"summary":"Switch Conversation Llm","description":"Swap the conversation's LLM to a caller-supplied object.\n\nUsed by app-servers that own the LLM directly and don't push profiles\nto the agent-server's filesystem (see #3017).","operationId":"switch_conversation_llm_api_conversations__conversation_id__switch_llm_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_switch_conversation_llm_api_conversations__conversation_id__switch_llm_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/switch_acp_model":{"post":{"tags":["Conversations"],"summary":"Switch Conversation Acp Model","description":"Switch the model of an ACP conversation.\n\nFor a conversation that has already started, issues a protocol-level\n``session/set_model`` call to the ACP subprocess so the new model applies to\nsubsequent turns without losing context. For one created but not yet run,\nthe value is persisted and applied when the first session starts (returns\n``200`` either way). Only valid for ACP conversations whose provider\nsupports model switching.","operationId":"switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Body_switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"400":{"description":"Agent is not ACP, or provider can't switch models"},"404":{"description":"Conversation not found"},"504":{"description":"ACP server did not answer the model switch in time"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/ask_agent":{"post":{"tags":["Conversations"],"summary":"Ask Agent","description":"Ask the agent a simple question without affecting conversation state.","operationId":"ask_agent_api_conversations__conversation_id__ask_agent_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskAgentRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AskAgentResponse"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/condense":{"post":{"tags":["Conversations"],"summary":"Condense Conversation","description":"Force condensation of the conversation history.","operationId":"condense_conversation_api_conversations__conversation_id__condense_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/fork":{"post":{"tags":["Conversations"],"summary":"Fork Conversation","description":"Fork a conversation, deep-copying its event history.\n\nThe fork starts in ``idle`` status with a fresh event loop.\nCalling ``run`` on the fork resumes from the copied state, meaning\nthe agent has full event memory of the source conversation.","operationId":"fork_conversation_api_conversations__conversation_id__fork_post","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"include_skills","in":"query","required":false,"schema":{"type":"boolean","title":"Whether to include ``agent.agent_context.skills`` in the response. Default ``false`` (breaking change as of this release): skills are trimmed to ``[]`` on the wire because no known consumer reads them from HTTP responses, and a stock agent inlines ~260 KB of skill content per fetch. Pass ``true`` to opt back into the legacy full-payload shape — useful only for callers that still rely on ``RemoteConversation.agent.agent_context.skills`` round-tripping over the wire. The persisted conversation state on disk and the in-memory runtime copy are untouched either way.","default":false}}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForkConversationRequest","default":{"reset_metrics":true}}}}},"responses":{"201":{"description":"Forked conversation created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConversationInfo"}}}},"404":{"description":"Source conversation not found"},"409":{"description":"Fork ID already in use"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/tools/":{"get":{"tags":["Tools"],"summary":"List Available Tools","description":"List all available tools.","operationId":"list_available_tools_api_tools__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Response List Available Tools Api Tools Get"}}}}}}},"/api/bash/bash_events/search":{"get":{"tags":["Bash"],"summary":"Search Bash Events","description":"Search / List bash event events","operationId":"search_bash_events_api_bash_bash_events_search_get","parameters":[{"name":"kind__eq","in":"query","required":false,"schema":{"anyOf":[{"enum":["BashCommand","BashOutput"],"type":"string"},{"type":"null"}],"title":"Kind Eq"}},{"name":"command_id__eq","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Command Id Eq"}},{"name":"timestamp__gte","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp Gte"}},{"name":"timestamp__lt","in":"query","required":false,"schema":{"anyOf":[{"type":"string","format":"date-time"},{"type":"null"}],"title":"Timestamp Lt"}},{"name":"order__gt","in":"query","required":false,"schema":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Filter to events with order greater than this value","description":"Only returns BashOutput events with order > this value. Useful for polling to fetch only new events since the last poll."},"description":"Only returns BashOutput events with order > this value. Useful for polling to fetch only new events since the last poll."},{"name":"sort_order","in":"query","required":false,"schema":{"$ref":"#/components/schemas/BashEventSortOrder","default":"TIMESTAMP"}},{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashEventPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/bash_events/{event_id}":{"get":{"tags":["Bash"],"summary":"Get Bash Event","description":"Get a bash event event given an id","operationId":"get_bash_event_api_bash_bash_events__event_id__get","parameters":[{"name":"event_id","in":"path","required":true,"schema":{"type":"string","title":"Event Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashEventBase"}}}},"404":{"description":"Item not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/bash_events/":{"get":{"tags":["Bash"],"summary":"Batch Get Bash Events","description":"Get a batch of bash event events given their ids, returning null for any\nmissing item.","operationId":"batch_get_bash_events_api_bash_bash_events__get","requestBody":{"content":{"application/json":{"schema":{"items":{"type":"string"},"type":"array","title":"Event Ids"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"items":{"anyOf":[{"$ref":"#/components/schemas/BashEventBase"},{"type":"null"}]},"type":"array","title":"Response Batch Get Bash Events Api Bash Bash Events Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/start_bash_command":{"post":{"tags":["Bash"],"summary":"Start Bash Command","description":"Execute a bash command in the background","operationId":"start_bash_command_api_bash_start_bash_command_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteBashRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashCommand"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/execute_bash_command":{"post":{"tags":["Bash"],"summary":"Execute Bash Command","description":"Execute a bash command and wait for a result","operationId":"execute_bash_command_api_bash_execute_bash_command_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ExecuteBashRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BashOutput"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/bash/bash_events":{"delete":{"tags":["Bash"],"summary":"Clear All Bash Events","description":"Clear all bash events from storage","operationId":"clear_all_bash_events_api_bash_bash_events_delete","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"type":"integer"},"type":"object","title":"Response Clear All Bash Events Api Bash Bash Events Delete"}}}}}}},"/api/git/changes":{"get":{"tags":["Git"],"summary":"Git Changes Query","description":"Get git changes using query parameter (preferred method).","operationId":"git_changes_query_api_git_changes_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"The git repository path","title":"Path"},"description":"The git repository path"},{"name":"ref","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected.","title":"Ref"},"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GitChange"},"title":"Response Git Changes Query Api Git Changes Get"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/git/diff":{"get":{"tags":["Git"],"summary":"Git Diff Query","description":"Get git diff using query parameter (preferred method).","operationId":"git_diff_query_api_git_diff_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"The file path to get diff for","title":"Path"},"description":"The file path to get diff for"},{"name":"ref","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected.","title":"Ref"},"description":"Optional git ref to diff against (e.g. 'HEAD' for git status-style changes, or a commit hash). When omitted, the upstream/default branch is auto-detected."}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GitDiff"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/upload":{"post":{"tags":["Files"],"summary":"Upload File Query","description":"Upload a file to the workspace using query parameter (preferred method).","operationId":"upload_file_query_api_file_upload_post","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute file path","title":"Path"},"description":"Absolute file path"}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"$ref":"#/components/schemas/Body_upload_file_query_api_file_upload_post"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Success"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/download":{"get":{"tags":["Files"],"summary":"Download File Query","description":"Download a file from the workspace using query parameter (preferred method).","operationId":"download_file_query_api_file_download_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute file path","title":"Path"},"description":"Absolute file path"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/home":{"get":{"tags":["Files"],"summary":"Get Home Directory","description":"Return the agent-server user's home directory and dynamic sidebar lists.\n\n``favorites`` is the set of visible top-level directories actually present\nin the user's home (so it reflects the real environment instead of a\nhardcoded list of names that may not exist). ``locations`` is the set of\nfilesystem roots — '/' on POSIX or available drive letters on Windows.","operationId":"get_home_directory_api_file_home_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HomeResponse"}}}}}}},"/api/file/search_subdirs":{"get":{"tags":["Files"],"summary":"Search Subdirs","description":"Search / List immediate subdirectories of `path`.\n\nUsed by the GUI's workspace picker. Hidden entries (names starting with '.')\nand symlinks are skipped. Files are skipped. Returns absolute paths so the\nGUI can use a result directly as ``workspace.working_dir``.\n\nResults are sorted case-insensitively by name and paginated. ``page_id`` is\nthe ``next_page_id`` returned by the previous page (the lowercase name of\nthe first item to include on the next page).","operationId":"search_subdirs_api_file_search_subdirs_get","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute directory path to list subdirectories of","title":"Path"},"description":"Absolute directory path to list subdirectories of"},{"name":"page_id","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Optional next_page_id from the previously returned page"}},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","exclusiveMinimum":0,"title":"The max number of results in the page","lte":100,"default":100}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubdirectoryPage"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/file/download-trajectory/{conversation_id}":{"get":{"tags":["Files"],"summary":"Download Trajectory","description":"Download a zip archive of a conversation trajectory.","operationId":"download_trajectory_api_file_download_trajectory__conversation_id__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/vscode/url":{"get":{"tags":["VSCode"],"summary":"Get Vscode Url","description":"Get the VSCode URL with authentication token.\n\nArgs:\n base_url: Base URL for the VSCode server (default: http://localhost:8001)\n workspace_dir: Path to workspace directory\n\nReturns:\n VSCode URL with token if available, None otherwise","operationId":"get_vscode_url_api_vscode_url_get","parameters":[{"name":"base_url","in":"query","required":false,"schema":{"type":"string","default":"http://localhost:8001","title":"Base Url"}},{"name":"workspace_dir","in":"query","required":false,"schema":{"type":"string","default":"workspace","title":"Workspace Dir"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VSCodeUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/vscode/status":{"get":{"tags":["VSCode"],"summary":"Get Vscode Status","description":"Get the VSCode server status.\n\nReturns:\n Dictionary with running status and enabled status","operationId":"get_vscode_status_api_vscode_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"additionalProperties":{"anyOf":[{"type":"boolean"},{"type":"string"}]},"type":"object","title":"Response Get Vscode Status Api Vscode Status Get"}}}}}}},"/api/desktop/url":{"get":{"tags":["Desktop"],"summary":"Get Desktop Url","description":"Get the noVNC URL for desktop access.\n\nArgs:\n base_url: Base URL for the noVNC server (default: http://localhost:8002)\n\nReturns:\n noVNC URL if available, None otherwise","operationId":"get_desktop_url_api_desktop_url_get","parameters":[{"name":"base_url","in":"query","required":false,"schema":{"type":"string","default":"http://localhost:8002","title":"Base Url"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DesktopUrlResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills":{"post":{"tags":["Skills"],"summary":"Get Skills","description":"Load and merge skills from all configured sources.\n\nSkills are loaded from multiple sources and merged with the following\nprecedence (later overrides earlier for duplicate names):\n1. Sandbox skills (lowest) - Exposed URLs from sandbox\n2. Public skills - From GitHub OpenHands/extensions repository\n3. User skills - From ~/.openhands/skills/\n4. Organization skills - From {org}/.openhands or equivalent\n5. Project skills (highest) - From {workspace}/.openhands/skills/\n\nArgs:\n request: SkillsRequest containing configuration for which sources to load.\n\nReturns:\n SkillsResponse containing merged skills and source counts.","operationId":"get_skills_api_skills_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillsRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SkillsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/sync":{"post":{"tags":["Skills"],"summary":"Sync Skills","description":"Force refresh of public skills from GitHub repository.\n\nThis triggers a git pull on the cached skills repository to get\nthe latest skills from the OpenHands/extensions repository.\n\nReturns:\n SyncResponse indicating success or failure.","operationId":"sync_skills_api_skills_sync_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SyncResponse"}}}}}}},"/api/skills/install":{"post":{"tags":["Skills"],"summary":"Install Skill Endpoint","description":"Install a skill from a source.\n\nInstalls a skill from a git URL, GitHub shorthand, or local path into\nthe user's installed skills directory (~/.openhands/skills/installed/).\n\nArgs:\n request: InstallSkillRequest containing source and options.\n\nReturns:\n InstalledSkillResponse with details about the installation.\n\nRaises:\n HTTPException 409: If skill is already installed and force=False.\n HTTPException 400: If fetching the skill source fails.\n HTTPException 422: If the skill is invalid.","operationId":"install_skill_endpoint_api_skills_install_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstallSkillRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstalledSkillResponse"}}}},"400":{"description":"Failed to fetch skill source"},"409":{"description":"Skill already installed (use force=true)"},"422":{"description":"Invalid skill (missing SKILL.md, etc.)"}}}},"/api/skills/installed":{"get":{"tags":["Skills"],"summary":"List Installed Skills Endpoint","description":"List all installed skills.\n\nReturns a list of all skills installed in the user's installed skills\ndirectory (~/.openhands/skills/installed/).\n\nReturns:\n InstalledSkillsListResponse containing list of installed skills.","operationId":"list_installed_skills_endpoint_api_skills_installed_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstalledSkillsListResponse"}}}}}}},"/api/skills/installed/{skill_name}":{"get":{"tags":["Skills"],"summary":"Get Installed Skill Endpoint","description":"Get information about a specific installed skill.\n\nArgs:\n skill_name: Name of the skill to get.\n\nReturns:\n InstalledSkillResponse with skill details.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"get_installed_skill_endpoint_api_skills_installed__skill_name__get","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstalledSkillResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"patch":{"tags":["Skills"],"summary":"Set Skill Enabled Endpoint","description":"Enable or disable an installed skill.\n\nArgs:\n skill_name: Name of the skill to update.\n request: UpdateSkillStateRequest with enabled state.\n\nReturns:\n UpdateSkillStateResponse indicating new state.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"set_skill_enabled_endpoint_api_skills_installed__skill_name__patch","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillStateRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillStateResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Skills"],"summary":"Uninstall Skill Endpoint","description":"Uninstall a skill by name.\n\nRemoves a skill from the user's installed skills directory.\n\nArgs:\n skill_name: Name of the skill to uninstall.\n\nReturns:\n UninstallSkillResponse with uninstall message.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"uninstall_skill_endpoint_api_skills_installed__skill_name__delete","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UninstallSkillResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/installed/{skill_name}/refresh":{"post":{"tags":["Skills"],"summary":"Refresh Skill Endpoint","description":"Refresh an installed skill to the latest version.\n\nRe-fetches the skill from its original source and updates the installation.\n\nArgs:\n skill_name: Name of the skill to refresh.\n\nReturns:\n UpdateSkillResponse with updated skill information.\n\nRaises:\n HTTPException 404: If the skill is not installed.","operationId":"refresh_skill_endpoint_api_skills_installed__skill_name__refresh_post","parameters":[{"name":"skill_name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":255,"pattern":"^[a-z0-9]+(-[a-z0-9]+)*$","description":"Skill name (lowercase alphanumeric, hyphens)","title":"Skill Name"},"description":"Skill name (lowercase alphanumeric, hyphens)"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateSkillResponse"}}}},"404":{"description":"Skill not installed"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/skills/marketplace":{"get":{"tags":["Skills"],"summary":"Get Marketplace Catalog","description":"Get the marketplace catalog with installation status.\n\nReturns a list of available skills from the OpenHands extensions\nrepository marketplace, along with their installation status.\n\nThis enables frontend applications to display a \"Marketplace\" tab\nwith installable skills.\n\nReturns:\n MarketplaceCatalogResponse containing list of available skills.","operationId":"get_marketplace_catalog_api_skills_marketplace_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MarketplaceCatalogResponse"}}}}}}},"/api/hooks":{"post":{"tags":["Hooks"],"summary":"Get Hooks","description":"Load hooks from the workspace .openhands/hooks.json file.\n\nThis endpoint reads the hooks configuration from the project's\n.openhands/hooks.json file if it exists.\n\nArgs:\n request: HooksRequest containing the project directory path.\n\nReturns:\n HooksResponse containing the hook configuration or None.","operationId":"get_hooks_api_hooks_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/HooksRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HooksResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/llm/providers":{"get":{"tags":["LLM"],"summary":"List Providers","description":"List all available LLM providers supported by LiteLLM.","operationId":"list_providers_api_llm_providers_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProvidersResponse"}}}}}}},"/api/llm/models":{"get":{"tags":["LLM"],"summary":"List Models","description":"List all available LLM models supported by LiteLLM.\n\nArgs:\n provider: Optional provider name to filter models by.\n\nNote: Bedrock models are excluded unless AWS credentials are configured.","operationId":"list_models_api_llm_models_get","parameters":[{"name":"provider","in":"query","required":false,"schema":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Filter models by provider (e.g., 'openai', 'anthropic')","title":"Provider"},"description":"Filter models by provider (e.g., 'openai', 'anthropic')"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ModelsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/llm/models/verified":{"get":{"tags":["LLM"],"summary":"List Verified Models","description":"List all verified LLM models organized by provider.\n\nVerified models are those that have been tested and confirmed to work well\nwith OpenHands.","operationId":"list_verified_models_api_llm_models_verified_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifiedModelsResponse"}}}}}}},"/api/llm/subscription/openai/models":{"get":{"tags":["LLM"],"summary":"List Openai Subscription Models","description":"List models available through ChatGPT subscription authentication.","operationId":"list_openai_subscription_models_api_llm_subscription_openai_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionModelsResponse"}}}}}}},"/api/llm/subscription/openai/status":{"get":{"tags":["LLM"],"summary":"Get Openai Subscription Status","description":"Return safe ChatGPT subscription connection state without tokens.","operationId":"get_openai_subscription_status_api_llm_subscription_openai_status_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"}}}}}}},"/api/llm/subscription/openai/device/start":{"post":{"tags":["LLM"],"summary":"Start Openai Subscription Device Login","description":"Start ChatGPT device-code sign-in without returning tokens.","operationId":"start_openai_subscription_device_login_api_llm_subscription_openai_device_start_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDeviceStartResponse"}}}}}}},"/api/llm/subscription/openai/device/poll":{"post":{"tags":["LLM"],"summary":"Poll Openai Subscription Device Login","description":"Poll a ChatGPT device-code sign-in without returning tokens.","operationId":"poll_openai_subscription_device_login_api_llm_subscription_openai_device_poll_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionDevicePollRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/llm/subscription/openai/logout":{"post":{"tags":["LLM"],"summary":"Logout Openai Subscription","description":"Remove stored ChatGPT subscription credentials.","operationId":"logout_openai_subscription_api_llm_subscription_openai_logout_post","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionStatusResponse"}}}}}}},"/api/mcp/test":{"post":{"tags":["MCP"],"summary":"Test an MCP server configuration","description":"Attempt to connect to a candidate MCP server and list its tools, without persisting any settings. Useful for validating user input in 'add MCP server' flows before storing the config. Optionally invokes one caller-chosen (read-only) tool via `tool_call` and reports its outcome in `tool_result`, so callers can verify credentials that are only exercised on tool invocation. Encrypted `env`/`headers` values round-tripped from settings are decrypted before the connection is attempted. Returns 200 with `ok=false` for connection / timeout failures (those are expected during validation, not server errors).","operationId":"test_mcp_server_api_mcp_test_post","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MCPTestRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/MCPTestSuccess"},{"$ref":"#/components/schemas/MCPTestFailure"}],"title":"Response Test Mcp Server Api Mcp Test Post"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings/agent-schema":{"get":{"tags":["Settings"],"summary":"Get Agent Settings Schema","description":"Return the schema used to render AgentSettings-based settings forms.","operationId":"get_agent_settings_schema_api_settings_agent_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsSchema"}}}}}}},"/api/settings/conversation-schema":{"get":{"tags":["Settings"],"summary":"Get Conversation Settings Schema","description":"Return the schema used to render ConversationSettings-based forms.","operationId":"get_conversation_settings_schema_api_settings_conversation_schema_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsSchema"}}}}}}},"/api/settings":{"get":{"tags":["Settings"],"summary":"Get Settings","description":"Get current settings.\n\nReturns the persisted settings including agent configuration,\nconversation settings, and whether an LLM API key is configured.\n\nUse the ``X-Expose-Secrets`` header to control secret exposure:\n- ``encrypted``: Returns cipher-encrypted values (safe for frontend clients)\n- ``plaintext``: Returns raw secret values (backend clients only!)\n- (absent): Returns redacted values (\"**********\")\n\nSecurity:\n When the server is configured with ``session_api_keys``, all endpoints\n under ``/api`` (including this one) require the ``X-Session-API-Key``\n header. When no session API keys are configured, endpoints are open.\n\n **Trust model:** All authenticated clients are treated as equally\n trusted. There is no role-based authorization for ``X-Expose-Secrets``\n modes—any authenticated client can request ``plaintext`` or\n ``encrypted`` exposure. This design assumes:\n\n - All clients sharing session API keys operate in the same trust domain\n - Network-level controls (firewalls, VPCs) restrict access to trusted\n clients only\n - Production deployments use session API keys to prevent anonymous access\n\n The ``plaintext`` mode exists for backend-to-backend communication\n (e.g., RemoteWorkspace). Frontend clients should prefer ``encrypted``\n mode for round-tripping secrets, or omit the header to receive redacted\n values.","operationId":"get_settings_api_settings_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}}}},"patch":{"tags":["Settings"],"summary":"Update Settings","description":"Update settings with partial changes.\n\nAccepts ``agent_settings_diff``, ``conversation_settings_diff``,\n``misc_settings_diff``, and/or ``active_profile`` for incremental updates.\nThe three ``*_settings_diff`` fields are deep-merged; nested objects merge\nrecursively, and a ``null`` value **inside a nested map deletes that entry**\n— the \"unset\" primitive that lets a client remove a single map key without\nround-tripping the whole map. To remove one MCP server's header::\n\n PATCH /api/settings\n {\"agent_settings_diff\":\n {\"mcp_config\": {\"mcpServers\": {\"svc\": {\"headers\": {\"X-Old\": null}}}}}}\n\nA ``null`` on a top-level *field* (e.g. ``{\"confirmation_mode\": null}``)\nis **not** an unset — it flows to model validation as before, so it still\nfails loudly rather than silently resetting the field to its default.\n\n``misc_settings_diff`` is deep-merged into the persisted ``misc_settings``\nblock. The agent-server treats ``misc_settings`` as opaque frontend-owned\ndata: nested dicts are merged recursively, lists are replaced wholesale,\nand the contents are never read or validated server-side.\n\nUses file locking to prevent concurrent updates from overwriting each other.\n\nRaises:\n HTTPException: 400 if the update payload contains invalid values.","operationId":"update_settings_api_settings_patch","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsUpdateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SettingsResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings/secrets":{"get":{"tags":["Settings"],"summary":"List Secrets","description":"List all available secrets (names and descriptions only, no values).","operationId":"list_secrets_api_settings_secrets_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretsListResponse"}}}}}},"put":{"tags":["Settings"],"summary":"Create Secret","description":"Create or update a custom secret (upsert).\n\nRaises:\n HTTPException: 400 if secret name format is invalid, 500 if file is corrupted.","operationId":"create_secret_api_settings_secrets_put","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretCreateRequest"}}},"required":true},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretItemResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/settings/secrets/{name}":{"get":{"tags":["Settings"],"summary":"Get Secret Value","description":"Get a single secret value by name.\n\nReturns the raw secret value as plain text. This endpoint is designed\nto be used with LookupSecret for lazy secret resolution.\n\nRaises:\n HTTPException: 400 if name format is invalid, 404 if secret not found.","operationId":"get_secret_value_api_settings_secrets__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Settings"],"summary":"Delete Secret","description":"Delete a custom secret by name.\n\nRaises:\n HTTPException: 400 if name format is invalid, 404 if secret not found,\n 500 if file is corrupted.","operationId":"delete_secret_api_settings_secrets__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"type":"object","additionalProperties":{"type":"boolean"},"title":"Response Delete Secret Api Settings Secrets Name Delete"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspaces":{"get":{"tags":["Workspaces"],"summary":"List Workspaces","description":"Return the saved workspaces and workspace parents.","operationId":"list_workspaces_api_workspaces_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacesListResponse"}}}}}},"post":{"tags":["Workspaces"],"summary":"Add Workspaces","description":"Append workspaces to the saved list. Idempotent — dedupes by ``path``.","operationId":"add_workspaces_api_workspaces_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddWorkspacesRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacesListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Workspaces"],"summary":"Delete Workspace","description":"Remove a workspace by its absolute path.","operationId":"delete_workspace_api_workspaces_delete","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute workspace path to remove","title":"Path"},"description":"Absolute workspace path to remove"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/workspaces/parents":{"post":{"tags":["Workspaces"],"summary":"Add Workspace Parents","description":"Append workspace parents. Idempotent — dedupes by ``path``.","operationId":"add_workspace_parents_api_workspaces_parents_post","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AddWorkspaceParentsRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacesListResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Workspaces"],"summary":"Delete Workspace Parent","description":"Remove a workspace parent by its absolute path.","operationId":"delete_workspace_parent_api_workspaces_parents_delete","parameters":[{"name":"path","in":"query","required":true,"schema":{"type":"string","description":"Absolute workspace parent path to remove","title":"Path"},"description":"Absolute workspace parent path to remove"}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles":{"get":{"tags":["Profiles"],"summary":"List Profiles","description":"List all saved LLM profiles.\n\nReturns the list of profiles along with the currently active profile name,\nif one has been activated. The active_profile tracks which LLM profile\nconfiguration is currently in use.","operationId":"list_profiles_api_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileListResponse"}}}}}}},"/api/profiles/{name}":{"get":{"tags":["Profiles"],"summary":"Get Profile","description":"Get a profile's configuration.\n\nUse the ``X-Expose-Secrets`` header to control secret exposure:\n- ``encrypted``: Returns cipher-encrypted values (safe for frontend clients)\n- ``plaintext``: Returns raw secret values (backend clients only!)\n- (absent): Returns nulled ``api_key`` with ``api_key_set`` indicator","operationId":"get_profile_api_profiles__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Profiles"],"summary":"Save Profile","description":"Save an LLM configuration as a named profile.\n\nOverwrites an existing profile of the same name. Returns 409 if creating\na new profile would exceed ``MAX_PROFILES``.\n\nWhen ``OH_SECRET_KEY`` is configured, secrets are encrypted at rest.\nClients can submit cipher-encrypted secrets which will be decrypted\nserver-side before re-encrypting with the storage cipher.","operationId":"save_profile_api_profiles__name__post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SaveProfileRequest"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Profiles"],"summary":"Delete Profile","description":"Delete a saved profile (idempotent).\n\nGuarded by the agent-profile FK: returns 409 naming the referrers if any\n``AgentProfile`` still cites this LLM profile via ``llm_profile_ref``.","operationId":"delete_profile_api_profiles__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/rename":{"post":{"tags":["Profiles"],"summary":"Rename Profile","description":"Rename a saved profile atomically.\n\nReturns 404 if the source does not exist, or 409 if ``new_name`` already\nexists. A same-name rename is a verified no-op (still 404s if missing).\n\nIf the renamed profile is the currently active profile, the active_profile\nsetting is updated to the new name. Any ``AgentProfile.llm_profile_ref``\nciting the old name is cascaded to the new name in lock-step.","operationId":"rename_profile_api_profiles__name__rename_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameProfileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/profiles/{name}/activate":{"post":{"tags":["Profiles"],"summary":"Activate Profile","description":"Activate a saved LLM profile.\n\nThis endpoint:\n1. Loads the named profile's LLM configuration\n2. Applies it to the current agent settings (updates ``agent_settings.llm``)\n3. Records the profile name as the active profile for frontend tracking\n\nReturns 404 if the profile does not exist.\n\nUse ``GET /api/profiles`` to see which profile is currently active via\nthe ``active_profile`` field.","operationId":"activate_profile_api_profiles__name__activate_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles":{"get":{"tags":["Agent Profiles"],"summary":"List Agent Profiles","description":"List all stored agent profiles and the active pointer.\n\nOn the first call against an empty store with no active pointer, lazily\nseeds one default profile from the current ``agent_settings`` and activates\nit (the one-time migration that replaces a dedicated seed step).","operationId":"list_agent_profiles_api_agent_profiles_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileListResponse"}}}}}}},"/api/agent-profiles/{name}":{"get":{"tags":["Agent Profiles"],"summary":"Get Agent Profile","description":"Get a stored profile.\n\nUse the ``X-Expose-Secrets`` header to control ``skills[].mcp_tools`` secret\nexposure (``encrypted`` / ``plaintext``); absent, those values are masked.","operationId":"get_agent_profile_api_agent_profiles__name__get","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileDetailResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"post":{"tags":["Agent Profiles"],"summary":"Save Agent Profile","description":"Save an ``AgentProfile`` under ``name`` (overwriting a namesake).\n\nThe path ``name`` is authoritative — it overrides any ``name`` in the body.\nWith ``OH_SECRET_KEY`` configured, ``skills[].mcp_tools`` secrets are\nencrypted at rest; otherwise they are redacted. Returns 409 if creating a\nnew profile would exceed ``MAX_AGENT_PROFILES``.","operationId":"save_agent_profile_api_agent_profiles__name__post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":true,"title":"Body"}}}},"responses":{"201":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}},"delete":{"tags":["Agent Profiles"],"summary":"Delete Agent Profile","description":"Delete a stored profile (idempotent).\n\nIf the deleted profile was the active one, ``active_agent_profile_id`` is\ncleared.","operationId":"delete_agent_profile_api_agent_profiles__name__delete","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles/{name}/rename":{"post":{"tags":["Agent Profiles"],"summary":"Rename Agent Profile","description":"Rename a stored profile atomically.\n\nThe stable ``id`` is preserved, so an active pointer (keyed on ``id``)\nsurvives the rename untouched. Returns 404 if the source is missing, 409 if\n``new_name`` is taken.","operationId":"rename_agent_profile_api_agent_profiles__name__rename_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RenameAgentProfileRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileMutationResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles/{profile_id}/activate":{"post":{"tags":["Agent Profiles"],"summary":"Activate Agent Profile","description":"Activate a profile by its stable ``id`` — pointer only.\n\nSets ``active_agent_profile_id`` and nothing else: unlike the LLM\n``/activate``, this does **not** write ``agent_settings`` (the\ncreation-time-only contract). Returns 404 if no stored profile has that id.","operationId":"activate_agent_profile_api_agent_profiles__profile_id__activate_post","parameters":[{"name":"profile_id","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":128,"title":"Profile Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActivateAgentProfileResponse"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/agent-profiles/{name}/materialize":{"post":{"tags":["Agent Profiles"],"summary":"Materialize Agent Profile","description":"Dry-run resolve a profile's LLM/MCP references; return a diagnostics report.\n\nDangling LLM/MCP references are reported in the body (valid=False) rather\nthan raising — the only error status is 404 (unknown profile name).\nresolved_settings is redacted (api_key_set booleans; no raw secrets).","operationId":"materialize_agent_profile_api_agent_profiles__name__materialize_post","parameters":[{"name":"name","in":"path","required":true,"schema":{"type":"string","minLength":1,"maxLength":64,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"Name"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AgentProfileDiagnostics"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/auth/workspace-session":{"post":{"tags":["Auth"],"summary":"Create Workspace Session","description":"Mint a workspace-scoped session cookie.\n\nCaller must already be authenticated by the ``X-Session-API-Key``\nheader (enforced by the parent router's dependency). The cookie value\nis the validated session API key itself; it is HttpOnly so JS in\nworkspace HTML cannot read it back.","operationId":"create_workspace_session_api_auth_workspace_session_post","responses":{"204":{"description":"Cookie set"},"401":{"description":"Missing or invalid X-Session-API-Key header"}}},"delete":{"tags":["Auth"],"summary":"Delete Workspace Session","description":"Clear the workspace session cookie.\n\nBrowsers identify cookies by ``(name, domain, path)``; the deletion\ncookie must therefore share the original cookie's attributes. We\noverwrite with an empty value and ``max_age=0`` so the browser drops\nit immediately.","operationId":"delete_workspace_session_api_auth_workspace_session_delete","responses":{"204":{"description":"Cookie cleared"}}}},"/v1/models":{"get":{"tags":["OpenAI Compatibility"],"summary":"Get Openai Models","operationId":"get_openai_models_v1_models_get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAIModelListResponse"}}}}}}},"/v1/chat/completions":{"post":{"tags":["OpenAI Compatibility"],"summary":"Create Chat Completion","operationId":"create_chat_completion_v1_chat_completions_post","parameters":[{"name":"X-OpenHands-ServerConversation-ID","in":"header","required":false,"schema":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"X-Openhands-Serverconversation-Id"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OpenAIChatCompletionRequest"}}}},"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ChatCompletion"}}}},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/workspace":{"get":{"tags":["Workspace"],"summary":"Serve Workspace Root","description":"Serve ``index.html`` from the conversation's workspace root.","operationId":"serve_workspace_root_api_conversations__conversation_id__workspace_get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"File or conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/api/conversations/{conversation_id}/workspace/{file_path}":{"get":{"tags":["Workspace"],"summary":"Serve Workspace File","description":"Serve a file (or directory ``index.html``) from the workspace.","operationId":"serve_workspace_file_api_conversations__conversation_id__workspace__file_path__get","parameters":[{"name":"conversation_id","in":"path","required":true,"schema":{"type":"string","format":"uuid","title":"Conversation Id"}},{"name":"file_path","in":"path","required":true,"schema":{"type":"string","title":"File Path"}}],"responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{}}}},"404":{"description":"File or conversation not found"},"422":{"description":"Validation Error","content":{"application/json":{"schema":{"$ref":"#/components/schemas/HTTPValidationError"}}}}}}},"/":{"get":{"tags":["Server Details"],"summary":"Get Server Info","operationId":"get_server_info__get","responses":{"200":{"description":"Successful Response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ServerInfo"}}}}}}}},"components":{"schemas":{"ACPAgent-Input":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"},"tools":{"items":{"$ref":"#/components/schemas/Tool-Input"},"type":"array","title":"Tools"},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools"},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Input"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Input"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Input"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"acp_command":{"items":{"type":"string"},"type":"array","title":"Acp Command","description":"Command to start the ACP server, e.g. ['npx', '-y', '@agentclientprotocol/claude-agent-acp']"},"acp_server":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Server","description":"Provider registry key identifying which ACP CLI this agent runs ('claude-code', 'codex', 'gemini-cli', or 'custom'); None when the agent is built directly rather than via ACPAgentSettings. Set by ACPAgentSettings.create_agent() from ACPAgentSettings.acp_server so the authoritative key survives onto the agent — and thus onto ConversationInfo.agent — because the launch command in acp_command does not reliably reverse-map to a provider. Informational only: consumers use it to resolve a provider brand label / model list; the subprocess is still launched from acp_command."},"acp_args":{"items":{"type":"string"},"type":"array","title":"Acp Args","description":"Additional arguments for the ACP server command"},"acp_session_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Session Mode","description":"Session mode ID to set after creating a session. If None (default), auto-detected from the ACP server type: 'bypassPermissions' for claude-agent-acp, 'full-access' for codex-acp."},"acp_prompt_timeout":{"type":"number","title":"Acp Prompt Timeout","description":"Inactivity timeout in seconds for a single ACP prompt() call. The deadline resets on every update from the ACP server (token, thought, tool-call progress, usage), so a steadily-progressing agent runs as long as it keeps making progress; the prompt is only aborted after this many seconds with no activity at all. Prevents indefinite hangs when the ACP server stops responding without killing legitimately long-running work.","default":1800.0},"acp_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Model","description":"Model for the ACP server to use (e.g. 'sonnet' or 'gpt-5.5'). Applied via the protocol — set_config_option(model) for configOptions-based servers (codex, claude), else set_session_model. If None, the server picks its default."},"acp_resume_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Resume Session Id","description":"Optional explicit ACP session id to resume. When set, takes precedence over the id persisted in ``state.agent_state`` and is used to call ``session/load`` on the ACP server. Designed for environments where the per-conversation filesystem (and therefore ``base_state.json``) does not survive across restarts (e.g. cloud sandbox recycles), but the id has been mirrored into durable storage elsewhere. Falls back to a fresh session if the server cannot load the id. Treated as a secret on the wire — possession of the id is enough to resume the underlying ACP session, so default serialization redacts it; pass ``expose_secrets='plaintext'`` (trusted backend) or ``expose_secrets='encrypted'`` plus a cipher (frontend round-trip) when the value must cross a serialization boundary."},"acp_file_secrets":{"items":{"$ref":"#/components/schemas/ACPFileSecretSpec"},"type":"array","title":"Acp File Secrets","description":"Reserved 'file-content' credential secrets to materialise to disk before launching the subprocess (e.g. Codex auth.json, Gemini Vertex SA JSON). The SDK owns the mechanism (write the file in the runtime pod, set the env var, seed-if-absent); these specs are the policy. Defaults to the built-in supported providers; a downstream application may override or extend this to support other ACP servers with different file-auth schemes."},"acp_isolate_data_dir":{"type":"boolean","title":"Acp Isolate Data Dir","description":"Give the ACP subprocess a per-conversation CLI data/config root instead of the shared user ``HOME``. When True and the provider is recognised, point its data-dir env var (``CODEX_HOME`` / ``CLAUDE_CONFIG_DIR`` / ``HOME``; see ``ACPProviderInfo.data_dir_env_var``) at ``/acp/`` — the same per-conversation tree materialised file-secrets use. Required for correctness when several of a user's conversations share one sandbox (``SandboxGroupingStrategy != NO_GROUPING``), where they would otherwise race on one set of CLI auth/config/cache/lock files (see #1019). Off by default: with one sandbox per conversation the shared HOME is already private, and relocating it would hide a pre-existing interactive login. Downstream policy decides when to enable it; the SDK owns where the root lives.","default":false},"kind":{"type":"string","const":"ACPAgent","title":"Kind"}},"type":"object","required":["acp_command"],"title":"ACPAgent","description":"Agent that delegates to an ACP-compatible subprocess server."},"ACPAgent-Output":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Output"},"tools":{"items":{"$ref":"#/components/schemas/openhands__sdk__tool__spec__Tool"},"type":"array","title":"Tools"},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools"},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Output"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Output"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Output"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"acp_command":{"items":{"type":"string"},"type":"array","title":"Acp Command","description":"Command to start the ACP server, e.g. ['npx', '-y', '@agentclientprotocol/claude-agent-acp']"},"acp_server":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Server","description":"Provider registry key identifying which ACP CLI this agent runs ('claude-code', 'codex', 'gemini-cli', or 'custom'); None when the agent is built directly rather than via ACPAgentSettings. Set by ACPAgentSettings.create_agent() from ACPAgentSettings.acp_server so the authoritative key survives onto the agent — and thus onto ConversationInfo.agent — because the launch command in acp_command does not reliably reverse-map to a provider. Informational only: consumers use it to resolve a provider brand label / model list; the subprocess is still launched from acp_command."},"acp_args":{"items":{"type":"string"},"type":"array","title":"Acp Args","description":"Additional arguments for the ACP server command"},"acp_session_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Session Mode","description":"Session mode ID to set after creating a session. If None (default), auto-detected from the ACP server type: 'bypassPermissions' for claude-agent-acp, 'full-access' for codex-acp."},"acp_prompt_timeout":{"type":"number","title":"Acp Prompt Timeout","description":"Inactivity timeout in seconds for a single ACP prompt() call. The deadline resets on every update from the ACP server (token, thought, tool-call progress, usage), so a steadily-progressing agent runs as long as it keeps making progress; the prompt is only aborted after this many seconds with no activity at all. Prevents indefinite hangs when the ACP server stops responding without killing legitimately long-running work.","default":1800.0},"acp_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Model","description":"Model for the ACP server to use (e.g. 'sonnet' or 'gpt-5.5'). Applied via the protocol — set_config_option(model) for configOptions-based servers (codex, claude), else set_session_model. If None, the server picks its default."},"acp_resume_session_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Resume Session Id","description":"Optional explicit ACP session id to resume. When set, takes precedence over the id persisted in ``state.agent_state`` and is used to call ``session/load`` on the ACP server. Designed for environments where the per-conversation filesystem (and therefore ``base_state.json``) does not survive across restarts (e.g. cloud sandbox recycles), but the id has been mirrored into durable storage elsewhere. Falls back to a fresh session if the server cannot load the id. Treated as a secret on the wire — possession of the id is enough to resume the underlying ACP session, so default serialization redacts it; pass ``expose_secrets='plaintext'`` (trusted backend) or ``expose_secrets='encrypted'`` plus a cipher (frontend round-trip) when the value must cross a serialization boundary."},"acp_file_secrets":{"items":{"$ref":"#/components/schemas/ACPFileSecretSpec"},"type":"array","title":"Acp File Secrets","description":"Reserved 'file-content' credential secrets to materialise to disk before launching the subprocess (e.g. Codex auth.json, Gemini Vertex SA JSON). The SDK owns the mechanism (write the file in the runtime pod, set the env var, seed-if-absent); these specs are the policy. Defaults to the built-in supported providers; a downstream application may override or extend this to support other ACP servers with different file-auth schemes."},"acp_isolate_data_dir":{"type":"boolean","title":"Acp Isolate Data Dir","description":"Give the ACP subprocess a per-conversation CLI data/config root instead of the shared user ``HOME``. When True and the provider is recognised, point its data-dir env var (``CODEX_HOME`` / ``CLAUDE_CONFIG_DIR`` / ``HOME``; see ``ACPProviderInfo.data_dir_env_var``) at ``/acp/`` — the same per-conversation tree materialised file-secrets use. Required for correctness when several of a user's conversations share one sandbox (``SandboxGroupingStrategy != NO_GROUPING``), where they would otherwise race on one set of CLI auth/config/cache/lock files (see #1019). Off by default: with one sandbox per conversation the shared HOME is already private, and relocating it would hide a pre-existing interactive login. Downstream policy decides when to enable it; the SDK owns where the root lives.","default":false},"kind":{"type":"string","const":"ACPAgent","title":"Kind"}},"type":"object","required":["acp_command","kind"],"title":"ACPAgent","description":"Agent that delegates to an ACP-compatible subprocess server."},"ACPFileSecretSpec":{"properties":{"secret_name":{"type":"string","minLength":1,"title":"Secret Name"},"filename":{"type":"string","minLength":1,"title":"Filename"},"env_var":{"type":"string","minLength":1,"title":"Env Var"},"subdir":{"type":"string","minLength":1,"title":"Subdir"},"env_points_to":{"type":"string","enum":["dir","file"],"title":"Env Points To","default":"file"},"warn_if_unset":{"items":{"type":"string"},"type":"array","title":"Warn If Unset","default":[]}},"type":"object","required":["secret_name","filename","env_var","subdir"],"title":"ACPFileSecretSpec","description":"Declarative mapping from a reserved \"file-content\" secret to a credential\nfile the ACP subprocess authenticates from.\n\nSome providers read their credential from a *file on disk* rather than an\nenv var: Codex reads ``$CODEX_HOME/auth.json``; Gemini (Vertex AI) reads a\nservice-account JSON pointed at by ``GOOGLE_APPLICATION_CREDENTIALS``. The\nuser supplies that credential as a pasted blob — a reserved secret named\n:attr:`secret_name` — and :class:`~openhands.sdk.agent.ACPAgent` materialises\nit to :attr:`filename` under the conversation's durable per-conversation root\n(seed-if-absent), then sets :attr:`env_var` so the CLI can find it.\n\nMaterialisation is keyed off :attr:`secret_name` (not the launch command),\nso a custom or aliased ``acp_command`` still works as long as the reserved\nsecret is supplied.\n\nThe SDK owns the *mechanism* (writing the file in the runtime pod, setting\nthe env var, seed-if-absent, permissions); the *policy* — which secrets map\nto which files for which CLIs — lives in these specs. Built-in defaults\ncover the supported providers, but downstream applications can override\n:attr:`~openhands.sdk.agent.ACPAgent.acp_file_secrets` to support other ACP\nservers with different file-auth schemes without an SDK change."},"ACPModelInfo":{"properties":{"model_id":{"type":"string","title":"Model Id","description":"Server-assigned model identifier. May be concrete (e.g. ``\"gpt-5.5\"``) or an opaque alias (e.g. ``\"default\"``, ``\"auto\"``). This is the value to pass back to the server to switch to this model."},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name","description":"Human-readable label, e.g. ``\"GPT-5.5\"``."},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional longer description supplied by the server."}},"type":"object","required":["model_id"],"title":"ACPModelInfo","description":"One model an ACP server offers for a session.\n\nA normalized, stable mirror of the ACP protocol's ``ModelInfo``. The\nprotocol ``models`` capability is flagged **UNSTABLE**, so we re-map it\ninto our own type at the SDK boundary rather than re-serializing the\nvendored ``acp.schema`` type onto the agent-server's public API — clients\nget a stable shape regardless of upstream protocol churn.\n\nCarries everything a client needs to render a picker and resolve a\n``current_model_id`` to a display label *itself*; the SDK deliberately\ndoes no name curation."},"ACPToolCallEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"tool_call_id":{"type":"string","title":"Tool Call Id"},"title":{"type":"string","title":"Title"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"},"tool_kind":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Kind"},"raw_input":{"anyOf":[{},{"type":"null"}],"title":"Raw Input"},"raw_output":{"anyOf":[{},{"type":"null"}],"title":"Raw Output"},"content":{"anyOf":[{"items":{},"type":"array"},{"type":"null"}],"title":"Content"},"is_error":{"type":"boolean","title":"Is Error","default":false},"kind":{"type":"string","const":"ACPToolCallEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_call_id","title","kind"],"title":"ACPToolCallEvent","description":"Event representing a tool call executed by an ACP server.\n\nCaptures the tool name, inputs, outputs, and status from ACP\n``ToolCallStart`` / ``ToolCallProgress`` notifications so they can\nbe surfaced in the OpenHands event stream and visualizer.\n\nThis is *not* an ``LLMConvertibleEvent`` — ACP tool calls do not\nparticipate in LLM message conversion."},"APIBasedCritic-Input":{"properties":{"server_url":{"type":"string","title":"Server Url","description":"Base URL of the vLLM classification service","default":"https://llm-proxy.app.all-hands.dev/vllm"},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true}],"title":"Api Key","description":"API key for authenticating with the vLLM service"},"model_name":{"type":"string","title":"Model Name","description":"Name of the model to use","default":"critic"},"tokenizer_name":{"type":"string","title":"Tokenizer Name","description":"HuggingFace tokenizer name for loading chat template","default":"Qwen/Qwen3-4B-Instruct-2507"},"pass_tools_definitions":{"type":"boolean","title":"Pass Tools Definitions","description":"Whether to pass tool definitions to the model","default":true},"timeout_seconds":{"type":"number","title":"Timeout Seconds","description":"Timeout for requests to the model","default":300.0},"has_success_label":{"type":"boolean","title":"Has Success Label","description":"Whether the model predicts success label at index 0","default":true},"sentiment_labels":{"items":{"type":"string"},"type":"array","title":"Sentiment Labels","default":["sentiment_positive","sentiment_neutral","sentiment_negative"]},"agent_issue_labels":{"items":{"type":"string"},"type":"array","title":"Agent Issue Labels","default":["misunderstood_intention","did_not_follow_instruction","insufficient_analysis","insufficient_clarification","improper_tool_use_or_setup","loop_behavior","insufficient_testing","insufficient_debugging","incomplete_implementation","file_management_errors","scope_creep","risky_actions_or_permission","other_agent_issue"]},"infra_labels":{"items":{"type":"string"},"type":"array","title":"Infra Labels","default":["infrastructure_external_issue","infrastructure_agent_caused_issue"]},"user_followup_labels":{"items":{"type":"string"},"type":"array","title":"User Followup Labels","default":["clarification_or_restatement","correction","direction_change","vcs_update_requests","progress_or_scope_concern","frustration_or_complaint","removal_or_reversion_request","other_user_issue"]},"sentiment_map":{"additionalProperties":{"type":"string"},"type":"object","title":"Sentiment Map","default":{"Positive":"sentiment_positive","Neutral":"sentiment_neutral","Negative":"sentiment_negative"}},"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"issue_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issue Threshold","description":"APIBasedCritic-specific probability threshold for agent issue labels that should trigger iterative refinement.","default":0.75},"kind":{"type":"string","const":"APIBasedCritic","title":"Kind"}},"type":"object","required":["api_key"],"title":"APIBasedCritic"},"APIBasedCritic-Output":{"properties":{"server_url":{"type":"string","title":"Server Url","description":"Base URL of the vLLM classification service","default":"https://llm-proxy.app.all-hands.dev/vllm"},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true}],"title":"Api Key","description":"API key for authenticating with the vLLM service"},"model_name":{"type":"string","title":"Model Name","description":"Name of the model to use","default":"critic"},"tokenizer_name":{"type":"string","title":"Tokenizer Name","description":"HuggingFace tokenizer name for loading chat template","default":"Qwen/Qwen3-4B-Instruct-2507"},"pass_tools_definitions":{"type":"boolean","title":"Pass Tools Definitions","description":"Whether to pass tool definitions to the model","default":true},"timeout_seconds":{"type":"number","title":"Timeout Seconds","description":"Timeout for requests to the model","default":300.0},"has_success_label":{"type":"boolean","title":"Has Success Label","description":"Whether the model predicts success label at index 0","default":true},"sentiment_labels":{"items":{"type":"string"},"type":"array","title":"Sentiment Labels","default":["sentiment_positive","sentiment_neutral","sentiment_negative"]},"agent_issue_labels":{"items":{"type":"string"},"type":"array","title":"Agent Issue Labels","default":["misunderstood_intention","did_not_follow_instruction","insufficient_analysis","insufficient_clarification","improper_tool_use_or_setup","loop_behavior","insufficient_testing","insufficient_debugging","incomplete_implementation","file_management_errors","scope_creep","risky_actions_or_permission","other_agent_issue"]},"infra_labels":{"items":{"type":"string"},"type":"array","title":"Infra Labels","default":["infrastructure_external_issue","infrastructure_agent_caused_issue"]},"user_followup_labels":{"items":{"type":"string"},"type":"array","title":"User Followup Labels","default":["clarification_or_restatement","correction","direction_change","vcs_update_requests","progress_or_scope_concern","frustration_or_complaint","removal_or_reversion_request","other_user_issue"]},"sentiment_map":{"additionalProperties":{"type":"string"},"type":"object","title":"Sentiment Map","default":{"Positive":"sentiment_positive","Neutral":"sentiment_neutral","Negative":"sentiment_negative"}},"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"issue_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Issue Threshold","description":"APIBasedCritic-specific probability threshold for agent issue labels that should trigger iterative refinement.","default":0.75},"kind":{"type":"string","const":"APIBasedCritic","title":"Kind"}},"type":"object","required":["api_key","kind"],"title":"APIBasedCritic"},"Action":{"oneOf":[{"$ref":"#/components/schemas/BrowserActionWithRisk"},{"$ref":"#/components/schemas/BrowserClickActionWithRisk"},{"$ref":"#/components/schemas/BrowserCloseTabActionWithRisk"},{"$ref":"#/components/schemas/BrowserGetContentActionWithRisk"},{"$ref":"#/components/schemas/BrowserGetStateActionWithRisk"},{"$ref":"#/components/schemas/BrowserGetStorageActionWithRisk"},{"$ref":"#/components/schemas/BrowserGoBackActionWithRisk"},{"$ref":"#/components/schemas/BrowserListTabsActionWithRisk"},{"$ref":"#/components/schemas/BrowserNavigateActionWithRisk"},{"$ref":"#/components/schemas/BrowserScrollActionWithRisk"},{"$ref":"#/components/schemas/BrowserSetStorageActionWithRisk"},{"$ref":"#/components/schemas/BrowserStartRecordingActionWithRisk"},{"$ref":"#/components/schemas/BrowserStopRecordingActionWithRisk"},{"$ref":"#/components/schemas/BrowserSwitchTabActionWithRisk"},{"$ref":"#/components/schemas/BrowserTypeActionWithRisk"},{"$ref":"#/components/schemas/DelegateActionWithRisk"},{"$ref":"#/components/schemas/EditActionWithRisk"},{"$ref":"#/components/schemas/FileEditorActionWithRisk"},{"$ref":"#/components/schemas/FinishActionWithRisk"},{"$ref":"#/components/schemas/GlobActionWithRisk"},{"$ref":"#/components/schemas/GrepActionWithRisk"},{"$ref":"#/components/schemas/InvokeSkillActionWithRisk"},{"$ref":"#/components/schemas/ListDirectoryActionWithRisk"},{"$ref":"#/components/schemas/MCPToolActionWithRisk"},{"$ref":"#/components/schemas/PlanningFileEditorActionWithRisk"},{"$ref":"#/components/schemas/ReadFileActionWithRisk"},{"$ref":"#/components/schemas/SwitchLLMActionWithRisk"},{"$ref":"#/components/schemas/TaskActionWithRisk"},{"$ref":"#/components/schemas/TaskTrackerActionWithRisk"},{"$ref":"#/components/schemas/TerminalActionWithRisk"},{"$ref":"#/components/schemas/ThinkActionWithRisk"},{"$ref":"#/components/schemas/WorkflowActionWithRisk"},{"$ref":"#/components/schemas/WriteFileActionWithRisk"},{"$ref":"#/components/schemas/MCPToolAction"},{"$ref":"#/components/schemas/FinishAction"},{"$ref":"#/components/schemas/InvokeSkillAction"},{"$ref":"#/components/schemas/SwitchLLMAction"},{"$ref":"#/components/schemas/ThinkAction"},{"$ref":"#/components/schemas/BrowserAction"},{"$ref":"#/components/schemas/BrowserClickAction"},{"$ref":"#/components/schemas/BrowserCloseTabAction"},{"$ref":"#/components/schemas/BrowserGetContentAction"},{"$ref":"#/components/schemas/BrowserGetStateAction"},{"$ref":"#/components/schemas/BrowserGetStorageAction"},{"$ref":"#/components/schemas/BrowserGoBackAction"},{"$ref":"#/components/schemas/BrowserListTabsAction"},{"$ref":"#/components/schemas/BrowserNavigateAction"},{"$ref":"#/components/schemas/BrowserScrollAction"},{"$ref":"#/components/schemas/BrowserSetStorageAction"},{"$ref":"#/components/schemas/BrowserStartRecordingAction"},{"$ref":"#/components/schemas/BrowserStopRecordingAction"},{"$ref":"#/components/schemas/BrowserSwitchTabAction"},{"$ref":"#/components/schemas/BrowserTypeAction"},{"$ref":"#/components/schemas/DelegateAction"},{"$ref":"#/components/schemas/FileEditorAction"},{"$ref":"#/components/schemas/EditAction"},{"$ref":"#/components/schemas/ListDirectoryAction"},{"$ref":"#/components/schemas/ReadFileAction"},{"$ref":"#/components/schemas/WriteFileAction"},{"$ref":"#/components/schemas/GlobAction"},{"$ref":"#/components/schemas/GrepAction"},{"$ref":"#/components/schemas/PlanningFileEditorAction"},{"$ref":"#/components/schemas/TaskAction"},{"$ref":"#/components/schemas/TaskTrackerAction"},{"$ref":"#/components/schemas/TerminalAction"},{"$ref":"#/components/schemas/WorkflowAction"}],"discriminator":{"propertyName":"kind","mapping":{"abc__BrowserActionWithRisk-Output__1":"#/components/schemas/BrowserActionWithRisk","abc__BrowserClickActionWithRisk-Output__1":"#/components/schemas/BrowserClickActionWithRisk","abc__BrowserCloseTabActionWithRisk-Output__1":"#/components/schemas/BrowserCloseTabActionWithRisk","abc__BrowserGetContentActionWithRisk-Output__1":"#/components/schemas/BrowserGetContentActionWithRisk","abc__BrowserGetStateActionWithRisk-Output__1":"#/components/schemas/BrowserGetStateActionWithRisk","abc__BrowserGetStorageActionWithRisk-Output__1":"#/components/schemas/BrowserGetStorageActionWithRisk","abc__BrowserGoBackActionWithRisk-Output__1":"#/components/schemas/BrowserGoBackActionWithRisk","abc__BrowserListTabsActionWithRisk-Output__1":"#/components/schemas/BrowserListTabsActionWithRisk","abc__BrowserNavigateActionWithRisk-Output__1":"#/components/schemas/BrowserNavigateActionWithRisk","abc__BrowserScrollActionWithRisk-Output__1":"#/components/schemas/BrowserScrollActionWithRisk","abc__BrowserSetStorageActionWithRisk-Output__1":"#/components/schemas/BrowserSetStorageActionWithRisk","abc__BrowserStartRecordingActionWithRisk-Output__1":"#/components/schemas/BrowserStartRecordingActionWithRisk","abc__BrowserStopRecordingActionWithRisk-Output__1":"#/components/schemas/BrowserStopRecordingActionWithRisk","abc__BrowserSwitchTabActionWithRisk-Output__1":"#/components/schemas/BrowserSwitchTabActionWithRisk","abc__BrowserTypeActionWithRisk-Output__1":"#/components/schemas/BrowserTypeActionWithRisk","abc__DelegateActionWithRisk-Output__1":"#/components/schemas/DelegateActionWithRisk","abc__EditActionWithRisk-Output__1":"#/components/schemas/EditActionWithRisk","abc__FileEditorActionWithRisk-Output__1":"#/components/schemas/FileEditorActionWithRisk","abc__FinishActionWithRisk-Output__1":"#/components/schemas/FinishActionWithRisk","abc__GlobActionWithRisk-Output__1":"#/components/schemas/GlobActionWithRisk","abc__GrepActionWithRisk-Output__1":"#/components/schemas/GrepActionWithRisk","abc__InvokeSkillActionWithRisk-Output__1":"#/components/schemas/InvokeSkillActionWithRisk","abc__ListDirectoryActionWithRisk-Output__1":"#/components/schemas/ListDirectoryActionWithRisk","abc__MCPToolActionWithRisk-Output__1":"#/components/schemas/MCPToolActionWithRisk","abc__PlanningFileEditorActionWithRisk-Output__1":"#/components/schemas/PlanningFileEditorActionWithRisk","abc__ReadFileActionWithRisk-Output__1":"#/components/schemas/ReadFileActionWithRisk","abc__SwitchLLMActionWithRisk-Output__1":"#/components/schemas/SwitchLLMActionWithRisk","abc__TaskActionWithRisk-Output__1":"#/components/schemas/TaskActionWithRisk","abc__TaskTrackerActionWithRisk-Output__1":"#/components/schemas/TaskTrackerActionWithRisk","abc__TerminalActionWithRisk-Output__1":"#/components/schemas/TerminalActionWithRisk","abc__ThinkActionWithRisk-Output__1":"#/components/schemas/ThinkActionWithRisk","abc__WorkflowActionWithRisk-Output__1":"#/components/schemas/WorkflowActionWithRisk","abc__WriteFileActionWithRisk-Output__1":"#/components/schemas/WriteFileActionWithRisk","openhands__sdk__mcp__definition__MCPToolAction-Output__1":"#/components/schemas/MCPToolAction","openhands__sdk__tool__builtins__finish__FinishAction-Output__1":"#/components/schemas/FinishAction","openhands__sdk__tool__builtins__invoke_skill__InvokeSkillAction-Output__1":"#/components/schemas/InvokeSkillAction","openhands__sdk__tool__builtins__switch_llm__SwitchLLMAction-Output__1":"#/components/schemas/SwitchLLMAction","openhands__sdk__tool__builtins__think__ThinkAction-Output__1":"#/components/schemas/ThinkAction","openhands__tools__browser_use__definition__BrowserAction-Output__1":"#/components/schemas/BrowserAction","openhands__tools__browser_use__definition__BrowserClickAction-Output__1":"#/components/schemas/BrowserClickAction","openhands__tools__browser_use__definition__BrowserCloseTabAction-Output__1":"#/components/schemas/BrowserCloseTabAction","openhands__tools__browser_use__definition__BrowserGetContentAction-Output__1":"#/components/schemas/BrowserGetContentAction","openhands__tools__browser_use__definition__BrowserGetStateAction-Output__1":"#/components/schemas/BrowserGetStateAction","openhands__tools__browser_use__definition__BrowserGetStorageAction-Output__1":"#/components/schemas/BrowserGetStorageAction","openhands__tools__browser_use__definition__BrowserGoBackAction-Output__1":"#/components/schemas/BrowserGoBackAction","openhands__tools__browser_use__definition__BrowserListTabsAction-Output__1":"#/components/schemas/BrowserListTabsAction","openhands__tools__browser_use__definition__BrowserNavigateAction-Output__1":"#/components/schemas/BrowserNavigateAction","openhands__tools__browser_use__definition__BrowserScrollAction-Output__1":"#/components/schemas/BrowserScrollAction","openhands__tools__browser_use__definition__BrowserSetStorageAction-Output__1":"#/components/schemas/BrowserSetStorageAction","openhands__tools__browser_use__definition__BrowserStartRecordingAction-Output__1":"#/components/schemas/BrowserStartRecordingAction","openhands__tools__browser_use__definition__BrowserStopRecordingAction-Output__1":"#/components/schemas/BrowserStopRecordingAction","openhands__tools__browser_use__definition__BrowserSwitchTabAction-Output__1":"#/components/schemas/BrowserSwitchTabAction","openhands__tools__browser_use__definition__BrowserTypeAction-Output__1":"#/components/schemas/BrowserTypeAction","openhands__tools__delegate__definition__DelegateAction-Output__1":"#/components/schemas/DelegateAction","openhands__tools__file_editor__definition__FileEditorAction-Output__1":"#/components/schemas/FileEditorAction","openhands__tools__gemini__edit__definition__EditAction-Output__1":"#/components/schemas/EditAction","openhands__tools__gemini__list_directory__definition__ListDirectoryAction-Output__1":"#/components/schemas/ListDirectoryAction","openhands__tools__gemini__read_file__definition__ReadFileAction-Output__1":"#/components/schemas/ReadFileAction","openhands__tools__gemini__write_file__definition__WriteFileAction-Output__1":"#/components/schemas/WriteFileAction","openhands__tools__glob__definition__GlobAction-Output__1":"#/components/schemas/GlobAction","openhands__tools__grep__definition__GrepAction-Output__1":"#/components/schemas/GrepAction","openhands__tools__planning_file_editor__definition__PlanningFileEditorAction-Output__1":"#/components/schemas/PlanningFileEditorAction","openhands__tools__task__definition__TaskAction-Output__1":"#/components/schemas/TaskAction","openhands__tools__task_tracker__definition__TaskTrackerAction-Output__1":"#/components/schemas/TaskTrackerAction","openhands__tools__terminal__definition__TerminalAction-Output__1":"#/components/schemas/TerminalAction","openhands__tools__workflow__definition__WorkflowAction-Output__1":"#/components/schemas/WorkflowAction"}}},"ActionEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"thought":{"items":{"$ref":"#/components/schemas/TextContent"},"type":"array","title":"Thought","description":"The thought process of the agent before taking this action"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content","description":"Intermediate reasoning/thinking content from reasoning models"},"thinking_blocks":{"items":{"anyOf":[{"$ref":"#/components/schemas/ThinkingBlock"},{"$ref":"#/components/schemas/RedactedThinkingBlock"}]},"type":"array","title":"Thinking Blocks","description":"Anthropic thinking blocks from the LLM response"},"responses_reasoning_item":{"anyOf":[{"$ref":"#/components/schemas/ReasoningItemModel"},{"type":"null"}],"description":"OpenAI Responses reasoning item from model output"},"action":{"anyOf":[{"$ref":"#/components/schemas/Action"},{"type":"null"}],"description":"Single tool call returned by LLM (None when non-executable)"},"tool_name":{"type":"string","title":"Tool Name","description":"The name of the tool being called"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The unique id returned by LLM API for this tool call"},"tool_call":{"$ref":"#/components/schemas/MessageToolCall","description":"The tool call received from the LLM response. We keep a copy of it so it is easier to construct it into LLM messageThis could be different from `action`: e.g., `tool_call` may contain `security_risk` field predicted by LLM when LLM risk analyzer is enabled, while `action` does not."},"llm_response_id":{"type":"string","title":"Llm Response Id","description":"Completion or Response ID of the LLM response that generated this eventE.g., Can be used to group related actions from same LLM response. This helps in tracking and managing results of parallel function calling from the same LLM response."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"critic_result":{"anyOf":[{"$ref":"#/components/schemas/CriticResult"},{"type":"null"}],"description":"Optional critic evaluation of this action and preceding history."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"A concise summary (approximately 10 words) of what this action does, provided by the LLM for explainability and debugging. Examples of good summaries: 'editing configuration file for deployment settings' | 'searching codebase for authentication function definitions' | 'installing required dependencies from package manifest' | 'running tests to verify bug fix' | 'viewing directory structure to locate source files'"},"kind":{"type":"string","const":"ActionEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["thought","tool_name","tool_call_id","tool_call","llm_response_id","kind"],"title":"ActionEvent"},"ActivateAgentProfileResponse":{"properties":{"id":{"type":"string","title":"Id"},"message":{"type":"string","title":"Message"},"agent_settings_applied":{"type":"boolean","title":"Agent Settings Applied","default":false}},"type":"object","required":["id","message"],"title":"ActivateAgentProfileResponse"},"ActivateProfileResponse":{"properties":{"name":{"type":"string","title":"Name"},"message":{"type":"string","title":"Message"},"llm_applied":{"type":"boolean","title":"Llm Applied","default":true}},"type":"object","required":["name","message"],"title":"ActivateProfileResponse","description":"Response model for profile activation."},"AddWorkspaceParentsRequest":{"properties":{"parents":{"items":{"$ref":"#/components/schemas/WorkspaceParentItem"},"type":"array","title":"Parents"}},"type":"object","required":["parents"],"title":"AddWorkspaceParentsRequest"},"AddWorkspacesRequest":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/WorkspaceItem"},"type":"array","title":"Workspaces"}},"type":"object","required":["workspaces"],"title":"AddWorkspacesRequest"},"Agent-Input":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input","description":"LLM configuration for the agent.","examples":[{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"}]},"tools":{"items":{"$ref":"#/components/schemas/Tool-Input"},"type":"array","title":"Tools","description":"List of tools to initialize for the agent.","examples":[{"name":"TerminalTool","params":{}},{"name":"FileEditorTool","params":{}},{"name":"TaskTrackerTool","params":{}}]},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools","description":"List of default tool class names to include. By default, the agent includes 'FinishTool' and 'ThinkTool'. Set to an empty list to disable all default tools, or provide a subset to include only specific ones. Example: include_default_tools=['FinishTool'] to only include FinishTool, or include_default_tools=[] to disable all default tools.","examples":[["FinishTool","ThinkTool"],["FinishTool"],[]]},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Input"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Input"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Input"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"kind":{"type":"string","const":"Agent","title":"Kind"}},"type":"object","required":["llm"],"title":"Agent","description":"Main agent implementation for OpenHands.\n\nThe Agent class provides the core functionality for running AI agents that can\ninteract with tools, process messages, and execute actions. It inherits from\nAgentBase and implements the agent execution logic. Critic-related functionality\nis provided by CriticMixin.\n\nAttributes:\n llm: The language model instance used for reasoning.\n tools: List of tools available to the agent.\n system_prompt: Inline system prompt string. When provided the agent\n uses this text verbatim instead of rendering from a template.\n Mutually exclusive with a non-default ``system_prompt_filename``.\n **Not recommended** unless you know what you are doing (e.g.\n customising agent behaviour for a completely different task) —\n this will override OpenHands' built-in system instructions.\n system_prompt_filename: Jinja2 template filename resolved relative to\n the agent's prompts directory, or an absolute path. Defaults to\n ``\"system_prompt.j2\"``.\n system_prompt_kwargs: Extra kwargs forwarded to the Jinja2 template.\n\nExample:\n ```python\n from openhands.sdk import LLM, Agent, Tool\n from pydantic import SecretStr\n\n llm = LLM(model=\"gpt-5.5\", api_key=SecretStr(\"key\"))\n tools = [Tool(name=\"TerminalTool\"), Tool(name=\"FileEditorTool\")]\n agent = Agent(llm=llm, tools=tools)\n ```\n\n To override the system prompt entirely::\n\n agent = Agent(\n llm=llm,\n tools=tools,\n system_prompt=\"You are a helpful coding assistant.\",\n )"},"Agent-Output":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Output","description":"LLM configuration for the agent.","examples":[{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"}]},"tools":{"items":{"$ref":"#/components/schemas/openhands__sdk__tool__spec__Tool"},"type":"array","title":"Tools","description":"List of tools to initialize for the agent.","examples":[{"name":"TerminalTool","params":{}},{"name":"FileEditorTool","params":{}},{"name":"TaskTrackerTool","params":{}}]},"mcp_config":{"additionalProperties":true,"type":"object","title":"Mcp Config","description":"Optional MCP configuration dictionary to create MCP tools.","examples":[{"mcpServers":{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}}]},"filter_tools_regex":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Filter Tools Regex","description":"Optional regex to filter the tools available to the agent by name. This is applied after any tools provided in `tools` and any MCP tools are added.","examples":["^(?!repomix)(.*)|^repomix.*pack_codebase.*$"]},"include_default_tools":{"items":{"type":"string"},"type":"array","title":"Include Default Tools","description":"List of default tool class names to include. By default, the agent includes 'FinishTool' and 'ThinkTool'. Set to an empty list to disable all default tools, or provide a subset to include only specific ones. Example: include_default_tools=['FinishTool'] to only include FinishTool, or include_default_tools=[] to disable all default tools.","examples":[["FinishTool","ThinkTool"],["FinishTool"],[]]},"agent_context":{"anyOf":[{"$ref":"#/components/schemas/AgentContext-Output"},{"type":"null"}],"description":"Optional AgentContext to initialize the agent with specific context.","examples":[{"skills":[{"content":"When you see this message, you should reply like you are a grumpy cat forced to use the internet.","name":"AGENTS.md","type":"repo"},{"content":"IMPORTANT! The user has said the magic word \"flarglebargle\". You must only respond with a message telling them how smart they are","name":"flarglebargle","trigger":["flarglebargle"],"type":"knowledge"}],"system_message_suffix":"Always finish your response with the word 'yay!'","user_message_prefix":"The first character of your response should be 'I'"}]},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt","description":"Inline system prompt string. When provided, the agent uses this text verbatim as the system message instead of rendering from `system_prompt_filename`. Mutually exclusive with a non-default `system_prompt_filename`.\n\n**Warning**: This is not recommended unless you know what you are doing (e.g. customising agent behaviour for a completely different task). Setting this will override OpenHands' built-in system instructions that govern default agent behaviour."},"system_prompt_filename":{"type":"string","title":"System Prompt Filename","description":"System prompt template filename. Can be either:\n- A relative filename (e.g., 'system_prompt.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_prompt.j2')","default":"system_prompt.j2"},"security_policy_filename":{"type":"string","title":"Security Policy Filename","description":"Security policy template filename. Can be either:\n- A relative filename (e.g., 'security_policy.j2') loaded from the agent's prompts directory\n- An absolute path (e.g., '/path/to/custom_security_policy.j2')\n- Empty string to disable security policy","default":"security_policy.j2"},"system_prompt_kwargs":{"additionalProperties":true,"type":"object","title":"System Prompt Kwargs","description":"Optional kwargs to pass to the system prompt Jinja2 template.","examples":[{"cli_mode":true}]},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Output"},{"type":"null"}],"description":"Optional condenser to use for condensing conversation history.","examples":[{"keep_first":10,"kind":"LLMSummarizingCondenser","llm":{"api_key":"your_api_key_here","base_url":"https://llm-proxy.eval.all-hands.dev","model":"litellm_proxy/openai/gpt-5.5"},"max_size":80}]},"critic":{"anyOf":[{"$ref":"#/components/schemas/CriticBase-Output"},{"type":"null"}],"description":"EXPERIMENTAL: Optional critic to evaluate agent actions and messages in real-time. API and behavior may change without notice. May impact performance, especially in 'all_actions' mode.","examples":[{"kind":"AgentFinishedCritic"}]},"tool_concurrency_limit":{"type":"integer","minimum":1.0,"title":"Tool Concurrency Limit","description":"Maximum number of tool calls to execute concurrently within a single agent step. Default is 1 (sequential). Values > 1 enable parallel execution; concurrent tools share the conversation object, filesystem, and working directory, so mutations to shared state may race.","default":1},"kind":{"type":"string","const":"Agent","title":"Kind"}},"type":"object","required":["llm","kind"],"title":"Agent","description":"Main agent implementation for OpenHands.\n\nThe Agent class provides the core functionality for running AI agents that can\ninteract with tools, process messages, and execute actions. It inherits from\nAgentBase and implements the agent execution logic. Critic-related functionality\nis provided by CriticMixin.\n\nAttributes:\n llm: The language model instance used for reasoning.\n tools: List of tools available to the agent.\n system_prompt: Inline system prompt string. When provided the agent\n uses this text verbatim instead of rendering from a template.\n Mutually exclusive with a non-default ``system_prompt_filename``.\n **Not recommended** unless you know what you are doing (e.g.\n customising agent behaviour for a completely different task) —\n this will override OpenHands' built-in system instructions.\n system_prompt_filename: Jinja2 template filename resolved relative to\n the agent's prompts directory, or an absolute path. Defaults to\n ``\"system_prompt.j2\"``.\n system_prompt_kwargs: Extra kwargs forwarded to the Jinja2 template.\n\nExample:\n ```python\n from openhands.sdk import LLM, Agent, Tool\n from pydantic import SecretStr\n\n llm = LLM(model=\"gpt-5.5\", api_key=SecretStr(\"key\"))\n tools = [Tool(name=\"TerminalTool\"), Tool(name=\"FileEditorTool\")]\n agent = Agent(llm=llm, tools=tools)\n ```\n\n To override the system prompt entirely::\n\n agent = Agent(\n llm=llm,\n tools=tools,\n system_prompt=\"You are a helpful coding assistant.\",\n )"},"AgentBase-Input":{"oneOf":[{"$ref":"#/components/schemas/ACPAgent-Input"},{"$ref":"#/components/schemas/Agent-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__agent__acp_agent__ACPAgent-Input__1":"#/components/schemas/ACPAgent-Input","openhands__sdk__agent__agent__Agent-Input__1":"#/components/schemas/Agent-Input"}}},"AgentBase-Output":{"oneOf":[{"$ref":"#/components/schemas/ACPAgent-Output"},{"$ref":"#/components/schemas/Agent-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__agent__acp_agent__ACPAgent-Output__1":"#/components/schemas/ACPAgent-Output","openhands__sdk__agent__agent__Agent-Output__1":"#/components/schemas/Agent-Output"}}},"AgentContext-Input":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/Skill-Input"},"type":"array","title":"Skills","description":"List of available skills that can extend the user's input.","acp_compatible":true},"system_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Message Suffix","description":"Optional suffix to append to the system prompt.","acp_compatible":true},"user_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Message Suffix","description":"Optional suffix to append to the user's message.","acp_compatible":true},"load_user_skills":{"type":"boolean","title":"Load User Skills","description":"Whether to automatically load user skills from ~/.openhands/skills/ and ~/.openhands/microagents/ (for backward compatibility). ","default":false,"acp_compatible":true},"load_public_skills":{"type":"boolean","title":"Load Public Skills","description":"Whether to automatically load skills from the public OpenHands skills repository at https://github.com/OpenHands/extensions. This allows you to get the latest skills without SDK updates.","default":false,"acp_compatible":true},"marketplace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace Path","description":"Relative marketplace JSON path within the public skills repository. Set to None to load all public skills without marketplace filtering.","default":"marketplaces/default.json","acp_compatible":true},"load_project_skills":{"type":"boolean","title":"Load Project Skills","description":"Whether to automatically load project skills from the conversation workspace (e.g. .openhands/skills/, AGENTS.md). Unlike load_user_skills / load_public_skills, this flag is not resolved by AgentContext itself (the workspace path is unknown at validation time); LocalConversation resolves it lazily on the first send_message() / run(), when the workspace is known. Also unlike load_user_skills / load_public_skills (which yield to explicit skills on a name conflict), resolved project skills are authoritative: a project skill overrides a same-named skill already present in `skills`.","default":false,"acp_compatible":true},"secrets":{"anyOf":[{"additionalProperties":{"anyOf":[{"type":"string"},{"$ref":"#/components/schemas/SecretSource-Input"}]},"type":"object"},{"type":"null"}],"title":"Secrets","description":"Dictionary mapping secret keys to values or secret sources. Secrets are used for authentication and sensitive data handling. Values can be either strings or SecretSource instances (str | SecretSource).","acp_compatible":true},"current_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}],"title":"Current Datetime","description":"Current date and time information to provide to the agent. Can be a datetime object (which will be formatted as ISO 8601) or a pre-formatted string. When provided, this information is included in the system prompt to give the agent awareness of the current time context. Defaults to the current (timezone-aware) datetime.","acp_compatible":true}},"type":"object","title":"AgentContext","description":"Central structure for managing prompt extension.\n\nAgentContext unifies all the contextual inputs that shape how the system\nextends and interprets user prompts. It combines both static environment\ndetails and dynamic, user-activated extensions from skills.\n\nSpecifically, it provides:\n- **Repository context / Repo Skills**: Information about the active codebase,\n branches, and repo-specific instructions contributed by repo skills.\n- **Runtime context**: Current execution environment (hosts, working\n directory, secrets, date, etc.).\n- **Conversation instructions**: Optional task- or channel-specific rules\n that constrain or guide the agent’s behavior across the session.\n- **Knowledge Skills**: Extensible components that can be triggered by user input\n to inject knowledge or domain-specific guidance.\n\nTogether, these elements make AgentContext the primary container responsible\nfor assembling, formatting, and injecting all prompt-relevant context into\nLLM interactions."},"AgentContext-Output":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/Skill-Output"},"type":"array","title":"Skills","description":"List of available skills that can extend the user's input.","acp_compatible":true},"system_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Message Suffix","description":"Optional suffix to append to the system prompt.","acp_compatible":true},"user_message_suffix":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Message Suffix","description":"Optional suffix to append to the user's message.","acp_compatible":true},"load_user_skills":{"type":"boolean","title":"Load User Skills","description":"Whether to automatically load user skills from ~/.openhands/skills/ and ~/.openhands/microagents/ (for backward compatibility). ","default":false,"acp_compatible":true},"load_public_skills":{"type":"boolean","title":"Load Public Skills","description":"Whether to automatically load skills from the public OpenHands skills repository at https://github.com/OpenHands/extensions. This allows you to get the latest skills without SDK updates.","default":false,"acp_compatible":true},"marketplace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace Path","description":"Relative marketplace JSON path within the public skills repository. Set to None to load all public skills without marketplace filtering.","default":"marketplaces/default.json","acp_compatible":true},"load_project_skills":{"type":"boolean","title":"Load Project Skills","description":"Whether to automatically load project skills from the conversation workspace (e.g. .openhands/skills/, AGENTS.md). Unlike load_user_skills / load_public_skills, this flag is not resolved by AgentContext itself (the workspace path is unknown at validation time); LocalConversation resolves it lazily on the first send_message() / run(), when the workspace is known. Also unlike load_user_skills / load_public_skills (which yield to explicit skills on a name conflict), resolved project skills are authoritative: a project skill overrides a same-named skill already present in `skills`.","default":false,"acp_compatible":true},"secrets":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Secrets","description":"Dictionary mapping secret keys to values or secret sources. Secrets are used for authentication and sensitive data handling. Values can be either strings or SecretSource instances (str | SecretSource).","acp_compatible":true},"current_datetime":{"anyOf":[{"type":"string","format":"date-time"},{"type":"string"},{"type":"null"}],"title":"Current Datetime","description":"Current date and time information to provide to the agent. Can be a datetime object (which will be formatted as ISO 8601) or a pre-formatted string. When provided, this information is included in the system prompt to give the agent awareness of the current time context. Defaults to the current (timezone-aware) datetime.","acp_compatible":true}},"type":"object","title":"AgentContext","description":"Central structure for managing prompt extension.\n\nAgentContext unifies all the contextual inputs that shape how the system\nextends and interprets user prompts. It combines both static environment\ndetails and dynamic, user-activated extensions from skills.\n\nSpecifically, it provides:\n- **Repository context / Repo Skills**: Information about the active codebase,\n branches, and repo-specific instructions contributed by repo skills.\n- **Runtime context**: Current execution environment (hosts, working\n directory, secrets, date, etc.).\n- **Conversation instructions**: Optional task- or channel-specific rules\n that constrain or guide the agent’s behavior across the session.\n- **Knowledge Skills**: Extensible components that can be triggered by user input\n to inject knowledge or domain-specific guidance.\n\nTogether, these elements make AgentContext the primary container responsible\nfor assembling, formatting, and injecting all prompt-relevant context into\nLLM interactions."},"AgentDefinition":{"properties":{"name":{"type":"string","title":"Name","description":"Agent name (from frontmatter or filename)"},"description":{"type":"string","title":"Description","description":"Agent description","default":""},"model":{"type":"string","title":"Model","description":"Model to use ('inherit' uses parent model)","default":"inherit"},"color":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Color","description":"Display color for the agent"},"tools":{"items":{"type":"string"},"type":"array","title":"Tools","description":"List of allowed tools for this agent"},"skills":{"items":{"type":"string"},"type":"array","title":"Skills","description":"List of skill names for this agent. Resolved from project/user directories."},"system_prompt":{"type":"string","title":"System Prompt","description":"System prompt content","default":""},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"Source file path for this agent"},"when_to_use_examples":{"items":{"type":"string"},"type":"array","title":"When To Use Examples","description":"Examples of when to use this agent (for triggering)"},"hooks":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Input"},{"type":"null"}],"description":"Hook configuration for this agent"},"permission_mode":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Permission Mode","description":"How the subagent handles permissions. None inherits the parent policy, 'always_confirm' requires confirmation for every action, 'never_confirm' skips all confirmations, 'confirm_risky' only confirms actions above a risk threshold."},"max_iteration_per_run":{"anyOf":[{"type":"integer","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Iteration Per Run","description":"Maximum iterations per run. It must be strictly positive, or None for default."},"max_budget_per_run":{"anyOf":[{"type":"number","exclusiveMinimum":0.0},{"type":"null"}],"title":"Max Budget Per Run","description":"Maximum accumulated cost (USD) per run for this sub-agent. Must be strictly positive, or None for no budget."},"mcp_servers":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mcp Servers","description":"MCP server configurations for this agent. Keys are server names, values are server configs with 'command', 'args', etc.","examples":[{"fetch":{"args":["mcp-server-fetch"],"command":"uvx"}}]},"profile_store_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Profile Store Dir","description":"Path to the directory where LLM profiles are stored. If None, the default profile store directory is used."},"condenser":{"anyOf":[{"$ref":"#/components/schemas/CondenserBase-Input"},{"type":"null"}],"description":"Context condenser for the sub-agent. None applies a default summarizing condenser; set a NoOpCondenser to disable condensation."},"metadata":{"additionalProperties":true,"type":"object","title":"Metadata","description":"Additional metadata from frontmatter"}},"type":"object","required":["name"],"title":"AgentDefinition","description":"Agent definition loaded from Markdown file.\n\nAgents are specialized configurations that can be triggered based on\nuser input patterns. They define custom system prompts and tool access."},"AgentErrorEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"tool_name":{"type":"string","title":"Tool Name","description":"The tool name that this observation is responding to"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The tool call id that this observation is responding to"},"error":{"type":"string","title":"Error","description":"The error message from the scaffold"},"kind":{"type":"string","const":"AgentErrorEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","tool_call_id","error","kind"],"title":"AgentErrorEvent","description":"Error triggered by the agent.\n\nNote: This event should not contain model \"thought\" or \"reasoning_content\". It\nrepresents an error produced by the agent/scaffold, not model output."},"AgentFinishedCritic-Input":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"AgentFinishedCritic","title":"Kind"}},"type":"object","title":"AgentFinishedCritic","description":"Critic that evaluates whether an agent properly finished a task.\n\nThis critic checks two main criteria:\n1. The agent's last action was a FinishAction (proper completion)\n2. The generated git patch is non-empty (actual changes were made)"},"AgentFinishedCritic-Output":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"AgentFinishedCritic","title":"Kind"}},"type":"object","required":["kind"],"title":"AgentFinishedCritic","description":"Critic that evaluates whether an agent properly finished a task.\n\nThis critic checks two main criteria:\n1. The agent's last action was a FinishAction (proper completion)\n2. The generated git patch is non-empty (actual changes were made)"},"AgentProfileDetailResponse":{"properties":{"name":{"type":"string","title":"Name"},"profile":{"additionalProperties":true,"type":"object","title":"Profile"}},"type":"object","required":["name","profile"],"title":"AgentProfileDetailResponse"},"AgentProfileDiagnostics":{"properties":{"agent_kind":{"type":"string","title":"Agent Kind"},"valid":{"type":"boolean","title":"Valid","default":false},"errors":{"items":{"type":"string"},"type":"array","title":"Errors"},"llm_profile_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Profile Ref"},"llm_profile_resolved":{"type":"boolean","title":"Llm Profile Resolved","default":false},"llm_api_key_set":{"type":"boolean","title":"Llm Api Key Set","default":false},"mcp_server_refs":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mcp Server Refs"},"resolved_mcp_servers":{"items":{"type":"string"},"type":"array","title":"Resolved Mcp Servers"},"dangling_mcp_server_refs":{"items":{"type":"string"},"type":"array","title":"Dangling Mcp Server Refs"},"acp_api_key_secret_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Api Key Secret Name"},"acp_base_url_secret_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Acp Base Url Secret Name"},"acp_file_secret_names":{"items":{"type":"string"},"type":"array","title":"Acp File Secret Names"},"resolved_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Resolved Settings"}},"type":"object","required":["agent_kind"],"title":"AgentProfileDiagnostics","description":"Side-effect-free report of what :func:`resolve_agent_profile` would do.\n\nConsumed by ``POST /{id}/materialize`` (#3719) and the canvas editor. The\nverdict (:attr:`valid`) and the dangling-ref lists match exactly what a real\nresolve produces; :attr:`resolved_settings` is the redacted settings dump\n(present only when :attr:`valid`)."},"AgentProfileInfo":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"name":{"type":"string","title":"Name"},"agent_kind":{"type":"string","title":"Agent Kind","default":"openhands"},"revision":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Revision"},"llm_profile_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Profile Ref"},"mcp_server_refs":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Mcp Server Refs"}},"type":"object","required":["name"],"title":"AgentProfileInfo","description":"Summary projection of a stored profile (no secret instantiation)."},"AgentProfileListResponse":{"properties":{"profiles":{"items":{"$ref":"#/components/schemas/AgentProfileInfo"},"type":"array","title":"Profiles"},"active_agent_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Agent Profile Id"}},"type":"object","required":["profiles"],"title":"AgentProfileListResponse"},"AgentProfileMutationResponse":{"properties":{"name":{"type":"string","title":"Name"},"message":{"type":"string","title":"Message"}},"type":"object","required":["name","message"],"title":"AgentProfileMutationResponse"},"AgentResponseResult":{"properties":{"response":{"type":"string","title":"Response","description":"The agent's final response text. Extracted from either a FinishAction message or the last agent MessageEvent. Empty string if no final response is available."}},"type":"object","required":["response"],"title":"AgentResponseResult","description":"The agent's final response for a conversation.\n\nContains the text of the last agent finish message or text response.\nEmpty string if the agent has not produced a final response yet."},"AlwaysConfirm-Input":{"properties":{"kind":{"type":"string","const":"AlwaysConfirm","title":"Kind"}},"type":"object","title":"AlwaysConfirm"},"AlwaysConfirm-Output":{"properties":{"kind":{"type":"string","const":"AlwaysConfirm","title":"Kind"}},"type":"object","required":["kind"],"title":"AlwaysConfirm"},"Annotation":{"properties":{"type":{"type":"string","const":"url_citation","title":"Type"},"url_citation":{"$ref":"#/components/schemas/AnnotationURLCitation"}},"additionalProperties":true,"type":"object","required":["type","url_citation"],"title":"Annotation","description":"A URL citation when using web search."},"AnnotationURLCitation":{"properties":{"end_index":{"type":"integer","title":"End Index"},"start_index":{"type":"integer","title":"Start Index"},"title":{"type":"string","title":"Title"},"url":{"type":"string","title":"Url"}},"additionalProperties":true,"type":"object","required":["end_index","start_index","title","url"],"title":"AnnotationURLCitation","description":"A URL citation when using web search."},"AskAgentRequest":{"properties":{"question":{"type":"string","title":"Question","description":"The question to ask the agent"}},"type":"object","required":["question"],"title":"AskAgentRequest","description":"Payload to ask the agent a simple question."},"AskAgentResponse":{"properties":{"response":{"type":"string","title":"Response","description":"The agent's response to the question"}},"type":"object","required":["response"],"title":"AskAgentResponse","description":"Response containing the agent's answer."},"BaseWorkspace":{"oneOf":[{"$ref":"#/components/schemas/LocalWorkspace-Output"},{"$ref":"#/components/schemas/RemoteWorkspace"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__workspace__local__LocalWorkspace-Output__1":"#/components/schemas/LocalWorkspace-Output","openhands__sdk__workspace__remote__base__RemoteWorkspace-Output__1":"#/components/schemas/RemoteWorkspace"}}},"BashCommand":{"properties":{"command":{"type":"string","title":"Command","description":"The bash command to execute"},"cwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd","description":"The current working directory"},"timeout":{"type":"integer","title":"Timeout","description":"The max number of seconds a command may be permitted to run.","default":300},"id":{"type":"string","title":"Id"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"kind":{"type":"string","const":"BashCommand","title":"Kind"}},"type":"object","required":["command","kind"],"title":"BashCommand"},"BashError":{"properties":{"id":{"type":"string","title":"Id"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"code":{"type":"string","title":"Code","description":"Code for the error - typically an error type"},"detail":{"type":"string","title":"Detail","description":"Details about the error"},"kind":{"type":"string","const":"BashError","title":"Kind"}},"type":"object","required":["code","detail","kind"],"title":"BashError"},"BashEventBase":{"oneOf":[{"$ref":"#/components/schemas/BashCommand"},{"$ref":"#/components/schemas/BashError"},{"$ref":"#/components/schemas/BashOutput"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__agent_server__models__BashCommand-Output__1":"#/components/schemas/BashCommand","openhands__agent_server__models__BashError-Output__1":"#/components/schemas/BashError","openhands__agent_server__models__BashOutput-Output__1":"#/components/schemas/BashOutput"}}},"BashEventPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/BashEventBase"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"BashEventPage"},"BashEventSortOrder":{"type":"string","enum":["TIMESTAMP","TIMESTAMP_DESC"],"title":"BashEventSortOrder"},"BashOutput":{"properties":{"id":{"type":"string","title":"Id"},"timestamp":{"type":"string","format":"date-time","title":"Timestamp"},"command_id":{"type":"string","title":"Command Id"},"order":{"type":"integer","title":"Order","description":"The order for this output, sequentially starting with 0","default":0},"exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exit Code","description":"Exit code None implies the command is still running."},"stdout":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stdout","description":"The standard output from the command"},"stderr":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Stderr","description":"The error output from the command"},"kind":{"type":"string","const":"BashOutput","title":"Kind"}},"type":"object","required":["command_id","kind"],"title":"BashOutput","description":"Output of a bash command. A single command may have multiple pieces of output\ndepending on how large the output is."},"Body_switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post":{"properties":{"model":{"type":"string","title":"Model"}},"type":"object","required":["model"],"title":"Body_switch_conversation_acp_model_api_conversations__conversation_id__switch_acp_model_post"},"Body_switch_conversation_llm_api_conversations__conversation_id__switch_llm_post":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"}},"type":"object","required":["llm"],"title":"Body_switch_conversation_llm_api_conversations__conversation_id__switch_llm_post"},"Body_switch_conversation_profile_api_conversations__conversation_id__switch_profile_post":{"properties":{"profile_name":{"type":"string","title":"Profile Name"}},"type":"object","required":["profile_name"],"title":"Body_switch_conversation_profile_api_conversations__conversation_id__switch_profile_post"},"Body_upload_file_query_api_file_upload_post":{"properties":{"file":{"type":"string","format":"binary","title":"File"}},"type":"object","required":["file"],"title":"Body_upload_file_query_api_file_upload_post"},"BrowserAction":{"properties":{"kind":{"type":"string","const":"BrowserAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserAction","description":"Base class for all browser actions.\n\nThis base class serves as the parent for all browser-related actions,\nenabling proper type hierarchy and eliminating the need for union types."},"BrowserActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserActionWithRisk"},"BrowserClickAction":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the element to click (from browser_get_state)"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open any resulting navigation in a new tab. Default: False","default":false},"kind":{"type":"string","const":"BrowserClickAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","kind"],"title":"BrowserClickAction","description":"Schema for clicking elements."},"BrowserClickActionWithRisk":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the element to click (from browser_get_state)"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open any resulting navigation in a new tab. Default: False","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserClickActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","kind"],"title":"BrowserClickActionWithRisk"},"BrowserClickTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserClickTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserClickTool","description":"Tool for clicking browser elements."},"BrowserCloseTabAction":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to close (from browser_list_tabs)"},"kind":{"type":"string","const":"BrowserCloseTabAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserCloseTabAction","description":"Schema for closing browser tabs."},"BrowserCloseTabActionWithRisk":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to close (from browser_list_tabs)"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserCloseTabActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserCloseTabActionWithRisk"},"BrowserCloseTabTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserCloseTabTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserCloseTabTool","description":"Tool for closing browser tabs."},"BrowserGetContentAction":{"properties":{"extract_links":{"type":"boolean","title":"Extract Links","description":"Whether to include links in the content (default: False)","default":false},"start_from_char":{"type":"integer","minimum":0.0,"title":"Start From Char","description":"Character index to start from in the page content (default: 0)","default":0},"kind":{"type":"string","const":"BrowserGetContentAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetContentAction","description":"Schema for getting page content in markdown."},"BrowserGetContentActionWithRisk":{"properties":{"extract_links":{"type":"boolean","title":"Extract Links","description":"Whether to include links in the content (default: False)","default":false},"start_from_char":{"type":"integer","minimum":0.0,"title":"Start From Char","description":"Character index to start from in the page content (default: 0)","default":0},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGetContentActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetContentActionWithRisk"},"BrowserGetContentTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGetContentTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGetContentTool","description":"Tool for getting page content in markdown."},"BrowserGetStateAction":{"properties":{"include_screenshot":{"type":"boolean","title":"Include Screenshot","description":"Whether to include a screenshot of the current page. Default: False","default":false},"kind":{"type":"string","const":"BrowserGetStateAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStateAction","description":"Schema for getting browser state."},"BrowserGetStateActionWithRisk":{"properties":{"include_screenshot":{"type":"boolean","title":"Include Screenshot","description":"Whether to include a screenshot of the current page. Default: False","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGetStateActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStateActionWithRisk"},"BrowserGetStateTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGetStateTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGetStateTool","description":"Tool for getting browser state."},"BrowserGetStorageAction":{"properties":{"kind":{"type":"string","const":"BrowserGetStorageAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStorageAction","description":"Schema for getting browser storage (cookies, local storage, session storage)."},"BrowserGetStorageActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGetStorageActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGetStorageActionWithRisk"},"BrowserGetStorageTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGetStorageTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGetStorageTool","description":"Tool for getting browser storage."},"BrowserGoBackAction":{"properties":{"kind":{"type":"string","const":"BrowserGoBackAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGoBackAction","description":"Schema for going back in browser history."},"BrowserGoBackActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserGoBackActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserGoBackActionWithRisk"},"BrowserGoBackTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserGoBackTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserGoBackTool","description":"Tool for going back in browser history."},"BrowserListTabsAction":{"properties":{"kind":{"type":"string","const":"BrowserListTabsAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserListTabsAction","description":"Schema for listing browser tabs."},"BrowserListTabsActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserListTabsActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserListTabsActionWithRisk"},"BrowserListTabsTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserListTabsTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserListTabsTool","description":"Tool for listing browser tabs."},"BrowserNavigateAction":{"properties":{"url":{"type":"string","title":"Url","description":"The URL to navigate to"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open in a new tab. Default: False","default":false},"kind":{"type":"string","const":"BrowserNavigateAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["url","kind"],"title":"BrowserNavigateAction","description":"Schema for browser navigation."},"BrowserNavigateActionWithRisk":{"properties":{"url":{"type":"string","title":"Url","description":"The URL to navigate to"},"new_tab":{"type":"boolean","title":"New Tab","description":"Whether to open in a new tab. Default: False","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserNavigateActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["url","kind"],"title":"BrowserNavigateActionWithRisk"},"BrowserNavigateTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserNavigateTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserNavigateTool","description":"Tool for browser navigation."},"BrowserObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"screenshot_data":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Screenshot Data","description":"Base64 screenshot data if available"},"full_output_save_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Output Save Dir","description":"Directory where full output files are saved"},"kind":{"type":"string","const":"BrowserObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserObservation","description":"Base observation for browser operations."},"BrowserScrollAction":{"properties":{"direction":{"type":"string","enum":["up","down"],"title":"Direction","description":"Direction to scroll. Options: 'up', 'down'. Default: 'down'","default":"down"},"kind":{"type":"string","const":"BrowserScrollAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserScrollAction","description":"Schema for scrolling the page."},"BrowserScrollActionWithRisk":{"properties":{"direction":{"type":"string","enum":["up","down"],"title":"Direction","description":"Direction to scroll. Options: 'up', 'down'. Default: 'down'","default":"down"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserScrollActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserScrollActionWithRisk"},"BrowserScrollTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserScrollTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserScrollTool","description":"Tool for scrolling the browser page."},"BrowserSetStorageAction":{"properties":{"storage_state":{"additionalProperties":true,"type":"object","title":"Storage State","description":"Storage state dictionary containing 'cookies' and 'origins' (from browser_get_storage)"},"kind":{"type":"string","const":"BrowserSetStorageAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["storage_state","kind"],"title":"BrowserSetStorageAction","description":"Schema for setting browser storage (cookies, local storage, session storage)."},"BrowserSetStorageActionWithRisk":{"properties":{"storage_state":{"additionalProperties":true,"type":"object","title":"Storage State","description":"Storage state dictionary containing 'cookies' and 'origins' (from browser_get_storage)"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserSetStorageActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["storage_state","kind"],"title":"BrowserSetStorageActionWithRisk"},"BrowserSetStorageTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserSetStorageTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserSetStorageTool","description":"Tool for setting browser storage."},"BrowserStartRecordingAction":{"properties":{"kind":{"type":"string","const":"BrowserStartRecordingAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStartRecordingAction","description":"Schema for starting browser session recording."},"BrowserStartRecordingActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserStartRecordingActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStartRecordingActionWithRisk"},"BrowserStartRecordingTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserStartRecordingTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserStartRecordingTool","description":"Tool for starting browser session recording."},"BrowserStopRecordingAction":{"properties":{"kind":{"type":"string","const":"BrowserStopRecordingAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStopRecordingAction","description":"Schema for stopping browser session recording."},"BrowserStopRecordingActionWithRisk":{"properties":{"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserStopRecordingActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"BrowserStopRecordingActionWithRisk"},"BrowserStopRecordingTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserStopRecordingTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserStopRecordingTool","description":"Tool for stopping browser session recording."},"BrowserSwitchTabAction":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to switch to (from browser_list_tabs)"},"kind":{"type":"string","const":"BrowserSwitchTabAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserSwitchTabAction","description":"Schema for switching browser tabs."},"BrowserSwitchTabActionWithRisk":{"properties":{"tab_id":{"type":"string","title":"Tab Id","description":"4 Character Tab ID of the tab to switch to (from browser_list_tabs)"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserSwitchTabActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tab_id","kind"],"title":"BrowserSwitchTabActionWithRisk"},"BrowserSwitchTabTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserSwitchTabTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserSwitchTabTool","description":"Tool for switching browser tabs."},"BrowserToolSet":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserToolSet","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserToolSet","description":"A set of all browser tools.\n\nThis tool set includes all available browser-related tools\n for interacting with web pages.\n\nThe toolset automatically checks for Chromium availability\nwhen created and automatically installs it if missing."},"BrowserTypeAction":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the input element (from browser_get_state)"},"text":{"type":"string","title":"Text","description":"The text to type"},"kind":{"type":"string","const":"BrowserTypeAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","text","kind"],"title":"BrowserTypeAction","description":"Schema for typing text into elements."},"BrowserTypeActionWithRisk":{"properties":{"index":{"type":"integer","minimum":0.0,"title":"Index","description":"The index of the input element (from browser_get_state)"},"text":{"type":"string","title":"Text","description":"The text to type"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"BrowserTypeActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["index","text","kind"],"title":"BrowserTypeActionWithRisk"},"BrowserTypeTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"BrowserTypeTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"BrowserTypeTool","description":"Tool for typing text into browser elements."},"ChatCompletion":{"properties":{"id":{"type":"string","title":"Id"},"choices":{"items":{"$ref":"#/components/schemas/Choice"},"type":"array","title":"Choices"},"created":{"type":"integer","title":"Created"},"model":{"type":"string","title":"Model"},"object":{"type":"string","const":"chat.completion","title":"Object"},"service_tier":{"anyOf":[{"type":"string","enum":["auto","default","flex","scale","priority"]},{"type":"null"}],"title":"Service Tier"},"system_fingerprint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Fingerprint"},"usage":{"anyOf":[{"$ref":"#/components/schemas/CompletionUsage"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["id","choices","created","model","object"],"title":"ChatCompletion","description":"Represents a chat completion response returned by model, based on the provided input."},"ChatCompletionAudio":{"properties":{"id":{"type":"string","title":"Id"},"data":{"type":"string","title":"Data"},"expires_at":{"type":"integer","title":"Expires At"},"transcript":{"type":"string","title":"Transcript"}},"additionalProperties":true,"type":"object","required":["id","data","expires_at","transcript"],"title":"ChatCompletionAudio","description":"If the audio output modality is requested, this object contains data\nabout the audio response from the model. [Learn more](https://platform.openai.com/docs/guides/audio)."},"ChatCompletionMessage":{"properties":{"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Refusal"},"role":{"type":"string","const":"assistant","title":"Role"},"annotations":{"anyOf":[{"items":{"$ref":"#/components/schemas/Annotation"},"type":"array"},{"type":"null"}],"title":"Annotations"},"audio":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionAudio"},{"type":"null"}]},"function_call":{"anyOf":[{"$ref":"#/components/schemas/FunctionCall"},{"type":"null"}]},"tool_calls":{"anyOf":[{"items":{"anyOf":[{"$ref":"#/components/schemas/ChatCompletionMessageFunctionToolCall"},{"$ref":"#/components/schemas/ChatCompletionMessageCustomToolCall"}]},"type":"array"},{"type":"null"}],"title":"Tool Calls"}},"additionalProperties":true,"type":"object","required":["role"],"title":"ChatCompletionMessage","description":"A chat completion message generated by the model."},"ChatCompletionMessageCustomToolCall":{"properties":{"id":{"type":"string","title":"Id"},"custom":{"$ref":"#/components/schemas/Custom"},"type":{"type":"string","const":"custom","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","custom","type"],"title":"ChatCompletionMessageCustomToolCall","description":"A call to a custom tool created by the model."},"ChatCompletionMessageFunctionToolCall":{"properties":{"id":{"type":"string","title":"Id"},"function":{"$ref":"#/components/schemas/Function"},"type":{"type":"string","const":"function","title":"Type"}},"additionalProperties":true,"type":"object","required":["id","function","type"],"title":"ChatCompletionMessageFunctionToolCall","description":"A call to a function tool created by the model."},"ChatCompletionTokenLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"},"top_logprobs":{"items":{"$ref":"#/components/schemas/TopLogprob"},"type":"array","title":"Top Logprobs"}},"additionalProperties":true,"type":"object","required":["token","logprob","top_logprobs"],"title":"ChatCompletionTokenLogprob"},"Choice":{"properties":{"finish_reason":{"type":"string","enum":["stop","length","tool_calls","content_filter","function_call"],"title":"Finish Reason"},"index":{"type":"integer","title":"Index"},"logprobs":{"anyOf":[{"$ref":"#/components/schemas/ChoiceLogprobs"},{"type":"null"}]},"message":{"$ref":"#/components/schemas/ChatCompletionMessage"}},"additionalProperties":true,"type":"object","required":["finish_reason","index","message"],"title":"Choice"},"ChoiceLogprobs":{"properties":{"content":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Content"},"refusal":{"anyOf":[{"items":{"$ref":"#/components/schemas/ChatCompletionTokenLogprob"},"type":"array"},{"type":"null"}],"title":"Refusal"}},"additionalProperties":true,"type":"object","title":"ChoiceLogprobs","description":"Log probability information for the choice."},"ClientTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"client_tool_name":{"type":"string","title":"Client Tool Name","description":"Per-instance tool name from the ClientToolSpec."},"input_schema":{"additionalProperties":true,"type":"object","title":"Input Schema","description":"The original JSON Schema for the tool's parameters, as provided by the client. Used verbatim when exporting the tool to the LLM so client-defined constraints (enum, nested objects, bounds, additionalProperties, ...) are preserved."},"kind":{"type":"string","const":"ClientTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","client_tool_name","input_schema","kind","title"],"title":"ClientTool","description":"A tool whose execution is deferred to the external client.\n\nCreated from a :class:`ClientToolSpec` at conversation start. The agent\nsees it as a normal tool and can call it; the ActionEvent is emitted\nover WebSocket for the client to handle."},"ClientToolObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"kind":{"type":"string","const":"ClientToolObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ClientToolObservation","description":"Observation returned when a client tool is called.\n\nThe actual execution happens on the client side; the SDK returns\nthis acknowledgment so the agent loop can continue."},"ClientToolSpec-Input":{"properties":{"name":{"type":"string","title":"Name","description":"Unique tool name the agent will use to call this tool."},"description":{"type":"string","title":"Description","description":"Description shown to the LLM explaining when and how to use this tool."},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters","description":"JSON Schema describing the tool's input parameters. Must be an object schema."},"annotations":{"anyOf":[{"$ref":"#/components/schemas/ToolAnnotations-Input"},{"type":"null"}],"description":"Optional MCP-style annotations for the tool. When omitted, the tool is treated conservatively (not read-only), so the agent is asked to predict a security risk before calling it."}},"type":"object","required":["name","description"],"title":"ClientToolSpec","description":"A tool defined by the client, executed externally (not by the SDK).\n\nClients pass these specs in ``POST /conversations`` to register tools\nwhose execution is handled outside the SDK (e.g., by a frontend\nlistening for ActionEvents over WebSocket)."},"ClientToolSpec-Output":{"properties":{"name":{"type":"string","title":"Name","description":"Unique tool name the agent will use to call this tool."},"description":{"type":"string","title":"Description","description":"Description shown to the LLM explaining when and how to use this tool."},"parameters":{"additionalProperties":true,"type":"object","title":"Parameters","description":"JSON Schema describing the tool's input parameters. Must be an object schema."},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}],"description":"Optional MCP-style annotations for the tool. When omitted, the tool is treated conservatively (not read-only), so the agent is asked to predict a security risk before calling it."}},"type":"object","required":["name","description"],"title":"ClientToolSpec","description":"A tool defined by the client, executed externally (not by the SDK).\n\nClients pass these specs in ``POST /conversations`` to register tools\nwhose execution is handled outside the SDK (e.g., by a frontend\nlistening for ActionEvents over WebSocket)."},"CmdOutputMetadata":{"properties":{"exit_code":{"type":"integer","title":"Exit Code","description":"The exit code of the last executed command.","default":-1},"pid":{"type":"integer","title":"Pid","description":"The process ID of the last executed command.","default":-1},"username":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Username","description":"The username of the current user."},"hostname":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Hostname","description":"The hostname of the machine."},"working_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Working Dir","description":"The current working directory."},"py_interpreter_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Py Interpreter Path","description":"The path to the current Python interpreter, if any."},"prefix":{"type":"string","title":"Prefix","description":"Prefix to add to command output","default":""},"suffix":{"type":"string","title":"Suffix","description":"Suffix to add to command output","default":""}},"type":"object","title":"CmdOutputMetadata","description":"Additional metadata captured from PS1"},"CompletionTokensDetails":{"properties":{"accepted_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Accepted Prediction Tokens"},"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"reasoning_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Reasoning Tokens"},"rejected_prediction_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Rejected Prediction Tokens"}},"additionalProperties":true,"type":"object","title":"CompletionTokensDetails","description":"Breakdown of tokens used in a completion."},"CompletionUsage":{"properties":{"completion_tokens":{"type":"integer","title":"Completion Tokens"},"prompt_tokens":{"type":"integer","title":"Prompt Tokens"},"total_tokens":{"type":"integer","title":"Total Tokens"},"completion_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/CompletionTokensDetails"},{"type":"null"}]},"prompt_tokens_details":{"anyOf":[{"$ref":"#/components/schemas/PromptTokensDetails"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["completion_tokens","prompt_tokens","total_tokens"],"title":"CompletionUsage","description":"Usage statistics for the completion request."},"Condensation":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"forgotten_event_ids":{"items":{"type":"string"},"type":"array","uniqueItems":true,"title":"Forgotten Event Ids","description":"The IDs of the events that are being forgotten (removed from the `View` given to the LLM)."},"summary":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Summary","description":"An optional summary of the events being forgotten."},"summary_offset":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Summary Offset","description":"An optional offset to the start of the resulting view (after forgotten events have been removed) indicating where the summary should be inserted. If not provided, the summary will not be inserted into the view."},"llm_response_id":{"type":"string","title":"Llm Response Id","description":"Completion or Response ID of the LLM response that generated this event"},"kind":{"type":"string","const":"Condensation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["llm_response_id","kind"],"title":"Condensation","description":"This action indicates a condensation of the conversation history is happening."},"CondensationRequest":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"kind":{"type":"string","const":"CondensationRequest","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"CondensationRequest","description":"This action is used to request a condensation of the conversation history.\n\nAttributes:\n action (str): The action type, namely ActionType.CONDENSATION_REQUEST."},"CondensationSummaryEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"summary":{"type":"string","title":"Summary"},"kind":{"type":"string","const":"CondensationSummaryEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["summary","kind"],"title":"CondensationSummaryEvent","description":"This event represents a summary generated by a condenser."},"CondenserBase-Input":{"oneOf":[{"$ref":"#/components/schemas/LLMSummarizingCondenser-Input"},{"$ref":"#/components/schemas/NoOpCondenser-Input"},{"$ref":"#/components/schemas/PipelineCondenser-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__context__condenser__llm_summarizing_condenser__LLMSummarizingCondenser-Input__1":"#/components/schemas/LLMSummarizingCondenser-Input","openhands__sdk__context__condenser__no_op_condenser__NoOpCondenser-Input__1":"#/components/schemas/NoOpCondenser-Input","openhands__sdk__context__condenser__pipeline_condenser__PipelineCondenser-Input__1":"#/components/schemas/PipelineCondenser-Input"}}},"CondenserBase-Output":{"oneOf":[{"$ref":"#/components/schemas/LLMSummarizingCondenser-Output"},{"$ref":"#/components/schemas/NoOpCondenser-Output"},{"$ref":"#/components/schemas/PipelineCondenser-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__context__condenser__llm_summarizing_condenser__LLMSummarizingCondenser-Output__1":"#/components/schemas/LLMSummarizingCondenser-Output","openhands__sdk__context__condenser__no_op_condenser__NoOpCondenser-Output__1":"#/components/schemas/NoOpCondenser-Output","openhands__sdk__context__condenser__pipeline_condenser__PipelineCondenser-Output__1":"#/components/schemas/PipelineCondenser-Output"}}},"ConfirmRisky-Input":{"properties":{"threshold":{"$ref":"#/components/schemas/SecurityRisk","default":"HIGH"},"confirm_unknown":{"type":"boolean","title":"Confirm Unknown","default":true},"kind":{"type":"string","const":"ConfirmRisky","title":"Kind"}},"type":"object","title":"ConfirmRisky"},"ConfirmRisky-Output":{"properties":{"threshold":{"$ref":"#/components/schemas/SecurityRisk","default":"HIGH"},"confirm_unknown":{"type":"boolean","title":"Confirm Unknown","default":true},"kind":{"type":"string","const":"ConfirmRisky","title":"Kind"}},"type":"object","required":["kind"],"title":"ConfirmRisky"},"ConfirmationPolicyBase-Input":{"oneOf":[{"$ref":"#/components/schemas/AlwaysConfirm-Input"},{"$ref":"#/components/schemas/ConfirmRisky-Input"},{"$ref":"#/components/schemas/NeverConfirm-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__confirmation_policy__AlwaysConfirm-Input__1":"#/components/schemas/AlwaysConfirm-Input","openhands__sdk__security__confirmation_policy__ConfirmRisky-Input__1":"#/components/schemas/ConfirmRisky-Input","openhands__sdk__security__confirmation_policy__NeverConfirm-Input__1":"#/components/schemas/NeverConfirm-Input"}}},"ConfirmationPolicyBase-Output":{"oneOf":[{"$ref":"#/components/schemas/AlwaysConfirm-Output"},{"$ref":"#/components/schemas/ConfirmRisky-Output"},{"$ref":"#/components/schemas/NeverConfirm-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__confirmation_policy__AlwaysConfirm-Output__1":"#/components/schemas/AlwaysConfirm-Output","openhands__sdk__security__confirmation_policy__ConfirmRisky-Output__1":"#/components/schemas/ConfirmRisky-Output","openhands__sdk__security__confirmation_policy__NeverConfirm-Output__1":"#/components/schemas/NeverConfirm-Output"}}},"ConfirmationResponseRequest":{"properties":{"accept":{"type":"boolean","title":"Accept"},"reason":{"type":"string","title":"Reason","default":"User rejected the action."}},"type":"object","required":["accept"],"title":"ConfirmationResponseRequest","description":"Payload to accept or reject a pending action."},"ConversationErrorEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","description":"The source of this event"},"code":{"type":"string","title":"Code","description":"Code for the error - typically a type"},"detail":{"type":"string","title":"Detail","description":"Details about the error"},"kind":{"type":"string","const":"ConversationErrorEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","code","detail","kind"],"title":"ConversationErrorEvent","description":"Conversation-level failure that is NOT sent back to the LLM.\n\nThis event is emitted by the conversation runtime when an unexpected\nexception bubbles up and prevents the run loop from continuing. It is\nintended for client applications (e.g., UIs) to present a top-level error\nstate, and for orchestration to react. It is not an observation and it is\nnot LLM-convertible.\n\nDifferences from AgentErrorEvent:\n- Not tied to any tool_name/tool_call_id (AgentErrorEvent is a tool\n observation).\n- Typically source='environment' and the run loop moves to an ERROR state,\n while AgentErrorEvent has source='agent' and the conversation can\n continue."},"ConversationExecutionStatus":{"type":"string","enum":["idle","running","paused","waiting_for_confirmation","finished","error","stuck","deleting"],"title":"ConversationExecutionStatus","description":"Enum representing the current execution state of the conversation."},"ConversationInfo":{"properties":{"id":{"type":"string","format":"uuid","title":"Id","description":"Unique conversation ID"},"workspace":{"$ref":"#/components/schemas/BaseWorkspace","description":"Workspace used by the agent to execute commands and read/write files. Not the process working directory."},"persistence_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Persistence Dir","description":"Directory for persisting conversation state and events. If None, conversation will not be persisted.","default":"workspace/conversations"},"max_iterations":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Iterations","description":"Maximum number of iterations the agent can perform in a single run.","default":500},"stuck_detection":{"type":"boolean","title":"Stuck Detection","description":"Whether to enable stuck detection for the agent.","default":true},"execution_status":{"$ref":"#/components/schemas/ConversationExecutionStatus","default":"idle"},"confirmation_policy":{"$ref":"#/components/schemas/ConfirmationPolicyBase-Output","default":{"kind":"NeverConfirm"}},"security_analyzer":{"anyOf":[{"$ref":"#/components/schemas/SecurityAnalyzerBase-Output"},{"type":"null"}],"description":"Optional security analyzer to evaluate action risks."},"activated_knowledge_skills":{"items":{"type":"string"},"type":"array","title":"Activated Knowledge Skills","description":"List of activated knowledge skills name"},"invoked_skills":{"items":{"type":"string"},"type":"array","title":"Invoked Skills","description":"Names of progressive-disclosure skills explicitly invoked via the `invoke_skill` tool."},"blocked_actions":{"additionalProperties":{"type":"string"},"type":"object","title":"Blocked Actions","description":"Actions blocked by PreToolUse hooks, keyed by action ID"},"blocked_messages":{"additionalProperties":{"type":"string"},"type":"object","title":"Blocked Messages","description":"Messages blocked by UserPromptSubmit hooks, keyed by message ID"},"last_user_message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Last User Message Id","description":"Most recent user MessageEvent id for hook block checks. Updated when user messages are emitted so Agent.step can pop blocked_messages without scanning the event log. If None, hook-blocked checks are skipped (legacy conversations)."},"stats":{"$ref":"#/components/schemas/ConversationStats","description":"Conversation statistics for tracking LLM metrics"},"secret_registry":{"$ref":"#/components/schemas/SecretRegistry","description":"Registry for handling secrets and sensitive data"},"agent_state":{"additionalProperties":true,"type":"object","title":"Agent State","description":"Dictionary for agent-specific runtime state that persists across iterations."},"hook_config":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Output"},{"type":"null"}],"description":"Hook configuration for this conversation. Includes definitions for PreToolUse, PostToolUse, UserPromptSubmit, SessionStart, SessionEnd, and Stop hooks."},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"User-defined title for the conversation"},"metrics":{"anyOf":[{"$ref":"#/components/schemas/MetricsSnapshot"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time","title":"Created At"},"updated_at":{"type":"string","format":"date-time","title":"Updated At"},"tags":{"additionalProperties":{"type":"string"},"type":"object","title":"Tags","description":"Key-value tags for the conversation. Keys must be lowercase alphanumeric. Values are arbitrary strings up to 256 characters."},"current_model_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Current Model Id","description":"Model the agent is actually using for this session. For ACP agents, this is lifted off ``ACPAgent.current_model_id`` (populated from the ``models.currentModelId`` field on the ACP session response, or from ``acp_model`` when the caller forced an override). May be an opaque alias (e.g. claude-agent-acp's ``\"default\"``); match it against ``available_models`` to get a display label. ``None`` for older ACP servers that don't surface the field, or while the agent is still initializing. Native OpenHands agents leave this ``None`` — consumers should read ``agent.llm.model`` for those."},"available_models":{"items":{"$ref":"#/components/schemas/ACPModelInfo"},"type":"array","title":"Available Models","description":"Models the ACP server offers for this session, lifted off ``ACPAgent.available_models`` (the ``models.availableModels`` field on the ACP session response). Each entry carries a ``model_id`` plus an optional ``name``/``description``. Surfaced verbatim so clients can render a model picker and resolve ``current_model_id`` to a display label themselves — the server does no name curation. Empty for ACP servers that don't surface the (UNSTABLE) capability and for native OpenHands agents. Client contract: ``current_model_id`` is NOT guaranteed to be a member — a forced ``acp_model`` override may name a model absent from the list — so treat a miss as 'show the raw id'. Some entries are opaque aliases whose human identity lives in ``description`` (e.g. claude-agent-acp's ``\"default\"`` -> ``\"Opus 4.7 with 1M context · ...\"``)."},"supports_runtime_model_switch":{"type":"boolean","title":"Supports Runtime Model Switch","description":"Whether a live, mid-conversation model switch will be attempted for this conversation — tells the inline picker whether to offer a live-switch control. Mirrors the SDK's switch gate: ``True`` for known switch-capable providers; ``False`` for unknown/custom ACP servers because their generic config writes are not guaranteed live-switch primitives. ``False`` for native OpenHands agents, for a known provider that declares no support, and before the conversation has started a session.","default":false},"launched_agent_profile":{"anyOf":[{"$ref":"#/components/schemas/LaunchedAgentProfile"},{"type":"null"}],"description":"Provenance snapshot of the agent profile that launched this conversation. Set at creation when the conversation was started via ``agent_profile_id``; ``None`` for conversations started directly with ``agent`` or ``agent_settings``. Clients use this to identify which agent profile is current without fragile settings-comparison."},"agent":{"$ref":"#/components/schemas/AgentBase-Output","description":"The agent running in the conversation."},"client_tools":{"items":{"$ref":"#/components/schemas/ClientToolSpec-Output"},"type":"array","title":"Client Tools","description":"Client-defined tool specs registered for this conversation. Surfaced so that a client re-attaching by conversation id can register the dynamic ClientAction_* action types before syncing persisted events, avoiding 'Unknown kind' deserialization errors."}},"type":"object","required":["id","workspace","agent"],"title":"ConversationInfo","description":"Information about a conversation running locally without a Runtime sandbox."},"ConversationPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/ConversationInfo"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"ConversationPage"},"ConversationSortOrder":{"type":"string","enum":["CREATED_AT","UPDATED_AT","CREATED_AT_DESC","UPDATED_AT_DESC"],"title":"ConversationSortOrder","description":"Enum for conversation sorting options."},"ConversationStateUpdateEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"key":{"type":"string","title":"Key","description":"Unique key for this state update event"},"value":{"title":"Value","description":"Serialized conversation state updates"},"kind":{"type":"string","const":"ConversationStateUpdateEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ConversationStateUpdateEvent","description":"Event that contains conversation state updates.\n\nThis event is sent via websocket whenever the conversation state changes,\nallowing remote clients to stay in sync without making REST API calls.\n\nAll fields are serialized versions of the corresponding ConversationState fields\nto ensure compatibility with websocket transmission."},"ConversationStats":{"additionalProperties":true,"type":"object"},"Cost":{"properties":{"model":{"type":"string","title":"Model"},"cost":{"type":"number","minimum":0.0,"title":"Cost","description":"Cost must be non-negative"},"timestamp":{"type":"number","title":"Timestamp"}},"type":"object","required":["model","cost"],"title":"Cost"},"CriticBase-Input":{"oneOf":[{"$ref":"#/components/schemas/AgentFinishedCritic-Input"},{"$ref":"#/components/schemas/APIBasedCritic-Input"},{"$ref":"#/components/schemas/EmptyPatchCritic-Input"},{"$ref":"#/components/schemas/PassCritic-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__critic__impl__agent_finished__AgentFinishedCritic-Input__1":"#/components/schemas/AgentFinishedCritic-Input","openhands__sdk__critic__impl__api__critic__APIBasedCritic-Input__1":"#/components/schemas/APIBasedCritic-Input","openhands__sdk__critic__impl__empty_patch__EmptyPatchCritic-Input__1":"#/components/schemas/EmptyPatchCritic-Input","openhands__sdk__critic__impl__pass_critic__PassCritic-Input__1":"#/components/schemas/PassCritic-Input"}}},"CriticBase-Output":{"oneOf":[{"$ref":"#/components/schemas/AgentFinishedCritic-Output"},{"$ref":"#/components/schemas/APIBasedCritic-Output"},{"$ref":"#/components/schemas/EmptyPatchCritic-Output"},{"$ref":"#/components/schemas/PassCritic-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__critic__impl__agent_finished__AgentFinishedCritic-Output__1":"#/components/schemas/AgentFinishedCritic-Output","openhands__sdk__critic__impl__api__critic__APIBasedCritic-Output__1":"#/components/schemas/APIBasedCritic-Output","openhands__sdk__critic__impl__empty_patch__EmptyPatchCritic-Output__1":"#/components/schemas/EmptyPatchCritic-Output","openhands__sdk__critic__impl__pass_critic__PassCritic-Output__1":"#/components/schemas/PassCritic-Output"}}},"CriticResult":{"properties":{"score":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Score","description":"A predicted probability of success between 0 and 1."},"message":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message","description":"An optional message explaining the score."},"metadata":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Metadata","description":"Optional metadata about the critic evaluation. Can include event_ids and categorized_features for visualization."}},"type":"object","required":["score","message"],"title":"CriticResult","description":"A critic result is a score and a message."},"Custom":{"properties":{"input":{"type":"string","title":"Input"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["input","name"],"title":"Custom","description":"The custom tool that the model called."},"DelegateAction":{"properties":{"command":{"type":"string","enum":["spawn","delegate"],"title":"Command","description":"The commands to run. Allowed options are: `spawn`, `delegate`."},"ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Ids","description":"Required parameter of `spawn` command. List of identifiers to initialize sub-agents with."},"agent_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Agent Types","description":"Optional parameter of `spawn` command. List of agent types for each ID (e.g., ['researcher', 'programmer']). If omitted or blank for an ID, the default general-purpose agent is used."},"tasks":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tasks","description":"Required parameter of `delegate` command. Dictionary mapping sub-agent identifiers to task descriptions."},"kind":{"type":"string","const":"DelegateAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"DelegateAction","description":"Schema for delegation operations."},"DelegateActionWithRisk":{"properties":{"command":{"type":"string","enum":["spawn","delegate"],"title":"Command","description":"The commands to run. Allowed options are: `spawn`, `delegate`."},"ids":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Ids","description":"Required parameter of `spawn` command. List of identifiers to initialize sub-agents with."},"agent_types":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Agent Types","description":"Optional parameter of `spawn` command. List of agent types for each ID (e.g., ['researcher', 'programmer']). If omitted or blank for an ID, the default general-purpose agent is used."},"tasks":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tasks","description":"Required parameter of `delegate` command. Dictionary mapping sub-agent identifiers to task descriptions."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"DelegateActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"DelegateActionWithRisk"},"DelegateObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["spawn","delegate"],"title":"Command","description":"The command that was executed"},"kind":{"type":"string","const":"DelegateObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"DelegateObservation","description":"Observation from delegation operations."},"DeleteResponse":{"properties":{"deleted":{"type":"boolean","title":"Deleted","default":true}},"type":"object","title":"DeleteResponse"},"DesktopUrlResponse":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"}},"type":"object","required":["url"],"title":"DesktopUrlResponse","description":"Response model for Desktop URL."},"EditAction":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to modify."},"old_string":{"type":"string","title":"Old String","description":"The text to replace. To create a new file, use an empty string. Must match the exact text in the file including whitespace."},"new_string":{"type":"string","title":"New String","description":"The text to replace it with."},"expected_replacements":{"type":"integer","minimum":0.0,"title":"Expected Replacements","description":"Number of replacements expected. Defaults to 1. Use when you want to replace multiple occurrences. The edit will fail if the actual count doesn't match.","default":1},"kind":{"type":"string","const":"EditAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","old_string","new_string","kind"],"title":"EditAction","description":"Schema for edit operation."},"EditActionWithRisk":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to modify."},"old_string":{"type":"string","title":"Old String","description":"The text to replace. To create a new file, use an empty string. Must match the exact text in the file including whitespace."},"new_string":{"type":"string","title":"New String","description":"The text to replace it with."},"expected_replacements":{"type":"integer","minimum":0.0,"title":"Expected Replacements","description":"Number of replacements expected. Defaults to 1. Use when you want to replace multiple occurrences. The edit will fail if the actual count doesn't match.","default":1},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"EditActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","old_string","new_string","kind"],"title":"EditActionWithRisk"},"EditObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path","description":"The file path that was edited."},"is_new_file":{"type":"boolean","title":"Is New File","description":"Whether a new file was created.","default":false},"replacements_made":{"type":"integer","title":"Replacements Made","description":"Number of replacements actually made.","default":0},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The content before the edit."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The content after the edit."},"kind":{"type":"string","const":"EditObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"EditObservation","description":"Observation from editing a file."},"EditTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"EditTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"EditTool","description":"Tool for editing files via find/replace."},"EmptyPatchCritic-Input":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"EmptyPatchCritic","title":"Kind"}},"type":"object","title":"EmptyPatchCritic","description":"Critic that only evaluates whether a git patch is non-empty.\n\nThis critic checks only one criterion:\n- The generated git patch is non-empty (actual changes were made)\n\nUnlike AgentFinishedCritic, this critic does not check for proper\nagent completion with FinishAction."},"EmptyPatchCritic-Output":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"EmptyPatchCritic","title":"Kind"}},"type":"object","required":["kind"],"title":"EmptyPatchCritic","description":"Critic that only evaluates whether a git patch is non-empty.\n\nThis critic checks only one criterion:\n- The generated git patch is non-empty (actual changes were made)\n\nUnlike AgentFinishedCritic, this critic does not check for proper\nagent completion with FinishAction."},"EnsembleSecurityAnalyzer-Input":{"properties":{"analyzers":{"items":{"$ref":"#/components/schemas/SecurityAnalyzerBase-Input"},"type":"array","minItems":1,"title":"Analyzers","description":"Analyzers whose assessments are combined via max-severity"},"propagate_unknown":{"type":"boolean","title":"Propagate Unknown","description":"When True, any child returning UNKNOWN causes the ensemble to return UNKNOWN. When False (default), UNKNOWN is filtered out if any child returns a concrete level.","default":false},"kind":{"type":"string","const":"EnsembleSecurityAnalyzer","title":"Kind"}},"type":"object","required":["analyzers"],"title":"EnsembleSecurityAnalyzer","description":"Wire multiple analyzers together and take the worst-case risk.\n\nUse this as the top-level analyzer you set on a conversation. It\ncalls each child analyzer, collects their risk assessments, and\nreturns the highest concrete risk. It does not perform any detection,\nextraction, or normalization of its own.\n\nHow UNKNOWN works (default, ``propagate_unknown=False``): if *all*\nchildren return UNKNOWN, the ensemble returns UNKNOWN (which\n``ConfirmRisky`` confirms by default). If any child returns a\nconcrete level, UNKNOWN results are filtered out and the highest\nconcrete level wins.\n\nWith ``propagate_unknown=True``: if *any* child returns UNKNOWN, the\nensemble returns UNKNOWN regardless of other results. Use this in\nstricter environments where incomplete assessment should trigger\nconfirmation.\n\nIf a child analyzer raises an exception, it contributes HIGH\n(fail-closed, logged). This prevents a broken analyzer from silently\ndegrading safety.\n\nExample::\n\n from openhands.sdk.security import (\n EnsembleSecurityAnalyzer,\n PatternSecurityAnalyzer,\n PolicyRailSecurityAnalyzer,\n ConfirmRisky,\n SecurityRisk,\n )\n\n analyzer = EnsembleSecurityAnalyzer(\n analyzers=[\n PolicyRailSecurityAnalyzer(),\n PatternSecurityAnalyzer(),\n ]\n )\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"EnsembleSecurityAnalyzer-Output":{"properties":{"analyzers":{"items":{"$ref":"#/components/schemas/SecurityAnalyzerBase-Output"},"type":"array","minItems":1,"title":"Analyzers","description":"Analyzers whose assessments are combined via max-severity"},"propagate_unknown":{"type":"boolean","title":"Propagate Unknown","description":"When True, any child returning UNKNOWN causes the ensemble to return UNKNOWN. When False (default), UNKNOWN is filtered out if any child returns a concrete level.","default":false},"kind":{"type":"string","const":"EnsembleSecurityAnalyzer","title":"Kind"}},"type":"object","required":["analyzers","kind"],"title":"EnsembleSecurityAnalyzer","description":"Wire multiple analyzers together and take the worst-case risk.\n\nUse this as the top-level analyzer you set on a conversation. It\ncalls each child analyzer, collects their risk assessments, and\nreturns the highest concrete risk. It does not perform any detection,\nextraction, or normalization of its own.\n\nHow UNKNOWN works (default, ``propagate_unknown=False``): if *all*\nchildren return UNKNOWN, the ensemble returns UNKNOWN (which\n``ConfirmRisky`` confirms by default). If any child returns a\nconcrete level, UNKNOWN results are filtered out and the highest\nconcrete level wins.\n\nWith ``propagate_unknown=True``: if *any* child returns UNKNOWN, the\nensemble returns UNKNOWN regardless of other results. Use this in\nstricter environments where incomplete assessment should trigger\nconfirmation.\n\nIf a child analyzer raises an exception, it contributes HIGH\n(fail-closed, logged). This prevents a broken analyzer from silently\ndegrading safety.\n\nExample::\n\n from openhands.sdk.security import (\n EnsembleSecurityAnalyzer,\n PatternSecurityAnalyzer,\n PolicyRailSecurityAnalyzer,\n ConfirmRisky,\n SecurityRisk,\n )\n\n analyzer = EnsembleSecurityAnalyzer(\n analyzers=[\n PolicyRailSecurityAnalyzer(),\n PatternSecurityAnalyzer(),\n ]\n )\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"Event":{"oneOf":[{"$ref":"#/components/schemas/ServerErrorEvent"},{"$ref":"#/components/schemas/ACPToolCallEvent"},{"$ref":"#/components/schemas/Condensation"},{"$ref":"#/components/schemas/CondensationRequest"},{"$ref":"#/components/schemas/CondensationSummaryEvent"},{"$ref":"#/components/schemas/ConversationErrorEvent"},{"$ref":"#/components/schemas/ConversationStateUpdateEvent"},{"$ref":"#/components/schemas/HookExecutionEvent"},{"$ref":"#/components/schemas/LLMCompletionLogEvent"},{"$ref":"#/components/schemas/ActionEvent"},{"$ref":"#/components/schemas/MessageEvent"},{"$ref":"#/components/schemas/AgentErrorEvent"},{"$ref":"#/components/schemas/ObservationEvent"},{"$ref":"#/components/schemas/UserRejectObservation"},{"$ref":"#/components/schemas/SystemPromptEvent"},{"$ref":"#/components/schemas/StreamingDeltaEvent"},{"$ref":"#/components/schemas/TokenEvent"},{"$ref":"#/components/schemas/InterruptEvent"},{"$ref":"#/components/schemas/PauseEvent"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__agent_server__models__ServerErrorEvent-Output__1":"#/components/schemas/ServerErrorEvent","openhands__sdk__event__acp_tool_call__ACPToolCallEvent-Output__1":"#/components/schemas/ACPToolCallEvent","openhands__sdk__event__condenser__Condensation-Output__1":"#/components/schemas/Condensation","openhands__sdk__event__condenser__CondensationRequest-Output__1":"#/components/schemas/CondensationRequest","openhands__sdk__event__condenser__CondensationSummaryEvent-Output__1":"#/components/schemas/CondensationSummaryEvent","openhands__sdk__event__conversation_error__ConversationErrorEvent-Output__1":"#/components/schemas/ConversationErrorEvent","openhands__sdk__event__conversation_state__ConversationStateUpdateEvent-Output__1":"#/components/schemas/ConversationStateUpdateEvent","openhands__sdk__event__hook_execution__HookExecutionEvent-Output__1":"#/components/schemas/HookExecutionEvent","openhands__sdk__event__llm_completion_log__LLMCompletionLogEvent-Output__1":"#/components/schemas/LLMCompletionLogEvent","openhands__sdk__event__llm_convertible__action__ActionEvent-Output__1":"#/components/schemas/ActionEvent","openhands__sdk__event__llm_convertible__message__MessageEvent-Output__1":"#/components/schemas/MessageEvent","openhands__sdk__event__llm_convertible__observation__AgentErrorEvent-Output__1":"#/components/schemas/AgentErrorEvent","openhands__sdk__event__llm_convertible__observation__ObservationEvent-Output__1":"#/components/schemas/ObservationEvent","openhands__sdk__event__llm_convertible__observation__UserRejectObservation-Output__1":"#/components/schemas/UserRejectObservation","openhands__sdk__event__llm_convertible__system__SystemPromptEvent-Output__1":"#/components/schemas/SystemPromptEvent","openhands__sdk__event__streaming_delta__StreamingDeltaEvent-Output__1":"#/components/schemas/StreamingDeltaEvent","openhands__sdk__event__token__TokenEvent-Output__1":"#/components/schemas/TokenEvent","openhands__sdk__event__user_action__InterruptEvent-Output__1":"#/components/schemas/InterruptEvent","openhands__sdk__event__user_action__PauseEvent-Output__1":"#/components/schemas/PauseEvent"}}},"EventPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/Event"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"EventPage"},"EventSortOrder":{"type":"string","enum":["TIMESTAMP","TIMESTAMP_DESC"],"title":"EventSortOrder","description":"Enum for event sorting options."},"ExecuteBashRequest":{"properties":{"command":{"type":"string","title":"Command","description":"The bash command to execute"},"cwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd","description":"The current working directory"},"timeout":{"type":"integer","title":"Timeout","description":"The max number of seconds a command may be permitted to run.","default":300}},"type":"object","required":["command"],"title":"ExecuteBashRequest"},"ExposedUrl":{"properties":{"name":{"type":"string","title":"Name"},"url":{"type":"string","title":"Url"},"port":{"type":"integer","title":"Port"}},"type":"object","required":["name","url","port"],"title":"ExposedUrl","description":"Represents an exposed URL from the sandbox."},"FallbackStrategy":{"properties":{"fallback_llms":{"items":{"type":"string"},"type":"array","title":"Fallback Llms","description":"Ordered list of LLM profile names to try on transient failure."},"profile_store_dir":{"anyOf":[{"type":"string"},{"type":"string","format":"path"},{"type":"null"}],"title":"Profile Store Dir","description":"Path to directory containing profiles. If not specified, defaults to `.openhands/profiles`."}},"type":"object","required":["fallback_llms"],"title":"FallbackStrategy","description":"Encapsulates fallback behavior for LLM calls.\n\nWhen the primary LLM fails with a transient error (after retries),\nthis strategy tries alternate LLMs loaded from LLMProfileStore profiles.\nFallback is per-call: each new request starts with the primary model."},"FileBrowserEntry":{"properties":{"label":{"type":"string","title":"Label"},"path":{"type":"string","title":"Path"}},"type":"object","required":["label","path"],"title":"FileBrowserEntry"},"FileEditorAction":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"kind":{"type":"string","const":"FileEditorAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"FileEditorAction","description":"Schema for file editor operations."},"FileEditorActionWithRisk":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"FileEditorActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"FileEditorActionWithRisk"},"FileEditorObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The command that was run: `view`, `create`, `str_replace`, `insert`, or `undo_edit`."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The file path that was edited."},"prev_exist":{"type":"boolean","title":"Prev Exist","description":"Indicates if the file previously existed. If not, it was created.","default":true},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The content of the file before the edit."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The content of the file after the edit."},"kind":{"type":"string","const":"FileEditorObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"FileEditorObservation","description":"A ToolResult that can be rendered as a CLI output."},"FileEditorTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"FileEditorTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"FileEditorTool","description":"A ToolDefinition subclass that automatically initializes a FileEditorExecutor."},"FileEntry":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the file or directory"},"path":{"type":"string","title":"Path","description":"Absolute path to the file or directory"},"is_directory":{"type":"boolean","title":"Is Directory","description":"Whether this entry is a directory"},"size":{"type":"integer","title":"Size","description":"Size of the file in bytes (0 for directories)"},"modified_time":{"type":"string","format":"date-time","title":"Modified Time","description":"Last modified timestamp"}},"type":"object","required":["name","path","is_directory","size","modified_time"],"title":"FileEntry","description":"Information about a file or directory."},"FinishAction":{"properties":{"message":{"type":"string","title":"Message","description":"Final message to send to the user."},"kind":{"type":"string","const":"FinishAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["message","kind"],"title":"FinishAction"},"FinishActionWithRisk":{"properties":{"message":{"type":"string","title":"Message","description":"Final message to send to the user."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"FinishActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["message","kind"],"title":"FinishActionWithRisk"},"FinishObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"kind":{"type":"string","const":"FinishObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"FinishObservation","description":"Observation returned after finishing a task.\nThe FinishAction itself contains the message sent to the user so no\nextra fields are needed here."},"FinishTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"FinishTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"FinishTool","description":"Tool for signaling the completion of a task or conversation."},"ForkConversationRequest":{"properties":{"id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Id","description":"ID for the forked conversation (auto-generated if null)"},"title":{"anyOf":[{"type":"string","maxLength":200},{"type":"null"}],"title":"Title","description":"Optional title for the forked conversation"},"tags":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tags","description":"Optional tags for the forked conversation. Keys must be lowercase alphanumeric."},"reset_metrics":{"type":"boolean","title":"Reset Metrics","description":"If true, cost/token stats start fresh on the fork. If false, metrics are copied from the source.","default":true}},"type":"object","title":"ForkConversationRequest","description":"Payload to fork a conversation."},"Function":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"Function","description":"The function that the model called."},"FunctionCall":{"properties":{"arguments":{"type":"string","title":"Arguments"},"name":{"type":"string","title":"Name"}},"additionalProperties":true,"type":"object","required":["arguments","name"],"title":"FunctionCall","description":"Deprecated and replaced by `tool_calls`.\n\nThe name and arguments of a function that should be called, as generated by the model."},"GitChange":{"properties":{"status":{"$ref":"#/components/schemas/GitChangeStatus"},"path":{"type":"string","format":"path","title":"Path"}},"type":"object","required":["status","path"],"title":"GitChange"},"GitChangeStatus":{"type":"string","enum":["MOVED","ADDED","DELETED","UPDATED"],"title":"GitChangeStatus"},"GitDiff":{"properties":{"modified":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Modified"},"original":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Original"}},"type":"object","required":["modified","original"],"title":"GitDiff"},"GlobAction":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The glob pattern to match files (e.g., \"**/*.js\", \"src/**/*.ts\")"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"kind":{"type":"string","const":"GlobAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GlobAction","description":"Schema for glob pattern matching operations."},"GlobActionWithRisk":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The glob pattern to match files (e.g., \"**/*.js\", \"src/**/*.ts\")"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"GlobActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GlobActionWithRisk"},"GlobObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"files":{"items":{"type":"string"},"type":"array","title":"Files","description":"List of matching file paths sorted by modification time"},"pattern":{"type":"string","title":"Pattern","description":"The glob pattern that was used"},"search_path":{"type":"string","title":"Search Path","description":"The directory that was searched"},"truncated":{"type":"boolean","title":"Truncated","description":"Whether results were truncated to 100 files","default":false},"kind":{"type":"string","const":"GlobObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["files","pattern","search_path","kind"],"title":"GlobObservation","description":"Observation from glob pattern matching operations."},"GlobTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"GlobTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"GlobTool","description":"A ToolDefinition subclass that automatically initializes a GlobExecutor."},"GraySwanAnalyzer-Input":{"properties":{"history_limit":{"type":"integer","title":"History Limit","description":"Number of recent events to include as context","default":20},"max_message_chars":{"type":"integer","title":"Max Message Chars","description":"Max characters for conversation processing","default":30000},"timeout":{"type":"number","title":"Timeout","description":"Request timeout in seconds","default":30.0},"low_threshold":{"type":"number","title":"Low Threshold","description":"Risk threshold for LOW classification (score <= threshold)","default":0.3},"medium_threshold":{"type":"number","title":"Medium Threshold","description":"Risk threshold for MEDIUM classification (score <= threshold)","default":0.7},"api_url":{"type":"string","title":"Api Url","description":"GraySwan Cygnal API endpoint","default":"https://api.grayswan.ai/cygnal/monitor"},"api_key":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"GraySwan API key (via GRAYSWAN_API_KEY env var)"},"policy_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy Id","description":"GraySwan policy ID (via GRAYSWAN_POLICY_ID env var)"},"kind":{"type":"string","const":"GraySwanAnalyzer","title":"Kind"}},"type":"object","title":"GraySwanAnalyzer","description":"Security analyzer using GraySwan's Cygnal API for AI safety monitoring.\n\nThis analyzer sends conversation history and pending actions to the GraySwan\nCygnal API for security analysis. The API returns a violation score which is\nmapped to SecurityRisk levels.\n\nEnvironment Variables:\n GRAYSWAN_API_KEY: Required API key for GraySwan authentication\n GRAYSWAN_POLICY_ID: Optional policy ID for custom GraySwan policy\n\nExample:\n >>> from openhands.sdk.security.grayswan import GraySwanAnalyzer\n >>> analyzer = GraySwanAnalyzer()\n >>> risk = analyzer.security_risk(action_event)"},"GraySwanAnalyzer-Output":{"properties":{"history_limit":{"type":"integer","title":"History Limit","description":"Number of recent events to include as context","default":20},"max_message_chars":{"type":"integer","title":"Max Message Chars","description":"Max characters for conversation processing","default":30000},"timeout":{"type":"number","title":"Timeout","description":"Request timeout in seconds","default":30.0},"low_threshold":{"type":"number","title":"Low Threshold","description":"Risk threshold for LOW classification (score <= threshold)","default":0.3},"medium_threshold":{"type":"number","title":"Medium Threshold","description":"Risk threshold for MEDIUM classification (score <= threshold)","default":0.7},"api_url":{"type":"string","title":"Api Url","description":"GraySwan Cygnal API endpoint","default":"https://api.grayswan.ai/cygnal/monitor"},"api_key":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"GraySwan API key (via GRAYSWAN_API_KEY env var)"},"policy_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Policy Id","description":"GraySwan policy ID (via GRAYSWAN_POLICY_ID env var)"},"kind":{"type":"string","const":"GraySwanAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"GraySwanAnalyzer","description":"Security analyzer using GraySwan's Cygnal API for AI safety monitoring.\n\nThis analyzer sends conversation history and pending actions to the GraySwan\nCygnal API for security analysis. The API returns a violation score which is\nmapped to SecurityRisk levels.\n\nEnvironment Variables:\n GRAYSWAN_API_KEY: Required API key for GraySwan authentication\n GRAYSWAN_POLICY_ID: Optional policy ID for custom GraySwan policy\n\nExample:\n >>> from openhands.sdk.security.grayswan import GraySwanAnalyzer\n >>> analyzer = GraySwanAnalyzer()\n >>> risk = analyzer.security_risk(action_event)"},"GrepAction":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The regex pattern to search for in file contents"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"include":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include","description":"Optional file pattern to filter which files to search (e.g., \"*.js\", \"*.{ts,tsx}\")"},"kind":{"type":"string","const":"GrepAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GrepAction","description":"Schema for grep content search operations."},"GrepActionWithRisk":{"properties":{"pattern":{"type":"string","title":"Pattern","description":"The regex pattern to search for in file contents"},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The directory (absolute path) to search in. Defaults to the current working directory."},"include":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include","description":"Optional file pattern to filter which files to search (e.g., \"*.js\", \"*.{ts,tsx}\")"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"GrepActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["pattern","kind"],"title":"GrepActionWithRisk"},"GrepObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"matches":{"items":{"type":"string"},"type":"array","title":"Matches","description":"List of file paths containing the pattern"},"pattern":{"type":"string","title":"Pattern","description":"The regex pattern that was used"},"search_path":{"type":"string","title":"Search Path","description":"The directory that was searched"},"include_pattern":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Include Pattern","description":"The file pattern filter that was used"},"truncated":{"type":"boolean","title":"Truncated","description":"Whether results were truncated to 100 files","default":false},"kind":{"type":"string","const":"GrepObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["matches","pattern","search_path","kind"],"title":"GrepObservation","description":"Observation from grep content search operations."},"GrepTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"GrepTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"GrepTool","description":"A ToolDefinition subclass that automatically initializes a GrepExecutor."},"HTTPValidationError":{"properties":{"detail":{"items":{"$ref":"#/components/schemas/ValidationError"},"type":"array","title":"Detail"}},"type":"object","title":"HTTPValidationError"},"HealthStatus":{"properties":{"status":{"type":"string","title":"Status"}},"type":"object","required":["status"],"title":"HealthStatus"},"HomeResponse":{"properties":{"home":{"type":"string","title":"Home"},"favorites":{"items":{"$ref":"#/components/schemas/FileBrowserEntry"},"type":"array","title":"Favorites","default":[]},"locations":{"items":{"$ref":"#/components/schemas/FileBrowserEntry"},"type":"array","title":"Locations","default":[]}},"type":"object","required":["home"],"title":"HomeResponse"},"HookConfig-Input":{"properties":{"pre_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Pre Tool Use","description":"Hooks that run before tool execution"},"post_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Post Tool Use","description":"Hooks that run after tool execution"},"user_prompt_submit":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"User Prompt Submit","description":"Hooks that run when user submits a prompt"},"session_start":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Session Start","description":"Hooks that run when a session starts"},"session_end":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Session End","description":"Hooks that run when a session ends"},"stop":{"items":{"$ref":"#/components/schemas/HookMatcher-Input"},"type":"array","title":"Stop","description":"Hooks that run when the agent attempts to stop"}},"additionalProperties":false,"type":"object","title":"HookConfig","description":"Configuration for all hooks.\n\nHooks can be configured either by loading from `.openhands/hooks.json` or\nby directly instantiating with typed fields:\n\n # Direct instantiation with typed fields (recommended):\n config = HookConfig(\n pre_tool_use=[\n HookMatcher(\n matcher=\"terminal\",\n hooks=[HookDefinition(command=\"block_dangerous.sh\")]\n )\n ]\n )\n\n # Load from JSON file:\n config = HookConfig.load(\".openhands/hooks.json\")"},"HookConfig-Output":{"properties":{"pre_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Pre Tool Use","description":"Hooks that run before tool execution"},"post_tool_use":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Post Tool Use","description":"Hooks that run after tool execution"},"user_prompt_submit":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"User Prompt Submit","description":"Hooks that run when user submits a prompt"},"session_start":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Session Start","description":"Hooks that run when a session starts"},"session_end":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Session End","description":"Hooks that run when a session ends"},"stop":{"items":{"$ref":"#/components/schemas/HookMatcher-Output"},"type":"array","title":"Stop","description":"Hooks that run when the agent attempts to stop"}},"additionalProperties":false,"type":"object","title":"HookConfig","description":"Configuration for all hooks.\n\nHooks can be configured either by loading from `.openhands/hooks.json` or\nby directly instantiating with typed fields:\n\n # Direct instantiation with typed fields (recommended):\n config = HookConfig(\n pre_tool_use=[\n HookMatcher(\n matcher=\"terminal\",\n hooks=[HookDefinition(command=\"block_dangerous.sh\")]\n )\n ]\n )\n\n # Load from JSON file:\n config = HookConfig.load(\".openhands/hooks.json\")"},"HookDefinition":{"properties":{"type":{"$ref":"#/components/schemas/HookType","default":"command"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"command":{"type":"string","title":"Command"},"prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt"},"system_prompt":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"System Prompt"},"tools":{"items":{"type":"string"},"type":"array","title":"Tools"},"timeout":{"type":"integer","title":"Timeout","default":60},"max_iterations":{"type":"integer","title":"Max Iterations","default":3},"async":{"type":"boolean","title":"Async","default":false}},"type":"object","required":["command"],"title":"HookDefinition","description":"A single hook definition."},"HookExecutionEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","description":"Source is always 'hook' for hook execution events","default":"hook"},"hook_event_type":{"type":"string","enum":["PreToolUse","PostToolUse","UserPromptSubmit","SessionStart","SessionEnd","Stop"],"title":"Hook Event Type","description":"The type of hook event that triggered this execution"},"hook_command":{"type":"string","title":"Hook Command","description":"The hook command that was executed"},"tool_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Name","description":"Tool name for PreToolUse/PostToolUse hooks"},"success":{"type":"boolean","title":"Success","description":"Whether the hook executed successfully"},"blocked":{"type":"boolean","title":"Blocked","description":"Whether the hook blocked the operation (exit code 2 or deny)","default":false},"exit_code":{"type":"integer","title":"Exit Code","description":"Exit code from the hook command"},"stdout":{"type":"string","title":"Stdout","description":"Standard output from the hook","default":""},"stderr":{"type":"string","title":"Stderr","description":"Standard error from the hook","default":""},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Reason provided by hook (for blocking)"},"additional_context":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Additional Context","description":"Additional context injected by hook (e.g., for UserPromptSubmit)"},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"Error message if hook execution failed"},"action_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Action Id","description":"ID of the action this hook is associated with (PreToolUse/PostToolUse)"},"message_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Message Id","description":"ID of the message this hook is associated with (UserPromptSubmit)"},"hook_input":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Hook Input","description":"The input data that was passed to the hook"},"kind":{"type":"string","const":"HookExecutionEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["hook_event_type","hook_command","success","exit_code","kind"],"title":"HookExecutionEvent","description":"Event emitted when a hook is executed.\n\nThis event provides observability into hook execution, including:\n- Which hook type was triggered\n- The command that was run\n- The result (success/blocked/error)\n- Any output from the hook\n\nThis allows clients to track hook execution via the event stream."},"HookMatcher-Input":{"properties":{"matcher":{"type":"string","title":"Matcher","default":"*"},"hooks":{"items":{"$ref":"#/components/schemas/HookDefinition"},"type":"array","title":"Hooks"}},"type":"object","title":"HookMatcher","description":"Matches events to hooks based on patterns.\n\nSupports exact match, wildcard (*), and regex (auto-detected or /pattern/)."},"HookMatcher-Output":{"properties":{"matcher":{"type":"string","title":"Matcher","default":"*"},"hooks":{"items":{"$ref":"#/components/schemas/HookDefinition"},"type":"array","title":"Hooks"}},"type":"object","title":"HookMatcher","description":"Matches events to hooks based on patterns.\n\nSupports exact match, wildcard (*), and regex (auto-detected or /pattern/)."},"HookType":{"type":"string","enum":["command","prompt","agent"],"title":"HookType","description":"Types of hooks that can be executed."},"HooksRequest":{"properties":{"project_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Dir","description":"Workspace directory path for project hooks"}},"type":"object","title":"HooksRequest","description":"Request body for loading hooks."},"HooksResponse":{"properties":{"hook_config":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Output"},{"type":"null"}],"description":"Hook configuration loaded from the workspace, or None if not found"}},"type":"object","title":"HooksResponse","description":"Response containing hooks configuration."},"Icon":{"properties":{"src":{"type":"string","title":"Src"},"mimeType":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Mimetype"},"sizes":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Sizes"}},"additionalProperties":true,"type":"object","required":["src"],"title":"Icon","description":"An icon for display in user interfaces."},"ImageContent":{"properties":{"cache_prompt":{"type":"boolean","title":"Cache Prompt","default":false},"type":{"type":"string","const":"image","title":"Type","default":"image"},"image_urls":{"items":{"type":"string"},"type":"array","title":"Image Urls"}},"type":"object","required":["image_urls"],"title":"ImageContent"},"InitRequest":{"properties":{"session_api_keys":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Session Api Keys","description":"Per-user session API keys. If provided, all subsequent /api/* requests must authenticate with one of these keys via the X-Session-API-Key header."},"secret_key":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Secret Key","description":"Symmetric secret used to encrypt persisted secrets. If not provided, falls back to the first session_api_key (matching the default Config behavior)."},"conversations_path":{"anyOf":[{"type":"string","format":"path"},{"type":"null"}],"title":"Conversations Path","description":"Directory where conversations are persisted. Override this to point at the mounted user workspace."},"bash_events_dir":{"anyOf":[{"type":"string","format":"path"},{"type":"null"}],"title":"Bash Events Dir","description":"Directory where bash events are persisted. Typically located inside the mounted user workspace."},"webhooks":{"anyOf":[{"items":{"$ref":"#/components/schemas/WebhookSpec"},"type":"array"},{"type":"null"}],"title":"Webhooks","description":"Per-user webhooks (e.g. for streaming events back)."},"web_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Web Url","description":"External URL where this server is reachable, used for root-path calculation. Only honored when not already set in dormant config."},"allow_cors_origins":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allow Cors Origins","description":"CORS origins to add to the existing localhost allowlist."},"max_concurrent_runs":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Concurrent Runs","description":"Override the conversation-step concurrency limit."},"env":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Env","description":"Process environment variables to set before conversation services start. Useful for credentials consumed by tools (e.g. GITHUB_TOKEN). These are applied with ``os.environ.update``; existing values are overwritten."}},"additionalProperties":false,"type":"object","title":"InitRequest","description":"Runtime configuration delivered at /api/init time.\n\nEach field is optional and overrides the equivalent field on the dormant\n``Config``. Fields not provided keep the value the server was constructed\nwith (typically from env vars at pod startup). The set of overridable\nfields is intentionally narrow — it covers the values that today are\n\"env-var shaped\" and must change per-user, not image-build-time\nconfiguration (Python deps, plugin set, etc.) which stays bound to the\nwarm-pool flavor."},"InitStatus":{"properties":{"state":{"type":"string","enum":["dormant","initializing","ready"],"title":"State","description":"``dormant`` — server is up but waiting for /api/init. ``initializing`` — /api/init has been received and services are starting. ``ready`` — initialization complete; all /api/* routes are live."},"error":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Error","description":"If a previous /api/init attempt failed, the error message. The state rolls back to ``dormant`` so /api/init can be retried."}},"type":"object","required":["state"],"title":"InitStatus"},"InputMetadata":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the input parameter"},"description":{"type":"string","title":"Description","description":"Description of the input parameter"}},"type":"object","required":["name","description"],"title":"InputMetadata","description":"Metadata for task skill inputs."},"InstallSkillRequest":{"properties":{"source":{"type":"string","minLength":1,"title":"Source","description":"Skill source - git URL, GitHub shorthand, or local path. Examples: 'https://github.com/OpenHands/extensions/tree/main/skills/github', 'github:OpenHands/extensions/skills/github', '/path/to/skill'"},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref","description":"Optional branch, tag, or commit to install"},"repo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Path","description":"Subdirectory path within the repository (for monorepos)"},"force":{"type":"boolean","title":"Force","description":"If true, overwrite existing installation","default":false}},"type":"object","required":["source"],"title":"InstallSkillRequest","description":"Request body for installing a skill."},"InstalledSkillResponse":{"properties":{"name":{"type":"string","title":"Name","description":"Skill name"},"version":{"type":"string","title":"Version","description":"Skill version","default":""},"description":{"type":"string","title":"Description","description":"Skill description","default":""},"enabled":{"type":"boolean","title":"Enabled","description":"Whether the skill is enabled","default":true},"source":{"type":"string","title":"Source","description":"Original source (e.g., 'github:owner/repo')"},"resolved_ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resolved Ref","description":"Resolved git commit SHA"},"repo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Path","description":"Subdirectory path within the repository"},"installed_at":{"type":"string","title":"Installed At","description":"ISO 8601 timestamp of installation"},"install_path":{"type":"string","title":"Install Path","description":"Path where the skill is installed"}},"type":"object","required":["name","source","installed_at","install_path"],"title":"InstalledSkillResponse","description":"Response containing installed skill information."},"InstalledSkillsListResponse":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/InstalledSkillResponse"},"type":"array","title":"Skills"}},"type":"object","required":["skills"],"title":"InstalledSkillsListResponse","description":"Response containing list of installed skills."},"InterruptEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"user"},"kind":{"type":"string","const":"InterruptEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"InterruptEvent","description":"Event indicating the agent was interrupted mid-operation.\n\nUnlike :class:`PauseEvent` which takes effect between agent steps,\nan interrupt cancels the in-flight LLM call immediately. The\nconversation state is set to PAUSED so it can be resumed later."},"InvokeSkillAction":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the loaded skill to invoke."},"kind":{"type":"string","const":"InvokeSkillAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","kind"],"title":"InvokeSkillAction"},"InvokeSkillActionWithRisk":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the loaded skill to invoke."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"InvokeSkillActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","kind"],"title":"InvokeSkillActionWithRisk"},"InvokeSkillObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"skill_name":{"type":"string","title":"Skill Name","description":"Name of the skill this observation corresponds to."},"kind":{"type":"string","const":"InvokeSkillObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["skill_name","kind"],"title":"InvokeSkillObservation"},"InvokeSkillTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"InvokeSkillTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"InvokeSkillTool","description":"Built-in tool for explicit invocation of progressive-disclosure skills."},"IterativeRefinementConfig":{"properties":{"success_threshold":{"type":"number","maximum":1.0,"minimum":0.0,"title":"Success Threshold","description":"Score threshold (0-1) to consider task successful.","default":0.6},"max_iterations":{"type":"integer","minimum":1.0,"title":"Max Iterations","description":"Maximum number of iterations before giving up.","default":3}},"type":"object","title":"IterativeRefinementConfig","description":"Configuration for iterative refinement based on critic feedback.\n\nWhen attached to a CriticBase, the Conversation.run() method will\nautomatically retry the task if the critic score is below the threshold.\n\nExample:\n critic = APIBasedCritic(\n server_url=\"...\",\n api_key=\"...\",\n model_name=\"critic\",\n iterative_refinement=IterativeRefinementConfig(\n success_threshold=0.7,\n max_iterations=3,\n ),\n )\n agent = Agent(llm=llm, tools=tools, critic=critic)\n conversation = Conversation(agent=agent, workspace=workspace)\n conversation.send_message(\"Create a calculator module...\")\n conversation.run() # Will automatically retry if critic score < 0.7"},"KeywordTrigger":{"properties":{"type":{"type":"string","const":"keyword","title":"Type","default":"keyword"},"keywords":{"items":{"type":"string"},"type":"array","title":"Keywords"}},"type":"object","required":["keywords"],"title":"KeywordTrigger","description":"Trigger for keyword-based skills.\n\nThese skills are activated when specific keywords appear in the user's query."},"LLM-Input":{"properties":{"model":{"type":"string","title":"Model","description":"Model name.","default":"gpt-5.5","openhands_settings":{"depends_on":[],"prominence":"critical"}},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"API key.","openhands_settings":{"depends_on":[],"label":"API Key","prominence":"critical"}},"auth_type":{"type":"string","enum":["api_key","subscription"],"title":"Auth Type","description":"Authentication mode for the LLM.","default":"api_key","openhands_settings":{"depends_on":[],"label":"Authentication","prominence":"critical"}},"subscription_vendor":{"anyOf":[{"type":"string","const":"openai"},{"type":"null"}],"title":"Subscription Vendor","description":"Subscription provider for subscription-backed LLM access.","openhands_settings":{"depends_on":["auth_type"],"label":"Subscription provider","prominence":"critical"}},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"Custom base URL.","openhands_settings":{"depends_on":[],"prominence":"major"}},"api_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Version","description":"API version (e.g., Azure)."},"aws_access_key_id":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Access Key Id"},"aws_secret_access_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Secret Access Key"},"aws_session_token":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Session Token"},"aws_region_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Region Name"},"aws_profile_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Profile Name"},"aws_role_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Role Name"},"aws_session_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Session Name"},"aws_bedrock_runtime_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Bedrock Runtime Endpoint"},"openrouter_site_url":{"type":"string","title":"Openrouter Site Url","default":"https://docs.all-hands.dev/"},"openrouter_app_name":{"type":"string","title":"Openrouter App Name","default":"OpenHands"},"num_retries":{"type":"integer","minimum":0.0,"title":"Num Retries","default":5},"retry_multiplier":{"type":"number","minimum":0.0,"title":"Retry Multiplier","default":8.0},"retry_min_wait":{"type":"integer","minimum":0.0,"title":"Retry Min Wait","default":8},"retry_max_wait":{"type":"integer","minimum":0.0,"title":"Retry Max Wait","default":64},"timeout":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"HTTP timeout in seconds. Default is 300s (5 minutes). Set to None to disable timeout (not recommended for production).","default":300},"max_message_chars":{"type":"integer","minimum":1.0,"title":"Max Message Chars","description":"Approx max chars in each event/content sent to the LLM.","default":30000},"temperature":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Temperature","description":"Sampling temperature for response generation. Defaults to None (uses provider default temperature). Set to 0.0 for deterministic outputs, or higher values (0.7-1.0) for more creative responses."},"top_p":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Top P","description":"Nucleus sampling parameter. Defaults to None (uses provider default). Set to a value between 0 and 1 to control diversity of outputs."},"top_k":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Top K"},"max_input_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Input Tokens","description":"The maximum number of input tokens. Note that this is currently unused, and the value at runtime is actually the total tokens in OpenAI (e.g. 128,000 tokens for GPT-4)."},"max_output_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Output Tokens","description":"The maximum number of output tokens. This is sent to the LLM."},"model_canonical_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Canonical Name","description":"Optional canonical model name for feature registry lookups. The OpenHands SDK maintains a model feature registry that maps model names to capabilities (e.g., vision support, prompt caching, responses API support). When using proxied or aliased model identifiers, set this field to the canonical model name (e.g., 'openai/gpt-4o') to ensure correct capability detection. If not provided, the 'model' field will be used for capability lookups."},"extra_headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Extra Headers","description":"Optional HTTP headers to forward to LiteLLM requests."},"input_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Input Cost Per Token","description":"The cost per input token. This will available in logs for user."},"output_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Output Cost Per Token","description":"The cost per output token. This will available in logs for user."},"ollama_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ollama Base Url"},"stream":{"type":"boolean","title":"Stream","description":"Enable streaming responses from the LLM. When enabled, the provided `on_token` callback in .completions and .responses will be invoked for each chunk of tokens.","default":false},"drop_params":{"type":"boolean","title":"Drop Params","default":true},"modify_params":{"type":"boolean","title":"Modify Params","description":"Modify params allows litellm to do transformations like adding a default message, when a message is empty.","default":true},"disable_vision":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Vision","description":"If model is vision capable, this option allows to disable image processing (useful for cost reduction)."},"disable_stop_word":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Stop Word","description":"Disable using of stop word.","default":false},"caching_prompt":{"type":"boolean","title":"Caching Prompt","description":"Enable caching of prompts.","default":true},"log_completions":{"type":"boolean","title":"Log Completions","description":"Enable logging of completions.","default":false},"log_completions_folder":{"type":"string","title":"Log Completions Folder","description":"The folder to log LLM completions to. Required if log_completions is True.","default":"logs/completions"},"custom_tokenizer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Tokenizer","description":"A custom tokenizer to use for token counting."},"native_tool_calling":{"type":"boolean","title":"Native Tool Calling","description":"Whether to use native tool calling.","default":true},"force_string_serializer":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force String Serializer","description":"Force using string content serializer when sending to LLM API. If None (default), auto-detect based on model. Useful for providers that do not support list content, like HuggingFace and Groq."},"inline_image_urls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Inline Image Urls","description":"If True, fetch any http(s) image URL in outgoing messages and inline it as a base64 ``data:`` URL before sending. If None (default), auto-detect based on model (some APIs such as Moonshot's public Kimi endpoint reject URL-formatted images and require base64). Set this explicitly when the model is reached through a proxy alias that hides the underlying provider (e.g. ``litellm_proxy/``). Note: inlining only runs when ``vision_is_active()`` is True, so the alias must still be recognised as vision-capable by litellm — otherwise images are not sent at all and there is nothing to inline."},"reasoning_effort":{"anyOf":[{"type":"string","enum":["low","medium","high","xhigh","none"]},{"type":"null"}],"title":"Reasoning Effort","description":"The effort to put into reasoning. This is a string that can be one of 'low', 'medium', 'high', 'xhigh', or 'none'. Can apply to all reasoning models.","default":"high"},"reasoning_summary":{"anyOf":[{"type":"string","enum":["auto","concise","detailed"]},{"type":"null"}],"title":"Reasoning Summary","description":"The level of detail for reasoning summaries. This is a string that can be one of 'auto', 'concise', or 'detailed'. Requires verified OpenAI organization. Only sent when explicitly set."},"enable_encrypted_reasoning":{"type":"boolean","title":"Enable Encrypted Reasoning","description":"If True, ask for ['reasoning.encrypted_content'] in Responses API include.","default":true},"prompt_cache_retention":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Cache Retention","description":"Retention policy for prompt cache. Only sent for supported models (GPT-5+ and GPT-4.1, excluding Azure deployments); explicitly stripped for all others.","default":"24h"},"extended_thinking_budget":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Extended Thinking Budget","description":"The budget tokens for extended thinking, supported by Anthropic models.","default":200000},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"The seed to use for random number generation."},"usage_id":{"type":"string","title":"Usage Id","description":"Unique usage identifier for the LLM. Used for registry lookups, telemetry, and spend tracking.","default":"default"},"litellm_extra_body":{"additionalProperties":true,"type":"object","title":"Litellm Extra Body","description":"Additional key-value pairs to pass to litellm's extra_body parameter. This is useful for custom inference endpoints that need additional parameters for configuration, routing, or advanced features. NOTE: Not all LLM providers support extra_body parameters. Some providers (e.g., OpenAI) may reject requests with unrecognized options. This is commonly supported by: - LiteLLM proxy servers (routing metadata, tracing) - vLLM endpoints (return_token_ids, etc.) - Custom inference clusters Examples: - Proxy routing: {'trace_version': '1.0.0', 'tags': ['agent:my-agent']} - vLLM features: {'return_token_ids': True}"},"fallback_strategy":{"anyOf":[{"$ref":"#/components/schemas/FallbackStrategy"},{"type":"null"}],"description":"Optional fallback strategy for trying alternate LLMs on transient failure. Construct with FallbackStrategy(fallback_llms=[...]).Excluded from serialization; must be reconfigured after load."}},"type":"object","title":"LLM","description":"Language model interface for OpenHands agents.\n\nThe LLM class provides a unified interface for interacting with various\nlanguage models through the litellm library. It handles model configuration,\nAPI authentication, retry logic, and tool calling capabilities.\n\nAttributes:\n model: Model name (e.g., \"gpt-5.5\").\n api_key: API key for authentication.\n base_url: Custom API base URL.\n num_retries: Number of retry attempts for failed requests.\n timeout: Request timeout in seconds.\n\nExample:\n ```python\n from openhands.sdk import LLM\n from pydantic import SecretStr\n\n llm = LLM(\n model=\"gpt-5.5\",\n api_key=SecretStr(\"your-api-key\"),\n usage_id=\"my-agent\"\n )\n # Use with agent or conversation\n ```"},"LLM-Output":{"properties":{"model":{"type":"string","title":"Model","description":"Model name.","default":"gpt-5.5","openhands_settings":{"depends_on":[],"prominence":"critical"}},"api_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Api Key","description":"API key.","openhands_settings":{"depends_on":[],"label":"API Key","prominence":"critical"}},"auth_type":{"type":"string","enum":["api_key","subscription"],"title":"Auth Type","description":"Authentication mode for the LLM.","default":"api_key","openhands_settings":{"depends_on":[],"label":"Authentication","prominence":"critical"}},"subscription_vendor":{"anyOf":[{"type":"string","const":"openai"},{"type":"null"}],"title":"Subscription Vendor","description":"Subscription provider for subscription-backed LLM access.","openhands_settings":{"depends_on":["auth_type"],"label":"Subscription provider","prominence":"critical"}},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url","description":"Custom base URL.","openhands_settings":{"depends_on":[],"prominence":"major"}},"api_version":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Version","description":"API version (e.g., Azure)."},"aws_access_key_id":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Access Key Id"},"aws_secret_access_key":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Secret Access Key"},"aws_session_token":{"anyOf":[{"type":"string"},{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Aws Session Token"},"aws_region_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Region Name"},"aws_profile_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Profile Name"},"aws_role_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Role Name"},"aws_session_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Session Name"},"aws_bedrock_runtime_endpoint":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Aws Bedrock Runtime Endpoint"},"openrouter_site_url":{"type":"string","title":"Openrouter Site Url","default":"https://docs.all-hands.dev/"},"openrouter_app_name":{"type":"string","title":"Openrouter App Name","default":"OpenHands"},"num_retries":{"type":"integer","minimum":0.0,"title":"Num Retries","default":5},"retry_multiplier":{"type":"number","minimum":0.0,"title":"Retry Multiplier","default":8.0},"retry_min_wait":{"type":"integer","minimum":0.0,"title":"Retry Min Wait","default":8},"retry_max_wait":{"type":"integer","minimum":0.0,"title":"Retry Max Wait","default":64},"timeout":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"HTTP timeout in seconds. Default is 300s (5 minutes). Set to None to disable timeout (not recommended for production).","default":300},"max_message_chars":{"type":"integer","minimum":1.0,"title":"Max Message Chars","description":"Approx max chars in each event/content sent to the LLM.","default":30000},"temperature":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Temperature","description":"Sampling temperature for response generation. Defaults to None (uses provider default temperature). Set to 0.0 for deterministic outputs, or higher values (0.7-1.0) for more creative responses."},"top_p":{"anyOf":[{"type":"number","maximum":1.0,"minimum":0.0},{"type":"null"}],"title":"Top P","description":"Nucleus sampling parameter. Defaults to None (uses provider default). Set to a value between 0 and 1 to control diversity of outputs."},"top_k":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Top K"},"max_input_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Input Tokens","description":"The maximum number of input tokens. Note that this is currently unused, and the value at runtime is actually the total tokens in OpenAI (e.g. 128,000 tokens for GPT-4)."},"max_output_tokens":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Max Output Tokens","description":"The maximum number of output tokens. This is sent to the LLM."},"model_canonical_name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model Canonical Name","description":"Optional canonical model name for feature registry lookups. The OpenHands SDK maintains a model feature registry that maps model names to capabilities (e.g., vision support, prompt caching, responses API support). When using proxied or aliased model identifiers, set this field to the canonical model name (e.g., 'openai/gpt-4o') to ensure correct capability detection. If not provided, the 'model' field will be used for capability lookups."},"extra_headers":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Extra Headers","description":"Optional HTTP headers to forward to LiteLLM requests."},"input_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Input Cost Per Token","description":"The cost per input token. This will available in logs for user."},"output_cost_per_token":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Output Cost Per Token","description":"The cost per output token. This will available in logs for user."},"ollama_base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ollama Base Url"},"stream":{"type":"boolean","title":"Stream","description":"Enable streaming responses from the LLM. When enabled, the provided `on_token` callback in .completions and .responses will be invoked for each chunk of tokens.","default":false},"drop_params":{"type":"boolean","title":"Drop Params","default":true},"modify_params":{"type":"boolean","title":"Modify Params","description":"Modify params allows litellm to do transformations like adding a default message, when a message is empty.","default":true},"disable_vision":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Vision","description":"If model is vision capable, this option allows to disable image processing (useful for cost reduction)."},"disable_stop_word":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Disable Stop Word","description":"Disable using of stop word.","default":false},"caching_prompt":{"type":"boolean","title":"Caching Prompt","description":"Enable caching of prompts.","default":true},"log_completions":{"type":"boolean","title":"Log Completions","description":"Enable logging of completions.","default":false},"log_completions_folder":{"type":"string","title":"Log Completions Folder","description":"The folder to log LLM completions to. Required if log_completions is True.","default":"logs/completions"},"custom_tokenizer":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Custom Tokenizer","description":"A custom tokenizer to use for token counting."},"native_tool_calling":{"type":"boolean","title":"Native Tool Calling","description":"Whether to use native tool calling.","default":true},"force_string_serializer":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Force String Serializer","description":"Force using string content serializer when sending to LLM API. If None (default), auto-detect based on model. Useful for providers that do not support list content, like HuggingFace and Groq."},"inline_image_urls":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Inline Image Urls","description":"If True, fetch any http(s) image URL in outgoing messages and inline it as a base64 ``data:`` URL before sending. If None (default), auto-detect based on model (some APIs such as Moonshot's public Kimi endpoint reject URL-formatted images and require base64). Set this explicitly when the model is reached through a proxy alias that hides the underlying provider (e.g. ``litellm_proxy/``). Note: inlining only runs when ``vision_is_active()`` is True, so the alias must still be recognised as vision-capable by litellm — otherwise images are not sent at all and there is nothing to inline."},"reasoning_effort":{"anyOf":[{"type":"string","enum":["low","medium","high","xhigh","none"]},{"type":"null"}],"title":"Reasoning Effort","description":"The effort to put into reasoning. This is a string that can be one of 'low', 'medium', 'high', 'xhigh', or 'none'. Can apply to all reasoning models.","default":"high"},"reasoning_summary":{"anyOf":[{"type":"string","enum":["auto","concise","detailed"]},{"type":"null"}],"title":"Reasoning Summary","description":"The level of detail for reasoning summaries. This is a string that can be one of 'auto', 'concise', or 'detailed'. Requires verified OpenAI organization. Only sent when explicitly set."},"enable_encrypted_reasoning":{"type":"boolean","title":"Enable Encrypted Reasoning","description":"If True, ask for ['reasoning.encrypted_content'] in Responses API include.","default":true},"prompt_cache_retention":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Prompt Cache Retention","description":"Retention policy for prompt cache. Only sent for supported models (GPT-5+ and GPT-4.1, excluding Azure deployments); explicitly stripped for all others.","default":"24h"},"extended_thinking_budget":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Extended Thinking Budget","description":"The budget tokens for extended thinking, supported by Anthropic models.","default":200000},"seed":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Seed","description":"The seed to use for random number generation."},"usage_id":{"type":"string","title":"Usage Id","description":"Unique usage identifier for the LLM. Used for registry lookups, telemetry, and spend tracking.","default":"default"},"litellm_extra_body":{"additionalProperties":true,"type":"object","title":"Litellm Extra Body","description":"Additional key-value pairs to pass to litellm's extra_body parameter. This is useful for custom inference endpoints that need additional parameters for configuration, routing, or advanced features. NOTE: Not all LLM providers support extra_body parameters. Some providers (e.g., OpenAI) may reject requests with unrecognized options. This is commonly supported by: - LiteLLM proxy servers (routing metadata, tracing) - vLLM endpoints (return_token_ids, etc.) - Custom inference clusters Examples: - Proxy routing: {'trace_version': '1.0.0', 'tags': ['agent:my-agent']} - vLLM features: {'return_token_ids': True}"}},"type":"object","title":"LLM","description":"Language model interface for OpenHands agents.\n\nThe LLM class provides a unified interface for interacting with various\nlanguage models through the litellm library. It handles model configuration,\nAPI authentication, retry logic, and tool calling capabilities.\n\nAttributes:\n model: Model name (e.g., \"gpt-5.5\").\n api_key: API key for authentication.\n base_url: Custom API base URL.\n num_retries: Number of retry attempts for failed requests.\n timeout: Request timeout in seconds.\n\nExample:\n ```python\n from openhands.sdk import LLM\n from pydantic import SecretStr\n\n llm = LLM(\n model=\"gpt-5.5\",\n api_key=SecretStr(\"your-api-key\"),\n usage_id=\"my-agent\"\n )\n # Use with agent or conversation\n ```"},"LLMCompletionLogEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"filename":{"type":"string","title":"Filename","description":"The intended filename for this log (relative to log directory)"},"log_data":{"type":"string","title":"Log Data","description":"The JSON-encoded log data to be written to the file"},"model_name":{"type":"string","title":"Model Name","description":"The model name for context","default":"unknown"},"usage_id":{"type":"string","title":"Usage Id","description":"The LLM usage_id that produced this log","default":"default"},"kind":{"type":"string","const":"LLMCompletionLogEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["filename","log_data","kind"],"title":"LLMCompletionLogEvent","description":"Event containing LLM completion log data.\n\nWhen an LLM is configured with log_completions=True in a remote conversation,\nthis event streams the completion log data back to the client through WebSocket\ninstead of writing it to a file inside the Docker container."},"LLMSecurityAnalyzer-Input":{"properties":{"kind":{"type":"string","const":"LLMSecurityAnalyzer","title":"Kind"}},"type":"object","title":"LLMSecurityAnalyzer","description":"LLM-based security analyzer.\n\nThis analyzer respects the security_risk attribute that can be set by the LLM\nwhen generating actions, similar to OpenHands' LLMRiskAnalyzer.\n\nIt provides a lightweight security analysis approach that leverages the LLM's\nunderstanding of action context and potential risks."},"LLMSecurityAnalyzer-Output":{"properties":{"kind":{"type":"string","const":"LLMSecurityAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"LLMSecurityAnalyzer","description":"LLM-based security analyzer.\n\nThis analyzer respects the security_risk attribute that can be set by the LLM\nwhen generating actions, similar to OpenHands' LLMRiskAnalyzer.\n\nIt provides a lightweight security analysis approach that leverages the LLM's\nunderstanding of action context and potential risks."},"LLMSummarizingCondenser-Input":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"},"max_size":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Size","default":240},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"keep_first":{"type":"integer","minimum":0.0,"title":"Keep First","default":2},"minimum_progress":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Minimum Progress","default":0.1},"hard_context_reset_max_retries":{"type":"integer","exclusiveMinimum":0.0,"title":"Hard Context Reset Max Retries","default":5},"hard_context_reset_context_scaling":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Hard Context Reset Context Scaling","default":0.8},"kind":{"type":"string","const":"LLMSummarizingCondenser","title":"Kind"}},"type":"object","required":["llm"],"title":"LLMSummarizingCondenser","description":"LLM-based condenser that summarizes forgotten events.\n\nUses an independent LLM (stored in the `llm` attribute) for generating summaries\nof forgotten events. The optional `agent_llm` parameter passed to condense() is\nthe LLM used by the agent for token counting purposes, and you should not assume\nit is the same as the one defined in this condenser."},"LLMSummarizingCondenser-Output":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Output"},"max_size":{"type":"integer","exclusiveMinimum":0.0,"title":"Max Size","default":240},"max_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Tokens"},"keep_first":{"type":"integer","minimum":0.0,"title":"Keep First","default":2},"minimum_progress":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Minimum Progress","default":0.1},"hard_context_reset_max_retries":{"type":"integer","exclusiveMinimum":0.0,"title":"Hard Context Reset Max Retries","default":5},"hard_context_reset_context_scaling":{"type":"number","exclusiveMaximum":1.0,"exclusiveMinimum":0.0,"title":"Hard Context Reset Context Scaling","default":0.8},"kind":{"type":"string","const":"LLMSummarizingCondenser","title":"Kind"}},"type":"object","required":["llm","kind"],"title":"LLMSummarizingCondenser","description":"LLM-based condenser that summarizes forgotten events.\n\nUses an independent LLM (stored in the `llm` attribute) for generating summaries\nof forgotten events. The optional `agent_llm` parameter passed to condense() is\nthe LLM used by the agent for token counting purposes, and you should not assume\nit is the same as the one defined in this condenser."},"LaunchedAgentProfile":{"properties":{"agent_profile_id":{"type":"string","format":"uuid","title":"Agent Profile Id","description":"Stable id of the agent profile that launched the conversation."},"revision":{"type":"integer","minimum":0.0,"title":"Revision","description":"Revision of the agent profile at launch time."}},"type":"object","required":["agent_profile_id","revision"],"title":"LaunchedAgentProfile","description":"Provenance snapshot recorded when an agent profile launches a conversation.\n\nStored on ``StoredConversation`` and projected onto ``ConversationInfo`` so\nts-client ``deriveSwitchPlan`` can identify which agent profile is current\nwithout fragile settings-comparison. See #3720."},"ListDirectoryAction":{"properties":{"dir_path":{"type":"string","title":"Dir Path","description":"The path to the directory to list. Defaults to current directory.","default":"."},"recursive":{"type":"boolean","title":"Recursive","description":"Whether to list subdirectories recursively (up to 2 levels).","default":false},"kind":{"type":"string","const":"ListDirectoryAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ListDirectoryAction","description":"Schema for list directory operation."},"ListDirectoryActionWithRisk":{"properties":{"dir_path":{"type":"string","title":"Dir Path","description":"The path to the directory to list. Defaults to current directory.","default":"."},"recursive":{"type":"boolean","title":"Recursive","description":"Whether to list subdirectories recursively (up to 2 levels).","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"ListDirectoryActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ListDirectoryActionWithRisk"},"ListDirectoryObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"dir_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Dir Path","description":"The directory path that was listed."},"entries":{"items":{"$ref":"#/components/schemas/FileEntry"},"type":"array","title":"Entries","description":"List of files and directories found."},"total_count":{"type":"integer","title":"Total Count","description":"Total number of entries found.","default":0},"is_truncated":{"type":"boolean","title":"Is Truncated","description":"Whether the listing was truncated due to too many entries.","default":false},"kind":{"type":"string","const":"ListDirectoryObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ListDirectoryObservation","description":"Observation from listing a directory."},"ListDirectoryTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"ListDirectoryTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"ListDirectoryTool","description":"Tool for listing directory contents with metadata."},"LocalWorkspace-Input":{"properties":{"working_dir":{"type":"string","title":"Working Dir","description":"The working directory for agent operations and tool execution. Accepts both string paths and Path objects. Path objects are automatically converted to strings."},"kind":{"type":"string","const":"LocalWorkspace","title":"Kind"}},"type":"object","required":["working_dir"],"title":"LocalWorkspace","description":"Local workspace implementation that operates on the host filesystem.\n\nLocalWorkspace provides direct access to the local filesystem and command execution\nenvironment. It's suitable for development and testing scenarios where the agent\nshould operate directly on the host system.\n\nExample:\n >>> workspace = LocalWorkspace(working_dir=\"/path/to/project\")\n >>> with workspace:\n ... result = workspace.execute_command(\"ls -la\")\n ... content = workspace.read_file(\"README.md\")"},"LocalWorkspace-Output":{"properties":{"working_dir":{"type":"string","title":"Working Dir","description":"The working directory for agent operations and tool execution. Accepts both string paths and Path objects. Path objects are automatically converted to strings."},"kind":{"type":"string","const":"LocalWorkspace","title":"Kind"}},"type":"object","required":["working_dir","kind"],"title":"LocalWorkspace","description":"Local workspace implementation that operates on the host filesystem.\n\nLocalWorkspace provides direct access to the local filesystem and command execution\nenvironment. It's suitable for development and testing scenarios where the agent\nshould operate directly on the host system.\n\nExample:\n >>> workspace = LocalWorkspace(working_dir=\"/path/to/project\")\n >>> with workspace:\n ... result = workspace.execute_command(\"ls -la\")\n ... content = workspace.read_file(\"README.md\")"},"LookupSecret-Input":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"url":{"type":"string","title":"Url"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"kind":{"type":"string","const":"LookupSecret","title":"Kind"}},"type":"object","required":["url"],"title":"LookupSecret","description":"A secret looked up from some external url"},"LookupSecret-Output":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"url":{"type":"string","title":"Url"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"kind":{"type":"string","const":"LookupSecret","title":"Kind"}},"type":"object","required":["url","kind"],"title":"LookupSecret","description":"A secret looked up from some external url"},"MCPTestFailure":{"properties":{"ok":{"type":"boolean","const":false,"title":"Ok","default":false},"error":{"type":"string","title":"Error","description":"Human-readable error message."},"error_kind":{"type":"string","enum":["timeout","connection","unknown"],"title":"Error Kind","description":"Coarse error classification, useful for branching UI."}},"type":"object","required":["error","error_kind"],"title":"MCPTestFailure","description":"Response when the candidate server fails to connect or list tools.\n\nThe endpoint returns HTTP 200 in both success and failure cases: a\nfailure here is the *expected* outcome of validating a user-supplied\nconfig, not a server-side error. The structured shape makes it easy\nfor the UI to render an actionable message."},"MCPTestRequest":{"properties":{"name":{"type":"string","maxLength":128,"minLength":1,"title":"Name","description":"Name to use for the server inside the temporary MCPConfig. Only affects error messages -- does not need to match any persisted setting.","default":"test-server"},"server":{"oneOf":[{"$ref":"#/components/schemas/_StdioMCPServerSpec"},{"$ref":"#/components/schemas/_RemoteMCPServerSpec"}],"title":"Server","discriminator":{"propertyName":"type","mapping":{"http":"#/components/schemas/_RemoteMCPServerSpec","shttp":"#/components/schemas/_RemoteMCPServerSpec","sse":"#/components/schemas/_RemoteMCPServerSpec","stdio":"#/components/schemas/_StdioMCPServerSpec","streamable-http":"#/components/schemas/_RemoteMCPServerSpec"}}},"timeout":{"type":"number","maximum":120.0,"exclusiveMinimum":0.0,"title":"Timeout","description":"Seconds to wait for connection + tools/list to complete.","default":15.0},"tool_call":{"anyOf":[{"$ref":"#/components/schemas/MCPToolCallSpec"},{"type":"null"}],"description":"Optional read-only tool to invoke after listing succeeds, so callers can verify credentials the server only exercises on tool invocation. Its outcome is reported verbatim in `tool_result` without affecting `ok`."}},"type":"object","required":["server"],"title":"MCPTestRequest","description":"Body for ``POST /api/mcp/test``."},"MCPTestSuccess":{"properties":{"ok":{"type":"boolean","const":true,"title":"Ok","default":true},"tools":{"items":{"type":"string"},"type":"array","title":"Tools","description":"Names of tools advertised by the MCP server."},"tool_result":{"anyOf":[{"$ref":"#/components/schemas/MCPToolCallResult"},{"type":"null"}],"description":"Outcome of the requested `tool_call`, when one was supplied."}},"type":"object","title":"MCPTestSuccess","description":"Response when the candidate server connects and lists its tools."},"MCPToolAction":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data","description":"Dynamic data fields from the tool call"},"kind":{"type":"string","const":"MCPToolAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"MCPToolAction","description":"Schema for MCP input action.\n\nIt is just a thin wrapper around raw JSON and does\nnot do any validation.\n\nValidation will be performed by MCPTool.__call__\nby constructing dynamically created Pydantic model\nfrom the MCP tool input schema."},"MCPToolActionWithRisk":{"properties":{"data":{"additionalProperties":true,"type":"object","title":"Data","description":"Dynamic data fields from the tool call"},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"MCPToolActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"MCPToolActionWithRisk"},"MCPToolCallResult":{"properties":{"is_error":{"type":"boolean","title":"Is Error","description":"The MCP-level isError flag of the result."},"text":{"type":"string","title":"Text","description":"Concatenated text content of the result."}},"type":"object","required":["is_error","text"],"title":"MCPToolCallResult","description":"Verbatim outcome of the requested ``tool_call``.\n\nThe endpoint stays provider-neutral: many servers report upstream\nfailures (e.g. Slack's ``{\"ok\": false, \"error\": \"invalid_auth\"}``)\nas ordinary text content with ``isError`` unset, so interpreting the\npayload is the caller's job."},"MCPToolCallSpec":{"properties":{"name":{"type":"string","minLength":1,"title":"Name","description":"Name of the tool to invoke"},"arguments":{"additionalProperties":true,"type":"object","title":"Arguments","description":"Arguments passed to the tool unchanged."}},"type":"object","required":["name"],"title":"MCPToolCallSpec","description":"A single tool invocation to run as part of the connection test.\n\nListing tools does not exercise the credentials many servers only use\ninside tool handlers, so callers can name one tool to invoke after the\nlisting succeeds. Callers are responsible for choosing a read-only tool;\nthe endpoint executes it verbatim."},"MCPToolDefinition":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"mcp_tool":{"$ref":"#/components/schemas/mcp__types__Tool","description":"The MCP tool definition."},"kind":{"type":"string","const":"MCPToolDefinition","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","mcp_tool","kind","title"],"title":"MCPToolDefinition","description":"MCP Tool that wraps an MCP client and provides tool functionality."},"MCPToolObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"tool_name":{"type":"string","title":"Tool Name","description":"Name of the tool that was called"},"kind":{"type":"string","const":"MCPToolObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","kind"],"title":"MCPToolObservation","description":"Observation from MCP tool execution."},"MarketplaceCatalogResponse":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/MarketplaceSkillInfo"},"type":"array","title":"Skills"}},"type":"object","required":["skills"],"title":"MarketplaceCatalogResponse","description":"Response containing the marketplace catalog."},"MarketplaceSkillInfo":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"source":{"type":"string","title":"Source"},"installed":{"type":"boolean","title":"Installed"}},"type":"object","required":["name","description","source","installed"],"title":"MarketplaceSkillInfo","description":"Information about a skill in the marketplace catalog."},"Message":{"properties":{"role":{"type":"string","enum":["user","system","assistant","tool"],"title":"Role"},"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content"},"tool_calls":{"anyOf":[{"items":{"$ref":"#/components/schemas/MessageToolCall"},"type":"array"},{"type":"null"}],"title":"Tool Calls"},"tool_call_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Tool Call Id"},"name":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Name"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content","description":"Intermediate reasoning/thinking content from reasoning models"},"thinking_blocks":{"items":{"anyOf":[{"$ref":"#/components/schemas/ThinkingBlock"},{"$ref":"#/components/schemas/RedactedThinkingBlock"}]},"type":"array","title":"Thinking Blocks","description":"Raw Anthropic thinking blocks for extended thinking feature"},"responses_reasoning_item":{"anyOf":[{"$ref":"#/components/schemas/ReasoningItemModel"},{"type":"null"}],"description":"OpenAI Responses reasoning item from model output"}},"type":"object","required":["role"],"title":"Message"},"MessageEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source"},"llm_message":{"$ref":"#/components/schemas/Message","description":"The exact LLM message for this message event"},"llm_response_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Llm Response Id","description":"Completion or Response ID of the LLM response that generated this eventIf the source != 'agent', this field is None"},"activated_skills":{"items":{"type":"string"},"type":"array","title":"Activated Skills","description":"List of activated skill name"},"extended_content":{"items":{"$ref":"#/components/schemas/TextContent"},"type":"array","title":"Extended Content","description":"List of content added by agent context"},"sender":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Sender","description":"Optional identifier of the sender. Can be used to track message origin in multi-agent scenarios."},"critic_result":{"anyOf":[{"$ref":"#/components/schemas/CriticResult"},{"type":"null"}],"description":"Optional critic evaluation of this message and preceding history."},"kind":{"type":"string","const":"MessageEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","llm_message","kind"],"title":"MessageEvent","description":"Message from either agent or user.\n\nThis is originally the \"MessageAction\", but it suppose not to be tool call."},"MessageToolCall":{"properties":{"id":{"type":"string","title":"Id","description":"Canonical tool call id"},"responses_item_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Responses Item Id","description":"Original Responses function_call.id, echoed verbatim on replay"},"name":{"type":"string","title":"Name","description":"Tool/function name"},"arguments":{"type":"string","title":"Arguments","description":"JSON string of arguments"},"origin":{"type":"string","enum":["completion","responses"],"title":"Origin","description":"Originating API family"}},"type":"object","required":["id","name","arguments","origin"],"title":"MessageToolCall","description":"Transport-agnostic tool call representation.\n\nOne canonical id is used for linking across actions/observations and\nfor Responses function_call_output call_id."},"Metrics":{"properties":{"model_name":{"type":"string","title":"Model Name","description":"Name of the model","default":"default"},"accumulated_cost":{"type":"number","minimum":0.0,"title":"Accumulated Cost","description":"Total accumulated cost, must be non-negative","default":0.0},"max_budget_per_task":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Budget Per Task","description":"Maximum budget per task"},"accumulated_token_usage":{"anyOf":[{"$ref":"#/components/schemas/TokenUsage"},{"type":"null"}],"description":"Accumulated token usage across all calls"},"costs":{"items":{"$ref":"#/components/schemas/Cost"},"type":"array","title":"Costs","description":"List of individual costs"},"response_latencies":{"items":{"$ref":"#/components/schemas/ResponseLatency"},"type":"array","title":"Response Latencies","description":"List of response latencies"},"token_usages":{"items":{"$ref":"#/components/schemas/TokenUsage"},"type":"array","title":"Token Usages","description":"List of token usage records"}},"type":"object","title":"Metrics","description":"Metrics class can record various metrics during running and evaluation.\nWe track:\n - accumulated_cost and costs\n - max_budget_per_task (budget limit)\n - A list of ResponseLatency\n - A list of TokenUsage (one per call)."},"MetricsSnapshot":{"properties":{"model_name":{"type":"string","title":"Model Name","description":"Name of the model","default":"default"},"accumulated_cost":{"type":"number","minimum":0.0,"title":"Accumulated Cost","description":"Total accumulated cost, must be non-negative","default":0.0},"max_budget_per_task":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Budget Per Task","description":"Maximum budget per task"},"accumulated_token_usage":{"anyOf":[{"$ref":"#/components/schemas/TokenUsage"},{"type":"null"}],"description":"Accumulated token usage across all calls"}},"type":"object","title":"MetricsSnapshot","description":"A snapshot of metrics at a point in time.\n\nDoes not include lists of individual costs, latencies, or token usages."},"Model":{"properties":{"id":{"type":"string","title":"Id"},"created":{"type":"integer","title":"Created"},"object":{"type":"string","const":"model","title":"Object"},"owned_by":{"type":"string","title":"Owned By"}},"additionalProperties":true,"type":"object","required":["id","created","object","owned_by"],"title":"Model","description":"Describes an OpenAI model offering that can be used with the API."},"ModelsResponse":{"properties":{"models":{"items":{"type":"string"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"ModelsResponse","description":"Response containing the list of available LLM models."},"NeverConfirm-Input":{"properties":{"kind":{"type":"string","const":"NeverConfirm","title":"Kind"}},"type":"object","title":"NeverConfirm"},"NeverConfirm-Output":{"properties":{"kind":{"type":"string","const":"NeverConfirm","title":"Kind"}},"type":"object","required":["kind"],"title":"NeverConfirm"},"NoOpCondenser-Input":{"properties":{"kind":{"type":"string","const":"NoOpCondenser","title":"Kind"}},"type":"object","title":"NoOpCondenser","description":"Simple condenser that returns a view un-manipulated.\n\nPrimarily intended for testing purposes."},"NoOpCondenser-Output":{"properties":{"kind":{"type":"string","const":"NoOpCondenser","title":"Kind"}},"type":"object","required":["kind"],"title":"NoOpCondenser","description":"Simple condenser that returns a view un-manipulated.\n\nPrimarily intended for testing purposes."},"Observation":{"oneOf":[{"$ref":"#/components/schemas/MCPToolObservation"},{"$ref":"#/components/schemas/FinishObservation"},{"$ref":"#/components/schemas/InvokeSkillObservation"},{"$ref":"#/components/schemas/SwitchLLMObservation"},{"$ref":"#/components/schemas/ThinkObservation"},{"$ref":"#/components/schemas/ClientToolObservation"},{"$ref":"#/components/schemas/BrowserObservation"},{"$ref":"#/components/schemas/DelegateObservation"},{"$ref":"#/components/schemas/FileEditorObservation"},{"$ref":"#/components/schemas/EditObservation"},{"$ref":"#/components/schemas/ListDirectoryObservation"},{"$ref":"#/components/schemas/ReadFileObservation"},{"$ref":"#/components/schemas/WriteFileObservation"},{"$ref":"#/components/schemas/GlobObservation"},{"$ref":"#/components/schemas/GrepObservation"},{"$ref":"#/components/schemas/PlanningFileEditorObservation"},{"$ref":"#/components/schemas/TaskObservation"},{"$ref":"#/components/schemas/TaskTrackerObservation"},{"$ref":"#/components/schemas/TerminalObservation"},{"$ref":"#/components/schemas/WorkflowObservation"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__mcp__definition__MCPToolObservation-Output__1":"#/components/schemas/MCPToolObservation","openhands__sdk__tool__builtins__finish__FinishObservation-Output__1":"#/components/schemas/FinishObservation","openhands__sdk__tool__builtins__invoke_skill__InvokeSkillObservation-Output__1":"#/components/schemas/InvokeSkillObservation","openhands__sdk__tool__builtins__switch_llm__SwitchLLMObservation-Output__1":"#/components/schemas/SwitchLLMObservation","openhands__sdk__tool__builtins__think__ThinkObservation-Output__1":"#/components/schemas/ThinkObservation","openhands__sdk__tool__client_tool__ClientToolObservation-Output__1":"#/components/schemas/ClientToolObservation","openhands__tools__browser_use__definition__BrowserObservation-Output__1":"#/components/schemas/BrowserObservation","openhands__tools__delegate__definition__DelegateObservation-Output__1":"#/components/schemas/DelegateObservation","openhands__tools__file_editor__definition__FileEditorObservation-Output__1":"#/components/schemas/FileEditorObservation","openhands__tools__gemini__edit__definition__EditObservation-Output__1":"#/components/schemas/EditObservation","openhands__tools__gemini__list_directory__definition__ListDirectoryObservation-Output__1":"#/components/schemas/ListDirectoryObservation","openhands__tools__gemini__read_file__definition__ReadFileObservation-Output__1":"#/components/schemas/ReadFileObservation","openhands__tools__gemini__write_file__definition__WriteFileObservation-Output__1":"#/components/schemas/WriteFileObservation","openhands__tools__glob__definition__GlobObservation-Output__1":"#/components/schemas/GlobObservation","openhands__tools__grep__definition__GrepObservation-Output__1":"#/components/schemas/GrepObservation","openhands__tools__planning_file_editor__definition__PlanningFileEditorObservation-Output__1":"#/components/schemas/PlanningFileEditorObservation","openhands__tools__task__definition__TaskObservation-Output__1":"#/components/schemas/TaskObservation","openhands__tools__task_tracker__definition__TaskTrackerObservation-Output__1":"#/components/schemas/TaskTrackerObservation","openhands__tools__terminal__definition__TerminalObservation-Output__1":"#/components/schemas/TerminalObservation","openhands__tools__workflow__definition__WorkflowObservation-Output__1":"#/components/schemas/WorkflowObservation"}}},"ObservationEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"tool_name":{"type":"string","title":"Tool Name","description":"The tool name that this observation is responding to"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The tool call id that this observation is responding to"},"observation":{"$ref":"#/components/schemas/Observation","description":"The observation (tool call) sent to LLM"},"action_id":{"type":"string","title":"Action Id","description":"The action id that this observation is responding to"},"kind":{"type":"string","const":"ObservationEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","tool_call_id","observation","action_id","kind"],"title":"ObservationEvent"},"OpenAIChatCompletionRequest":{"properties":{"model":{"type":"string","title":"Model"},"messages":{"items":{"$ref":"#/components/schemas/OpenAIChatMessage"},"type":"array","title":"Messages"},"stream":{"type":"boolean","title":"Stream","default":false},"stream_options":{"anyOf":[{"$ref":"#/components/schemas/OpenAIStreamOptions"},{"type":"null"}]}},"type":"object","required":["model","messages"],"title":"OpenAIChatCompletionRequest"},"OpenAIChatMessage":{"properties":{"role":{"type":"string","enum":["system","developer","user","assistant","tool"],"title":"Role"},"content":{"anyOf":[{"type":"string"},{"items":{"$ref":"#/components/schemas/OpenAIContentPart"},"type":"array"},{"type":"null"}],"title":"Content"}},"type":"object","required":["role"],"title":"OpenAIChatMessage"},"OpenAIContentPart":{"properties":{"type":{"type":"string","title":"Type"},"text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Text"},"image_url":{"anyOf":[{"$ref":"#/components/schemas/OpenAIImageURL"},{"type":"string"},{"type":"null"}],"title":"Image Url"}},"type":"object","required":["type"],"title":"OpenAIContentPart"},"OpenAIImageURL":{"properties":{"url":{"type":"string","title":"Url"}},"type":"object","required":["url"],"title":"OpenAIImageURL"},"OpenAIModelListResponse":{"properties":{"object":{"type":"string","const":"list","title":"Object","default":"list"},"data":{"items":{"$ref":"#/components/schemas/Model"},"type":"array","title":"Data"}},"type":"object","required":["data"],"title":"OpenAIModelListResponse"},"OpenAIStreamOptions":{"properties":{"include_usage":{"type":"boolean","title":"Include Usage","default":false}},"type":"object","title":"OpenAIStreamOptions"},"OrgConfig":{"properties":{"repository":{"type":"string","title":"Repository","description":"Selected repository (e.g., 'owner/repo')"},"provider":{"type":"string","title":"Provider","description":"Git provider type: github, gitlab, azure, bitbucket"},"org_repo_url":{"type":"string","title":"Org Repo Url","description":"Pre-authenticated Git URL for the organization repository. Contains sensitive credentials - handle with care and avoid logging."},"org_name":{"type":"string","title":"Org Name","description":"Organization name"}},"type":"object","required":["repository","provider","org_repo_url","org_name"],"title":"OrgConfig","description":"Configuration for loading organization-level skills."},"PassCritic-Input":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"PassCritic","title":"Kind"}},"type":"object","title":"PassCritic","description":"Critic that always returns success.\n\nThis critic can be used when no evaluation is needed or when\nall instances should be considered successful regardless of their output."},"PassCritic-Output":{"properties":{"mode":{"type":"string","enum":["finish_and_message","all_actions"],"title":"Mode","description":"When to run critic evaluation:\n- 'finish_and_message': Evaluate on FinishAction and agent MessageEvent (default, minimal performance impact)\n- 'all_actions': Evaluate after every agent action (WARNING: significantly slower due to API calls on each action)","default":"finish_and_message"},"iterative_refinement":{"anyOf":[{"$ref":"#/components/schemas/IterativeRefinementConfig"},{"type":"null"}],"description":"Optional configuration for iterative refinement. When set, Conversation.run() will automatically retry the task if the critic score is below the success_threshold, up to max_iterations."},"kind":{"type":"string","const":"PassCritic","title":"Kind"}},"type":"object","required":["kind"],"title":"PassCritic","description":"Critic that always returns success.\n\nThis critic can be used when no evaluation is needed or when\nall instances should be considered successful regardless of their output."},"PatternSecurityAnalyzer-Input":{"properties":{"high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"High Patterns","description":"HIGH patterns scanned against executable fields only"},"medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Medium Patterns","description":"MEDIUM patterns scanned against executable fields only"},"injection_high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection High Patterns","description":"HIGH patterns scanned against all fields"},"injection_medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection Medium Patterns","description":"MEDIUM patterns scanned against all fields"},"kind":{"type":"string","const":"PatternSecurityAnalyzer","title":"Kind"}},"type":"object","title":"PatternSecurityAnalyzer","description":"Catch dangerous agent actions through deterministic signature scanning.\n\nUse this when you want fast, local, no-network threat detection at the\naction boundary. It returns ``SecurityRisk.HIGH``, ``MEDIUM``, or ``LOW``\n-- pair it with ``ConfirmRisky`` to decide what gets confirmed.\n\nThe key design choice: shell-destructive patterns only scan what the\nagent will *execute* (tool arguments), never what it *thought about*\n(reasoning text). Injection patterns scan everything, because\n\"ignore all previous instructions\" is dangerous wherever it appears.\n\nNormalization is always on -- invisible characters and fullwidth\nsubstitutions are collapsed before matching.\n\nExample::\n\n from openhands.sdk.security import PatternSecurityAnalyzer, ConfirmRisky\n\n analyzer = PatternSecurityAnalyzer()\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"PatternSecurityAnalyzer-Output":{"properties":{"high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"High Patterns","description":"HIGH patterns scanned against executable fields only"},"medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Medium Patterns","description":"MEDIUM patterns scanned against executable fields only"},"injection_high_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection High Patterns","description":"HIGH patterns scanned against all fields"},"injection_medium_patterns":{"items":{"prefixItems":[{"type":"string"},{"type":"string"},{"type":"string"}],"type":"array","maxItems":3,"minItems":3},"type":"array","title":"Injection Medium Patterns","description":"MEDIUM patterns scanned against all fields"},"kind":{"type":"string","const":"PatternSecurityAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"PatternSecurityAnalyzer","description":"Catch dangerous agent actions through deterministic signature scanning.\n\nUse this when you want fast, local, no-network threat detection at the\naction boundary. It returns ``SecurityRisk.HIGH``, ``MEDIUM``, or ``LOW``\n-- pair it with ``ConfirmRisky`` to decide what gets confirmed.\n\nThe key design choice: shell-destructive patterns only scan what the\nagent will *execute* (tool arguments), never what it *thought about*\n(reasoning text). Injection patterns scan everything, because\n\"ignore all previous instructions\" is dangerous wherever it appears.\n\nNormalization is always on -- invisible characters and fullwidth\nsubstitutions are collapsed before matching.\n\nExample::\n\n from openhands.sdk.security import PatternSecurityAnalyzer, ConfirmRisky\n\n analyzer = PatternSecurityAnalyzer()\n policy = ConfirmRisky(threshold=SecurityRisk.MEDIUM)"},"PauseEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"user"},"kind":{"type":"string","const":"PauseEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"PauseEvent","description":"Event indicating that the agent execution was paused by user request."},"PipelineCondenser-Input":{"properties":{"condensers":{"items":{"$ref":"#/components/schemas/CondenserBase-Input"},"type":"array","title":"Condensers"},"kind":{"type":"string","const":"PipelineCondenser","title":"Kind"}},"type":"object","required":["condensers"],"title":"PipelineCondenser","description":"A condenser that applies a sequence of condensers in order.\n\nAll condensers are defined primarily by their `condense` method, which takes a\n`View` and an optional `agent_llm` parameter, returning either a new `View` or a\n`Condensation` event. That means we can chain multiple condensers together by\npassing `View`s along and exiting early if any condenser returns a `Condensation`.\n\nFor example:\n\n # Use the pipeline condenser to chain multiple other condensers together\n condenser = PipelineCondenser(condensers=[\n CondenserA(...),\n CondenserB(...),\n CondenserC(...),\n ])\n\n result = condenser.condense(view, agent_llm=agent_llm)\n\n # Doing the same thing without the pipeline condenser requires more boilerplate\n # for the monadic chaining\n other_result = view\n\n if isinstance(other_result, View):\n other_result = CondenserA(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserB(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserC(...).condense(other_result, agent_llm=agent_llm)\n\n assert result == other_result"},"PipelineCondenser-Output":{"properties":{"condensers":{"items":{"$ref":"#/components/schemas/CondenserBase-Output"},"type":"array","title":"Condensers"},"kind":{"type":"string","const":"PipelineCondenser","title":"Kind"}},"type":"object","required":["condensers","kind"],"title":"PipelineCondenser","description":"A condenser that applies a sequence of condensers in order.\n\nAll condensers are defined primarily by their `condense` method, which takes a\n`View` and an optional `agent_llm` parameter, returning either a new `View` or a\n`Condensation` event. That means we can chain multiple condensers together by\npassing `View`s along and exiting early if any condenser returns a `Condensation`.\n\nFor example:\n\n # Use the pipeline condenser to chain multiple other condensers together\n condenser = PipelineCondenser(condensers=[\n CondenserA(...),\n CondenserB(...),\n CondenserC(...),\n ])\n\n result = condenser.condense(view, agent_llm=agent_llm)\n\n # Doing the same thing without the pipeline condenser requires more boilerplate\n # for the monadic chaining\n other_result = view\n\n if isinstance(other_result, View):\n other_result = CondenserA(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserB(...).condense(other_result, agent_llm=agent_llm)\n\n if isinstance(other_result, View):\n other_result = CondenserC(...).condense(other_result, agent_llm=agent_llm)\n\n assert result == other_result"},"PlanningFileEditorAction":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"kind":{"type":"string","const":"PlanningFileEditorAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"PlanningFileEditorAction","description":"Schema for planning file editor operations.\n\nInherits from FileEditorAction but restricts editing to PLAN.md only.\nAllows viewing any file but only editing PLAN.md."},"PlanningFileEditorActionWithRisk":{"properties":{"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The commands to run. Allowed options are: `view`, `create`, `str_replace`, `insert`, `undo_edit`."},"path":{"type":"string","title":"Path","description":"Absolute path to file or directory."},"file_text":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Text","description":"Required parameter of `create` command, with the content of the file to be created."},"old_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Str","description":"Required parameter of `str_replace` command containing the string in `path` to replace."},"new_str":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Str","description":"Optional parameter of `str_replace` command containing the new string (if not given, no string will be added). Required parameter of `insert` command containing the string to insert."},"insert_line":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Insert Line","description":"Required parameter of `insert` command. The `new_str` will be inserted AFTER the line `insert_line` of `path`."},"view_range":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"View Range","description":"Optional parameter of `view` command when `path` points to a file. If none is given, the full file is shown. If provided, the file will be shown in the indicated line number range, e.g. [11, 12] will show lines 11 and 12. Indexing at 1 to start. Setting `[start_line, -1]` shows all lines from `start_line` to the end of the file."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"PlanningFileEditorActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","path","kind"],"title":"PlanningFileEditorActionWithRisk"},"PlanningFileEditorObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["view","create","str_replace","insert","undo_edit"],"title":"Command","description":"The command that was run: `view`, `create`, `str_replace`, `insert`, or `undo_edit`."},"path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Path","description":"The file path that was edited."},"prev_exist":{"type":"boolean","title":"Prev Exist","description":"Indicates if the file previously existed. If not, it was created.","default":true},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The content of the file before the edit."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The content of the file after the edit."},"kind":{"type":"string","const":"PlanningFileEditorObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"PlanningFileEditorObservation","description":"Observation from planning file editor operations.\n\nInherits from FileEditorObservation - same structure, just different type."},"PlanningFileEditorTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"PlanningFileEditorTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"PlanningFileEditorTool","description":"A planning file editor tool with read-all, edit-PLAN.md-only access."},"PluginSource":{"properties":{"source":{"type":"string","title":"Source","description":"Plugin source: 'github:owner/repo', any git URL, or local path"},"ref":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Ref","description":"Optional branch, tag, or commit (only for git sources)"},"repo_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Repo Path","description":"Subdirectory path within the git repository (e.g., 'plugins/my-plugin' for monorepos). Only relevant for git sources, not local paths."}},"type":"object","required":["source"],"title":"PluginSource","description":"Specification for a plugin to load.\n\nThis model describes where to find a plugin and is used by load_plugins()\nto fetch and load plugins from various sources.\n\nExamples:\n >>> # GitHub repository\n >>> PluginSource(source=\"github:owner/repo\", ref=\"v1.0.0\")\n\n >>> # Plugin from monorepo subdirectory\n >>> PluginSource(\n ... source=\"github:owner/monorepo\",\n ... repo_path=\"plugins/my-plugin\"\n ... )\n\n >>> # Local path\n >>> PluginSource(source=\"/path/to/plugin\")"},"PolicyRailSecurityAnalyzer-Input":{"properties":{"kind":{"type":"string","const":"PolicyRailSecurityAnalyzer","title":"Kind"}},"type":"object","title":"PolicyRailSecurityAnalyzer","description":"Catch composed threats that plain regex signatures would miss.\n\nUse this when you need to detect threats defined by *combinations*\nof tokens (e.g., ``curl`` piped to ``bash``) rather than individual\nsignatures. While these rails *could* each be expressed as a single\nregex, keeping them as named rules with per-segment evaluation makes\nthe threat model more interpretable, the rules easier to maintain,\nand the audit trail clearer than a flat pattern list.\n\nEvaluates normalized executable segments only -- reasoning text is\nnever scanned.\n\nReturns ``SecurityRisk.HIGH`` when a rail fires, ``LOW`` otherwise.\nPair with ``ConfirmRisky`` and compose via ``EnsembleSecurityAnalyzer``.\n\nv1 rails: fetch-to-exec, raw-disk-op, catastrophic-delete.\n\nExample::\n\n from openhands.sdk.security import PolicyRailSecurityAnalyzer\n\n analyzer = PolicyRailSecurityAnalyzer()\n # risk = analyzer.security_risk(action)"},"PolicyRailSecurityAnalyzer-Output":{"properties":{"kind":{"type":"string","const":"PolicyRailSecurityAnalyzer","title":"Kind"}},"type":"object","required":["kind"],"title":"PolicyRailSecurityAnalyzer","description":"Catch composed threats that plain regex signatures would miss.\n\nUse this when you need to detect threats defined by *combinations*\nof tokens (e.g., ``curl`` piped to ``bash``) rather than individual\nsignatures. While these rails *could* each be expressed as a single\nregex, keeping them as named rules with per-segment evaluation makes\nthe threat model more interpretable, the rules easier to maintain,\nand the audit trail clearer than a flat pattern list.\n\nEvaluates normalized executable segments only -- reasoning text is\nnever scanned.\n\nReturns ``SecurityRisk.HIGH`` when a rail fires, ``LOW`` otherwise.\nPair with ``ConfirmRisky`` and compose via ``EnsembleSecurityAnalyzer``.\n\nv1 rails: fetch-to-exec, raw-disk-op, catastrophic-delete.\n\nExample::\n\n from openhands.sdk.security import PolicyRailSecurityAnalyzer\n\n analyzer = PolicyRailSecurityAnalyzer()\n # risk = analyzer.security_risk(action)"},"ProfileDetailResponse":{"properties":{"name":{"type":"string","title":"Name"},"config":{"additionalProperties":true,"type":"object","title":"Config"},"api_key_set":{"type":"boolean","title":"Api Key Set","default":false}},"type":"object","required":["name","config"],"title":"ProfileDetailResponse","description":"``config.api_key`` is always nulled; use ``api_key_set`` instead."},"ProfileInfo":{"properties":{"name":{"type":"string","title":"Name"},"model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Model"},"base_url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Base Url"},"api_key_set":{"type":"boolean","title":"Api Key Set","default":false}},"type":"object","required":["name"],"title":"ProfileInfo"},"ProfileListResponse":{"properties":{"profiles":{"items":{"$ref":"#/components/schemas/ProfileInfo"},"type":"array","title":"Profiles"},"active_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Profile"}},"type":"object","required":["profiles"],"title":"ProfileListResponse"},"ProfileMutationResponse":{"properties":{"name":{"type":"string","title":"Name"},"message":{"type":"string","title":"Message"}},"type":"object","required":["name","message"],"title":"ProfileMutationResponse"},"PromptTokensDetails":{"properties":{"audio_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Audio Tokens"},"cached_tokens":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Cached Tokens"}},"additionalProperties":true,"type":"object","title":"PromptTokensDetails","description":"Breakdown of tokens used in the prompt."},"ProvidersResponse":{"properties":{"providers":{"items":{"type":"string"},"type":"array","title":"Providers"}},"type":"object","required":["providers"],"title":"ProvidersResponse","description":"Response containing the list of available LLM providers."},"ReadFileAction":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to read."},"offset":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Offset","description":"Optional: The 0-based line number to start reading from. Use for paginating through large files."},"limit":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Limit","description":"Optional: Maximum number of lines to read. Use with 'offset' to paginate through large files."},"kind":{"type":"string","const":"ReadFileAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","kind"],"title":"ReadFileAction","description":"Schema for read file operation."},"ReadFileActionWithRisk":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to read."},"offset":{"anyOf":[{"type":"integer","minimum":0.0},{"type":"null"}],"title":"Offset","description":"Optional: The 0-based line number to start reading from. Use for paginating through large files."},"limit":{"anyOf":[{"type":"integer","minimum":1.0},{"type":"null"}],"title":"Limit","description":"Optional: Maximum number of lines to read. Use with 'offset' to paginate through large files."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"ReadFileActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","kind"],"title":"ReadFileActionWithRisk"},"ReadFileObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"file_path":{"type":"string","title":"File Path","description":"The file path that was read."},"file_content":{"type":"string","title":"File Content","description":"The content read from the file.","default":""},"is_truncated":{"type":"boolean","title":"Is Truncated","description":"Whether the content was truncated due to size limits.","default":false},"lines_shown":{"anyOf":[{"prefixItems":[{"type":"integer"},{"type":"integer"}],"type":"array","maxItems":2,"minItems":2},{"type":"null"}],"title":"Lines Shown","description":"If truncated, the range of lines shown (start, end) - 1-indexed."},"total_lines":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Total Lines","description":"Total number of lines in the file."},"kind":{"type":"string","const":"ReadFileObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","kind"],"title":"ReadFileObservation","description":"Observation from reading a file."},"ReadFileTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"ReadFileTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"ReadFileTool","description":"Tool for reading file contents with pagination support."},"ReasoningItemModel":{"properties":{"id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Id"},"summary":{"items":{"type":"string"},"type":"array","title":"Summary"},"content":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Content"},"encrypted_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Encrypted Content"},"status":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Status"}},"type":"object","title":"ReasoningItemModel","description":"OpenAI Responses reasoning item (non-stream, subset we consume).\n\nDo not log or render encrypted_content."},"RedactedThinkingBlock":{"properties":{"type":{"type":"string","const":"redacted_thinking","title":"Type","default":"redacted_thinking"},"data":{"type":"string","title":"Data","description":"The redacted thinking content"}},"type":"object","required":["data"],"title":"RedactedThinkingBlock","description":"Redacted thinking block for previous responses without extended thinking.\n\nThis is used as a placeholder for assistant messages that were generated\nbefore extended thinking was enabled."},"RemoteWorkspace":{"properties":{"working_dir":{"type":"string","title":"Working Dir","description":"The working directory for agent operations and tool execution."},"host":{"type":"string","title":"Host","description":"The remote host URL for the workspace."},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"API key for authenticating with the remote host."},"read_timeout":{"type":"number","title":"Read Timeout","description":"Timeout in seconds for reading operations of httpx.Client.","default":600.0},"max_connections":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Max Connections","description":"Maximum number of connections for httpx.Client. None means no limit, useful for running many conversations in parallel."},"kind":{"type":"string","const":"RemoteWorkspace","title":"Kind"}},"type":"object","required":["working_dir","host","kind"],"title":"RemoteWorkspace","description":"Remote workspace implementation that connects to an OpenHands agent server.\n\nRemoteWorkspace provides access to a sandboxed environment running on a remote\nOpenHands agent server. This is the recommended approach for production deployments\nas it provides better isolation and security.\n\nSupports optional completion callbacks on exit via environment variables:\n - ``AUTOMATION_CALLBACK_URL`` — URL to POST completion status to\n - ``AUTOMATION_CALLBACK_API_KEY`` — Bearer token for callback auth (optional)\n - ``AUTOMATION_RUN_ID`` — Run ID to include in callback payload (optional)\n\nExample:\n >>> workspace = RemoteWorkspace(\n ... host=\"https://agent-server.example.com\",\n ... working_dir=\"/workspace\"\n ... )\n >>> with workspace:\n ... result = workspace.execute_command(\"ls -la\")\n ... content = workspace.read_file(\"README.md\")"},"RenameAgentProfileRequest":{"properties":{"new_name":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"New Name"}},"type":"object","required":["new_name"],"title":"RenameAgentProfileRequest"},"RenameProfileRequest":{"properties":{"new_name":{"type":"string","maxLength":64,"minLength":1,"pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","title":"New Name"}},"type":"object","required":["new_name"],"title":"RenameProfileRequest"},"ResponseLatency":{"properties":{"model":{"type":"string","title":"Model"},"latency":{"type":"number","minimum":0.0,"title":"Latency","description":"Latency must be non-negative"},"response_id":{"type":"string","title":"Response Id"}},"type":"object","required":["model","latency","response_id"],"title":"ResponseLatency","description":"Metric tracking the round-trip time per completion call."},"SandboxConfig":{"properties":{"exposed_urls":{"items":{"$ref":"#/components/schemas/ExposedUrl"},"type":"array","title":"Exposed Urls","description":"List of exposed URLs from the sandbox"}},"type":"object","title":"SandboxConfig","description":"Configuration for loading sandbox-specific skills."},"SaveProfileRequest":{"properties":{"llm":{"$ref":"#/components/schemas/LLM-Input"},"include_secrets":{"type":"boolean","title":"Include Secrets","description":"Whether to persist the API key with the profile.","default":true}},"type":"object","required":["llm"],"title":"SaveProfileRequest"},"SecretCreateRequest":{"properties":{"name":{"type":"string","title":"Name"},"value":{"type":"string","format":"password","title":"Value","writeOnly":true},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name","value"],"title":"SecretCreateRequest","description":"Request model for PUT /api/settings/secrets.\n\nCreates or updates a secret with the given name and value."},"SecretItemResponse":{"properties":{"name":{"type":"string","title":"Name"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"}},"type":"object","required":["name"],"title":"SecretItemResponse","description":"Response model for a secret item (without value).\n\nUsed in list responses and as the response for create/update operations."},"SecretRegistry":{"properties":{"secret_sources":{"additionalProperties":{"$ref":"#/components/schemas/SecretSource-Output"},"type":"object","title":"Secret Sources"}},"type":"object","title":"SecretRegistry","description":"Manages secrets and injects them into bash commands when needed.\n\nThe secret registry stores a mapping of secret keys to SecretSources\nthat retrieve the actual secret values. When a bash command is about to be\nexecuted, it scans the command for any secret keys and injects the corresponding\nenvironment variables.\n\nSecret sources will redact / encrypt their sensitive values as appropriate when\nserializing, depending on the content of the context. If a context is present\nand contains a 'cipher' object, this is used for encryption. If it contains a\nboolean 'expose_secrets' flag set to True, secrets are dunped in plain text.\nOtherwise secrets are redacted.\n\nAdditionally, it tracks the latest exported values to enable consistent masking\neven when callable secrets fail on subsequent calls."},"SecretSource-Input":{"oneOf":[{"$ref":"#/components/schemas/LookupSecret-Input"},{"$ref":"#/components/schemas/StaticSecret-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__secret__secrets__LookupSecret-Input__1":"#/components/schemas/LookupSecret-Input","openhands__sdk__secret__secrets__StaticSecret-Input__1":"#/components/schemas/StaticSecret-Input"}}},"SecretSource-Output":{"oneOf":[{"$ref":"#/components/schemas/LookupSecret-Output"},{"$ref":"#/components/schemas/StaticSecret-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__secret__secrets__LookupSecret-Output__1":"#/components/schemas/LookupSecret-Output","openhands__sdk__secret__secrets__StaticSecret-Output__1":"#/components/schemas/StaticSecret-Output"}}},"SecretsListResponse":{"properties":{"secrets":{"items":{"$ref":"#/components/schemas/SecretItemResponse"},"type":"array","title":"Secrets"}},"type":"object","required":["secrets"],"title":"SecretsListResponse","description":"Response model for GET /api/settings/secrets.\n\nLists all available secrets with their names and descriptions.\nValues are never included in list responses."},"SecurityAnalyzerBase-Input":{"oneOf":[{"$ref":"#/components/schemas/PatternSecurityAnalyzer-Input"},{"$ref":"#/components/schemas/PolicyRailSecurityAnalyzer-Input"},{"$ref":"#/components/schemas/EnsembleSecurityAnalyzer-Input"},{"$ref":"#/components/schemas/GraySwanAnalyzer-Input"},{"$ref":"#/components/schemas/LLMSecurityAnalyzer-Input"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__defense_in_depth__pattern__PatternSecurityAnalyzer-Input__1":"#/components/schemas/PatternSecurityAnalyzer-Input","openhands__sdk__security__defense_in_depth__policy_rails__PolicyRailSecurityAnalyzer-Input__1":"#/components/schemas/PolicyRailSecurityAnalyzer-Input","openhands__sdk__security__ensemble__EnsembleSecurityAnalyzer-Input__1":"#/components/schemas/EnsembleSecurityAnalyzer-Input","openhands__sdk__security__grayswan__analyzer__GraySwanAnalyzer-Input__1":"#/components/schemas/GraySwanAnalyzer-Input","openhands__sdk__security__llm_analyzer__LLMSecurityAnalyzer-Input__1":"#/components/schemas/LLMSecurityAnalyzer-Input"}}},"SecurityAnalyzerBase-Output":{"oneOf":[{"$ref":"#/components/schemas/PatternSecurityAnalyzer-Output"},{"$ref":"#/components/schemas/PolicyRailSecurityAnalyzer-Output"},{"$ref":"#/components/schemas/EnsembleSecurityAnalyzer-Output"},{"$ref":"#/components/schemas/GraySwanAnalyzer-Output"},{"$ref":"#/components/schemas/LLMSecurityAnalyzer-Output"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__security__defense_in_depth__pattern__PatternSecurityAnalyzer-Output__1":"#/components/schemas/PatternSecurityAnalyzer-Output","openhands__sdk__security__defense_in_depth__policy_rails__PolicyRailSecurityAnalyzer-Output__1":"#/components/schemas/PolicyRailSecurityAnalyzer-Output","openhands__sdk__security__ensemble__EnsembleSecurityAnalyzer-Output__1":"#/components/schemas/EnsembleSecurityAnalyzer-Output","openhands__sdk__security__grayswan__analyzer__GraySwanAnalyzer-Output__1":"#/components/schemas/GraySwanAnalyzer-Output","openhands__sdk__security__llm_analyzer__LLMSecurityAnalyzer-Output__1":"#/components/schemas/LLMSecurityAnalyzer-Output"}}},"SecurityRisk":{"type":"string","enum":["UNKNOWN","LOW","MEDIUM","HIGH"],"title":"SecurityRisk","description":"Security risk levels for actions.\n\nBased on OpenHands security risk levels but adapted for agent-sdk.\nInteger values allow for easy comparison and ordering."},"SendMessageRequest":{"properties":{"role":{"type":"string","enum":["user","system","assistant","tool"],"title":"Role","default":"user"},"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content"},"run":{"type":"boolean","title":"Run","description":"Whether the agent loop should automatically run if not running","default":false}},"type":"object","title":"SendMessageRequest","description":"Payload to send a message to the agent."},"ServerErrorEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","description":"The source of this event"},"code":{"type":"string","title":"Code","description":"Code for the error - typically an error type"},"detail":{"type":"string","title":"Detail","description":"Details about the error"},"kind":{"type":"string","const":"ServerErrorEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","code","detail","kind"],"title":"ServerErrorEvent","description":"Event emitted by the agent server when a server-level error occurs.\n\nThis event is used for errors that originate from the agent server itself,\nsuch as MCP connection failures, WebSocket errors, or other infrastructure\nissues. Unlike ConversationErrorEvent which is for conversation-level failures,\nthis event indicates a problem with the server environment."},"ServerInfo":{"properties":{"uptime":{"type":"number","title":"Uptime"},"idle_time":{"type":"number","title":"Idle Time"},"title":{"type":"string","title":"Title","default":"OpenHands Agent Server"},"version":{"type":"string","title":"Version"},"sdk_version":{"type":"string","title":"Sdk Version"},"tools_version":{"type":"string","title":"Tools Version"},"workspace_version":{"type":"string","title":"Workspace Version"},"build_git_sha":{"type":"string","title":"Build Git Sha"},"build_git_ref":{"type":"string","title":"Build Git Ref"},"python_version":{"type":"string","title":"Python Version"},"usable_tools":{"items":{"type":"string"},"type":"array","title":"Usable Tools"},"runtime_idle_timeout_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Runtime Idle Timeout Seconds"},"max_foreground_terminal_timeout_seconds":{"anyOf":[{"type":"number"},{"type":"null"}],"title":"Max Foreground Terminal Timeout Seconds"},"docs":{"type":"string","title":"Docs","default":"/docs"},"redoc":{"type":"string","title":"Redoc","default":"/redoc"}},"type":"object","required":["uptime","idle_time"],"title":"ServerInfo"},"SetConfirmationPolicyRequest":{"properties":{"policy":{"$ref":"#/components/schemas/ConfirmationPolicyBase-Input","description":"The confirmation policy to set"}},"type":"object","required":["policy"],"title":"SetConfirmationPolicyRequest","description":"Payload to set confirmation policy for a conversation."},"SetSecurityAnalyzerRequest":{"properties":{"security_analyzer":{"anyOf":[{"$ref":"#/components/schemas/SecurityAnalyzerBase-Input"},{"type":"null"}],"description":"The security analyzer to set"}},"type":"object","required":["security_analyzer"],"title":"SetSecurityAnalyzerRequest","description":"Payload to set security analyzer for a conversation"},"SettingProminence":{"type":"string","enum":["critical","major","minor"],"title":"SettingProminence"},"SettingsChoice":{"properties":{"value":{"anyOf":[{"type":"boolean"},{"type":"integer"},{"type":"number"},{"type":"string"}],"title":"Value"},"label":{"type":"string","title":"Label"}},"type":"object","required":["value","label"],"title":"SettingsChoice"},"SettingsFieldSchema":{"properties":{"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"section":{"type":"string","title":"Section"},"section_label":{"type":"string","title":"Section Label"},"value_type":{"type":"string","enum":["string","integer","number","boolean","array","object"],"title":"Value Type"},"default":{"title":"Default"},"prominence":{"$ref":"#/components/schemas/SettingProminence","default":"minor"},"depends_on":{"items":{"type":"string"},"type":"array","title":"Depends On"},"secret":{"type":"boolean","title":"Secret","default":false},"choices":{"items":{"$ref":"#/components/schemas/SettingsChoice"},"type":"array","title":"Choices"},"variant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Variant","description":"When set, the field only applies to the named ``AgentSettings`` variant (``'openhands'`` or ``'acp'``). The GUI filters fields by the user's current variant; fields with ``variant=None`` are shown regardless."}},"type":"object","required":["key","label","section","section_label","value_type"],"title":"SettingsFieldSchema"},"SettingsResponse":{"properties":{"agent_settings":{"additionalProperties":true,"type":"object","title":"Agent Settings"},"conversation_settings":{"additionalProperties":true,"type":"object","title":"Conversation Settings"},"llm_api_key_is_set":{"type":"boolean","title":"Llm Api Key Is Set"},"active_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Profile","description":"Name of the currently active LLM profile, if one is selected."},"active_agent_profile_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Agent Profile Id","description":"Stable id of the currently active AgentProfile, if one is set."},"misc_settings":{"additionalProperties":true,"type":"object","title":"Misc Settings"}},"type":"object","required":["agent_settings","conversation_settings","llm_api_key_is_set"],"title":"SettingsResponse","description":"Response model for GET /api/settings.\n\nContains the full settings payload including agent configuration,\nconversation settings, active LLM profile, miscellaneous frontend-owned\nsettings, and a flag indicating whether an LLM API key is set.\n\nThe ``agent_settings`` and ``conversation_settings`` fields are raw dicts\nbecause the server controls secret serialization via context. Use the\ntyped accessor methods for validation:\n\nExample::\n\n response = SettingsResponse.model_validate(api_response.json())\n agent = response.get_agent_settings() # Returns AgentSettingsConfig\n conv = response.get_conversation_settings() # Returns ConversationSettings\n\n``misc_settings`` is an opaque container for frontend-owned data that the\nagent-server persists but does not interpret — see the docstring of\n:class:`PersistedSettings.misc_settings`."},"SettingsSchema":{"properties":{"model_name":{"type":"string","title":"Model Name"},"sections":{"items":{"$ref":"#/components/schemas/SettingsSectionSchema"},"type":"array","title":"Sections"}},"type":"object","required":["model_name","sections"],"title":"SettingsSchema"},"SettingsSectionSchema":{"properties":{"key":{"type":"string","title":"Key"},"label":{"type":"string","title":"Label"},"fields":{"items":{"$ref":"#/components/schemas/SettingsFieldSchema"},"type":"array","title":"Fields"},"variant":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Variant","description":"When set, this section only applies to the named ``AgentSettings`` variant (e.g. ``'openhands'`` or ``'acp'``). The GUI filters sections by the current ``agent_kind`` value; sections with ``variant=None`` are always shown."}},"type":"object","required":["key","label","fields"],"title":"SettingsSectionSchema"},"SettingsUpdateRequest":{"properties":{"agent_settings_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Agent Settings Diff"},"conversation_settings_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Conversation Settings Diff"},"misc_settings_diff":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Misc Settings Diff"},"active_profile":{"anyOf":[{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"},{"type":"null"}],"title":"Active Profile","description":"Name of the active LLM profile to persist; null clears it."},"active_agent_profile_id":{"anyOf":[{"type":"string","pattern":"^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$"},{"type":"null"}],"title":"Active Agent Profile Id","description":"Stable id of the active AgentProfile to persist; null clears it."}},"type":"object","title":"SettingsUpdateRequest","description":"Request model for PATCH /api/settings.\n\nSupports partial updates via diff objects that are deep-merged with\nexisting settings. ``misc_settings_diff`` is deep-merged into the\npersisted ``misc_settings`` block with the same semantics as\n``agent_settings_diff`` and ``conversation_settings_diff``: nested dicts\nmerge recursively, and lists are replaced wholesale rather than merged.\nBecause ``misc_settings`` is opaque to the agent-server, callers are\nresponsible for the shape of what they store there."},"Skill-Input":{"properties":{"name":{"type":"string","title":"Name"},"content":{"type":"string","title":"Content"},"trigger":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/KeywordTrigger"},{"$ref":"#/components/schemas/TaskTrigger"}],"discriminator":{"propertyName":"type","mapping":{"keyword":"#/components/schemas/KeywordTrigger","task":"#/components/schemas/TaskTrigger"}}},{"type":"null"}],"title":"Trigger","description":"Trigger determines when skill content is auto-injected. None = no auto-injection (for AgentSkills: agent reads on demand; for legacy: full content always in system prompt). KeywordTrigger = auto-inject when keywords appear in user messages. TaskTrigger = auto-inject for specific tasks, may require user input."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"The source path or identifier of the skill. When it is None, it is treated as a programmatically defined skill."},"mcp_tools":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mcp Tools","description":"MCP tools configuration for the skill (repo skills only). It should conform to the MCPConfig schema: https://gofastmcp.com/clients/client#configuration-format"},"inputs":{"items":{"$ref":"#/components/schemas/InputMetadata"},"type":"array","title":"Inputs","description":"Input metadata for the skill (task skills only)"},"is_agentskills_format":{"type":"boolean","title":"Is Agentskills Format","description":"Whether this skill was loaded from a SKILL.md file following the AgentSkills standard. AgentSkills-format skills use progressive disclosure: always listed in with name, description, and location. If the skill also has triggers, content is auto-injected when triggered AND agent can read file anytime.","default":false},"version":{"type":"string","title":"Version","description":"Skill version (AgentSkills standard field).","default":"1.0.0"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A brief description of what the skill does and when to use it. Descriptions exceeding MAX_DESCRIPTION_LENGTH are truncated with a notice pointing to the skill's source path."},"license":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"License","description":"The license under which the skill is distributed. AgentSkills standard field (e.g., 'Apache-2.0', 'MIT')."},"compatibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compatibility","description":"Environment requirements or compatibility notes for the skill. AgentSkills standard field (e.g., 'Requires git and docker')."},"metadata":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Metadata","description":"Arbitrary key-value metadata for the skill. AgentSkills standard field for extensibility."},"allowed_tools":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tools","description":"List of pre-approved tools for this skill. AgentSkills standard field (parsed from space-delimited string)."},"disable_model_invocation":{"type":"boolean","title":"Disable Model Invocation","description":"Whether this skill can only be activated by trigger matching and should not be advertised to the model for direct invocation.","default":false},"resources":{"anyOf":[{"$ref":"#/components/schemas/SkillResources"},{"type":"null"}],"description":"Resource directories for the skill (scripts/, references/, assets/). AgentSkills standard field. Only populated for SKILL.md directory format."}},"type":"object","required":["name","content"],"title":"Skill","description":"A skill provides specialized knowledge or functionality.\n\nSkill behavior depends on format (is_agentskills_format) and trigger:\n\nAgentSkills format (SKILL.md files):\n- Always listed in with name, description, location\n- Agent reads full content on demand (progressive disclosure)\n- If has triggers: content is ALSO auto-injected when triggered\n\nLegacy OpenHands format:\n- With triggers: Listed in , content injected on trigger\n- Without triggers (None): Full content in , always active\n\nThis model supports both OpenHands-specific fields and AgentSkills standard\nfields (https://agentskills.io/specification) for cross-platform compatibility."},"Skill-Output":{"properties":{"name":{"type":"string","title":"Name"},"content":{"type":"string","title":"Content"},"trigger":{"anyOf":[{"oneOf":[{"$ref":"#/components/schemas/KeywordTrigger"},{"$ref":"#/components/schemas/TaskTrigger"}],"discriminator":{"propertyName":"type","mapping":{"keyword":"#/components/schemas/KeywordTrigger","task":"#/components/schemas/TaskTrigger"}}},{"type":"null"}],"title":"Trigger","description":"Trigger determines when skill content is auto-injected. None = no auto-injection (for AgentSkills: agent reads on demand; for legacy: full content always in system prompt). KeywordTrigger = auto-inject when keywords appear in user messages. TaskTrigger = auto-inject for specific tasks, may require user input."},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source","description":"The source path or identifier of the skill. When it is None, it is treated as a programmatically defined skill."},"mcp_tools":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Mcp Tools","description":"MCP tools configuration for the skill (repo skills only). It should conform to the MCPConfig schema: https://gofastmcp.com/clients/client#configuration-format"},"inputs":{"items":{"$ref":"#/components/schemas/InputMetadata"},"type":"array","title":"Inputs","description":"Input metadata for the skill (task skills only)"},"is_agentskills_format":{"type":"boolean","title":"Is Agentskills Format","description":"Whether this skill was loaded from a SKILL.md file following the AgentSkills standard. AgentSkills-format skills use progressive disclosure: always listed in with name, description, and location. If the skill also has triggers, content is auto-injected when triggered AND agent can read file anytime.","default":false},"version":{"type":"string","title":"Version","description":"Skill version (AgentSkills standard field).","default":"1.0.0"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A brief description of what the skill does and when to use it. Descriptions exceeding MAX_DESCRIPTION_LENGTH are truncated with a notice pointing to the skill's source path."},"license":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"License","description":"The license under which the skill is distributed. AgentSkills standard field (e.g., 'Apache-2.0', 'MIT')."},"compatibility":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Compatibility","description":"Environment requirements or compatibility notes for the skill. AgentSkills standard field (e.g., 'Requires git and docker')."},"metadata":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Metadata","description":"Arbitrary key-value metadata for the skill. AgentSkills standard field for extensibility."},"allowed_tools":{"anyOf":[{"items":{"type":"string"},"type":"array"},{"type":"null"}],"title":"Allowed Tools","description":"List of pre-approved tools for this skill. AgentSkills standard field (parsed from space-delimited string)."},"disable_model_invocation":{"type":"boolean","title":"Disable Model Invocation","description":"Whether this skill can only be activated by trigger matching and should not be advertised to the model for direct invocation.","default":false},"resources":{"anyOf":[{"$ref":"#/components/schemas/SkillResources"},{"type":"null"}],"description":"Resource directories for the skill (scripts/, references/, assets/). AgentSkills standard field. Only populated for SKILL.md directory format."}},"type":"object","required":["name","content"],"title":"Skill","description":"A skill provides specialized knowledge or functionality.\n\nSkill behavior depends on format (is_agentskills_format) and trigger:\n\nAgentSkills format (SKILL.md files):\n- Always listed in with name, description, location\n- Agent reads full content on demand (progressive disclosure)\n- If has triggers: content is ALSO auto-injected when triggered\n\nLegacy OpenHands format:\n- With triggers: Listed in , content injected on trigger\n- Without triggers (None): Full content in , always active\n\nThis model supports both OpenHands-specific fields and AgentSkills standard\nfields (https://agentskills.io/specification) for cross-platform compatibility."},"SkillInfo":{"properties":{"name":{"type":"string","title":"Name"},"type":{"type":"string","enum":["repo","knowledge","agentskills"],"title":"Type"},"content":{"type":"string","title":"Content"},"triggers":{"items":{"type":"string"},"type":"array","title":"Triggers"},"source":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Source"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"is_agentskills_format":{"type":"boolean","title":"Is Agentskills Format","default":false},"disable_model_invocation":{"type":"boolean","title":"Disable Model Invocation","default":false}},"type":"object","required":["name","type","content"],"title":"SkillInfo","description":"Skill information returned by the API."},"SkillResources":{"properties":{"skill_root":{"type":"string","title":"Skill Root","description":"Root directory of the skill (absolute path)"},"scripts":{"items":{"type":"string"},"type":"array","title":"Scripts","description":"List of script files in scripts/ directory (relative paths)"},"references":{"items":{"type":"string"},"type":"array","title":"References","description":"List of reference files in references/ directory (relative paths)"},"assets":{"items":{"type":"string"},"type":"array","title":"Assets","description":"List of asset files in assets/ directory (relative paths)"}},"type":"object","required":["skill_root"],"title":"SkillResources","description":"Resource directories for a skill (AgentSkills standard).\n\nPer the AgentSkills specification, skills can include:\n- scripts/: Executable scripts the agent can run\n- references/: Reference documentation and examples\n- assets/: Static assets (images, data files, etc.)"},"SkillsRequest":{"properties":{"load_public":{"type":"boolean","title":"Load Public","description":"Load public skills from OpenHands/extensions repo","default":true},"load_user":{"type":"boolean","title":"Load User","description":"Load user skills from ~/.openhands/skills/","default":true},"load_project":{"type":"boolean","title":"Load Project","description":"Load project skills from workspace","default":true},"load_org":{"type":"boolean","title":"Load Org","description":"Load organization-level skills","default":true},"marketplace_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Marketplace Path","description":"Relative marketplace JSON path for public skills. Set to null to load all public skills.","default":"marketplaces/default.json"},"project_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Project Dir","description":"Workspace directory path for project skills"},"org_configs":{"anyOf":[{"items":{"$ref":"#/components/schemas/OrgConfig"},"type":"array"},{"type":"null"}],"title":"Org Configs","description":"Organization/user skill repositories to load concurrently"},"org_config":{"anyOf":[{"$ref":"#/components/schemas/OrgConfig"},{"type":"null"}],"description":"Deprecated since v1.28.0 and scheduled for removal in v1.33.0. Single organization skills configuration; prefer org_configs.","deprecated":true},"sandbox_config":{"anyOf":[{"$ref":"#/components/schemas/SandboxConfig"},{"type":"null"}],"description":"Sandbox skills configuration"}},"type":"object","title":"SkillsRequest","description":"Request body for loading skills."},"SkillsResponse":{"properties":{"skills":{"items":{"$ref":"#/components/schemas/SkillInfo"},"type":"array","title":"Skills"},"sources":{"additionalProperties":{"type":"integer"},"type":"object","title":"Sources","description":"Count of skills loaded from each source"}},"type":"object","required":["skills"],"title":"SkillsResponse","description":"Response containing all available skills."},"StartConversationRequest":{"properties":{"workspace":{"$ref":"#/components/schemas/LocalWorkspace-Input","description":"Working directory for agent operations and tool execution."},"worktree":{"type":"boolean","title":"Worktree","description":"If true and the workspace is already inside a git repository, create a dedicated git worktree for this conversation under `/tmp/conversation-worktrees//`.","default":false},"conversation_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Conversation Id","description":"Optional conversation ID. If not provided, a random UUID will be generated."},"confirmation_policy":{"$ref":"#/components/schemas/ConfirmationPolicyBase-Input","description":"Controls when the conversation will prompt the user before continuing. Defaults to never.","default":{"kind":"NeverConfirm"}},"security_analyzer":{"anyOf":[{"$ref":"#/components/schemas/SecurityAnalyzerBase-Input"},{"type":"null"}],"description":"Optional security analyzer to evaluate action risks."},"initial_message":{"anyOf":[{"$ref":"#/components/schemas/SendMessageRequest"},{"type":"null"}],"description":"Initial message to pass to the LLM"},"max_iterations":{"type":"integer","minimum":1.0,"title":"Max Iterations","description":"If set, the max number of iterations the agent will run before stopping. This is useful to prevent infinite loops.","default":500},"stuck_detection":{"type":"boolean","title":"Stuck Detection","description":"If true, the conversation will use stuck detection to prevent infinite loops.","default":true},"secrets":{"additionalProperties":{"$ref":"#/components/schemas/SecretSource-Input"},"type":"object","title":"Secrets","description":"Secrets available in the conversation"},"secrets_encrypted":{"type":"boolean","title":"Secrets Encrypted","description":"If true, indicates that secret values in the agent configuration are cipher-encrypted and should be decrypted by the server before use. This enables secure round-tripping of settings through untrusted clients (e.g., frontend) that received encrypted values via the X-Expose-Secrets header. Flow: client calls GET /api/settings with X-Expose-Secrets: encrypted to receive cipher-encrypted secrets, then passes them in the agent config with secrets_encrypted=True so the server can decrypt them.","default":false},"tool_module_qualnames":{"additionalProperties":{"type":"string"},"type":"object","title":"Tool Module Qualnames","description":"Mapping of tool names to their module qualnames from the client's registry. These modules will be dynamically imported on the server to register the tools for this conversation."},"client_tools":{"items":{"$ref":"#/components/schemas/ClientToolSpec-Input"},"type":"array","title":"Client Tools","description":"Tools defined by the client via JSON spec. These tools have no server-side executor — when the agent calls them, an ActionEvent is emitted over the WebSocket and the client handles execution. The SDK returns an acknowledgment observation immediately."},"agent_definitions":{"items":{"$ref":"#/components/schemas/AgentDefinition"},"type":"array","title":"Agent Definitions","description":"Agent definitions from the client's registry. These are registered on the server so that task tools can see user-registered subagents."},"plugins":{"anyOf":[{"items":{"$ref":"#/components/schemas/PluginSource"},"type":"array"},{"type":"null"}],"title":"Plugins","description":"List of plugins to load for this conversation. Plugins are loaded and their skills/MCP config are merged into the agent. Hooks are extracted and stored for runtime execution."},"hook_config":{"anyOf":[{"$ref":"#/components/schemas/HookConfig-Input"},{"type":"null"}],"description":"Optional hook configuration for this conversation. Hooks are shell scripts that run at key lifecycle events (PreToolUse, PostToolUse, UserPromptSubmit, Stop, etc.). If both hook_config and plugins are provided, they are merged with explicit hooks running before plugin hooks."},"tags":{"additionalProperties":{"type":"string"},"type":"object","title":"Tags","description":"Key-value tags for the conversation. Keys must be lowercase alphanumeric. Values are arbitrary strings up to 256 characters."},"user_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"User Id","description":"Optional user ID to associate with observability traces. When set, this is passed to Laminar.set_trace_user_id() so traces can be queried by user."},"observability_metadata":{"additionalProperties":{"$ref":"#/components/schemas/TraceMetadataValue"},"type":"object","title":"Observability Metadata","description":"Trace-level metadata to attach to observability backends. Values must be scalars or homogeneous scalar lists supported by OpenTelemetry."},"observability_tags":{"items":{"type":"string"},"type":"array","title":"Observability Tags","description":"Tags to attach to the conversation root observability span."},"autotitle":{"type":"boolean","title":"Autotitle","description":"If true, automatically generate a title for the conversation from the first user message. Precedence: title_llm_profile (if set and loads) → agent.llm → message truncation.","default":true},"title_llm_profile":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title Llm Profile","description":"Optional LLM profile name for title generation. If set, the LLM is loaded from LLMProfileStore (~/.openhands/profiles/) and used for LLM-based title generation. This enables using a fast/cheap model for titles regardless of the agent's main model. If not set (or profile loading fails), title generation falls back to the agent's LLM."},"agent_settings":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Agent Settings","description":"Optional agent settings payload. If `agent` is omitted, this is validated with the AgentSettingsBase `agent_kind` discriminator and used to construct the concrete agent."},"agent_profile_id":{"anyOf":[{"type":"string","format":"uuid"},{"type":"null"}],"title":"Agent Profile Id","description":"Optional agent profile ID. When set, the agent-server resolves the referenced profile server-side (stores + cipher are required) and builds the agent from it. Mutually exclusive with `agent` and `agent_settings`. The SDK validator enforces exclusivity only — resolution happens in conversation_service, not here."},"agent":{"$ref":"#/components/schemas/AgentBase-Input"}},"type":"object","required":["workspace"],"title":"StartConversationRequest","description":"Payload to create a new conversation.\n\nSupports any concrete :class:`AgentBase` implementation, including regular\nOpenHands agents and ACP agents. Clients may provide either a concrete\n``agent`` payload or an ``agent_settings`` payload; when ``agent_settings``\nis provided without ``agent``, the settings are validated with the\n``agent_kind`` discriminator and converted to the appropriate agent type."},"StartGoalRequest":{"properties":{"objective":{"type":"string","title":"Objective","description":"The goal objective to pursue and audit."},"max_iterations":{"type":"integer","minimum":1.0,"title":"Max Iterations","description":"Maximum audit rounds before giving up.","default":10}},"type":"object","required":["objective"],"title":"StartGoalRequest","description":"Payload to start a ``/goal`` loop inside a conversation."},"StaticSecret-Input":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"value":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Value"},"kind":{"type":"string","const":"StaticSecret","title":"Kind"}},"type":"object","title":"StaticSecret","description":"A secret stored locally"},"StaticSecret-Output":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"Optional description for this secret"},"value":{"anyOf":[{"type":"string","format":"password","writeOnly":true},{"type":"null"}],"title":"Value"},"kind":{"type":"string","const":"StaticSecret","title":"Kind"}},"type":"object","required":["kind"],"title":"StaticSecret","description":"A secret stored locally"},"StreamingDeltaEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Content"},"reasoning_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reasoning Content"},"kind":{"type":"string","const":"StreamingDeltaEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"StreamingDeltaEvent","description":"Transient LLM token delta for real-time WebSocket delivery.\n\nNot persisted to the conversation event log: these events are published\ndirectly to PubSub, bypassing the callback chain that writes to\nConversationState.events. Clients reconnecting mid-stream will receive\nthe final MessageEvent from history but none of the deltas that produced\nit — deltas are a UX affordance, not part of the durable conversation\nrecord."},"SubdirectoryEntry":{"properties":{"name":{"type":"string","title":"Name"},"path":{"type":"string","title":"Path"}},"type":"object","required":["name","path"],"title":"SubdirectoryEntry"},"SubdirectoryPage":{"properties":{"items":{"items":{"$ref":"#/components/schemas/SubdirectoryEntry"},"type":"array","title":"Items"},"next_page_id":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Next Page Id"}},"type":"object","required":["items"],"title":"SubdirectoryPage"},"SubscriptionDevicePollRequest":{"properties":{"device_code":{"type":"string","title":"Device Code"}},"type":"object","required":["device_code"],"title":"SubscriptionDevicePollRequest","description":"Poll request for a previously-started subscription device login."},"SubscriptionDeviceStartResponse":{"properties":{"device_code":{"type":"string","title":"Device Code","description":"Opaque server-side polling token."},"user_code":{"type":"string","title":"User Code"},"verification_uri":{"type":"string","title":"Verification Uri"},"verification_uri_complete":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Verification Uri Complete"},"expires_at":{"type":"integer","title":"Expires At"},"interval_seconds":{"type":"integer","title":"Interval Seconds"}},"type":"object","required":["device_code","user_code","verification_uri","expires_at","interval_seconds"],"title":"SubscriptionDeviceStartResponse","description":"Device-code challenge details for browser sign-in."},"SubscriptionModelsResponse":{"properties":{"vendor":{"type":"string","title":"Vendor","default":"openai"},"models":{"items":{"type":"string"},"type":"array","title":"Models"}},"type":"object","required":["models"],"title":"SubscriptionModelsResponse","description":"Models available through a subscription provider."},"SubscriptionStatusResponse":{"properties":{"vendor":{"type":"string","title":"Vendor","default":"openai"},"connected":{"type":"boolean","title":"Connected"},"account_email":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Account Email"},"expires_at":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Expires At"}},"type":"object","required":["connected"],"title":"SubscriptionStatusResponse","description":"Safe subscription authentication status."},"Success":{"properties":{"success":{"type":"boolean","title":"Success","default":true}},"type":"object","title":"Success"},"SwitchLLMAction":{"properties":{"profile_name":{"type":"string","title":"Profile Name","description":"Name of the saved LLM profile to use for future agent steps."},"reason":{"type":"string","title":"Reason","description":"Brief reason why this profile is a better fit for the next step."},"kind":{"type":"string","const":"SwitchLLMAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["profile_name","reason","kind"],"title":"SwitchLLMAction","description":"Action for switching this conversation to a saved LLM profile."},"SwitchLLMActionWithRisk":{"properties":{"profile_name":{"type":"string","title":"Profile Name","description":"Name of the saved LLM profile to use for future agent steps."},"reason":{"type":"string","title":"Reason","description":"Brief reason why this profile is a better fit for the next step."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"SwitchLLMActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["profile_name","reason","kind"],"title":"SwitchLLMActionWithRisk"},"SwitchLLMObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"profile_name":{"type":"string","title":"Profile Name","description":"Name of the profile that the tool attempted to activate."},"reason":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Reason","description":"Reason the agent gave for attempting this LLM profile switch."},"active_model":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Active Model","description":"Model configured by the activated profile, when available."},"kind":{"type":"string","const":"SwitchLLMObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["profile_name","kind"],"title":"SwitchLLMObservation","description":"Observation returned after switching this conversation's LLM profile."},"SwitchLLMTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"SwitchLLMTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"SwitchLLMTool","description":"Tool for switching a conversation to a saved LLM profile."},"SyncResponse":{"properties":{"status":{"type":"string","enum":["success","error"],"title":"Status"},"message":{"type":"string","title":"Message"}},"type":"object","required":["status","message"],"title":"SyncResponse","description":"Response from skill sync operation."},"SystemPromptEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"agent"},"system_prompt":{"$ref":"#/components/schemas/TextContent","description":"The system prompt text"},"tools":{"items":{"$ref":"#/components/schemas/ToolDefinition"},"type":"array","title":"Tools","description":"List of tools as ToolDefinition objects"},"dynamic_context":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"type":"null"}],"description":"Optional dynamic per-conversation context (runtime info, repo context, secrets). When provided, this is included as a second content block in the system message (not cached)."},"kind":{"type":"string","const":"SystemPromptEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["system_prompt","tools","kind"],"title":"SystemPromptEvent","description":"System prompt added by the agent.\n\nThe system prompt can optionally include dynamic context that varies between\nconversations. When ``dynamic_context`` is provided, it is included as a\nsecond content block in the same system message. Cache markers are NOT\napplied here - they are applied by ``LLM._apply_prompt_caching()`` when\ncaching is enabled, ensuring provider-specific cache control is only added\nwhen appropriate.\n\nAttributes:\n system_prompt: The static system prompt text (cacheable across conversations)\n tools: List of available tools\n dynamic_context: Optional per-conversation context (hosts, repo info, etc.)\n Sent as a second TextContent block inside the system message."},"TaskAction":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A short (3-5 word) description of the task."},"prompt":{"type":"string","title":"Prompt","description":"The task for the agent to perform."},"subagent_type":{"type":"string","title":"Subagent Type","description":"The type of specialized agent to use for this task.","default":"general-purpose"},"resume":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resume","description":"Task ID of the task to resume from."},"kind":{"type":"string","const":"TaskAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["prompt","kind"],"title":"TaskAction","description":"Schema for launching a sub-agent task."},"TaskActionWithRisk":{"properties":{"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description","description":"A short (3-5 word) description of the task."},"prompt":{"type":"string","title":"Prompt","description":"The task for the agent to perform."},"subagent_type":{"type":"string","title":"Subagent Type","description":"The type of specialized agent to use for this task.","default":"general-purpose"},"resume":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Resume","description":"Task ID of the task to resume from."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"TaskActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["prompt","kind"],"title":"TaskActionWithRisk"},"TaskItem":{"properties":{"title":{"type":"string","title":"Title","description":"A brief title for the task."},"notes":{"type":"string","title":"Notes","description":"Additional details or notes about the task.","default":""},"status":{"type":"string","enum":["todo","in_progress","done"],"title":"Status","description":"The current status of the task. One of 'todo', 'in_progress', or 'done'.","default":"todo"}},"type":"object","required":["title"],"title":"TaskItem"},"TaskObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"task_id":{"type":"string","title":"Task Id","description":"The unique identifier of the task."},"subagent":{"type":"string","title":"Subagent","description":"The subagent of the task."},"status":{"type":"string","title":"Status","description":"The status of the task."},"kind":{"type":"string","const":"TaskObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["task_id","subagent","status","kind"],"title":"TaskObservation","description":"Observation from a task execution."},"TaskTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TaskTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TaskTool","description":"Tool for launching (blocking) sub-agent tasks."},"TaskToolSet":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TaskToolSet","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TaskToolSet","description":"Task tool set.\n\nCreates the Task tool backed by a shared TaskManager.\n\nUsage:\n from openhands.tools.task import TaskToolSet\n\n agent = Agent(\n llm=llm,\n tools=[\n Tool(name=TerminalTool.name),\n Tool(name=FileEditorTool.name),\n Tool(name=TaskToolSet.name),\n ],\n )"},"TaskTrackerAction":{"properties":{"command":{"type":"string","enum":["view","plan"],"title":"Command","description":"The command to execute. `view` shows the current task list. `plan` creates or updates the task list based on provided requirements and progress. Always `view` the current list before making changes.","default":"view"},"task_list":{"items":{"$ref":"#/components/schemas/TaskItem"},"type":"array","title":"Task List","description":"The full task list. Required parameter of `plan` command."},"kind":{"type":"string","const":"TaskTrackerAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"TaskTrackerAction","description":"An action where the agent writes or updates a task list for task management."},"TaskTrackerActionWithRisk":{"properties":{"command":{"type":"string","enum":["view","plan"],"title":"Command","description":"The command to execute. `view` shows the current task list. `plan` creates or updates the task list based on provided requirements and progress. Always `view` the current list before making changes.","default":"view"},"task_list":{"items":{"$ref":"#/components/schemas/TaskItem"},"type":"array","title":"Task List","description":"The full task list. Required parameter of `plan` command."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"TaskTrackerActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"TaskTrackerActionWithRisk"},"TaskTrackerObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"type":"string","enum":["view","plan"],"title":"Command","description":"The command that was executed: \"view\" or \"plan\"."},"task_list":{"items":{"$ref":"#/components/schemas/TaskItem"},"type":"array","title":"Task List","description":"The current task list"},"kind":{"type":"string","const":"TaskTrackerObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TaskTrackerObservation","description":"This data class represents the result of a task tracking operation."},"TaskTrackerTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TaskTrackerTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TaskTrackerTool","description":"A ToolDefinition subclass that automatically initializes a TaskTrackerExecutor."},"TaskTrigger":{"properties":{"type":{"type":"string","const":"task","title":"Type","default":"task"},"triggers":{"items":{"type":"string"},"type":"array","title":"Triggers"}},"type":"object","required":["triggers"],"title":"TaskTrigger","description":"Trigger for task-specific skills.\n\nThese skills are activated for specific task types and can modify prompts."},"TerminalAction":{"properties":{"command":{"type":"string","title":"Command","description":"The shell command to execute. Can be empty string to view additional logs when the previous exit code is `-1`. Can be a special key name when `is_input` is True: `C-c` (Ctrl+C), `C-d` (Ctrl+D/EOF), `C-z` (Ctrl+Z), or any `C-` for Ctrl sequences; navigation keys `UP`, `DOWN`, `LEFT`, `RIGHT`, `HOME`, `END`, `PGUP`, `PGDN`; and `TAB`, `ESC`, `BS` (Backspace), `ENTER`. You can only execute one command at a time. Use the platform-appropriate shell syntax described in the tool description when chaining commands."},"is_input":{"type":"boolean","title":"Is Input","description":"If True, the command is an input to the running process. If False, the command is executed in the terminal session. Default is False.","default":false},"timeout":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"Optional. Sets a maximum time limit (in seconds) for running the command. If the command takes longer than this limit, you’ll be asked whether to continue or stop it. If you don’t set a value, the command will instead pause and ask for confirmation when it produces no new output for 30 seconds. Use a higher value if the command is expected to take a long time (like installation or testing), or if it has a known fixed duration (like sleep)."},"reset":{"type":"boolean","title":"Reset","description":"If True, reset the terminal by creating a new session. Use this only when the terminal becomes unresponsive. Note that all previously set environment variables and session state will be lost after reset. Cannot be used with is_input=True.","default":false},"kind":{"type":"string","const":"TerminalAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TerminalAction","description":"Schema for terminal command execution."},"TerminalActionWithRisk":{"properties":{"command":{"type":"string","title":"Command","description":"The shell command to execute. Can be empty string to view additional logs when the previous exit code is `-1`. Can be a special key name when `is_input` is True: `C-c` (Ctrl+C), `C-d` (Ctrl+D/EOF), `C-z` (Ctrl+Z), or any `C-` for Ctrl sequences; navigation keys `UP`, `DOWN`, `LEFT`, `RIGHT`, `HOME`, `END`, `PGUP`, `PGDN`; and `TAB`, `ESC`, `BS` (Backspace), `ENTER`. You can only execute one command at a time. Use the platform-appropriate shell syntax described in the tool description when chaining commands."},"is_input":{"type":"boolean","title":"Is Input","description":"If True, the command is an input to the running process. If False, the command is executed in the terminal session. Default is False.","default":false},"timeout":{"anyOf":[{"type":"number","minimum":0.0},{"type":"null"}],"title":"Timeout","description":"Optional. Sets a maximum time limit (in seconds) for running the command. If the command takes longer than this limit, you’ll be asked whether to continue or stop it. If you don’t set a value, the command will instead pause and ask for confirmation when it produces no new output for 30 seconds. Use a higher value if the command is expected to take a long time (like installation or testing), or if it has a known fixed duration (like sleep)."},"reset":{"type":"boolean","title":"Reset","description":"If True, reset the terminal by creating a new session. Use this only when the terminal becomes unresponsive. Note that all previously set environment variables and session state will be lost after reset. Cannot be used with is_input=True.","default":false},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"TerminalActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TerminalActionWithRisk"},"TerminalObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"command":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Command","description":"The shell command that was executed. Can be empty string if the observation is from a previous command that hit soft timeout and is not yet finished."},"exit_code":{"anyOf":[{"type":"integer"},{"type":"null"}],"title":"Exit Code","description":"The exit code of the command. -1 indicates the process hit the soft timeout and is not yet finished."},"timeout":{"type":"boolean","title":"Timeout","description":"Whether the command execution timed out.","default":false},"metadata":{"$ref":"#/components/schemas/CmdOutputMetadata","description":"Additional metadata captured from PS1 after command execution."},"full_output_save_dir":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Full Output Save Dir","description":"Directory where full output files are saved"},"kind":{"type":"string","const":"TerminalObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["command","kind"],"title":"TerminalObservation","description":"A ToolResult that can be rendered as a CLI output."},"TerminalTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"TerminalTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"TerminalTool","description":"A ToolDefinition subclass that automatically initializes a TerminalExecutor with auto-detection."},"TextContent":{"properties":{"cache_prompt":{"type":"boolean","title":"Cache Prompt","default":false},"type":{"type":"string","const":"text","title":"Type","default":"text"},"text":{"type":"string","title":"Text"}},"additionalProperties":false,"type":"object","required":["text"],"title":"TextContent"},"ThinkAction":{"properties":{"thought":{"type":"string","title":"Thought","description":"The thought to log."},"kind":{"type":"string","const":"ThinkAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["thought","kind"],"title":"ThinkAction","description":"Action for logging a thought without making any changes."},"ThinkActionWithRisk":{"properties":{"thought":{"type":"string","title":"Thought","description":"The thought to log."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"ThinkActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["thought","kind"],"title":"ThinkActionWithRisk"},"ThinkObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"kind":{"type":"string","const":"ThinkObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"ThinkObservation","description":"Observation returned after logging a thought.\nThe ThinkAction itself contains the thought logged so no extra\nfields are needed here."},"ThinkTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"ThinkTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"ThinkTool","description":"Tool for logging thoughts without making changes."},"ThinkingBlock":{"properties":{"type":{"type":"string","const":"thinking","title":"Type","default":"thinking"},"thinking":{"type":"string","title":"Thinking","description":"The thinking content"},"signature":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Signature","description":"Cryptographic signature for the thinking block"}},"type":"object","required":["thinking"],"title":"ThinkingBlock","description":"Anthropic thinking block for extended thinking feature.\n\nThis represents the raw thinking blocks returned by Anthropic models\nwhen extended thinking is enabled. These blocks must be preserved\nand passed back to the API for tool use scenarios."},"TokenEvent":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source"},"prompt_token_ids":{"items":{"type":"integer"},"type":"array","title":"Prompt Token Ids","description":"The exact prompt token IDs for this message event"},"response_token_ids":{"items":{"type":"integer"},"type":"array","title":"Response Token Ids","description":"The exact response token IDs for this message event"},"kind":{"type":"string","const":"TokenEvent","title":"Kind"}},"additionalProperties":false,"type":"object","required":["source","prompt_token_ids","response_token_ids","kind"],"title":"TokenEvent","description":"Event from VLLM representing token IDs used in LLM interaction."},"TokenUsage":{"properties":{"model":{"type":"string","title":"Model","default":""},"prompt_tokens":{"type":"integer","minimum":0.0,"title":"Prompt Tokens","description":"Prompt tokens must be non-negative","default":0},"completion_tokens":{"type":"integer","minimum":0.0,"title":"Completion Tokens","description":"Completion tokens must be non-negative","default":0},"cache_read_tokens":{"type":"integer","minimum":0.0,"title":"Cache Read Tokens","description":"Cache read tokens must be non-negative","default":0},"cache_write_tokens":{"type":"integer","minimum":0.0,"title":"Cache Write Tokens","description":"Cache write tokens must be non-negative","default":0},"reasoning_tokens":{"type":"integer","minimum":0.0,"title":"Reasoning Tokens","description":"Reasoning tokens must be non-negative","default":0},"context_window":{"type":"integer","minimum":0.0,"title":"Context Window","description":"Context window must be non-negative","default":0},"per_turn_token":{"type":"integer","minimum":0.0,"title":"Per Turn Token","description":"Per turn tokens must be non-negative","default":0},"response_id":{"type":"string","title":"Response Id","default":""}},"type":"object","title":"TokenUsage","description":"Metric tracking detailed token usage per completion call."},"Tool-Input":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the tool class, e.g., 'TerminalTool'. Import it from an `openhands.tools.` subpackage.","examples":["TerminalTool","FileEditorTool","TaskTrackerTool"]},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"Parameters for the tool's .create() method, e.g., {'working_dir': '/app'}","examples":[{"working_dir":"/workspace"}]}},"type":"object","required":["name"],"title":"Tool","description":"Defines a tool to be initialized for the agent.\n\nThis is only used in agent-sdk for type schema for server use."},"ToolAnnotations-Input":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"A human-readable title for the tool."},"readOnlyHint":{"type":"boolean","title":"Readonlyhint","description":"If true, the tool does not modify its environment. Default: false","default":false},"destructiveHint":{"type":"boolean","title":"Destructivehint","description":"If true, the tool may perform destructive updates to its environment. If false, the tool performs only additive updates. (This property is meaningful only when `readOnlyHint == false`) Default: true","default":true},"idempotentHint":{"type":"boolean","title":"Idempotenthint","description":"If true, calling the tool repeatedly with the same arguments will have no additional effect on the its environment. (This property is meaningful only when `readOnlyHint == false`) Default: false","default":false},"openWorldHint":{"type":"boolean","title":"Openworldhint","description":"If true, this tool may interact with an 'open world' of external entities. If false, the tool's domain of interaction is closed. For example, the world of a web search tool is open, whereas that of a memory tool is not. Default: true","default":true}},"type":"object","title":"openhands.sdk.tool.tool.ToolAnnotations","description":"Annotations to provide hints about the tool's behavior.\n\nBased on Model Context Protocol (MCP) spec:\nhttps://github.com/modelcontextprotocol/modelcontextprotocol/blob/caf3424488b10b4a7b1f8cb634244a450a1f4400/schema/2025-06-18/schema.ts#L838"},"ToolDefinition":{"oneOf":[{"$ref":"#/components/schemas/MCPToolDefinition"},{"$ref":"#/components/schemas/FinishTool"},{"$ref":"#/components/schemas/InvokeSkillTool"},{"$ref":"#/components/schemas/SwitchLLMTool"},{"$ref":"#/components/schemas/ThinkTool"},{"$ref":"#/components/schemas/ClientTool"},{"$ref":"#/components/schemas/BrowserClickTool"},{"$ref":"#/components/schemas/BrowserCloseTabTool"},{"$ref":"#/components/schemas/BrowserGetContentTool"},{"$ref":"#/components/schemas/BrowserGetStateTool"},{"$ref":"#/components/schemas/BrowserGetStorageTool"},{"$ref":"#/components/schemas/BrowserGoBackTool"},{"$ref":"#/components/schemas/BrowserListTabsTool"},{"$ref":"#/components/schemas/BrowserNavigateTool"},{"$ref":"#/components/schemas/BrowserScrollTool"},{"$ref":"#/components/schemas/BrowserSetStorageTool"},{"$ref":"#/components/schemas/BrowserStartRecordingTool"},{"$ref":"#/components/schemas/BrowserStopRecordingTool"},{"$ref":"#/components/schemas/BrowserSwitchTabTool"},{"$ref":"#/components/schemas/BrowserToolSet"},{"$ref":"#/components/schemas/BrowserTypeTool"},{"$ref":"#/components/schemas/FileEditorTool"},{"$ref":"#/components/schemas/EditTool"},{"$ref":"#/components/schemas/ListDirectoryTool"},{"$ref":"#/components/schemas/ReadFileTool"},{"$ref":"#/components/schemas/WriteFileTool"},{"$ref":"#/components/schemas/GlobTool"},{"$ref":"#/components/schemas/GrepTool"},{"$ref":"#/components/schemas/PlanningFileEditorTool"},{"$ref":"#/components/schemas/TaskTool"},{"$ref":"#/components/schemas/TaskToolSet"},{"$ref":"#/components/schemas/TaskTrackerTool"},{"$ref":"#/components/schemas/TerminalTool"},{"$ref":"#/components/schemas/WorkflowTool"},{"$ref":"#/components/schemas/WorkflowToolSet"}],"discriminator":{"propertyName":"kind","mapping":{"openhands__sdk__mcp__tool__MCPToolDefinition-Output__1":"#/components/schemas/MCPToolDefinition","openhands__sdk__tool__builtins__finish__FinishTool-Output__1":"#/components/schemas/FinishTool","openhands__sdk__tool__builtins__invoke_skill__InvokeSkillTool-Output__1":"#/components/schemas/InvokeSkillTool","openhands__sdk__tool__builtins__switch_llm__SwitchLLMTool-Output__1":"#/components/schemas/SwitchLLMTool","openhands__sdk__tool__builtins__think__ThinkTool-Output__1":"#/components/schemas/ThinkTool","openhands__sdk__tool__client_tool__ClientTool-Output__1":"#/components/schemas/ClientTool","openhands__tools__browser_use__definition__BrowserClickTool-Output__1":"#/components/schemas/BrowserClickTool","openhands__tools__browser_use__definition__BrowserCloseTabTool-Output__1":"#/components/schemas/BrowserCloseTabTool","openhands__tools__browser_use__definition__BrowserGetContentTool-Output__1":"#/components/schemas/BrowserGetContentTool","openhands__tools__browser_use__definition__BrowserGetStateTool-Output__1":"#/components/schemas/BrowserGetStateTool","openhands__tools__browser_use__definition__BrowserGetStorageTool-Output__1":"#/components/schemas/BrowserGetStorageTool","openhands__tools__browser_use__definition__BrowserGoBackTool-Output__1":"#/components/schemas/BrowserGoBackTool","openhands__tools__browser_use__definition__BrowserListTabsTool-Output__1":"#/components/schemas/BrowserListTabsTool","openhands__tools__browser_use__definition__BrowserNavigateTool-Output__1":"#/components/schemas/BrowserNavigateTool","openhands__tools__browser_use__definition__BrowserScrollTool-Output__1":"#/components/schemas/BrowserScrollTool","openhands__tools__browser_use__definition__BrowserSetStorageTool-Output__1":"#/components/schemas/BrowserSetStorageTool","openhands__tools__browser_use__definition__BrowserStartRecordingTool-Output__1":"#/components/schemas/BrowserStartRecordingTool","openhands__tools__browser_use__definition__BrowserStopRecordingTool-Output__1":"#/components/schemas/BrowserStopRecordingTool","openhands__tools__browser_use__definition__BrowserSwitchTabTool-Output__1":"#/components/schemas/BrowserSwitchTabTool","openhands__tools__browser_use__definition__BrowserToolSet-Output__1":"#/components/schemas/BrowserToolSet","openhands__tools__browser_use__definition__BrowserTypeTool-Output__1":"#/components/schemas/BrowserTypeTool","openhands__tools__file_editor__definition__FileEditorTool-Output__1":"#/components/schemas/FileEditorTool","openhands__tools__gemini__edit__definition__EditTool-Output__1":"#/components/schemas/EditTool","openhands__tools__gemini__list_directory__definition__ListDirectoryTool-Output__1":"#/components/schemas/ListDirectoryTool","openhands__tools__gemini__read_file__definition__ReadFileTool-Output__1":"#/components/schemas/ReadFileTool","openhands__tools__gemini__write_file__definition__WriteFileTool-Output__1":"#/components/schemas/WriteFileTool","openhands__tools__glob__definition__GlobTool-Output__1":"#/components/schemas/GlobTool","openhands__tools__grep__definition__GrepTool-Output__1":"#/components/schemas/GrepTool","openhands__tools__planning_file_editor__definition__PlanningFileEditorTool-Output__1":"#/components/schemas/PlanningFileEditorTool","openhands__tools__task__definition__TaskTool-Output__1":"#/components/schemas/TaskTool","openhands__tools__task__definition__TaskToolSet-Output__1":"#/components/schemas/TaskToolSet","openhands__tools__task_tracker__definition__TaskTrackerTool-Output__1":"#/components/schemas/TaskTrackerTool","openhands__tools__terminal__definition__TerminalTool-Output__1":"#/components/schemas/TerminalTool","openhands__tools__workflow__definition__WorkflowTool-Output__1":"#/components/schemas/WorkflowTool","openhands__tools__workflow__definition__WorkflowToolSet-Output__1":"#/components/schemas/WorkflowToolSet"}}},"ToolExecution":{"properties":{"taskSupport":{"anyOf":[{"type":"string","enum":["forbidden","optional","required"]},{"type":"null"}],"title":"Tasksupport"}},"additionalProperties":true,"type":"object","title":"ToolExecution","description":"Execution-related properties for a tool."},"TopLogprob":{"properties":{"token":{"type":"string","title":"Token"},"bytes":{"anyOf":[{"items":{"type":"integer"},"type":"array"},{"type":"null"}],"title":"Bytes"},"logprob":{"type":"number","title":"Logprob"}},"additionalProperties":true,"type":"object","required":["token","logprob"],"title":"TopLogprob"},"TraceMetadataValue":{"anyOf":[{"type":"string"},{"type":"boolean"},{"type":"integer"},{"type":"number"},{"items":{"type":"string"},"type":"array"},{"items":{"type":"boolean"},"type":"array"},{"items":{"type":"integer"},"type":"array"},{"items":{"type":"number"},"type":"array"}]},"UninstallSkillResponse":{"properties":{"message":{"type":"string","title":"Message"}},"type":"object","required":["message"],"title":"UninstallSkillResponse","description":"Response from skill uninstall operation."},"UpdateConversationRequest":{"properties":{"title":{"anyOf":[{"type":"string","maxLength":200,"minLength":1},{"type":"null"}],"title":"Title","description":"New conversation title"},"tags":{"anyOf":[{"additionalProperties":{"type":"string"},"type":"object"},{"type":"null"}],"title":"Tags","description":"Key-value tags to set on the conversation. Keys must be lowercase alphanumeric. Values are arbitrary strings up to 256 characters. Replaces all existing tags when provided."}},"type":"object","title":"UpdateConversationRequest","description":"Payload to update conversation metadata."},"UpdateSecretsRequest":{"properties":{"secrets":{"additionalProperties":{"$ref":"#/components/schemas/SecretSource-Input"},"type":"object","title":"Secrets","description":"Dictionary mapping secret keys to values"}},"type":"object","required":["secrets"],"title":"UpdateSecretsRequest","description":"Payload to update secrets in a conversation."},"UpdateSkillResponse":{"properties":{"message":{"type":"string","title":"Message"},"skill":{"$ref":"#/components/schemas/InstalledSkillResponse"}},"type":"object","required":["message","skill"],"title":"UpdateSkillResponse","description":"Response from skill update operation."},"UpdateSkillStateRequest":{"properties":{"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["enabled"],"title":"UpdateSkillStateRequest","description":"Request body for updating skill state (enable/disable)."},"UpdateSkillStateResponse":{"properties":{"name":{"type":"string","title":"Name"},"enabled":{"type":"boolean","title":"Enabled"}},"type":"object","required":["name","enabled"],"title":"UpdateSkillStateResponse","description":"Response from skill state update operation."},"UserRejectObservation":{"properties":{"id":{"type":"string","title":"Id","description":"Unique event id (ULID/UUID)"},"timestamp":{"type":"string","title":"Timestamp","description":"Event timestamp"},"source":{"type":"string","enum":["agent","user","environment","hook"],"title":"Source","default":"environment"},"tool_name":{"type":"string","title":"Tool Name","description":"The tool name that this observation is responding to"},"tool_call_id":{"type":"string","title":"Tool Call Id","description":"The tool call id that this observation is responding to"},"rejection_reason":{"type":"string","title":"Rejection Reason","description":"Reason for rejecting the action","default":"User rejected the action"},"rejection_source":{"type":"string","enum":["user","hook"],"title":"Rejection Source","description":"Source of the rejection: 'user' for confirmation mode rejections, 'hook' for PreToolUse hook blocks","default":"user"},"action_id":{"type":"string","title":"Action Id","description":"The action id that this observation is responding to"},"kind":{"type":"string","const":"UserRejectObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["tool_name","tool_call_id","action_id","kind"],"title":"UserRejectObservation","description":"Observation when an action is rejected by user or hook.\n\nThis event is emitted when:\n- User rejects an action during confirmation mode (rejection_source=\"user\")\n- A PreToolUse hook blocks an action (rejection_source=\"hook\")"},"VSCodeUrlResponse":{"properties":{"url":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Url"}},"type":"object","required":["url"],"title":"VSCodeUrlResponse","description":"Response model for VSCode URL."},"ValidationError":{"properties":{"loc":{"items":{"anyOf":[{"type":"string"},{"type":"integer"}]},"type":"array","title":"Location"},"msg":{"type":"string","title":"Message"},"type":{"type":"string","title":"Error Type"},"input":{"title":"Input"},"ctx":{"type":"object","title":"Context"}},"type":"object","required":["loc","msg","type"],"title":"ValidationError"},"VerifiedModelsResponse":{"properties":{"models":{"additionalProperties":{"items":{"type":"string"},"type":"array"},"type":"object","title":"Models"}},"type":"object","required":["models"],"title":"VerifiedModelsResponse","description":"Response containing verified LLM models organized by provider."},"WebhookSpec":{"properties":{"event_buffer_size":{"type":"integer","minimum":1.0,"title":"Event Buffer Size","description":"The number of events to buffer locally before posting to the webhook","default":5},"base_url":{"type":"string","title":"Base Url","description":"The base URL of the webhook service. Events will be sent to {base_url}/events and conversation info to {base_url}/conversations"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"flush_delay":{"type":"number","exclusiveMinimum":0.0,"title":"Flush Delay","description":"The delay in seconds after which buffered events will be flushed to the webhook, even if the buffer is not full. Timer is reset on each new event.","default":30.0},"num_retries":{"type":"integer","minimum":0.0,"title":"Num Retries","description":"The number of times to retry if the post operation fails","default":3},"retry_delay":{"type":"integer","minimum":0.0,"title":"Retry Delay","description":"The delay between retries","default":5},"max_queue_size":{"type":"integer","minimum":1.0,"title":"Max Queue Size","description":"Upper bound on the number of events buffered for delivery. When the downstream is failing and events are re-queued for retry, the oldest events are dropped past this bound to prevent unbounded memory growth.","default":1000}},"type":"object","required":["base_url"],"title":"WebhookSpec","description":"Spec to create a webhook. All webhook requests use POST method."},"WorkflowAction":{"properties":{"name":{"type":"string","title":"Name","description":"A short name for this workflow run."},"script":{"type":"string","title":"Script","description":"Python workflow script to run. It must define `async def main(wf):` and coordinate work only through the provided `wf` object."},"max_concurrency":{"type":"integer","maximum":64.0,"minimum":1.0,"title":"Max Concurrency","description":"Maximum number of sub-agent tasks to run concurrently. Consider 2–4 for LLM-heavy workflows to avoid hitting API rate limits.","default":8},"kind":{"type":"string","const":"WorkflowAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","script","kind"],"title":"WorkflowAction","description":"Schema for running a Python dynamic workflow script."},"WorkflowActionWithRisk":{"properties":{"name":{"type":"string","title":"Name","description":"A short name for this workflow run."},"script":{"type":"string","title":"Script","description":"Python workflow script to run. It must define `async def main(wf):` and coordinate work only through the provided `wf` object."},"max_concurrency":{"type":"integer","maximum":64.0,"minimum":1.0,"title":"Max Concurrency","description":"Maximum number of sub-agent tasks to run concurrently. Consider 2–4 for LLM-heavy workflows to avoid hitting API rate limits.","default":8},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"WorkflowActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","script","kind"],"title":"WorkflowActionWithRisk"},"WorkflowObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"name":{"type":"string","title":"Name","description":"The workflow name that was executed."},"status":{"type":"string","enum":["completed","error"],"title":"Status","description":"The workflow execution status."},"kind":{"type":"string","const":"WorkflowObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["name","status","kind"],"title":"WorkflowObservation","description":"Observation from a dynamic workflow run."},"WorkflowTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"WorkflowTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"WorkflowTool","description":"Low-level tool for explicit executor injection.\n\nPrefer ``WorkflowToolSet`` for standard SDK auto-create usage.\nUse ``WorkflowTool`` when you need to inject a custom executor\n(e.g., in tests or extensions)."},"WorkflowToolSet":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"WorkflowToolSet","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"WorkflowToolSet","description":"Tool set that creates the dynamic workflow tool."},"WorkspaceItem":{"properties":{"id":{"type":"string","maxLength":4096,"minLength":1,"title":"Id"},"name":{"type":"string","maxLength":256,"minLength":1,"title":"Name"},"path":{"type":"string","maxLength":4096,"minLength":1,"title":"Path"},"parentPath":{"anyOf":[{"type":"string","maxLength":4096},{"type":"null"}],"title":"Parentpath"}},"type":"object","required":["id","name","path"],"title":"WorkspaceItem"},"WorkspaceParentItem":{"properties":{"id":{"type":"string","maxLength":4096,"minLength":1,"title":"Id"},"name":{"type":"string","maxLength":256,"minLength":1,"title":"Name"},"path":{"type":"string","maxLength":4096,"minLength":1,"title":"Path"}},"type":"object","required":["id","name","path"],"title":"WorkspaceParentItem"},"WorkspacesListResponse":{"properties":{"workspaces":{"items":{"$ref":"#/components/schemas/WorkspaceItem"},"type":"array","title":"Workspaces"},"workspaceParents":{"items":{"$ref":"#/components/schemas/WorkspaceParentItem"},"type":"array","title":"Workspaceparents"}},"type":"object","title":"WorkspacesListResponse"},"WriteFileAction":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to write to."},"content":{"type":"string","title":"Content","description":"The content to write to the file."},"kind":{"type":"string","const":"WriteFileAction","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","content","kind"],"title":"WriteFileAction","description":"Schema for write file operation."},"WriteFileActionWithRisk":{"properties":{"file_path":{"type":"string","title":"File Path","description":"The path to the file to write to."},"content":{"type":"string","title":"Content","description":"The content to write to the file."},"security_risk":{"$ref":"#/components/schemas/SecurityRisk","description":"The LLM's assessment of the safety risk of this action.","default":"UNKNOWN"},"kind":{"type":"string","const":"WriteFileActionWithRisk","title":"Kind"}},"additionalProperties":false,"type":"object","required":["file_path","content","kind"],"title":"WriteFileActionWithRisk"},"WriteFileObservation":{"properties":{"content":{"items":{"anyOf":[{"$ref":"#/components/schemas/TextContent"},{"$ref":"#/components/schemas/ImageContent"}]},"type":"array","title":"Content","description":"Content returned from the tool as a list of TextContent/ImageContent objects. When there is an error, it should be written in this field."},"is_error":{"type":"boolean","title":"Is Error","description":"Whether the observation indicates an error","default":false},"file_path":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"File Path","description":"The file path that was written."},"is_new_file":{"type":"boolean","title":"Is New File","description":"Whether a new file was created.","default":false},"old_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Old Content","description":"The previous content of the file (if it existed)."},"new_content":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"New Content","description":"The new content written to the file."},"kind":{"type":"string","const":"WriteFileObservation","title":"Kind"}},"additionalProperties":false,"type":"object","required":["kind"],"title":"WriteFileObservation","description":"Observation from writing a file."},"WriteFileTool":{"properties":{"description":{"type":"string","title":"Description"},"action_type":{"type":"string","title":"Action Type"},"observation_type":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Observation Type"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/openhands__sdk__tool__tool__ToolAnnotations"},{"type":"null"}]},"meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"kind":{"type":"string","const":"WriteFileTool","title":"Kind"},"title":{"type":"string","title":"Title","readOnly":true}},"type":"object","required":["description","action_type","kind","title"],"title":"WriteFileTool","description":"Tool for writing complete file contents."},"_RemoteMCPServerSpec":{"properties":{"type":{"type":"string","enum":["http","shttp","streamable-http","sse"],"title":"Type"},"url":{"type":"string","minLength":1,"title":"Url"},"headers":{"additionalProperties":{"type":"string"},"type":"object","title":"Headers"},"api_key":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Api Key","description":"Bearer token. If provided, sent as 'Authorization: Bearer '."}},"type":"object","required":["type","url"],"title":"_RemoteMCPServerSpec","description":"Remote (HTTP / SSE) MCP server spec."},"_StdioMCPServerSpec":{"properties":{"type":{"type":"string","const":"stdio","title":"Type","default":"stdio"},"command":{"type":"string","minLength":1,"title":"Command","description":"Executable to invoke"},"args":{"items":{"type":"string"},"type":"array","title":"Args"},"env":{"additionalProperties":{"type":"string"},"type":"object","title":"Env"},"cwd":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Cwd"}},"type":"object","required":["command"],"title":"_StdioMCPServerSpec","description":"Stdio (subprocess) MCP server spec.\n\nMirrors the subset of ``fastmcp.mcp_config.StdioMCPServer`` fields the\nOpenHands UI exposes today."},"mcp__types__Tool":{"properties":{"name":{"type":"string","title":"Name"},"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"description":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Description"},"inputSchema":{"additionalProperties":true,"type":"object","title":"Inputschema"},"outputSchema":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Outputschema"},"icons":{"anyOf":[{"items":{"$ref":"#/components/schemas/Icon"},"type":"array"},{"type":"null"}],"title":"Icons"},"annotations":{"anyOf":[{"$ref":"#/components/schemas/mcp__types__ToolAnnotations"},{"type":"null"}]},"_meta":{"anyOf":[{"additionalProperties":true,"type":"object"},{"type":"null"}],"title":"Meta"},"execution":{"anyOf":[{"$ref":"#/components/schemas/ToolExecution"},{"type":"null"}]}},"additionalProperties":true,"type":"object","required":["name","inputSchema"],"title":"Tool","description":"Definition for a tool the client can call."},"mcp__types__ToolAnnotations":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title"},"readOnlyHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Readonlyhint"},"destructiveHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Destructivehint"},"idempotentHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Idempotenthint"},"openWorldHint":{"anyOf":[{"type":"boolean"},{"type":"null"}],"title":"Openworldhint"}},"additionalProperties":true,"type":"object","title":"ToolAnnotations","description":"Additional properties describing a Tool to clients.\n\nNOTE: all properties in ToolAnnotations are **hints**.\nThey are not guaranteed to provide a faithful description of\ntool behavior (including descriptive properties like `title`).\n\nClients should never make tool use decisions based on ToolAnnotations\nreceived from untrusted servers."},"openhands__sdk__tool__spec__Tool":{"properties":{"name":{"type":"string","title":"Name","description":"Name of the tool class, e.g., 'TerminalTool'. Import it from an `openhands.tools.` subpackage.","examples":["TerminalTool","FileEditorTool","TaskTrackerTool"]},"params":{"additionalProperties":true,"type":"object","title":"Params","description":"Parameters for the tool's .create() method, e.g., {'working_dir': '/app'}","examples":[{"working_dir":"/workspace"}]}},"type":"object","required":["name"],"title":"Tool","description":"Defines a tool to be initialized for the agent.\n\nThis is only used in agent-sdk for type schema for server use."},"openhands__sdk__tool__tool__ToolAnnotations":{"properties":{"title":{"anyOf":[{"type":"string"},{"type":"null"}],"title":"Title","description":"A human-readable title for the tool."},"readOnlyHint":{"type":"boolean","title":"Readonlyhint","description":"If true, the tool does not modify its environment. Default: false","default":false},"destructiveHint":{"type":"boolean","title":"Destructivehint","description":"If true, the tool may perform destructive updates to its environment. If false, the tool performs only additive updates. (This property is meaningful only when `readOnlyHint == false`) Default: true","default":true},"idempotentHint":{"type":"boolean","title":"Idempotenthint","description":"If true, calling the tool repeatedly with the same arguments will have no additional effect on the its environment. (This property is meaningful only when `readOnlyHint == false`) Default: false","default":false},"openWorldHint":{"type":"boolean","title":"Openworldhint","description":"If true, this tool may interact with an 'open world' of external entities. If false, the tool's domain of interaction is closed. For example, the world of a web search tool is open, whereas that of a memory tool is not. Default: true","default":true}},"type":"object","title":"openhands.sdk.tool.tool.ToolAnnotations","description":"Annotations to provide hints about the tool's behavior.\n\nBased on Model Context Protocol (MCP) spec:\nhttps://github.com/modelcontextprotocol/modelcontextprotocol/blob/caf3424488b10b4a7b1f8cb634244a450a1f4400/schema/2025-06-18/schema.ts#L838"}},"securitySchemes":{"APIKeyHeader":{"type":"apiKey","in":"header","name":"X-Init-API-Key"}}}} \ No newline at end of file