mirror of
https://github.com/harivansh-afk/sandbox-agent.git
synced 2026-04-15 06:04:43 +00:00
feat: add configuration for model, mode, and thought level (#205)
* feat: add configuration for model, mode, and thought level
* docs: document Claude effort-level filesystem config
* fix: prevent panic on empty modes/thoughtLevels in parse_agent_config
Use `.first()` with safe fallback instead of direct `[0]` index access,
which would panic if the Vec is empty and no default is set.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden session lifecycle and align cli.mdx example with claude.json
- destroySession: wrap session/cancel RPC in try/catch so local cleanup
always succeeds even when the agent is unreachable
- createSession/resumeOrCreateSession: clean up the remote session if
post-creation config calls (setMode/setModel/setThoughtLevel) fail,
preventing leaked orphan sessions
- cli.mdx: fix example output to match current claude.json (model name,
model order, and populated modes)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: harden session lifecycle and align config persistence logic
- resumeOrCreateSession: Remove destroy-on-error for the resume path. Config
errors now propagate without destroying a pre-existing session. The destroy
pattern remains in createSession (where the session is newly created and has
no prior state to preserve).
- setSessionMode fallback: When session/set_mode returns -32601 and the
fallback uses session/set_config_option, now keep modes.currentModeId
in sync with the updated currentValue. Prevents stale cached state in
getModes() when the fallback path is used.
- persistSessionStateFromMethod: Re-read the record from persistence instead
of using a stale pre-await snapshot. Prevents race conditions where
concurrent session/update events (processed by persistSessionStateFromEvent)
are silently overwritten by optimistic updates.
Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
* fix: correct doc examples with valid Codex modes and update stable API list
- Replace invalid Codex mode values ("plan", "build") with valid ones
("auto", "full-access") in agent-sessions.mdx and sdk-overview.mdx
- Update CLAUDE.md stable method enumerations to include new session
config methods (setSessionMode, setSessionModel, etc.)
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: add OpenAPI annotations for process endpoints and fix config persistence race
Add summary/description to all process management endpoint specs and the
not_found error type. Fix hydrateSessionConfigOptions to re-read from
persistence after the network call, and sync mode-category configOptions
on session/update current_mode_update events.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
e7343e14bd
commit
c91791f88d
18 changed files with 1675 additions and 70 deletions
|
|
@ -1,5 +1,6 @@
|
|||
/**
|
||||
* Fetches model/mode lists from agent backends and writes them to resources/.
|
||||
* Fetches model/mode/thought-level lists from agent backends and writes them
|
||||
* to resources/.
|
||||
*
|
||||
* Usage:
|
||||
* npx tsx dump.ts # Dump all agents
|
||||
|
|
@ -10,11 +11,24 @@
|
|||
* Claude — Anthropic API (GET /v1/models?beta=true). Extracts API key from
|
||||
* ANTHROPIC_API_KEY env. Falls back to aliases (default, sonnet, opus, haiku)
|
||||
* on 401/403 or missing credentials.
|
||||
* Modes are hardcoded (discovered by ACP session/set_mode probing).
|
||||
* Claude does not implement session/set_config_option at all.
|
||||
* Codex — Codex app-server JSON-RPC (model/list over stdio, paginated).
|
||||
* Modes and thought levels are hardcoded (discovered from Codex's
|
||||
* ACP session/new configOptions response).
|
||||
* OpenCode — OpenCode HTTP server (GET {base_url}/config/providers, fallback /provider).
|
||||
* Model IDs formatted as {provider_id}/{model_id}.
|
||||
* Model IDs formatted as {provider_id}/{model_id}. Modes hardcoded.
|
||||
* Cursor — `cursor-agent models` CLI command. Parses the text output.
|
||||
*
|
||||
* Derivation of hardcoded values:
|
||||
* When agents don't expose modes/thought levels through their model listing
|
||||
* APIs, we discover them by ACP probing against a running sandbox-agent server:
|
||||
* 1. Create an ACP session via session/new and inspect the configOptions and
|
||||
* modes fields in the response.
|
||||
* 2. Test session/set_mode with candidate mode IDs.
|
||||
* 3. Test session/set_config_option with candidate config IDs and values.
|
||||
* See /tmp/probe-agents.sh or /tmp/probe-agents.ts for example probe scripts.
|
||||
*
|
||||
* Output goes to resources/ alongside this script. These JSON files are committed
|
||||
* to the repo and included in the sandbox-agent binary at compile time via include_str!.
|
||||
*/
|
||||
|
|
@ -37,11 +51,19 @@ interface ModeEntry {
|
|||
description?: string;
|
||||
}
|
||||
|
||||
interface ThoughtLevelEntry {
|
||||
id: string;
|
||||
name: string;
|
||||
description?: string;
|
||||
}
|
||||
|
||||
interface AgentModelList {
|
||||
defaultModel: string;
|
||||
models: ModelEntry[];
|
||||
defaultMode?: string;
|
||||
modes?: ModeEntry[];
|
||||
defaultThoughtLevel?: string;
|
||||
thoughtLevels?: ThoughtLevelEntry[];
|
||||
}
|
||||
|
||||
// ─── CLI ──────────────────────────────────────────────────────────────────────
|
||||
|
|
@ -100,8 +122,13 @@ function writeList(agent: string, list: AgentModelList) {
|
|||
const filePath = path.join(RESOURCES_DIR, `${agent}.json`);
|
||||
fs.writeFileSync(filePath, JSON.stringify(list, null, 2) + "\n");
|
||||
const modeCount = list.modes?.length ?? 0;
|
||||
const thoughtCount = list.thoughtLevels?.length ?? 0;
|
||||
const extras = [
|
||||
modeCount ? `${modeCount} modes` : null,
|
||||
thoughtCount ? `${thoughtCount} thought levels` : null,
|
||||
].filter(Boolean).join(", ");
|
||||
console.log(
|
||||
` Wrote ${list.models.length} models${modeCount ? `, ${modeCount} modes` : ""} to ${filePath} (default: ${list.defaultModel})`
|
||||
` Wrote ${list.models.length} models${extras ? `, ${extras}` : ""} to ${filePath} (default: ${list.defaultModel})`
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -110,14 +137,28 @@ function writeList(agent: string, list: AgentModelList) {
|
|||
const ANTHROPIC_API_URL = "https://api.anthropic.com/v1/models?beta=true";
|
||||
const ANTHROPIC_VERSION = "2023-06-01";
|
||||
|
||||
// Claude v0.20.0 (@zed-industries/claude-agent-acp) returns configOptions and
|
||||
// modes from session/new. Models and modes below match the ACP adapter source.
|
||||
// Note: `opus` is gated by subscription — it may not appear in session/new for
|
||||
// all credentials, but exists in the SDK model list. Thought levels are supported
|
||||
// by the Claude SDK (effort levels: low/medium/high/max for opus-4-6 and
|
||||
// sonnet-4-6) but the ACP adapter does not expose them as configOptions yet.
|
||||
const CLAUDE_FALLBACK: AgentModelList = {
|
||||
defaultModel: "default",
|
||||
models: [
|
||||
{ id: "default", name: "Default (recommended)" },
|
||||
{ id: "opus", name: "Opus" },
|
||||
{ id: "default", name: "Default" },
|
||||
{ id: "sonnet", name: "Sonnet" },
|
||||
{ id: "opus", name: "Opus" },
|
||||
{ id: "haiku", name: "Haiku" },
|
||||
],
|
||||
defaultMode: "default",
|
||||
modes: [
|
||||
{ id: "default", name: "Default" },
|
||||
{ id: "acceptEdits", name: "Accept Edits" },
|
||||
{ id: "plan", name: "Plan" },
|
||||
{ id: "dontAsk", name: "Don't Ask" },
|
||||
{ id: "bypassPermissions", name: "Bypass Permissions" },
|
||||
],
|
||||
};
|
||||
|
||||
async function dumpClaude() {
|
||||
|
|
@ -185,6 +226,9 @@ async function dumpClaude() {
|
|||
writeList("claude", {
|
||||
defaultModel: defaultModel ?? models[0]?.id ?? "default",
|
||||
models,
|
||||
// Modes from Claude ACP adapter v0.20.0 session/new response.
|
||||
defaultMode: "default",
|
||||
modes: CLAUDE_FALLBACK.modes,
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -277,9 +321,26 @@ async function dumpCodex() {
|
|||
|
||||
models.sort((a, b) => a.id.localeCompare(b.id));
|
||||
|
||||
// Codex modes and thought levels come from its ACP session/new configOptions
|
||||
// response (category: "mode" and category: "thought_level"). The model/list
|
||||
// RPC only returns models, so modes/thought levels are hardcoded here based
|
||||
// on probing Codex's session/new response.
|
||||
writeList("codex", {
|
||||
defaultModel: defaultModel ?? models[0]?.id ?? "",
|
||||
models,
|
||||
defaultMode: "read-only",
|
||||
modes: [
|
||||
{ id: "read-only", name: "Read Only", description: "Codex can read files in the current workspace. Approval is required to edit files or access the internet." },
|
||||
{ id: "auto", name: "Default", description: "Codex can read and edit files in the current workspace, and run commands. Approval is required to access the internet or edit other files." },
|
||||
{ id: "full-access", name: "Full Access", description: "Codex can edit files outside this workspace and access the internet without asking for approval." },
|
||||
],
|
||||
defaultThoughtLevel: "high",
|
||||
thoughtLevels: [
|
||||
{ id: "low", name: "Low", description: "Fast responses with lighter reasoning" },
|
||||
{ id: "medium", name: "Medium", description: "Balances speed and reasoning depth for everyday tasks" },
|
||||
{ id: "high", name: "High", description: "Greater reasoning depth for complex problems" },
|
||||
{ id: "xhigh", name: "Xhigh", description: "Extra high reasoning depth for complex problems" },
|
||||
],
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,19 +3,42 @@
|
|||
"models": [
|
||||
{
|
||||
"id": "default",
|
||||
"name": "Default (recommended)"
|
||||
},
|
||||
{
|
||||
"id": "opus",
|
||||
"name": "Opus"
|
||||
"name": "Default"
|
||||
},
|
||||
{
|
||||
"id": "sonnet",
|
||||
"name": "Sonnet"
|
||||
},
|
||||
{
|
||||
"id": "opus",
|
||||
"name": "Opus"
|
||||
},
|
||||
{
|
||||
"id": "haiku",
|
||||
"name": "Haiku"
|
||||
}
|
||||
],
|
||||
"defaultMode": "default",
|
||||
"modes": [
|
||||
{
|
||||
"id": "default",
|
||||
"name": "Default"
|
||||
},
|
||||
{
|
||||
"id": "acceptEdits",
|
||||
"name": "Accept Edits"
|
||||
},
|
||||
{
|
||||
"id": "plan",
|
||||
"name": "Plan"
|
||||
},
|
||||
{
|
||||
"id": "dontAsk",
|
||||
"name": "Don't Ask"
|
||||
},
|
||||
{
|
||||
"id": "bypassPermissions",
|
||||
"name": "Bypass Permissions"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,24 +2,62 @@
|
|||
"defaultModel": "gpt-5.3-codex",
|
||||
"models": [
|
||||
{
|
||||
"id": "gpt-5.1-codex-max",
|
||||
"name": "gpt-5.1-codex-max"
|
||||
"id": "gpt-5.3-codex",
|
||||
"name": "gpt-5.3-codex"
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.1-codex-mini",
|
||||
"name": "gpt-5.1-codex-mini"
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.2",
|
||||
"name": "gpt-5.2"
|
||||
"id": "gpt-5.3-codex-spark",
|
||||
"name": "GPT-5.3-Codex-Spark"
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.2-codex",
|
||||
"name": "gpt-5.2-codex"
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.3-codex",
|
||||
"name": "gpt-5.3-codex"
|
||||
"id": "gpt-5.1-codex-max",
|
||||
"name": "gpt-5.1-codex-max"
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.2",
|
||||
"name": "gpt-5.2"
|
||||
},
|
||||
{
|
||||
"id": "gpt-5.1-codex-mini",
|
||||
"name": "gpt-5.1-codex-mini"
|
||||
}
|
||||
],
|
||||
"defaultMode": "read-only",
|
||||
"modes": [
|
||||
{
|
||||
"id": "read-only",
|
||||
"name": "Read Only"
|
||||
},
|
||||
{
|
||||
"id": "auto",
|
||||
"name": "Default"
|
||||
},
|
||||
{
|
||||
"id": "full-access",
|
||||
"name": "Full Access"
|
||||
}
|
||||
],
|
||||
"defaultThoughtLevel": "high",
|
||||
"thoughtLevels": [
|
||||
{
|
||||
"id": "low",
|
||||
"name": "Low"
|
||||
},
|
||||
{
|
||||
"id": "medium",
|
||||
"name": "Medium"
|
||||
},
|
||||
{
|
||||
"id": "high",
|
||||
"name": "High"
|
||||
},
|
||||
{
|
||||
"id": "xhigh",
|
||||
"name": "Xhigh"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue