@getpaseo/server 0.1.69 → 0.1.70
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/server/client/daemon-client-runtime-metrics.js.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +33 -0
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +37 -1
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +8 -0
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +54 -5
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-response-loop.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +15 -2
- package/dist/server/server/agent/agent-sdk-types.d.ts.map +1 -1
- package/dist/server/server/agent/agent-stream-coalescer.d.ts +1 -1
- package/dist/server/server/agent/agent-stream-coalescer.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.js +1 -1
- package/dist/server/server/agent/agent-timeline-store.js.map +1 -1
- package/dist/server/server/agent/create-agent-mode.d.ts +14 -0
- package/dist/server/server/agent/create-agent-mode.d.ts.map +1 -0
- package/dist/server/server/agent/create-agent-mode.js +23 -0
- package/dist/server/server/agent/create-agent-mode.js.map +1 -0
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +36 -12
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/mcp-shared.d.ts +6 -2
- package/dist/server/server/agent/mcp-shared.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-shared.js +12 -5
- package/dist/server/server/agent/mcp-shared.js.map +1 -1
- package/dist/server/server/agent/pcm16-resampler.js.map +1 -1
- package/dist/server/server/agent/prompt-attachments.d.ts.map +1 -1
- package/dist/server/server/agent/prompt-attachments.js +2 -0
- package/dist/server/server/agent/prompt-attachments.js.map +1 -1
- package/dist/server/server/agent/provider-launch-config.js.map +1 -1
- package/dist/server/server/agent/provider-manifest.d.ts +4 -1
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
- package/dist/server/server/agent/provider-manifest.js +11 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -1
- package/dist/server/server/agent/provider-registry.d.ts.map +1 -1
- package/dist/server/server/agent/provider-registry.js +8 -3
- package/dist/server/server/agent/provider-registry.js.map +1 -1
- package/dist/server/server/agent/provider-snapshot-manager.js.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts +2 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.js +35 -17
- package/dist/server/server/agent/providers/acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/{claude-agent.d.ts → claude/agent.d.ts} +9 -6
- package/dist/server/server/agent/providers/claude/agent.d.ts.map +1 -0
- package/dist/server/server/agent/providers/{claude-agent.js → claude/agent.js} +170 -152
- package/dist/server/server/agent/providers/claude/agent.js.map +1 -0
- package/dist/server/server/agent/providers/claude/{claude-models.d.ts → models.d.ts} +1 -1
- package/dist/server/server/agent/providers/claude/models.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/{claude-models.js → models.js} +8 -1
- package/dist/server/server/agent/providers/claude/models.js.map +1 -0
- package/dist/server/server/agent/providers/claude/query.d.ts +14 -0
- package/dist/server/server/agent/providers/claude/query.d.ts.map +1 -0
- package/dist/server/server/agent/providers/claude/query.js +84 -0
- package/dist/server/server/agent/providers/claude/query.js.map +1 -0
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +11 -2
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.js +408 -91
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/diagnostic-utils.d.ts.map +1 -1
- package/dist/server/server/agent/providers/diagnostic-utils.js +4 -0
- package/dist/server/server/agent/providers/diagnostic-utils.js.map +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/generic-acp-agent.js +0 -3
- package/dist/server/server/agent/providers/generic-acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.js +6 -2
- package/dist/server/server/agent/providers/mock-load-test-agent.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +32 -27
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/provider-image-output.d.ts +20 -0
- package/dist/server/server/agent/providers/provider-image-output.d.ts.map +1 -0
- package/dist/server/server/agent/providers/provider-image-output.js +51 -0
- package/dist/server/server/agent/providers/provider-image-output.js.map +1 -0
- package/dist/server/server/agent/providers/provider-runner.d.ts +3 -3
- package/dist/server/server/agent/providers/provider-runner.d.ts.map +1 -1
- package/dist/server/server/agent/providers/test-utils/session-stream-adapter.js.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +7 -7
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js +12 -18
- package/dist/server/server/agent/providers/tool-call-detail-primitives.js.map +1 -1
- package/dist/server/server/agent/stt-manager.d.ts +1 -0
- package/dist/server/server/agent/stt-manager.d.ts.map +1 -1
- package/dist/server/server/agent/stt-manager.js +3 -0
- package/dist/server/server/agent/stt-manager.js.map +1 -1
- package/dist/server/server/agent/tool-name-normalization.js.map +1 -1
- package/dist/server/server/agent/tts-manager.js.map +1 -1
- package/dist/server/server/bootstrap.d.ts +1 -0
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +3 -1
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/config.d.ts +1 -0
- package/dist/server/server/config.d.ts.map +1 -1
- package/dist/server/server/config.js +7 -1
- package/dist/server/server/config.js.map +1 -1
- package/dist/server/server/connection-offer.d.ts +1 -0
- package/dist/server/server/connection-offer.d.ts.map +1 -1
- package/dist/server/server/daemon-config-store.d.ts.map +1 -1
- package/dist/server/server/daemon-config-store.js +2 -6
- package/dist/server/server/daemon-config-store.js.map +1 -1
- package/dist/server/server/daemon-keypair.js.map +1 -1
- package/dist/server/server/daemon-worker.js +3 -0
- package/dist/server/server/daemon-worker.js.map +1 -1
- package/dist/server/server/editor-targets.js.map +1 -1
- package/dist/server/server/json-utils.js.map +1 -1
- package/dist/server/server/logger.js.map +1 -1
- package/dist/server/server/loop/rpc-schemas.d.ts +68 -0
- package/dist/server/server/loop/rpc-schemas.d.ts.map +1 -1
- package/dist/server/server/loop/rpc-schemas.js +4 -0
- package/dist/server/server/loop/rpc-schemas.js.map +1 -1
- package/dist/server/server/loop-service.d.ts +8 -0
- package/dist/server/server/loop-service.d.ts.map +1 -1
- package/dist/server/server/loop-service.js +11 -2
- package/dist/server/server/loop-service.js.map +1 -1
- package/dist/server/server/package-version.d.ts +12 -0
- package/dist/server/server/package-version.d.ts.map +1 -1
- package/dist/server/server/package-version.js +13 -1
- package/dist/server/server/package-version.js.map +1 -1
- package/dist/server/server/pairing-offer.d.ts +1 -0
- package/dist/server/server/pairing-offer.d.ts.map +1 -1
- package/dist/server/server/pairing-offer.js +2 -1
- package/dist/server/server/pairing-offer.js.map +1 -1
- package/dist/server/server/pairing-qr.js +1 -1
- package/dist/server/server/pairing-qr.js.map +1 -1
- package/dist/server/server/paseo-env.d.ts +7 -3
- package/dist/server/server/paseo-env.d.ts.map +1 -1
- package/dist/server/server/paseo-env.js +16 -33
- package/dist/server/server/paseo-env.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts +9 -0
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +1 -0
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/persistence-hooks.js.map +1 -1
- package/dist/server/server/pid-lock.d.ts +21 -4
- package/dist/server/server/pid-lock.d.ts.map +1 -1
- package/dist/server/server/pid-lock.js +30 -8
- package/dist/server/server/pid-lock.js.map +1 -1
- package/dist/server/server/relay-transport.d.ts +2 -1
- package/dist/server/server/relay-transport.d.ts.map +1 -1
- package/dist/server/server/relay-transport.js +8 -5
- package/dist/server/server/relay-transport.js.map +1 -1
- package/dist/server/server/schedule/rpc-schemas.d.ts +1136 -0
- package/dist/server/server/schedule/rpc-schemas.d.ts.map +1 -1
- package/dist/server/server/schedule/rpc-schemas.js +39 -0
- package/dist/server/server/schedule/rpc-schemas.js.map +1 -1
- package/dist/server/server/schedule/service.d.ts +3 -1
- package/dist/server/server/schedule/service.d.ts.map +1 -1
- package/dist/server/server/schedule/service.js +92 -5
- package/dist/server/server/schedule/service.js.map +1 -1
- package/dist/server/server/schedule/types.d.ts +16 -0
- package/dist/server/server/schedule/types.d.ts.map +1 -1
- package/dist/server/server/script-health-monitor.js.map +1 -1
- package/dist/server/server/session.d.ts +3 -4
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +160 -120
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/speech/audio.js.map +1 -1
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js +52 -52
- package/dist/server/server/speech/providers/local/pocket/pocket-tts-onnx.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js +9 -3
- package/dist/server/server/speech/providers/local/sherpa/model-catalog.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.d.ts.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js +12 -10
- package/dist/server/server/speech/providers/local/sherpa/model-downloader.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js +2 -2
- package/dist/server/server/speech/providers/local/sherpa/sherpa-realtime-session.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-stt.js.map +1 -1
- package/dist/server/server/speech/providers/local/sherpa/sherpa-tts.js.map +1 -1
- package/dist/server/server/voice/voice-turn-controller.d.ts +16 -13
- package/dist/server/server/voice/voice-turn-controller.d.ts.map +1 -1
- package/dist/server/server/voice/voice-turn-controller.js +303 -71
- package/dist/server/server/voice/voice-turn-controller.js.map +1 -1
- package/dist/server/server/voice-config.js +1 -1
- package/dist/server/server/voice-config.js.map +1 -1
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/server/workspace-directory.d.ts.map +1 -1
- package/dist/server/server/workspace-directory.js +4 -2
- package/dist/server/server/workspace-directory.js.map +1 -1
- package/dist/server/server/workspace-git-metadata.d.ts.map +1 -1
- package/dist/server/server/workspace-git-metadata.js +12 -5
- package/dist/server/server/workspace-git-metadata.js.map +1 -1
- package/dist/server/server/workspace-git-service.d.ts +2 -0
- package/dist/server/server/workspace-git-service.d.ts.map +1 -1
- package/dist/server/server/workspace-git-service.js +49 -1
- package/dist/server/server/workspace-git-service.js.map +1 -1
- package/dist/server/server/workspace-registry-model.d.ts.map +1 -1
- package/dist/server/server/workspace-registry-model.js +10 -3
- package/dist/server/server/workspace-registry-model.js.map +1 -1
- package/dist/server/server/worktree-session.js +1 -1
- package/dist/server/server/worktree-session.js.map +1 -1
- package/dist/server/services/github-service.d.ts.map +1 -1
- package/dist/server/services/github-service.js +9 -2
- package/dist/server/services/github-service.js.map +1 -1
- package/dist/server/shared/connection-offer.d.ts +10 -0
- package/dist/server/shared/connection-offer.d.ts.map +1 -1
- package/dist/server/shared/connection-offer.js +1 -0
- package/dist/server/shared/connection-offer.js.map +1 -1
- package/dist/server/shared/daemon-endpoints.d.ts +4 -0
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -1
- package/dist/server/shared/daemon-endpoints.js +6 -1
- package/dist/server/shared/daemon-endpoints.js.map +1 -1
- package/dist/server/shared/error-utils.d.ts +11 -0
- package/dist/server/shared/error-utils.d.ts.map +1 -0
- package/dist/server/shared/error-utils.js +27 -0
- package/dist/server/shared/error-utils.js.map +1 -0
- package/dist/server/shared/messages.d.ts +6475 -2265
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +5 -1
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/shared/tool-call-display.d.ts.map +1 -1
- package/dist/server/shared/tool-call-display.js +2 -0
- package/dist/server/shared/tool-call-display.js.map +1 -1
- package/dist/server/terminal/terminal-manager.d.ts +2 -1
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -1
- package/dist/server/terminal/terminal-manager.js +2 -1
- package/dist/server/terminal/terminal-manager.js.map +1 -1
- package/dist/server/terminal/terminal-output-coalescer.js.map +1 -1
- package/dist/server/terminal/terminal-session-controller.d.ts.map +1 -1
- package/dist/server/terminal/terminal-session-controller.js +2 -0
- package/dist/server/terminal/terminal-session-controller.js.map +1 -1
- package/dist/server/terminal/terminal.d.ts +1 -1
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +53 -8
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/terminal/worker-terminal-manager.js.map +1 -1
- package/dist/server/utils/checkout-git.d.ts.map +1 -1
- package/dist/server/utils/checkout-git.js +67 -11
- package/dist/server/utils/checkout-git.js.map +1 -1
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/server/utils/executable.d.ts +2 -1
- package/dist/server/utils/executable.d.ts.map +1 -1
- package/dist/server/utils/executable.js +50 -51
- package/dist/server/utils/executable.js.map +1 -1
- package/dist/server/utils/paseo-config-file.d.ts +1 -1
- package/dist/server/utils/paseo-config-file.d.ts.map +1 -1
- package/dist/server/utils/spawn.d.ts +2 -0
- package/dist/server/utils/spawn.d.ts.map +1 -1
- package/dist/server/utils/spawn.js +2 -1
- package/dist/server/utils/spawn.js.map +1 -1
- package/dist/server/utils/tree-kill.d.ts +18 -0
- package/dist/server/utils/tree-kill.d.ts.map +1 -0
- package/dist/server/utils/{process-tree.js → tree-kill.js} +14 -33
- package/dist/server/utils/tree-kill.js.map +1 -0
- package/dist/server/utils/worktree.js.map +1 -1
- package/dist/src/server/agent/provider-launch-config.js.map +1 -1
- package/dist/src/server/agent/provider-manifest.js +11 -0
- package/dist/src/server/agent/provider-manifest.js.map +1 -1
- package/dist/src/server/loop/rpc-schemas.js +4 -0
- package/dist/src/server/loop/rpc-schemas.js.map +1 -1
- package/dist/src/server/paseo-env.js +16 -33
- package/dist/src/server/paseo-env.js.map +1 -1
- package/dist/src/server/persisted-config.js +1 -0
- package/dist/src/server/persisted-config.js.map +1 -1
- package/dist/src/server/pid-lock.js +30 -8
- package/dist/src/server/pid-lock.js.map +1 -1
- package/dist/src/server/schedule/rpc-schemas.js +39 -0
- package/dist/src/server/schedule/rpc-schemas.js.map +1 -1
- package/dist/src/shared/messages.js +5 -1
- package/dist/src/shared/messages.js.map +1 -1
- package/dist/src/utils/executable.js +50 -51
- package/dist/src/utils/executable.js.map +1 -1
- package/dist/src/utils/spawn.js +2 -1
- package/dist/src/utils/spawn.js.map +1 -1
- package/package.json +5 -4
- package/dist/server/server/agent/providers/claude/claude-models.d.ts.map +0 -1
- package/dist/server/server/agent/providers/claude/claude-models.js.map +0 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +0 -1
- package/dist/server/server/agent/providers/claude-agent.js.map +0 -1
- package/dist/server/server/voice/fixed-duration-pcm-ring-buffer.d.ts +0 -16
- package/dist/server/server/voice/fixed-duration-pcm-ring-buffer.d.ts.map +0 -1
- package/dist/server/server/voice/fixed-duration-pcm-ring-buffer.js +0 -35
- package/dist/server/server/voice/fixed-duration-pcm-ring-buffer.js.map +0 -1
- package/dist/server/utils/process-tree.d.ts +0 -25
- package/dist/server/utils/process-tree.d.ts.map +0 -1
- package/dist/server/utils/process-tree.js.map +0 -1
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { homedir } from "node:os";
|
|
2
2
|
import { randomUUID } from "node:crypto";
|
|
3
|
+
import * as fsSync from "node:fs";
|
|
3
4
|
import fs from "node:fs/promises";
|
|
4
5
|
import os from "node:os";
|
|
5
6
|
import path from "node:path";
|
|
@@ -10,12 +11,21 @@ import { curateAgentActivity } from "../activity-curator.js";
|
|
|
10
11
|
import { mapCodexRolloutToolCall, mapCodexToolCallFromThreadItem, } from "./codex/tool-call-mapper.js";
|
|
11
12
|
import { createProviderEnv, createProviderEnvSpec, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
|
|
12
13
|
import { findExecutable, isCommandAvailable } from "../../../utils/executable.js";
|
|
13
|
-
import {
|
|
14
|
+
import { terminateWithTreeKill } from "../../../utils/tree-kill.js";
|
|
14
15
|
import { spawnProcess } from "../../../utils/spawn.js";
|
|
15
16
|
import { extractCodexTerminalSessionId, nonEmptyString } from "./tool-call-mapper-utils.js";
|
|
16
17
|
import { buildCodexFeatures, codexModelSupportsFastMode } from "./codex-feature-definitions.js";
|
|
18
|
+
import { renderProviderImageOutputAsAssistantMarkdown, } from "./provider-image-output.js";
|
|
17
19
|
import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
|
|
18
20
|
import { runProviderTurn } from "./provider-runner.js";
|
|
21
|
+
function assertChildWithPipes(child) {
|
|
22
|
+
if (!child.stdin || !child.stdout || !child.stderr) {
|
|
23
|
+
throw new Error("Child process did not expose stdio pipes");
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
function isRecord(value) {
|
|
27
|
+
return value != null && typeof value === "object" && !Array.isArray(value);
|
|
28
|
+
}
|
|
19
29
|
const DEFAULT_TIMEOUT_MS = 14 * 24 * 60 * 60 * 1000;
|
|
20
30
|
const TURN_START_TIMEOUT_MS = 90 * 1000;
|
|
21
31
|
const INTERRUPT_TIMEOUT_MS = 2000;
|
|
@@ -24,7 +34,52 @@ const APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS = 1000;
|
|
|
24
34
|
const CODEX_PROVIDER = "codex";
|
|
25
35
|
const CODEX_IMAGE_ATTACHMENT_DIR = "paseo-attachments";
|
|
26
36
|
const ASSISTANT_MESSAGE_BOUNDARY_MARKDOWN = "\n\n---\n\n";
|
|
37
|
+
const CODEX_TOOL_THREAD_ITEM_TYPES = new Set([
|
|
38
|
+
"commandExecution",
|
|
39
|
+
"fileChange",
|
|
40
|
+
"mcpToolCall",
|
|
41
|
+
"webSearch",
|
|
42
|
+
"collabAgentToolCall",
|
|
43
|
+
]);
|
|
27
44
|
const CODEX_PLAN_IMPLEMENTATION_PROMPT_PREFIX = "The user approved the plan. Implement it now. Do not restate or revise the plan unless blocked.";
|
|
45
|
+
// Codex's experimental `goals` feature ships in 0.128.0+. Older binaries reject
|
|
46
|
+
// `--enable goals` at launch, so we gate by version and silently skip the flag
|
|
47
|
+
// (and the /goal slash command) when the binary is too old.
|
|
48
|
+
const CODEX_GOALS_MIN_VERSION = [0, 128, 0];
|
|
49
|
+
function parseCodexVersion(versionOutput) {
|
|
50
|
+
const match = versionOutput.match(/(\d+)\.(\d+)\.(\d+)/);
|
|
51
|
+
if (!match)
|
|
52
|
+
return null;
|
|
53
|
+
return [Number(match[1]), Number(match[2]), Number(match[3])];
|
|
54
|
+
}
|
|
55
|
+
function codexVersionAtLeast(versionOutput, min) {
|
|
56
|
+
const parsed = parseCodexVersion(versionOutput);
|
|
57
|
+
if (!parsed)
|
|
58
|
+
return false;
|
|
59
|
+
for (let i = 0; i < 3; i += 1) {
|
|
60
|
+
if (parsed[i] > min[i])
|
|
61
|
+
return true;
|
|
62
|
+
if (parsed[i] < min[i])
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
function parseGoalSubcommand(args) {
|
|
68
|
+
const trimmed = (args ?? "").trim();
|
|
69
|
+
if (!trimmed)
|
|
70
|
+
return { kind: "usage" };
|
|
71
|
+
const lower = trimmed.toLowerCase();
|
|
72
|
+
if (lower === "pause")
|
|
73
|
+
return { kind: "pause" };
|
|
74
|
+
if (lower === "resume")
|
|
75
|
+
return { kind: "resume" };
|
|
76
|
+
if (lower === "clear")
|
|
77
|
+
return { kind: "clear" };
|
|
78
|
+
return { kind: "set", objective: trimmed };
|
|
79
|
+
}
|
|
80
|
+
function formatOutOfBandStatusMessage(text) {
|
|
81
|
+
return `${text.replace(/\n+$/u, "")}\n\n`;
|
|
82
|
+
}
|
|
28
83
|
const CODEX_APP_SERVER_CAPABILITIES = {
|
|
29
84
|
supportsStreaming: true,
|
|
30
85
|
supportsSessionPersistence: true,
|
|
@@ -397,8 +452,50 @@ function toCodexMcpConfig(config) {
|
|
|
397
452
|
url: config.url,
|
|
398
453
|
http_headers: config.headers,
|
|
399
454
|
};
|
|
455
|
+
default: {
|
|
456
|
+
const _exhaustive = config;
|
|
457
|
+
throw new Error(`Unsupported MCP config type: ${String(_exhaustive.type)}`);
|
|
458
|
+
}
|
|
400
459
|
}
|
|
401
460
|
}
|
|
461
|
+
function isJsonRpcResponse(msg) {
|
|
462
|
+
if (!isRecord(msg))
|
|
463
|
+
return false;
|
|
464
|
+
if (typeof msg.id !== "number")
|
|
465
|
+
return false;
|
|
466
|
+
return msg.result !== undefined || !!msg.error;
|
|
467
|
+
}
|
|
468
|
+
function isJsonRpcRequest(msg) {
|
|
469
|
+
if (!isRecord(msg))
|
|
470
|
+
return false;
|
|
471
|
+
return typeof msg.id === "number" && typeof msg.method === "string";
|
|
472
|
+
}
|
|
473
|
+
function isJsonRpcNotification(msg) {
|
|
474
|
+
if (!isRecord(msg))
|
|
475
|
+
return false;
|
|
476
|
+
return typeof msg.method === "string" && typeof msg.id !== "number";
|
|
477
|
+
}
|
|
478
|
+
function toObjectRecord(value) {
|
|
479
|
+
return isRecord(value) ? value : undefined;
|
|
480
|
+
}
|
|
481
|
+
const CodexModelListResponseSchema = z.object({
|
|
482
|
+
data: z
|
|
483
|
+
.array(z.object({
|
|
484
|
+
id: z.string(),
|
|
485
|
+
displayName: z.string().optional(),
|
|
486
|
+
description: z.string().optional(),
|
|
487
|
+
isDefault: z.boolean().optional(),
|
|
488
|
+
model: z.string().optional(),
|
|
489
|
+
defaultReasoningEffort: z.string().optional(),
|
|
490
|
+
supportedReasoningEfforts: z
|
|
491
|
+
.array(z.object({
|
|
492
|
+
reasoningEffort: z.string().optional(),
|
|
493
|
+
description: z.string().optional(),
|
|
494
|
+
}))
|
|
495
|
+
.optional(),
|
|
496
|
+
}))
|
|
497
|
+
.optional(),
|
|
498
|
+
});
|
|
402
499
|
class CodexAppServerClient {
|
|
403
500
|
constructor(child, logger) {
|
|
404
501
|
this.child = child;
|
|
@@ -490,7 +587,7 @@ class CodexAppServerClient {
|
|
|
490
587
|
catch {
|
|
491
588
|
// ignore
|
|
492
589
|
}
|
|
493
|
-
const result = await
|
|
590
|
+
const result = await terminateWithTreeKill(this.child, {
|
|
494
591
|
gracefulTimeoutMs: APP_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS,
|
|
495
592
|
forceTimeoutMs: APP_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS,
|
|
496
593
|
onForceSignal: () => {
|
|
@@ -504,33 +601,30 @@ class CodexAppServerClient {
|
|
|
504
601
|
async handleLine(line) {
|
|
505
602
|
if (!line.trim())
|
|
506
603
|
return;
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
}
|
|
511
|
-
catch (error) {
|
|
512
|
-
this.logger.warn({ error, line }, "Failed to parse Codex app-server JSON");
|
|
604
|
+
const raw = JSON.parse(line);
|
|
605
|
+
if (!isRecord(raw)) {
|
|
606
|
+
this.logger.warn({ line }, "Parsed JSON is not an object");
|
|
513
607
|
return;
|
|
514
608
|
}
|
|
515
|
-
if (
|
|
516
|
-
const id =
|
|
517
|
-
if (
|
|
609
|
+
if (isJsonRpcResponse(raw)) {
|
|
610
|
+
const id = raw.id;
|
|
611
|
+
if (raw.result !== undefined || raw.error) {
|
|
518
612
|
const pending = this.pending.get(id);
|
|
519
613
|
if (!pending)
|
|
520
614
|
return;
|
|
521
615
|
clearTimeout(pending.timer);
|
|
522
616
|
this.pending.delete(id);
|
|
523
|
-
if (
|
|
524
|
-
pending.reject(new Error(
|
|
617
|
+
if (raw.error) {
|
|
618
|
+
pending.reject(new Error(raw.error.message ?? "Unknown error"));
|
|
525
619
|
}
|
|
526
620
|
else {
|
|
527
|
-
pending.resolve(
|
|
621
|
+
pending.resolve(raw.result);
|
|
528
622
|
}
|
|
529
623
|
return;
|
|
530
624
|
}
|
|
531
625
|
// Server-initiated request
|
|
532
|
-
if (
|
|
533
|
-
const request =
|
|
626
|
+
if (isJsonRpcRequest(raw)) {
|
|
627
|
+
const request = raw;
|
|
534
628
|
const handler = this.requestHandlers.get(request.method);
|
|
535
629
|
try {
|
|
536
630
|
const result = handler ? await handler(request.params) : {};
|
|
@@ -545,22 +639,22 @@ class CodexAppServerClient {
|
|
|
545
639
|
return;
|
|
546
640
|
}
|
|
547
641
|
}
|
|
548
|
-
if (
|
|
549
|
-
|
|
550
|
-
this.notificationHandler?.(notification.method, notification.params);
|
|
642
|
+
if (isJsonRpcNotification(raw)) {
|
|
643
|
+
this.notificationHandler?.(raw.method, raw.params);
|
|
551
644
|
}
|
|
552
645
|
}
|
|
553
646
|
}
|
|
554
647
|
function toAgentUsage(tokenUsage) {
|
|
555
|
-
|
|
648
|
+
const usage = toObjectRecord(tokenUsage);
|
|
649
|
+
if (!usage)
|
|
556
650
|
return undefined;
|
|
557
|
-
const
|
|
651
|
+
const last = toObjectRecord(usage.last);
|
|
558
652
|
const contextWindowMaxTokens = firstPositiveFiniteNumber(usage.model_context_window, usage.modelContextWindow);
|
|
559
|
-
const contextWindowUsedTokens = firstPositiveFiniteNumber(
|
|
653
|
+
const contextWindowUsedTokens = firstPositiveFiniteNumber(last?.total_tokens, last?.totalTokens);
|
|
560
654
|
return {
|
|
561
|
-
inputTokens:
|
|
562
|
-
cachedInputTokens:
|
|
563
|
-
outputTokens:
|
|
655
|
+
inputTokens: typeof last?.inputTokens === "number" ? last.inputTokens : undefined,
|
|
656
|
+
cachedInputTokens: typeof last?.cachedInputTokens === "number" ? last.cachedInputTokens : undefined,
|
|
657
|
+
outputTokens: typeof last?.outputTokens === "number" ? last.outputTokens : undefined,
|
|
564
658
|
...(contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {}),
|
|
565
659
|
...(contextWindowUsedTokens !== undefined ? { contextWindowUsedTokens } : {}),
|
|
566
660
|
};
|
|
@@ -570,11 +664,12 @@ function extractUserText(content) {
|
|
|
570
664
|
return null;
|
|
571
665
|
const parts = [];
|
|
572
666
|
for (const item of content) {
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
667
|
+
const record = toObjectRecord(item);
|
|
668
|
+
if (!record) {
|
|
669
|
+
continue;
|
|
670
|
+
}
|
|
671
|
+
if (record.type === "text" && typeof record.text === "string") {
|
|
672
|
+
parts.push(record.text);
|
|
578
673
|
}
|
|
579
674
|
}
|
|
580
675
|
return parts.length > 0 ? parts.join("\n") : null;
|
|
@@ -661,10 +756,10 @@ function normalizeCodexQuestionPrompts(raw) {
|
|
|
661
756
|
}
|
|
662
757
|
const questions = [];
|
|
663
758
|
for (const item of raw) {
|
|
664
|
-
|
|
759
|
+
const record = toObjectRecord(item);
|
|
760
|
+
if (!record) {
|
|
665
761
|
continue;
|
|
666
762
|
}
|
|
667
|
-
const record = item;
|
|
668
763
|
const id = nonEmptyString(record.id);
|
|
669
764
|
const header = nonEmptyString(record.header);
|
|
670
765
|
const question = nonEmptyString(record.question);
|
|
@@ -673,10 +768,10 @@ function normalizeCodexQuestionPrompts(raw) {
|
|
|
673
768
|
}
|
|
674
769
|
const options = Array.isArray(record.options)
|
|
675
770
|
? record.options.flatMap((option) => {
|
|
676
|
-
|
|
771
|
+
const optionRecord = toObjectRecord(option);
|
|
772
|
+
if (!optionRecord) {
|
|
677
773
|
return [];
|
|
678
774
|
}
|
|
679
|
-
const optionRecord = option;
|
|
680
775
|
const label = nonEmptyString(optionRecord.label);
|
|
681
776
|
if (!label) {
|
|
682
777
|
return [];
|
|
@@ -771,10 +866,9 @@ function mapCodexQuestionResponseByHeader(params) {
|
|
|
771
866
|
if (params.response.behavior !== "allow") {
|
|
772
867
|
return null;
|
|
773
868
|
}
|
|
774
|
-
const
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
if (!answersRecord || typeof answersRecord !== "object") {
|
|
869
|
+
const updatedInputRecord = toObjectRecord(params.response.updatedInput);
|
|
870
|
+
const answersRecord = toObjectRecord(updatedInputRecord?.answers);
|
|
871
|
+
if (!answersRecord) {
|
|
778
872
|
return null;
|
|
779
873
|
}
|
|
780
874
|
const answers = {};
|
|
@@ -800,10 +894,10 @@ function mapCodexQuestionResponseByHeader(params) {
|
|
|
800
894
|
return Object.keys(answers).length > 0 ? answers : null;
|
|
801
895
|
}
|
|
802
896
|
function extractPatchLikeText(value) {
|
|
803
|
-
|
|
897
|
+
const record = toObjectRecord(value);
|
|
898
|
+
if (!record) {
|
|
804
899
|
return undefined;
|
|
805
900
|
}
|
|
806
|
-
const record = value;
|
|
807
901
|
const candidates = [
|
|
808
902
|
record.diff,
|
|
809
903
|
record.patch,
|
|
@@ -842,6 +936,10 @@ function normalizeCodexThreadItemType(rawType) {
|
|
|
842
936
|
return "webSearch";
|
|
843
937
|
case "CollabAgentToolCall":
|
|
844
938
|
return "collabAgentToolCall";
|
|
939
|
+
case "ImageView":
|
|
940
|
+
return "imageView";
|
|
941
|
+
case "ImageGeneration":
|
|
942
|
+
return "imageGeneration";
|
|
845
943
|
default:
|
|
846
944
|
return rawType;
|
|
847
945
|
}
|
|
@@ -900,10 +998,10 @@ function parseCodexPatchChanges(changes) {
|
|
|
900
998
|
if (Array.isArray(changes)) {
|
|
901
999
|
return changes
|
|
902
1000
|
.map((entry) => {
|
|
903
|
-
|
|
1001
|
+
const record = toObjectRecord(entry);
|
|
1002
|
+
if (!record) {
|
|
904
1003
|
return null;
|
|
905
1004
|
}
|
|
906
|
-
const record = entry;
|
|
907
1005
|
const pathValue = resolvePathFromRecord(record);
|
|
908
1006
|
if (!pathValue) {
|
|
909
1007
|
return null;
|
|
@@ -918,7 +1016,10 @@ function parseCodexPatchChanges(changes) {
|
|
|
918
1016
|
})
|
|
919
1017
|
.filter((entry) => entry !== null);
|
|
920
1018
|
}
|
|
921
|
-
const recordChanges = changes;
|
|
1019
|
+
const recordChanges = toObjectRecord(changes);
|
|
1020
|
+
if (!recordChanges) {
|
|
1021
|
+
return [];
|
|
1022
|
+
}
|
|
922
1023
|
const directPathValue = resolvePathFromRecord(recordChanges);
|
|
923
1024
|
if (directPathValue) {
|
|
924
1025
|
return [
|
|
@@ -1118,16 +1219,81 @@ function mapCodexThreadUserMessageItem(normalizedItem, includeUserMessage) {
|
|
|
1118
1219
|
const text = extractUserText(normalizedItem.content) ?? "";
|
|
1119
1220
|
return { type: "user_message", text };
|
|
1120
1221
|
}
|
|
1222
|
+
function firstStringField(record, fields) {
|
|
1223
|
+
for (const field of fields) {
|
|
1224
|
+
const value = record[field];
|
|
1225
|
+
if (typeof value === "string") {
|
|
1226
|
+
return value;
|
|
1227
|
+
}
|
|
1228
|
+
}
|
|
1229
|
+
return null;
|
|
1230
|
+
}
|
|
1231
|
+
function codexImageOutputFromResult(result) {
|
|
1232
|
+
if (typeof result === "string") {
|
|
1233
|
+
const trimmed = result.trim();
|
|
1234
|
+
if (trimmed.toLowerCase().startsWith("data:image/") ||
|
|
1235
|
+
(/^[A-Za-z0-9+/]+={0,2}$/.test(trimmed) && trimmed.length > 64)) {
|
|
1236
|
+
return { data: trimmed };
|
|
1237
|
+
}
|
|
1238
|
+
return { url: trimmed };
|
|
1239
|
+
}
|
|
1240
|
+
const resultRecord = toObjectRecord(result);
|
|
1241
|
+
if (!resultRecord) {
|
|
1242
|
+
return null;
|
|
1243
|
+
}
|
|
1244
|
+
return {
|
|
1245
|
+
path: firstStringField(resultRecord, ["path", "savedPath", "saved_path"]),
|
|
1246
|
+
url: firstStringField(resultRecord, ["url"]),
|
|
1247
|
+
data: firstStringField(resultRecord, ["data"]),
|
|
1248
|
+
mimeType: firstStringField(resultRecord, ["mimeType", "mime_type"]),
|
|
1249
|
+
};
|
|
1250
|
+
}
|
|
1251
|
+
function writeImageAttachmentSync(mimeType, data) {
|
|
1252
|
+
const attachmentsDir = path.join(os.tmpdir(), CODEX_IMAGE_ATTACHMENT_DIR);
|
|
1253
|
+
fsSync.mkdirSync(attachmentsDir, { recursive: true });
|
|
1254
|
+
const normalized = normalizeImageData(mimeType, data);
|
|
1255
|
+
const extension = getImageExtension(normalized.mimeType);
|
|
1256
|
+
const filename = `${randomUUID()}.${extension}`;
|
|
1257
|
+
const filePath = path.join(attachmentsDir, filename);
|
|
1258
|
+
fsSync.writeFileSync(filePath, Buffer.from(normalized.data, "base64"));
|
|
1259
|
+
return filePath;
|
|
1260
|
+
}
|
|
1261
|
+
function materializeCodexImageOutput(image) {
|
|
1262
|
+
return {
|
|
1263
|
+
path: writeImageAttachmentSync(image.mimeType ?? "image/png", image.data),
|
|
1264
|
+
};
|
|
1265
|
+
}
|
|
1266
|
+
function mapCodexThreadImageItem(normalizedType, normalizedItem) {
|
|
1267
|
+
if (normalizedType === "imageView") {
|
|
1268
|
+
return renderProviderImageOutputAsAssistantMarkdown({
|
|
1269
|
+
path: firstStringField(normalizedItem, ["path"]),
|
|
1270
|
+
});
|
|
1271
|
+
}
|
|
1272
|
+
const savedPath = firstStringField(normalizedItem, ["savedPath", "saved_path"]);
|
|
1273
|
+
const result = codexImageOutputFromResult(normalizedItem.result);
|
|
1274
|
+
return renderProviderImageOutputAsAssistantMarkdown({
|
|
1275
|
+
path: savedPath ?? result?.path ?? null,
|
|
1276
|
+
url: result?.url ?? null,
|
|
1277
|
+
data: result?.data ?? null,
|
|
1278
|
+
mimeType: result?.mimeType ?? null,
|
|
1279
|
+
}, { materialize: materializeCodexImageOutput });
|
|
1280
|
+
}
|
|
1121
1281
|
function threadItemToTimeline(item, options) {
|
|
1122
|
-
|
|
1282
|
+
const itemRecord = toObjectRecord(item);
|
|
1283
|
+
if (!itemRecord)
|
|
1123
1284
|
return null;
|
|
1124
|
-
const itemRecord = item;
|
|
1125
1285
|
const includeUserMessage = options?.includeUserMessage ?? true;
|
|
1126
1286
|
const cwd = options?.cwd ?? null;
|
|
1127
1287
|
const normalizedType = normalizeCodexThreadItemType(typeof itemRecord.type === "string" ? itemRecord.type : undefined);
|
|
1128
1288
|
const normalizedItem = normalizedType && normalizedType !== itemRecord.type
|
|
1129
1289
|
? { ...itemRecord, type: normalizedType }
|
|
1130
1290
|
: itemRecord;
|
|
1291
|
+
if (normalizedType === "imageView" || normalizedType === "imageGeneration") {
|
|
1292
|
+
return mapCodexThreadImageItem(normalizedType, normalizedItem);
|
|
1293
|
+
}
|
|
1294
|
+
if (normalizedType && CODEX_TOOL_THREAD_ITEM_TYPES.has(normalizedType)) {
|
|
1295
|
+
return mapCodexToolCallFromThreadItem(normalizedItem, { cwd });
|
|
1296
|
+
}
|
|
1131
1297
|
switch (normalizedType) {
|
|
1132
1298
|
case "userMessage":
|
|
1133
1299
|
return mapCodexThreadUserMessageItem(normalizedItem, includeUserMessage);
|
|
@@ -1140,12 +1306,6 @@ function threadItemToTimeline(item, options) {
|
|
|
1140
1306
|
return mapCodexThreadPlanItem(normalizedItem);
|
|
1141
1307
|
case "reasoning":
|
|
1142
1308
|
return mapCodexThreadReasoningItem(normalizedItem);
|
|
1143
|
-
case "commandExecution":
|
|
1144
|
-
case "fileChange":
|
|
1145
|
-
case "mcpToolCall":
|
|
1146
|
-
case "webSearch":
|
|
1147
|
-
case "collabAgentToolCall":
|
|
1148
|
-
return mapCodexToolCallFromThreadItem(normalizedItem, { cwd });
|
|
1149
1309
|
default:
|
|
1150
1310
|
return null;
|
|
1151
1311
|
}
|
|
@@ -1816,10 +1976,13 @@ async function writeImageAttachment(mimeType, data) {
|
|
|
1816
1976
|
async function readCodexConfiguredDefaults(client, logger) {
|
|
1817
1977
|
let savedConfigDefaults = {};
|
|
1818
1978
|
try {
|
|
1819
|
-
const response = (await client.request("getUserSavedConfig", {}));
|
|
1979
|
+
const response = toObjectRecord(await client.request("getUserSavedConfig", {}));
|
|
1980
|
+
const config = toObjectRecord(response?.config);
|
|
1981
|
+
const modelValue = typeof config?.model === "string" ? config.model : undefined;
|
|
1982
|
+
const thinkingOptionValue = typeof config?.modelReasoningEffort === "string" ? config.modelReasoningEffort : null;
|
|
1820
1983
|
savedConfigDefaults = {
|
|
1821
|
-
model: normalizeCodexModelId(
|
|
1822
|
-
thinkingOptionId: normalizeCodexThinkingOptionId(
|
|
1984
|
+
model: normalizeCodexModelId(modelValue),
|
|
1985
|
+
thinkingOptionId: normalizeCodexThinkingOptionId(thinkingOptionValue),
|
|
1823
1986
|
};
|
|
1824
1987
|
}
|
|
1825
1988
|
catch (error) {
|
|
@@ -1830,10 +1993,13 @@ async function readCodexConfiguredDefaults(client, logger) {
|
|
|
1830
1993
|
}
|
|
1831
1994
|
let configReadDefaults = {};
|
|
1832
1995
|
try {
|
|
1833
|
-
const response = (await client.request("config/read", {}));
|
|
1996
|
+
const response = toObjectRecord(await client.request("config/read", {}));
|
|
1997
|
+
const config = toObjectRecord(response?.config);
|
|
1998
|
+
const modelValue = typeof config?.model === "string" ? config.model : undefined;
|
|
1999
|
+
const thinkingOptionValue = typeof config?.model_reasoning_effort === "string" ? config.model_reasoning_effort : null;
|
|
1834
2000
|
configReadDefaults = {
|
|
1835
|
-
model: normalizeCodexModelId(
|
|
1836
|
-
thinkingOptionId: normalizeCodexThinkingOptionId(
|
|
2001
|
+
model: normalizeCodexModelId(modelValue),
|
|
2002
|
+
thinkingOptionId: normalizeCodexThinkingOptionId(thinkingOptionValue),
|
|
1837
2003
|
};
|
|
1838
2004
|
}
|
|
1839
2005
|
catch (error) {
|
|
@@ -1905,11 +2071,12 @@ function buildCodexAppServerInitializeParams() {
|
|
|
1905
2071
|
};
|
|
1906
2072
|
}
|
|
1907
2073
|
class CodexAppServerAgentSession {
|
|
1908
|
-
constructor(config, resumeHandle, logger, spawnAppServer, deps = {}, ephemeral = false) {
|
|
2074
|
+
constructor(config, resumeHandle, logger, spawnAppServer, deps = {}, ephemeral = false, goalsEnabled = false) {
|
|
1909
2075
|
this.resumeHandle = resumeHandle;
|
|
1910
2076
|
this.spawnAppServer = spawnAppServer;
|
|
1911
2077
|
this.deps = deps;
|
|
1912
2078
|
this.ephemeral = ephemeral;
|
|
2079
|
+
this.goalsEnabled = goalsEnabled;
|
|
1913
2080
|
this.provider = CODEX_PROVIDER;
|
|
1914
2081
|
this.capabilities = CODEX_APP_SERVER_CAPABILITIES;
|
|
1915
2082
|
this.currentThreadId = null;
|
|
@@ -1999,15 +2166,20 @@ class CodexAppServerAgentSession {
|
|
|
1999
2166
|
if (!this.client)
|
|
2000
2167
|
return;
|
|
2001
2168
|
try {
|
|
2002
|
-
const response = (await this.client.request("collaborationMode/list", {}));
|
|
2169
|
+
const response = toObjectRecord(await this.client.request("collaborationMode/list", {}));
|
|
2003
2170
|
const data = Array.isArray(response?.data) ? response.data : [];
|
|
2004
|
-
this.collaborationModes = data.map((entry) =>
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2171
|
+
this.collaborationModes = data.map((entry) => {
|
|
2172
|
+
const record = toObjectRecord(entry);
|
|
2173
|
+
return {
|
|
2174
|
+
name: typeof record?.name === "string" ? record.name : "",
|
|
2175
|
+
mode: typeof record?.mode === "string" ? record.mode : null,
|
|
2176
|
+
model: typeof record?.model === "string" ? record.model : null,
|
|
2177
|
+
reasoning_effort: typeof record?.reasoning_effort === "string" ? record.reasoning_effort : null,
|
|
2178
|
+
developer_instructions: typeof record?.developer_instructions === "string"
|
|
2179
|
+
? record.developer_instructions
|
|
2180
|
+
: null,
|
|
2181
|
+
};
|
|
2182
|
+
});
|
|
2011
2183
|
}
|
|
2012
2184
|
catch (error) {
|
|
2013
2185
|
this.logger.trace({ error }, "Failed to load collaboration modes");
|
|
@@ -2019,22 +2191,22 @@ class CodexAppServerAgentSession {
|
|
|
2019
2191
|
if (!this.client)
|
|
2020
2192
|
return;
|
|
2021
2193
|
try {
|
|
2022
|
-
const response = (await this.client.request("skills/list", {
|
|
2194
|
+
const response = toObjectRecord(await this.client.request("skills/list", {
|
|
2023
2195
|
cwd: [this.config.cwd],
|
|
2024
2196
|
}));
|
|
2025
2197
|
const entries = Array.isArray(response?.data) ? response.data : [];
|
|
2026
2198
|
const skills = [];
|
|
2027
2199
|
for (const entry of entries) {
|
|
2028
|
-
const
|
|
2029
|
-
|
|
2030
|
-
: [];
|
|
2200
|
+
const entryRecord = toObjectRecord(entry);
|
|
2201
|
+
const list = Array.isArray(entryRecord?.skills) ? entryRecord.skills : [];
|
|
2031
2202
|
for (const skill of list) {
|
|
2032
|
-
|
|
2203
|
+
const skillRecord = toObjectRecord(skill);
|
|
2204
|
+
if (typeof skillRecord?.name !== "string" || typeof skillRecord?.path !== "string")
|
|
2033
2205
|
continue;
|
|
2034
2206
|
skills.push({
|
|
2035
|
-
name:
|
|
2036
|
-
description: resolveSkillDescription(
|
|
2037
|
-
path:
|
|
2207
|
+
name: skillRecord.name,
|
|
2208
|
+
description: resolveSkillDescription(skillRecord),
|
|
2209
|
+
path: skillRecord.path,
|
|
2038
2210
|
});
|
|
2039
2211
|
}
|
|
2040
2212
|
}
|
|
@@ -2183,7 +2355,7 @@ class CodexAppServerAgentSession {
|
|
|
2183
2355
|
if (!this.client || !this.currentThreadId)
|
|
2184
2356
|
return;
|
|
2185
2357
|
try {
|
|
2186
|
-
const loaded = (await this.client.request("thread/loaded/list", {}));
|
|
2358
|
+
const loaded = toObjectRecord(await this.client.request("thread/loaded/list", {}));
|
|
2187
2359
|
const ids = Array.isArray(loaded?.data) ? loaded.data : [];
|
|
2188
2360
|
if (ids.includes(this.currentThreadId)) {
|
|
2189
2361
|
return;
|
|
@@ -2622,7 +2794,86 @@ class CodexAppServerAgentSession {
|
|
|
2622
2794
|
const fallbackSkills = appServerSkills.length === 0
|
|
2623
2795
|
? await listCodexSkills(this.config.cwd, this.deps.workspaceGitService)
|
|
2624
2796
|
: [];
|
|
2625
|
-
|
|
2797
|
+
const builtin = [];
|
|
2798
|
+
if (this.goalsEnabled) {
|
|
2799
|
+
builtin.push({
|
|
2800
|
+
name: "goal",
|
|
2801
|
+
description: "Set, pause, resume, or clear the agent's goal",
|
|
2802
|
+
argumentHint: "[<objective>|pause|resume|clear]",
|
|
2803
|
+
});
|
|
2804
|
+
}
|
|
2805
|
+
return [...builtin, ...appServerSkills, ...fallbackSkills, ...prompts].sort((a, b) => a.name.localeCompare(b.name));
|
|
2806
|
+
}
|
|
2807
|
+
tryHandleOutOfBand(prompt) {
|
|
2808
|
+
if (!this.goalsEnabled)
|
|
2809
|
+
return null;
|
|
2810
|
+
if (typeof prompt !== "string")
|
|
2811
|
+
return null;
|
|
2812
|
+
const parsed = this.parseSlashCommandInput(prompt);
|
|
2813
|
+
if (!parsed || parsed.commandName !== "goal")
|
|
2814
|
+
return null;
|
|
2815
|
+
const subcommand = parseGoalSubcommand(parsed.args);
|
|
2816
|
+
return {
|
|
2817
|
+
run: async ({ emit }) => {
|
|
2818
|
+
const text = formatOutOfBandStatusMessage(await this.executeGoalSubcommand(subcommand));
|
|
2819
|
+
emit({
|
|
2820
|
+
type: "timeline",
|
|
2821
|
+
provider: CODEX_PROVIDER,
|
|
2822
|
+
item: { type: "assistant_message", text },
|
|
2823
|
+
});
|
|
2824
|
+
},
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
async executeGoalSubcommand(subcommand) {
|
|
2828
|
+
if (subcommand.kind === "usage") {
|
|
2829
|
+
return "Usage: /goal <objective>|pause|resume|clear";
|
|
2830
|
+
}
|
|
2831
|
+
try {
|
|
2832
|
+
await this.connect();
|
|
2833
|
+
if (this.currentThreadId) {
|
|
2834
|
+
await this.ensureThreadLoaded();
|
|
2835
|
+
}
|
|
2836
|
+
else {
|
|
2837
|
+
await this.ensureThread();
|
|
2838
|
+
}
|
|
2839
|
+
if (!this.client || !this.currentThreadId) {
|
|
2840
|
+
throw new Error("Codex thread is not available");
|
|
2841
|
+
}
|
|
2842
|
+
switch (subcommand.kind) {
|
|
2843
|
+
case "set": {
|
|
2844
|
+
await this.client.request("thread/goal/set", {
|
|
2845
|
+
threadId: this.currentThreadId,
|
|
2846
|
+
objective: subcommand.objective,
|
|
2847
|
+
status: "active",
|
|
2848
|
+
});
|
|
2849
|
+
return `Goal set: ${subcommand.objective}`;
|
|
2850
|
+
}
|
|
2851
|
+
case "pause": {
|
|
2852
|
+
await this.client.request("thread/goal/set", {
|
|
2853
|
+
threadId: this.currentThreadId,
|
|
2854
|
+
status: "paused",
|
|
2855
|
+
});
|
|
2856
|
+
return "Goal paused.";
|
|
2857
|
+
}
|
|
2858
|
+
case "resume": {
|
|
2859
|
+
await this.client.request("thread/goal/set", {
|
|
2860
|
+
threadId: this.currentThreadId,
|
|
2861
|
+
status: "active",
|
|
2862
|
+
});
|
|
2863
|
+
return "Goal resumed.";
|
|
2864
|
+
}
|
|
2865
|
+
case "clear": {
|
|
2866
|
+
await this.client.request("thread/goal/clear", {
|
|
2867
|
+
threadId: this.currentThreadId,
|
|
2868
|
+
});
|
|
2869
|
+
return "Goal cleared.";
|
|
2870
|
+
}
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
catch (error) {
|
|
2874
|
+
const message = error instanceof Error ? error.message : "unknown error";
|
|
2875
|
+
return `Failed to update goal: ${message}`;
|
|
2876
|
+
}
|
|
2626
2877
|
}
|
|
2627
2878
|
async resolveModelAndThinking() {
|
|
2628
2879
|
if (!this.client) {
|
|
@@ -2641,8 +2892,20 @@ class CodexAppServerAgentSession {
|
|
|
2641
2892
|
thinkingOptionId = configuredDefaults.thinkingOptionId;
|
|
2642
2893
|
}
|
|
2643
2894
|
if (!model || !thinkingOptionId) {
|
|
2644
|
-
const modelResponse = (await this.client.request("model/list", {}));
|
|
2645
|
-
const
|
|
2895
|
+
const modelResponse = toObjectRecord(await this.client.request("model/list", {}));
|
|
2896
|
+
const modelData = Array.isArray(modelResponse?.data) ? modelResponse.data : [];
|
|
2897
|
+
const models = modelData
|
|
2898
|
+
.map((m) => {
|
|
2899
|
+
const record = toObjectRecord(m);
|
|
2900
|
+
return {
|
|
2901
|
+
id: typeof record?.id === "string" ? record.id : "",
|
|
2902
|
+
isDefault: !!record?.isDefault,
|
|
2903
|
+
defaultReasoningEffort: typeof record?.defaultReasoningEffort === "string"
|
|
2904
|
+
? record.defaultReasoningEffort
|
|
2905
|
+
: undefined,
|
|
2906
|
+
};
|
|
2907
|
+
})
|
|
2908
|
+
.filter((m) => m.id);
|
|
2646
2909
|
const defaultModel = models.find((m) => m.isDefault) ?? models[0];
|
|
2647
2910
|
if (!defaultModel) {
|
|
2648
2911
|
throw new Error("No models available from Codex app-server");
|
|
@@ -2672,7 +2935,7 @@ class CodexAppServerAgentSession {
|
|
|
2672
2935
|
const approvalPolicy = this.config.approvalPolicy ?? preset.approvalPolicy;
|
|
2673
2936
|
const sandbox = this.config.sandboxMode ?? preset.sandbox;
|
|
2674
2937
|
const innerConfig = this.buildCodexInnerConfig();
|
|
2675
|
-
const
|
|
2938
|
+
const rawResponse = await this.client.request("thread/start", {
|
|
2676
2939
|
model,
|
|
2677
2940
|
cwd: this.config.cwd ?? null,
|
|
2678
2941
|
approvalPolicy,
|
|
@@ -2682,8 +2945,10 @@ class CodexAppServerAgentSession {
|
|
|
2682
2945
|
: {}),
|
|
2683
2946
|
...(innerConfig ? { config: innerConfig } : {}),
|
|
2684
2947
|
...(this.ephemeral ? { ephemeral: true } : {}),
|
|
2685
|
-
})
|
|
2686
|
-
const
|
|
2948
|
+
});
|
|
2949
|
+
const response = toObjectRecord(rawResponse);
|
|
2950
|
+
const threadRecord = toObjectRecord(response?.thread);
|
|
2951
|
+
const threadId = typeof threadRecord?.id === "string" ? threadRecord.id : undefined;
|
|
2687
2952
|
if (!threadId) {
|
|
2688
2953
|
throw new Error("Codex app-server did not return thread id");
|
|
2689
2954
|
}
|
|
@@ -3367,7 +3632,16 @@ class CodexAppServerAgentSession {
|
|
|
3367
3632
|
}, "Codex edit tool call is missing diff/content fields");
|
|
3368
3633
|
}
|
|
3369
3634
|
handleCommandApprovalRequest(params) {
|
|
3370
|
-
const parsed =
|
|
3635
|
+
const parsed = z
|
|
3636
|
+
.object({
|
|
3637
|
+
itemId: z.string(),
|
|
3638
|
+
threadId: z.string(),
|
|
3639
|
+
turnId: z.string(),
|
|
3640
|
+
command: z.string().nullable().optional(),
|
|
3641
|
+
cwd: z.string().nullable().optional(),
|
|
3642
|
+
reason: z.string().nullable().optional(),
|
|
3643
|
+
})
|
|
3644
|
+
.parse(params);
|
|
3371
3645
|
const commandPreview = mapCodexExecNotificationToToolCall({
|
|
3372
3646
|
callId: parsed.itemId,
|
|
3373
3647
|
command: parsed.command,
|
|
@@ -3408,7 +3682,14 @@ class CodexAppServerAgentSession {
|
|
|
3408
3682
|
});
|
|
3409
3683
|
}
|
|
3410
3684
|
handleFileChangeApprovalRequest(params) {
|
|
3411
|
-
const parsed =
|
|
3685
|
+
const parsed = z
|
|
3686
|
+
.object({
|
|
3687
|
+
itemId: z.string(),
|
|
3688
|
+
threadId: z.string(),
|
|
3689
|
+
turnId: z.string(),
|
|
3690
|
+
reason: z.string().nullable().optional(),
|
|
3691
|
+
})
|
|
3692
|
+
.parse(params);
|
|
3412
3693
|
const requestId = `permission-${parsed.itemId}`;
|
|
3413
3694
|
const request = {
|
|
3414
3695
|
id: requestId,
|
|
@@ -3437,7 +3718,14 @@ class CodexAppServerAgentSession {
|
|
|
3437
3718
|
});
|
|
3438
3719
|
}
|
|
3439
3720
|
handleToolApprovalRequest(params) {
|
|
3440
|
-
const parsed =
|
|
3721
|
+
const parsed = z
|
|
3722
|
+
.object({
|
|
3723
|
+
itemId: z.string(),
|
|
3724
|
+
threadId: z.string(),
|
|
3725
|
+
turnId: z.string(),
|
|
3726
|
+
questions: z.array(z.unknown()),
|
|
3727
|
+
})
|
|
3728
|
+
.parse(params);
|
|
3441
3729
|
const requestId = `permission-${parsed.itemId}`;
|
|
3442
3730
|
const questions = normalizeCodexQuestionPrompts(parsed.questions);
|
|
3443
3731
|
const request = {
|
|
@@ -3487,13 +3775,37 @@ export class CodexAppServerAgentClient {
|
|
|
3487
3775
|
this.deps = deps;
|
|
3488
3776
|
this.provider = CODEX_PROVIDER;
|
|
3489
3777
|
this.capabilities = CODEX_APP_SERVER_CAPABILITIES;
|
|
3778
|
+
this.goalsEnabledPromise = null;
|
|
3490
3779
|
}
|
|
3491
|
-
|
|
3780
|
+
resolveGoalsEnabled() {
|
|
3781
|
+
if (!this.goalsEnabledPromise) {
|
|
3782
|
+
this.goalsEnabledPromise = (async () => {
|
|
3783
|
+
try {
|
|
3784
|
+
const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
|
|
3785
|
+
const versionOutput = await resolveBinaryVersion(launchPrefix.command);
|
|
3786
|
+
const enabled = codexVersionAtLeast(versionOutput, CODEX_GOALS_MIN_VERSION);
|
|
3787
|
+
this.logger.trace({ versionOutput, enabled }, "Resolved codex goals feature gate");
|
|
3788
|
+
return enabled;
|
|
3789
|
+
}
|
|
3790
|
+
catch (error) {
|
|
3791
|
+
this.logger.warn({ err: error }, "Failed to probe codex version for goals gate");
|
|
3792
|
+
return false;
|
|
3793
|
+
}
|
|
3794
|
+
})();
|
|
3795
|
+
}
|
|
3796
|
+
return this.goalsEnabledPromise;
|
|
3797
|
+
}
|
|
3798
|
+
async spawnAppServer(launchEnv, options) {
|
|
3492
3799
|
const launchPrefix = await resolveCodexLaunchPrefix(this.runtimeSettings);
|
|
3800
|
+
const args = [...launchPrefix.args, "app-server"];
|
|
3801
|
+
if (options?.goalsEnabled) {
|
|
3802
|
+
args.push("--enable", "goals");
|
|
3803
|
+
}
|
|
3493
3804
|
this.logger.trace({
|
|
3494
3805
|
launchPrefix,
|
|
3806
|
+
goalsEnabled: options?.goalsEnabled === true,
|
|
3495
3807
|
}, "Spawning Codex app server");
|
|
3496
|
-
|
|
3808
|
+
const child = spawnProcess(launchPrefix.command, args, {
|
|
3497
3809
|
detached: process.platform !== "win32",
|
|
3498
3810
|
stdio: ["pipe", "pipe", "pipe"],
|
|
3499
3811
|
...createProviderEnvSpec({
|
|
@@ -3501,10 +3813,13 @@ export class CodexAppServerAgentClient {
|
|
|
3501
3813
|
overlays: [launchEnv],
|
|
3502
3814
|
}),
|
|
3503
3815
|
});
|
|
3816
|
+
assertChildWithPipes(child);
|
|
3817
|
+
return child;
|
|
3504
3818
|
}
|
|
3505
3819
|
async createSession(config, launchContext, options) {
|
|
3506
3820
|
const sessionConfig = { ...config, provider: CODEX_PROVIDER };
|
|
3507
|
-
const
|
|
3821
|
+
const goalsEnabled = await this.resolveGoalsEnabled();
|
|
3822
|
+
const session = new CodexAppServerAgentSession(sessionConfig, null, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled }), this.deps, options?.persistSession === false, goalsEnabled);
|
|
3508
3823
|
await session.connect();
|
|
3509
3824
|
return session;
|
|
3510
3825
|
}
|
|
@@ -3516,7 +3831,8 @@ export class CodexAppServerAgentClient {
|
|
|
3516
3831
|
provider: CODEX_PROVIDER,
|
|
3517
3832
|
cwd: overrides?.cwd ?? storedConfig.cwd ?? process.cwd(),
|
|
3518
3833
|
};
|
|
3519
|
-
const
|
|
3834
|
+
const goalsEnabled = await this.resolveGoalsEnabled();
|
|
3835
|
+
const session = new CodexAppServerAgentSession(merged, handle, this.logger, () => this.spawnAppServer(launchContext?.env, { goalsEnabled }), this.deps, false, goalsEnabled);
|
|
3520
3836
|
await session.connect();
|
|
3521
3837
|
return session;
|
|
3522
3838
|
}
|
|
@@ -3527,7 +3843,7 @@ export class CodexAppServerAgentClient {
|
|
|
3527
3843
|
await client.request("initialize", buildCodexAppServerInitializeParams());
|
|
3528
3844
|
client.notify("initialized", {});
|
|
3529
3845
|
const limit = options?.limit ?? 20;
|
|
3530
|
-
const response = (await client.request("thread/list", { limit }));
|
|
3846
|
+
const response = toObjectRecord(await client.request("thread/list", { limit }));
|
|
3531
3847
|
const threads = Array.isArray(response?.data) ? response.data : [];
|
|
3532
3848
|
const descriptors = await Promise.all(threads.slice(0, limit).map(async (thread) => {
|
|
3533
3849
|
const threadId = typeof thread.id === "string" ? thread.id : "";
|
|
@@ -3581,8 +3897,9 @@ export class CodexAppServerAgentClient {
|
|
|
3581
3897
|
try {
|
|
3582
3898
|
await client.request("initialize", buildCodexAppServerInitializeParams());
|
|
3583
3899
|
client.notify("initialized", {});
|
|
3584
|
-
const
|
|
3585
|
-
const
|
|
3900
|
+
const rawResponse = await client.request("model/list", {});
|
|
3901
|
+
const parsedResponse = CodexModelListResponseSchema.safeParse(rawResponse);
|
|
3902
|
+
const models = parsedResponse.success ? (parsedResponse.data.data ?? []) : [];
|
|
3586
3903
|
const configuredDefaults = await readCodexConfiguredDefaults(client, this.logger);
|
|
3587
3904
|
const configuredDefaultModelId = configuredDefaults.model;
|
|
3588
3905
|
const configuredDefaultThinkingOptionId = configuredDefaults.thinkingOptionId;
|