@getpaseo/server 0.1.63 → 0.1.65
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-transport-types.d.ts +2 -0
- package/dist/server/client/daemon-client-transport-types.d.ts.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.d.ts +2 -1
- package/dist/server/client/daemon-client-websocket-transport.d.ts.map +1 -1
- package/dist/server/client/daemon-client-websocket-transport.js +4 -4
- package/dist/server/client/daemon-client-websocket-transport.js.map +1 -1
- package/dist/server/client/daemon-client.d.ts +30 -20
- package/dist/server/client/daemon-client.d.ts.map +1 -1
- package/dist/server/client/daemon-client.js +206 -98
- package/dist/server/client/daemon-client.js.map +1 -1
- package/dist/server/client/terminal-stream-router.d.ts +24 -0
- package/dist/server/client/terminal-stream-router.d.ts.map +1 -0
- package/dist/server/client/terminal-stream-router.js +100 -0
- package/dist/server/client/terminal-stream-router.js.map +1 -0
- package/dist/server/server/agent/activity-curator.d.ts +6 -3
- package/dist/server/server/agent/activity-curator.d.ts.map +1 -1
- package/dist/server/server/agent/activity-curator.js +45 -138
- package/dist/server/server/agent/activity-curator.js.map +1 -1
- package/dist/server/server/agent/agent-manager.d.ts +3 -14
- package/dist/server/server/agent/agent-manager.d.ts.map +1 -1
- package/dist/server/server/agent/agent-manager.js +75 -140
- package/dist/server/server/agent/agent-manager.js.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.d.ts +0 -5
- package/dist/server/server/agent/agent-metadata-generator.d.ts.map +1 -1
- package/dist/server/server/agent/agent-metadata-generator.js +3 -93
- package/dist/server/server/agent/agent-metadata-generator.js.map +1 -1
- package/dist/server/server/agent/agent-sdk-types.d.ts +15 -1
- 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-stream-coalescer.js +1 -1
- package/dist/server/server/agent/agent-stream-coalescer.js.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.d.ts.map +1 -1
- package/dist/server/server/agent/agent-timeline-store.js +29 -32
- package/dist/server/server/agent/agent-timeline-store.js.map +1 -1
- package/dist/server/server/agent/foreground-run-state.d.ts +50 -0
- package/dist/server/server/agent/foreground-run-state.d.ts.map +1 -0
- package/dist/server/server/agent/foreground-run-state.js +162 -0
- package/dist/server/server/agent/foreground-run-state.js.map +1 -0
- package/dist/server/server/agent/mcp-server.d.ts +5 -3
- package/dist/server/server/agent/mcp-server.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-server.js +110 -99
- package/dist/server/server/agent/mcp-server.js.map +1 -1
- package/dist/server/server/agent/mcp-shared.d.ts.map +1 -1
- package/dist/server/server/agent/mcp-shared.js +7 -1
- package/dist/server/server/agent/mcp-shared.js.map +1 -1
- package/dist/server/server/agent/prompt-attachments.d.ts +4 -3
- package/dist/server/server/agent/prompt-attachments.d.ts.map +1 -1
- package/dist/server/server/agent/prompt-attachments.js +43 -4
- package/dist/server/server/agent/prompt-attachments.js.map +1 -1
- package/dist/server/server/agent/provider-manifest.d.ts.map +1 -1
- package/dist/server/server/agent/provider-manifest.js +7 -0
- package/dist/server/server/agent/provider-manifest.js.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts +38 -1
- package/dist/server/server/agent/providers/acp-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/acp-agent.js +257 -140
- package/dist/server/server/agent/providers/acp-agent.js.map +1 -1
- package/dist/server/server/agent/providers/claude/sidechain-tracker.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/sidechain-tracker.js +1 -1
- package/dist/server/server/agent/providers/claude/sidechain-tracker.js.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js +68 -198
- package/dist/server/server/agent/providers/claude/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/claude-agent.js +52 -102
- package/dist/server/server/agent/providers/claude-agent.js.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js +125 -141
- package/dist/server/server/agent/providers/codex/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/codex-app-server-agent.d.ts +36 -6
- 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 +374 -219
- package/dist/server/server/agent/providers/codex-app-server-agent.js.map +1 -1
- package/dist/server/server/agent/providers/mock-load-test-agent.d.ts +6 -2
- 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 +294 -113
- package/dist/server/server/agent/providers/mock-load-test-agent.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js +94 -2
- package/dist/server/server/agent/providers/opencode/tool-call-detail-parser.js.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js +24 -115
- package/dist/server/server/agent/providers/opencode/tool-call-mapper.js.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts +102 -1
- package/dist/server/server/agent/providers/opencode-agent.d.ts.map +1 -1
- package/dist/server/server/agent/providers/opencode-agent.js +416 -158
- package/dist/server/server/agent/providers/opencode-agent.js.map +1 -1
- package/dist/server/server/agent/providers/provider-runner.d.ts +27 -0
- package/dist/server/server/agent/providers/provider-runner.d.ts.map +1 -0
- package/dist/server/server/agent/providers/provider-runner.js +80 -0
- package/dist/server/server/agent/providers/provider-runner.js.map +1 -0
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts +6 -3
- package/dist/server/server/agent/providers/tool-call-detail-primitives.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts +2 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.d.ts.map +1 -1
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js +31 -0
- package/dist/server/server/agent/providers/tool-call-mapper-utils.js.map +1 -1
- package/dist/server/server/agent/timeline-projection.d.ts +21 -5
- package/dist/server/server/agent/timeline-projection.d.ts.map +1 -1
- package/dist/server/server/agent/timeline-projection.js +59 -9
- package/dist/server/server/agent/timeline-projection.js.map +1 -1
- package/dist/server/server/auth.d.ts +25 -0
- package/dist/server/server/auth.d.ts.map +1 -0
- package/dist/server/server/auth.js +93 -0
- package/dist/server/server/auth.js.map +1 -0
- package/dist/server/server/bootstrap.d.ts +3 -1
- package/dist/server/server/bootstrap.d.ts.map +1 -1
- package/dist/server/server/bootstrap.js +87 -30
- package/dist/server/server/bootstrap.js.map +1 -1
- package/dist/server/server/config.d.ts.map +1 -1
- package/dist/server/server/config.js +11 -0
- package/dist/server/server/config.js.map +1 -1
- package/dist/server/server/exports.d.ts +7 -1
- package/dist/server/server/exports.d.ts.map +1 -1
- package/dist/server/server/exports.js +6 -1
- package/dist/server/server/exports.js.map +1 -1
- package/dist/server/server/file-explorer/service.d.ts +10 -0
- package/dist/server/server/file-explorer/service.d.ts.map +1 -1
- package/dist/server/server/file-explorer/service.js +38 -4
- package/dist/server/server/file-explorer/service.js.map +1 -1
- package/dist/server/server/index.js +9 -6
- package/dist/server/server/index.js.map +1 -1
- package/dist/server/server/logger.d.ts.map +1 -1
- package/dist/server/server/logger.js +15 -1
- package/dist/server/server/logger.js.map +1 -1
- package/dist/server/server/pagination/cursor.d.ts +16 -0
- package/dist/server/server/pagination/cursor.d.ts.map +1 -0
- package/dist/server/server/pagination/cursor.js +62 -0
- package/dist/server/server/pagination/cursor.js.map +1 -0
- package/dist/server/server/pagination/sortable-pager.d.ts +24 -0
- package/dist/server/server/pagination/sortable-pager.d.ts.map +1 -0
- package/dist/server/server/pagination/sortable-pager.js +68 -0
- package/dist/server/server/pagination/sortable-pager.js.map +1 -0
- package/dist/server/server/paseo-worktree-archive-service.d.ts +3 -1
- package/dist/server/server/paseo-worktree-archive-service.d.ts.map +1 -1
- package/dist/server/server/paseo-worktree-archive-service.js +61 -53
- package/dist/server/server/paseo-worktree-archive-service.js.map +1 -1
- package/dist/server/server/paseo-worktree-service.d.ts +13 -0
- package/dist/server/server/paseo-worktree-service.d.ts.map +1 -1
- package/dist/server/server/paseo-worktree-service.js +72 -3
- package/dist/server/server/paseo-worktree-service.js.map +1 -1
- package/dist/server/server/persisted-config.d.ts +25 -0
- package/dist/server/server/persisted-config.d.ts.map +1 -1
- package/dist/server/server/persisted-config.js +9 -0
- package/dist/server/server/persisted-config.js.map +1 -1
- package/dist/server/server/relay-transport.d.ts.map +1 -1
- package/dist/server/server/relay-transport.js +16 -4
- package/dist/server/server/relay-transport.js.map +1 -1
- package/dist/server/server/resolve-worktree-creation-intent.d.ts +0 -10
- package/dist/server/server/resolve-worktree-creation-intent.d.ts.map +1 -1
- package/dist/server/server/resolve-worktree-creation-intent.js +1 -45
- package/dist/server/server/resolve-worktree-creation-intent.js.map +1 -1
- package/dist/server/server/script-status-projection.d.ts +6 -1
- package/dist/server/server/script-status-projection.d.ts.map +1 -1
- package/dist/server/server/script-status-projection.js +12 -3
- package/dist/server/server/script-status-projection.js.map +1 -1
- package/dist/server/server/session.d.ts +19 -51
- package/dist/server/server/session.d.ts.map +1 -1
- package/dist/server/server/session.js +354 -1069
- package/dist/server/server/session.js.map +1 -1
- package/dist/server/server/websocket-server.d.ts +4 -2
- package/dist/server/server/websocket-server.d.ts.map +1 -1
- package/dist/server/server/websocket-server.js +65 -12
- package/dist/server/server/websocket-server.js.map +1 -1
- package/dist/server/server/workspace-directory.d.ts +69 -0
- package/dist/server/server/workspace-directory.d.ts.map +1 -0
- package/dist/server/server/workspace-directory.js +229 -0
- package/dist/server/server/workspace-directory.js.map +1 -0
- package/dist/server/server/worktree-bootstrap.d.ts.map +1 -1
- package/dist/server/server/worktree-bootstrap.js +6 -2
- package/dist/server/server/worktree-bootstrap.js.map +1 -1
- package/dist/server/server/worktree-core.d.ts +2 -0
- package/dist/server/server/worktree-core.d.ts.map +1 -1
- package/dist/server/server/worktree-core.js.map +1 -1
- package/dist/server/server/worktree-errors.d.ts +1 -1
- package/dist/server/server/worktree-errors.d.ts.map +1 -1
- package/dist/server/server/worktree-errors.js +1 -4
- package/dist/server/server/worktree-errors.js.map +1 -1
- package/dist/server/server/worktree-session.d.ts +47 -20
- package/dist/server/server/worktree-session.d.ts.map +1 -1
- package/dist/server/server/worktree-session.js +68 -25
- package/dist/server/server/worktree-session.js.map +1 -1
- package/dist/server/shared/binary-frames/file-transfer.d.ts +56 -0
- package/dist/server/shared/binary-frames/file-transfer.d.ts.map +1 -0
- package/dist/server/shared/binary-frames/file-transfer.js +108 -0
- package/dist/server/shared/binary-frames/file-transfer.js.map +1 -0
- package/dist/server/shared/binary-frames/index.d.ts +3 -0
- package/dist/server/shared/binary-frames/index.d.ts.map +1 -0
- package/dist/server/shared/binary-frames/index.js +3 -0
- package/dist/server/shared/binary-frames/index.js.map +1 -0
- package/dist/server/shared/{terminal-stream-protocol.d.ts → binary-frames/terminal.d.ts} +2 -2
- package/dist/server/shared/binary-frames/terminal.d.ts.map +1 -0
- package/dist/server/shared/{terminal-stream-protocol.js → binary-frames/terminal.js} +2 -2
- package/dist/server/shared/binary-frames/terminal.js.map +1 -0
- package/dist/server/shared/client-capabilities.d.ts +5 -0
- package/dist/server/shared/client-capabilities.d.ts.map +1 -0
- package/dist/server/shared/client-capabilities.js +4 -0
- package/dist/server/shared/client-capabilities.js.map +1 -0
- package/dist/server/shared/connection-offer.d.ts +8 -0
- package/dist/server/shared/connection-offer.d.ts.map +1 -1
- package/dist/server/shared/connection-offer.js +35 -0
- package/dist/server/shared/connection-offer.js.map +1 -1
- package/dist/server/shared/daemon-endpoints.d.ts +16 -1
- package/dist/server/shared/daemon-endpoints.d.ts.map +1 -1
- package/dist/server/shared/daemon-endpoints.js +65 -6
- package/dist/server/shared/daemon-endpoints.js.map +1 -1
- package/dist/server/shared/host-connection-schema.d.ts +23 -0
- package/dist/server/shared/host-connection-schema.d.ts.map +1 -0
- package/dist/server/shared/host-connection-schema.js +9 -0
- package/dist/server/shared/host-connection-schema.js.map +1 -0
- package/dist/server/shared/messages.d.ts +3242 -535
- package/dist/server/shared/messages.d.ts.map +1 -1
- package/dist/server/shared/messages.js +73 -34
- package/dist/server/shared/messages.js.map +1 -1
- package/dist/server/terminal/terminal-manager-factory.d.ts +7 -0
- package/dist/server/terminal/terminal-manager-factory.d.ts.map +1 -0
- package/dist/server/terminal/terminal-manager-factory.js +13 -0
- package/dist/server/terminal/terminal-manager-factory.js.map +1 -0
- package/dist/server/terminal/terminal-manager.d.ts +7 -1
- package/dist/server/terminal/terminal-manager.d.ts.map +1 -1
- package/dist/server/terminal/terminal-manager.js +14 -1
- package/dist/server/terminal/terminal-manager.js.map +1 -1
- package/dist/server/terminal/terminal-session-controller.d.ts +63 -0
- package/dist/server/terminal/terminal-session-controller.d.ts.map +1 -0
- package/dist/server/terminal/terminal-session-controller.js +615 -0
- package/dist/server/terminal/terminal-session-controller.js.map +1 -0
- package/dist/server/terminal/terminal-ts-loader.mjs +20 -0
- package/dist/server/terminal/terminal-worker-process.d.ts +2 -0
- package/dist/server/terminal/terminal-worker-process.d.ts.map +1 -0
- package/dist/server/terminal/terminal-worker-process.js +221 -0
- package/dist/server/terminal/terminal-worker-process.js.map +1 -0
- package/dist/server/terminal/terminal-worker-protocol.d.ts +113 -0
- package/dist/server/terminal/terminal-worker-protocol.d.ts.map +1 -0
- package/dist/server/terminal/terminal-worker-protocol.js +2 -0
- package/dist/server/terminal/terminal-worker-protocol.js.map +1 -0
- package/dist/server/terminal/terminal.d.ts +7 -0
- package/dist/server/terminal/terminal.d.ts.map +1 -1
- package/dist/server/terminal/terminal.js +22 -9
- package/dist/server/terminal/terminal.js.map +1 -1
- package/dist/server/terminal/worker-terminal-manager.d.ts +19 -0
- package/dist/server/terminal/worker-terminal-manager.d.ts.map +1 -0
- package/dist/server/terminal/worker-terminal-manager.js +466 -0
- package/dist/server/terminal/worker-terminal-manager.js.map +1 -0
- package/dist/server/utils/directory-suggestions.d.ts.map +1 -1
- package/dist/server/utils/directory-suggestions.js +10 -1
- package/dist/server/utils/directory-suggestions.js.map +1 -1
- package/dist/server/utils/process-tree.d.ts +25 -0
- package/dist/server/utils/process-tree.d.ts.map +1 -0
- package/dist/server/utils/process-tree.js +96 -0
- package/dist/server/utils/process-tree.js.map +1 -0
- package/dist/server/utils/windows-command.d.ts.map +1 -1
- package/dist/server/utils/windows-command.js +5 -1
- package/dist/server/utils/windows-command.js.map +1 -1
- package/dist/server/utils/worktree-metadata.d.ts +44 -0
- package/dist/server/utils/worktree-metadata.d.ts.map +1 -1
- package/dist/server/utils/worktree-metadata.js +58 -0
- package/dist/server/utils/worktree-metadata.js.map +1 -1
- package/dist/server/utils/worktree.d.ts +14 -2
- package/dist/server/utils/worktree.d.ts.map +1 -1
- package/dist/server/utils/worktree.js +22 -13
- package/dist/server/utils/worktree.js.map +1 -1
- package/package.json +5 -4
- package/dist/server/shared/terminal-stream-protocol.d.ts.map +0 -1
- package/dist/server/shared/terminal-stream-protocol.js.map +0 -1
|
@@ -4,10 +4,13 @@ import net from "node:net";
|
|
|
4
4
|
import { z } from "zod";
|
|
5
5
|
import { createProviderEnvSpec, resolveProviderCommandPrefix, } from "../provider-launch-config.js";
|
|
6
6
|
import { findExecutable, isCommandAvailable } from "../../../utils/executable.js";
|
|
7
|
+
import { terminateProcessTree } from "../../../utils/process-tree.js";
|
|
7
8
|
import { withTimeout } from "../../../utils/promise-timeout.js";
|
|
8
9
|
import { spawnProcess } from "../../../utils/spawn.js";
|
|
10
|
+
import { buildToolCallDisplayModel } from "../../../shared/tool-call-display.js";
|
|
9
11
|
import { mapOpencodeToolCall } from "./opencode/tool-call-mapper.js";
|
|
10
12
|
import { formatDiagnosticStatus, formatProviderDiagnostic, formatProviderDiagnosticError, resolveBinaryVersion, toDiagnosticErrorMessage, } from "./diagnostic-utils.js";
|
|
13
|
+
import { runProviderTurn } from "./provider-runner.js";
|
|
11
14
|
import { renderPromptAttachmentAsText } from "../prompt-attachments.js";
|
|
12
15
|
const OPENCODE_CAPABILITIES = {
|
|
13
16
|
supportsStreaming: true,
|
|
@@ -17,9 +20,11 @@ const OPENCODE_CAPABILITIES = {
|
|
|
17
20
|
supportsReasoningStream: true,
|
|
18
21
|
supportsToolInvocations: true,
|
|
19
22
|
};
|
|
23
|
+
const OPENCODE_BUILD_MODE_ID = "build";
|
|
24
|
+
const OPENCODE_FULL_ACCESS_MODE_ID = "full-access";
|
|
20
25
|
const DEFAULT_MODES = [
|
|
21
26
|
{
|
|
22
|
-
id:
|
|
27
|
+
id: OPENCODE_BUILD_MODE_ID,
|
|
23
28
|
label: "Build",
|
|
24
29
|
description: "Allows edits and tool execution for implementation work",
|
|
25
30
|
},
|
|
@@ -28,9 +33,20 @@ const DEFAULT_MODES = [
|
|
|
28
33
|
label: "Plan",
|
|
29
34
|
description: "Read-only planning mode that avoids file edits",
|
|
30
35
|
},
|
|
36
|
+
{
|
|
37
|
+
id: OPENCODE_FULL_ACCESS_MODE_ID,
|
|
38
|
+
label: "Full Access",
|
|
39
|
+
description: "Automatically approves all tool permission prompts for the session",
|
|
40
|
+
},
|
|
31
41
|
];
|
|
32
42
|
const MCP_ALREADY_PRESENT_ERROR_TOKENS = ["already", "exists", "connected"];
|
|
33
43
|
const OPENCODE_PROVIDER_LIST_TIMEOUT_MS = 30000;
|
|
44
|
+
const OPENCODE_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS = 5000;
|
|
45
|
+
const OPENCODE_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS = 1000;
|
|
46
|
+
const OPENCODE_HANDLED_BUILTIN_SLASH_COMMANDS = [
|
|
47
|
+
{ name: "compact", description: "Compact the current session", argumentHint: "" },
|
|
48
|
+
{ name: "summarize", description: "Compact the current session", argumentHint: "" },
|
|
49
|
+
];
|
|
34
50
|
const OPENCODE_FATAL_RETRY_MESSAGE_TOKENS = [
|
|
35
51
|
"insufficient balance",
|
|
36
52
|
"no resource package",
|
|
@@ -268,10 +284,26 @@ function resolvePartDedupeKey(part, partType) {
|
|
|
268
284
|
function normalizeOpenCodeModeId(modeId) {
|
|
269
285
|
const trimmed = typeof modeId === "string" ? modeId.trim() : "";
|
|
270
286
|
if (!trimmed || trimmed === "default") {
|
|
271
|
-
return
|
|
287
|
+
return OPENCODE_BUILD_MODE_ID;
|
|
272
288
|
}
|
|
273
289
|
return trimmed;
|
|
274
290
|
}
|
|
291
|
+
function resolveOpenCodeRuntimeAgentId(modeId) {
|
|
292
|
+
const normalizedModeId = normalizeOpenCodeModeId(modeId);
|
|
293
|
+
return normalizedModeId === OPENCODE_FULL_ACCESS_MODE_ID
|
|
294
|
+
? OPENCODE_BUILD_MODE_ID
|
|
295
|
+
: normalizedModeId;
|
|
296
|
+
}
|
|
297
|
+
function isSelectableOpenCodeAgent(agent) {
|
|
298
|
+
return (agent.mode === "primary" || agent.mode === "all") && agent.hidden !== true;
|
|
299
|
+
}
|
|
300
|
+
function mergeOpenCodeModes(discoveredModes) {
|
|
301
|
+
const modesById = new Map(DEFAULT_MODES.map((mode) => [mode.id, mode]));
|
|
302
|
+
for (const mode of discoveredModes) {
|
|
303
|
+
modesById.set(mode.id, mode);
|
|
304
|
+
}
|
|
305
|
+
return sortOpenCodeModes(Array.from(modesById.values()));
|
|
306
|
+
}
|
|
275
307
|
function sortOpenCodeModes(modes) {
|
|
276
308
|
const order = new Map(DEFAULT_MODES.map((mode, index) => [mode.id, index]));
|
|
277
309
|
return [...modes].sort((left, right) => {
|
|
@@ -457,18 +489,18 @@ function buildOpenCodePromptParts(prompt) {
|
|
|
457
489
|
output.push({ type: "text", text: part.text });
|
|
458
490
|
continue;
|
|
459
491
|
}
|
|
460
|
-
if (part.type === "
|
|
461
|
-
|
|
492
|
+
if (part.type === "image") {
|
|
493
|
+
attachmentOrdinal += 1;
|
|
494
|
+
const normalized = toOpenCodeDataUrl(part.mimeType, part.data);
|
|
495
|
+
output.push({
|
|
496
|
+
type: "file",
|
|
497
|
+
mime: normalized.mimeType,
|
|
498
|
+
filename: `attachment-${attachmentOrdinal}.${getOpenCodeAttachmentExtension(normalized.mimeType)}`,
|
|
499
|
+
url: normalized.url,
|
|
500
|
+
});
|
|
462
501
|
continue;
|
|
463
502
|
}
|
|
464
|
-
|
|
465
|
-
const normalized = toOpenCodeDataUrl(part.mimeType, part.data);
|
|
466
|
-
output.push({
|
|
467
|
-
type: "file",
|
|
468
|
-
mime: normalized.mimeType,
|
|
469
|
-
filename: `attachment-${attachmentOrdinal}.${getOpenCodeAttachmentExtension(normalized.mimeType)}`,
|
|
470
|
-
url: normalized.url,
|
|
471
|
-
});
|
|
503
|
+
output.push({ type: "text", text: renderPromptAttachmentAsText(part) });
|
|
472
504
|
}
|
|
473
505
|
return output;
|
|
474
506
|
}
|
|
@@ -484,6 +516,10 @@ export const __openCodeInternals = {
|
|
|
484
516
|
reconcileOpenCodeSessionClose,
|
|
485
517
|
resolveOpenCodeModelLookupKeyFromAssistantMessage,
|
|
486
518
|
resolveOpenCodeSelectedModelContextWindow,
|
|
519
|
+
isSelectableOpenCodeAgent,
|
|
520
|
+
get OpenCodeAgentSession() {
|
|
521
|
+
return OpenCodeAgentSession;
|
|
522
|
+
},
|
|
487
523
|
};
|
|
488
524
|
export class OpenCodeServerManager {
|
|
489
525
|
constructor(logger, runtimeSettings) {
|
|
@@ -600,6 +636,7 @@ export class OpenCodeServerManager {
|
|
|
600
636
|
const launchPrefix = await resolveProviderCommandPrefix(this.runtimeSettings?.command, resolveOpenCodeBinary);
|
|
601
637
|
return new Promise((resolve, reject) => {
|
|
602
638
|
const serverProcess = spawnProcess(launchPrefix.command, [...launchPrefix.args, "serve", "--port", String(port)], {
|
|
639
|
+
detached: process.platform !== "win32",
|
|
603
640
|
stdio: ["ignore", "pipe", "pipe"],
|
|
604
641
|
...createProviderEnvSpec({ runtimeSettings: this.runtimeSettings }),
|
|
605
642
|
});
|
|
@@ -693,25 +730,16 @@ export class OpenCodeServerManager {
|
|
|
693
730
|
if (server.process.killed) {
|
|
694
731
|
return;
|
|
695
732
|
}
|
|
696
|
-
await
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
pendingResolve = null;
|
|
703
|
-
fn();
|
|
704
|
-
};
|
|
705
|
-
const timeout = setTimeout(() => {
|
|
706
|
-
server.process.kill("SIGKILL");
|
|
707
|
-
settle();
|
|
708
|
-
}, 5000);
|
|
709
|
-
server.process.on("exit", () => {
|
|
710
|
-
clearTimeout(timeout);
|
|
711
|
-
settle();
|
|
712
|
-
});
|
|
713
|
-
server.process.kill("SIGTERM");
|
|
733
|
+
const result = await terminateProcessTree(server.process, {
|
|
734
|
+
gracefulTimeoutMs: OPENCODE_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS,
|
|
735
|
+
forceTimeoutMs: OPENCODE_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS,
|
|
736
|
+
onForceSignal: () => {
|
|
737
|
+
this.logger.warn({ timeoutMs: OPENCODE_SERVER_GRACEFUL_SHUTDOWN_TIMEOUT_MS }, "OpenCode server did not exit after SIGTERM; sending SIGKILL");
|
|
738
|
+
},
|
|
714
739
|
});
|
|
740
|
+
if (result === "kill-timeout") {
|
|
741
|
+
this.logger.warn({ timeoutMs: OPENCODE_SERVER_FORCE_SHUTDOWN_TIMEOUT_MS }, "OpenCode server did not report exit after SIGKILL");
|
|
742
|
+
}
|
|
715
743
|
}
|
|
716
744
|
}
|
|
717
745
|
OpenCodeServerManager.instance = null;
|
|
@@ -832,16 +860,14 @@ export class OpenCodeAgentClient {
|
|
|
832
860
|
if (response.error || !response.data) {
|
|
833
861
|
return DEFAULT_MODES;
|
|
834
862
|
}
|
|
835
|
-
const discovered = response.data
|
|
836
|
-
.filter((agent) => agent.mode === "primary" && agent.hidden !== true)
|
|
837
|
-
.map((agent) => ({
|
|
863
|
+
const discovered = response.data.filter(isSelectableOpenCodeAgent).map((agent) => ({
|
|
838
864
|
id: agent.name,
|
|
839
865
|
label: agent.name.charAt(0).toUpperCase() + agent.name.slice(1),
|
|
840
866
|
description: typeof agent.description === "string" && agent.description.trim().length > 0
|
|
841
867
|
? agent.description.trim()
|
|
842
868
|
: DEFAULT_MODES.find((mode) => mode.id === agent.name)?.description,
|
|
843
869
|
}));
|
|
844
|
-
return
|
|
870
|
+
return mergeOpenCodeModes(discovered);
|
|
845
871
|
}
|
|
846
872
|
finally {
|
|
847
873
|
acquisition.release();
|
|
@@ -936,6 +962,8 @@ export class OpenCodeAgentClient {
|
|
|
936
962
|
}
|
|
937
963
|
}
|
|
938
964
|
}
|
|
965
|
+
const MAX_OPENCODE_SUB_AGENT_ACTIONS = 200;
|
|
966
|
+
const MAX_OPENCODE_PENDING_CHILD_TOOL_PARTS = 200;
|
|
939
967
|
function stringifyStructuredAssistantMessage(value) {
|
|
940
968
|
if (value === undefined) {
|
|
941
969
|
return null;
|
|
@@ -1132,6 +1160,191 @@ function resetOpenCodeTurnTrackingState(state) {
|
|
|
1132
1160
|
state.streamedPartKeys.clear();
|
|
1133
1161
|
state.partTypes.clear();
|
|
1134
1162
|
}
|
|
1163
|
+
function getOpenCodeSubAgentMaps(state) {
|
|
1164
|
+
state.subAgentsByCallId ?? (state.subAgentsByCallId = new Map());
|
|
1165
|
+
state.subAgentCallIdByChildSessionId ?? (state.subAgentCallIdByChildSessionId = new Map());
|
|
1166
|
+
state.pendingChildToolPartsBySessionId ?? (state.pendingChildToolPartsBySessionId = new Map());
|
|
1167
|
+
return {
|
|
1168
|
+
byCallId: state.subAgentsByCallId,
|
|
1169
|
+
callIdByChildSessionId: state.subAgentCallIdByChildSessionId,
|
|
1170
|
+
pendingChildToolPartsBySessionId: state.pendingChildToolPartsBySessionId,
|
|
1171
|
+
};
|
|
1172
|
+
}
|
|
1173
|
+
function getOpenCodeSubAgentState(callId, state, toolCall) {
|
|
1174
|
+
const maps = getOpenCodeSubAgentMaps(state);
|
|
1175
|
+
const existing = maps.byCallId.get(callId);
|
|
1176
|
+
if (existing) {
|
|
1177
|
+
existing.toolCall = toolCall;
|
|
1178
|
+
return existing;
|
|
1179
|
+
}
|
|
1180
|
+
const created = {
|
|
1181
|
+
toolCall,
|
|
1182
|
+
actions: [],
|
|
1183
|
+
actionIndexByKey: new Map(),
|
|
1184
|
+
nextActionIndex: 1,
|
|
1185
|
+
};
|
|
1186
|
+
maps.byCallId.set(callId, created);
|
|
1187
|
+
return created;
|
|
1188
|
+
}
|
|
1189
|
+
function linkOpenCodeSubAgentChildSession(activity, childSessionId, state) {
|
|
1190
|
+
activity.childSessionId = childSessionId;
|
|
1191
|
+
const maps = getOpenCodeSubAgentMaps(state);
|
|
1192
|
+
maps.callIdByChildSessionId.set(childSessionId, activity.toolCall.callId);
|
|
1193
|
+
}
|
|
1194
|
+
function buildOpenCodeSubAgentLog(detail, activity) {
|
|
1195
|
+
const actionLog = activity.actions
|
|
1196
|
+
.map((action) => action.summary ? `[${action.toolName}] ${action.summary}` : `[${action.toolName}]`)
|
|
1197
|
+
.join("\n");
|
|
1198
|
+
const parts = [actionLog, detail.log].filter((part) => part.trim().length > 0);
|
|
1199
|
+
return parts.join("\n\n");
|
|
1200
|
+
}
|
|
1201
|
+
function buildOpenCodeSubAgentTimelineItem(activity) {
|
|
1202
|
+
const toolCall = activity.toolCall;
|
|
1203
|
+
if (toolCall.detail.type !== "sub_agent") {
|
|
1204
|
+
return toolCall;
|
|
1205
|
+
}
|
|
1206
|
+
const childSessionId = activity.childSessionId ?? toolCall.detail.childSessionId;
|
|
1207
|
+
return {
|
|
1208
|
+
...toolCall,
|
|
1209
|
+
detail: {
|
|
1210
|
+
...toolCall.detail,
|
|
1211
|
+
...(childSessionId ? { childSessionId } : {}),
|
|
1212
|
+
log: buildOpenCodeSubAgentLog(toolCall.detail, activity),
|
|
1213
|
+
},
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
function registerOpenCodeSubAgentToolCall(item, state) {
|
|
1217
|
+
if (item.detail.type !== "sub_agent") {
|
|
1218
|
+
return item;
|
|
1219
|
+
}
|
|
1220
|
+
const activity = getOpenCodeSubAgentState(item.callId, state, item);
|
|
1221
|
+
if (item.detail.childSessionId) {
|
|
1222
|
+
linkOpenCodeSubAgentChildSession(activity, item.detail.childSessionId, state);
|
|
1223
|
+
}
|
|
1224
|
+
return buildOpenCodeSubAgentTimelineItem(activity);
|
|
1225
|
+
}
|
|
1226
|
+
function bufferOpenCodeSubAgentChildToolPart(part, state) {
|
|
1227
|
+
const maps = getOpenCodeSubAgentMaps(state);
|
|
1228
|
+
if (maps.byCallId.size === 0) {
|
|
1229
|
+
return;
|
|
1230
|
+
}
|
|
1231
|
+
const totalPending = [...maps.pendingChildToolPartsBySessionId.values()].reduce((total, parts) => total + parts.length, 0);
|
|
1232
|
+
if (totalPending >= MAX_OPENCODE_PENDING_CHILD_TOOL_PARTS) {
|
|
1233
|
+
return;
|
|
1234
|
+
}
|
|
1235
|
+
const pending = maps.pendingChildToolPartsBySessionId.get(part.sessionID) ?? [];
|
|
1236
|
+
pending.push(part);
|
|
1237
|
+
maps.pendingChildToolPartsBySessionId.set(part.sessionID, pending);
|
|
1238
|
+
}
|
|
1239
|
+
function flushOpenCodeSubAgentChildToolParts(childSessionId, state, events) {
|
|
1240
|
+
const maps = getOpenCodeSubAgentMaps(state);
|
|
1241
|
+
const pending = maps.pendingChildToolPartsBySessionId.get(childSessionId);
|
|
1242
|
+
if (!pending || pending.length === 0) {
|
|
1243
|
+
return;
|
|
1244
|
+
}
|
|
1245
|
+
maps.pendingChildToolPartsBySessionId.delete(childSessionId);
|
|
1246
|
+
for (const part of pending) {
|
|
1247
|
+
appendOpenCodeSubAgentChildToolPart(part, state, events);
|
|
1248
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
function findOnlyOpenCodeSubAgentWaitingForChild(state) {
|
|
1251
|
+
const maps = getOpenCodeSubAgentMaps(state);
|
|
1252
|
+
const candidates = [...maps.byCallId.values()].filter((activity) => activity.toolCall.status === "running" &&
|
|
1253
|
+
activity.toolCall.detail.type === "sub_agent" &&
|
|
1254
|
+
!activity.childSessionId);
|
|
1255
|
+
return candidates.length === 1 ? (candidates[0] ?? null) : null;
|
|
1256
|
+
}
|
|
1257
|
+
function summarizeOpenCodeSubAgentAction(item, cwd) {
|
|
1258
|
+
const display = buildToolCallDisplayModel({
|
|
1259
|
+
name: item.name,
|
|
1260
|
+
status: item.status,
|
|
1261
|
+
error: item.error,
|
|
1262
|
+
metadata: item.metadata,
|
|
1263
|
+
detail: item.detail,
|
|
1264
|
+
cwd,
|
|
1265
|
+
});
|
|
1266
|
+
return display.summary ?? display.errorText;
|
|
1267
|
+
}
|
|
1268
|
+
function appendOpenCodeSubAgentAction(activity, item, cwd) {
|
|
1269
|
+
const key = item.callId || `${item.name}:${activity.actions.length}`;
|
|
1270
|
+
const existingIndex = activity.actionIndexByKey.get(key);
|
|
1271
|
+
const summary = summarizeOpenCodeSubAgentAction(item, cwd);
|
|
1272
|
+
if (existingIndex !== undefined) {
|
|
1273
|
+
const action = activity.actions[existingIndex];
|
|
1274
|
+
if (!action) {
|
|
1275
|
+
return false;
|
|
1276
|
+
}
|
|
1277
|
+
const changed = action.toolName !== item.name || action.summary !== summary;
|
|
1278
|
+
action.toolName = item.name;
|
|
1279
|
+
if (summary) {
|
|
1280
|
+
action.summary = summary;
|
|
1281
|
+
}
|
|
1282
|
+
else {
|
|
1283
|
+
delete action.summary;
|
|
1284
|
+
}
|
|
1285
|
+
return changed;
|
|
1286
|
+
}
|
|
1287
|
+
if (activity.actions.length >= MAX_OPENCODE_SUB_AGENT_ACTIONS) {
|
|
1288
|
+
return false;
|
|
1289
|
+
}
|
|
1290
|
+
activity.actionIndexByKey.set(key, activity.actions.length);
|
|
1291
|
+
activity.actions.push({
|
|
1292
|
+
index: activity.nextActionIndex,
|
|
1293
|
+
key,
|
|
1294
|
+
toolName: item.name,
|
|
1295
|
+
...(summary ? { summary } : {}),
|
|
1296
|
+
});
|
|
1297
|
+
activity.nextActionIndex += 1;
|
|
1298
|
+
return true;
|
|
1299
|
+
}
|
|
1300
|
+
function appendOpenCodeToolCallTimelineItem(item, state, events) {
|
|
1301
|
+
const timelineItem = registerOpenCodeSubAgentToolCall(item, state);
|
|
1302
|
+
events.push({
|
|
1303
|
+
type: "timeline",
|
|
1304
|
+
provider: "opencode",
|
|
1305
|
+
item: timelineItem,
|
|
1306
|
+
});
|
|
1307
|
+
if (timelineItem.detail.type === "sub_agent" && timelineItem.detail.childSessionId) {
|
|
1308
|
+
flushOpenCodeSubAgentChildToolParts(timelineItem.detail.childSessionId, state, events);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
function appendOpenCodeSubAgentChildSessionLinked(childSessionId, state, events) {
|
|
1312
|
+
const activity = findOnlyOpenCodeSubAgentWaitingForChild(state);
|
|
1313
|
+
if (!activity) {
|
|
1314
|
+
return;
|
|
1315
|
+
}
|
|
1316
|
+
linkOpenCodeSubAgentChildSession(activity, childSessionId, state);
|
|
1317
|
+
events.push({
|
|
1318
|
+
type: "timeline",
|
|
1319
|
+
provider: "opencode",
|
|
1320
|
+
item: buildOpenCodeSubAgentTimelineItem(activity),
|
|
1321
|
+
});
|
|
1322
|
+
flushOpenCodeSubAgentChildToolParts(childSessionId, state, events);
|
|
1323
|
+
}
|
|
1324
|
+
function appendOpenCodeSubAgentChildToolPart(part, state, events) {
|
|
1325
|
+
const maps = getOpenCodeSubAgentMaps(state);
|
|
1326
|
+
const parentCallId = maps.callIdByChildSessionId.get(part.sessionID);
|
|
1327
|
+
if (!parentCallId) {
|
|
1328
|
+
bufferOpenCodeSubAgentChildToolPart(part, state);
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
const activity = maps.byCallId.get(parentCallId);
|
|
1332
|
+
if (!activity) {
|
|
1333
|
+
return;
|
|
1334
|
+
}
|
|
1335
|
+
const parsedToolPart = OpencodeToolPartToTimelineItemSchema.safeParse(part);
|
|
1336
|
+
if (!parsedToolPart.success || !parsedToolPart.data) {
|
|
1337
|
+
return;
|
|
1338
|
+
}
|
|
1339
|
+
if (!appendOpenCodeSubAgentAction(activity, parsedToolPart.data, state.cwd)) {
|
|
1340
|
+
return;
|
|
1341
|
+
}
|
|
1342
|
+
events.push({
|
|
1343
|
+
type: "timeline",
|
|
1344
|
+
provider: "opencode",
|
|
1345
|
+
item: buildOpenCodeSubAgentTimelineItem(activity),
|
|
1346
|
+
});
|
|
1347
|
+
}
|
|
1135
1348
|
function appendOpenCodeSessionCreatedOrUpdated(event, state, events) {
|
|
1136
1349
|
if (event.properties.info.id === state.sessionId) {
|
|
1137
1350
|
events.push({
|
|
@@ -1139,6 +1352,12 @@ function appendOpenCodeSessionCreatedOrUpdated(event, state, events) {
|
|
|
1139
1352
|
sessionId: state.sessionId,
|
|
1140
1353
|
provider: "opencode",
|
|
1141
1354
|
});
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
const info = readOpenCodeRecord(event.properties.info);
|
|
1358
|
+
const parentSessionId = readNonEmptyString(info?.parentID) ?? readNonEmptyString(info?.parentId);
|
|
1359
|
+
if (parentSessionId === state.sessionId) {
|
|
1360
|
+
appendOpenCodeSubAgentChildSessionLinked(event.properties.info.id, state, events);
|
|
1142
1361
|
}
|
|
1143
1362
|
}
|
|
1144
1363
|
function appendOpenCodeMessageUpdated(event, state, events) {
|
|
@@ -1174,6 +1393,9 @@ function appendOpenCodeMessageUpdated(event, state, events) {
|
|
|
1174
1393
|
function appendOpenCodeMessagePartUpdated(event, state, events) {
|
|
1175
1394
|
const part = event.properties.part;
|
|
1176
1395
|
if (part.sessionID !== state.sessionId) {
|
|
1396
|
+
if (part.type === "tool") {
|
|
1397
|
+
appendOpenCodeSubAgentChildToolPart(part, state, events);
|
|
1398
|
+
}
|
|
1177
1399
|
return;
|
|
1178
1400
|
}
|
|
1179
1401
|
const messageRole = state.messageRoles.get(part.messageID);
|
|
@@ -1189,7 +1411,7 @@ function appendOpenCodeMessagePartUpdated(event, state, events) {
|
|
|
1189
1411
|
if (part.type === "tool") {
|
|
1190
1412
|
const parsedToolPart = OpencodeToolPartToTimelineItemSchema.safeParse(part);
|
|
1191
1413
|
if (parsedToolPart.success && parsedToolPart.data) {
|
|
1192
|
-
|
|
1414
|
+
appendOpenCodeToolCallTimelineItem(parsedToolPart.data, state, events);
|
|
1193
1415
|
}
|
|
1194
1416
|
return;
|
|
1195
1417
|
}
|
|
@@ -1380,6 +1602,15 @@ function appendOpenCodeSessionStatus(event, state, events) {
|
|
|
1380
1602
|
}
|
|
1381
1603
|
// "retry" and "busy" are transient — no terminal event.
|
|
1382
1604
|
}
|
|
1605
|
+
function createDeferred() {
|
|
1606
|
+
let resolve;
|
|
1607
|
+
let reject;
|
|
1608
|
+
const promise = new Promise((res, rej) => {
|
|
1609
|
+
resolve = res;
|
|
1610
|
+
reject = rej;
|
|
1611
|
+
});
|
|
1612
|
+
return { promise, resolve, reject };
|
|
1613
|
+
}
|
|
1383
1614
|
class OpenCodeAgentSession {
|
|
1384
1615
|
constructor(config, client, sessionId, logger, modelContextWindowsByModelKey = new Map(), releaseServer) {
|
|
1385
1616
|
this.provider = "opencode";
|
|
@@ -1403,6 +1634,9 @@ class OpenCodeAgentSession {
|
|
|
1403
1634
|
this.nextTurnOrdinal = 0;
|
|
1404
1635
|
this.activeForegroundTurnId = null;
|
|
1405
1636
|
this.runningToolCalls = new Map();
|
|
1637
|
+
this.subAgentsByCallId = new Map();
|
|
1638
|
+
this.subAgentCallIdByChildSessionId = new Map();
|
|
1639
|
+
this.pendingChildToolPartsBySessionId = new Map();
|
|
1406
1640
|
this.config = config;
|
|
1407
1641
|
this.client = client;
|
|
1408
1642
|
this.sessionId = sessionId;
|
|
@@ -1435,75 +1669,13 @@ class OpenCodeAgentSession {
|
|
|
1435
1669
|
this.config.thinkingOptionId = normalizedThinkingOptionId ?? undefined;
|
|
1436
1670
|
}
|
|
1437
1671
|
async run(prompt, options) {
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
let resolveCompletion;
|
|
1445
|
-
let rejectCompletion;
|
|
1446
|
-
const processEvent = (event) => {
|
|
1447
|
-
if (settled) {
|
|
1448
|
-
return;
|
|
1449
|
-
}
|
|
1450
|
-
const eventTurnId = event.turnId;
|
|
1451
|
-
if (turnId && eventTurnId && eventTurnId !== turnId) {
|
|
1452
|
-
return;
|
|
1453
|
-
}
|
|
1454
|
-
if (event.type === "timeline") {
|
|
1455
|
-
timeline.push(event.item);
|
|
1456
|
-
if (event.item.type === "assistant_message") {
|
|
1457
|
-
finalText = event.item.text;
|
|
1458
|
-
}
|
|
1459
|
-
return;
|
|
1460
|
-
}
|
|
1461
|
-
if (event.type === "turn_completed") {
|
|
1462
|
-
usage = event.usage;
|
|
1463
|
-
settled = true;
|
|
1464
|
-
resolveCompletion();
|
|
1465
|
-
return;
|
|
1466
|
-
}
|
|
1467
|
-
if (event.type === "turn_failed") {
|
|
1468
|
-
settled = true;
|
|
1469
|
-
rejectCompletion(new Error(event.error));
|
|
1470
|
-
return;
|
|
1471
|
-
}
|
|
1472
|
-
if (event.type === "turn_canceled") {
|
|
1473
|
-
settled = true;
|
|
1474
|
-
resolveCompletion();
|
|
1475
|
-
}
|
|
1476
|
-
};
|
|
1477
|
-
const completion = new Promise((resolve, reject) => {
|
|
1478
|
-
resolveCompletion = resolve;
|
|
1479
|
-
rejectCompletion = reject;
|
|
1480
|
-
});
|
|
1481
|
-
const unsubscribe = this.subscribe((event) => {
|
|
1482
|
-
if (!turnId) {
|
|
1483
|
-
bufferedEvents.push(event);
|
|
1484
|
-
return;
|
|
1485
|
-
}
|
|
1486
|
-
processEvent(event);
|
|
1672
|
+
return runProviderTurn({
|
|
1673
|
+
prompt,
|
|
1674
|
+
runOptions: options,
|
|
1675
|
+
startTurn: (p, o) => this.startTurn(p, o),
|
|
1676
|
+
subscribe: (callback) => this.subscribe(callback),
|
|
1677
|
+
getSessionId: () => this.sessionId,
|
|
1487
1678
|
});
|
|
1488
|
-
try {
|
|
1489
|
-
const result = await this.startTurn(prompt, options);
|
|
1490
|
-
turnId = result.turnId;
|
|
1491
|
-
for (const event of bufferedEvents) {
|
|
1492
|
-
processEvent(event);
|
|
1493
|
-
}
|
|
1494
|
-
if (!settled) {
|
|
1495
|
-
await completion;
|
|
1496
|
-
}
|
|
1497
|
-
}
|
|
1498
|
-
finally {
|
|
1499
|
-
unsubscribe();
|
|
1500
|
-
}
|
|
1501
|
-
return {
|
|
1502
|
-
sessionId: this.sessionId,
|
|
1503
|
-
finalText,
|
|
1504
|
-
usage,
|
|
1505
|
-
timeline,
|
|
1506
|
-
};
|
|
1507
1679
|
}
|
|
1508
1680
|
async interrupt() {
|
|
1509
1681
|
const turnId = this.activeForegroundTurnId;
|
|
@@ -1522,6 +1694,9 @@ class OpenCodeAgentSession {
|
|
|
1522
1694
|
throw new Error("A foreground turn is already active");
|
|
1523
1695
|
}
|
|
1524
1696
|
this.runningToolCalls.clear();
|
|
1697
|
+
this.subAgentsByCallId.clear();
|
|
1698
|
+
this.subAgentCallIdByChildSessionId.clear();
|
|
1699
|
+
this.pendingChildToolPartsBySessionId.clear();
|
|
1525
1700
|
const turnAbortController = new AbortController();
|
|
1526
1701
|
this.abortController = turnAbortController;
|
|
1527
1702
|
await this.ensureMcpServersConfigured();
|
|
@@ -1531,12 +1706,54 @@ class OpenCodeAgentSession {
|
|
|
1531
1706
|
const model = this.parseModel(this.config.model);
|
|
1532
1707
|
const thinkingOptionId = this.config.thinkingOptionId;
|
|
1533
1708
|
const effectiveVariant = thinkingOptionId ?? undefined;
|
|
1534
|
-
const effectiveMode =
|
|
1709
|
+
const effectiveMode = resolveOpenCodeRuntimeAgentId(this.currentMode);
|
|
1535
1710
|
const turnId = this.createTurnId();
|
|
1536
1711
|
this.activeForegroundTurnId = turnId;
|
|
1537
|
-
|
|
1712
|
+
// OpenCode's /event SSE endpoint does NOT replay past events. If we send
|
|
1713
|
+
// the prompt before our reader is connected, terminal events fired early
|
|
1714
|
+
// by the server (e.g. session.error / session.idle for invalid model or
|
|
1715
|
+
// mode) are missed and the turn hangs forever. Wait for the subscription
|
|
1716
|
+
// to be established before sending anything.
|
|
1717
|
+
const subscriptionReady = createDeferred();
|
|
1718
|
+
void this.consumeEventStream(turnId, turnAbortController, subscriptionReady);
|
|
1719
|
+
try {
|
|
1720
|
+
await subscriptionReady.promise;
|
|
1721
|
+
}
|
|
1722
|
+
catch {
|
|
1723
|
+
// consumeEventStream already finished the turn with the subscription error.
|
|
1724
|
+
return { turnId };
|
|
1725
|
+
}
|
|
1538
1726
|
const slashCommand = await this.resolveSlashCommandInvocation(prompt);
|
|
1539
1727
|
if (slashCommand) {
|
|
1728
|
+
if (slashCommand.commandName === "compact" || slashCommand.commandName === "summarize") {
|
|
1729
|
+
void this.client.session
|
|
1730
|
+
.summarize({
|
|
1731
|
+
sessionID: this.sessionId,
|
|
1732
|
+
directory: this.config.cwd,
|
|
1733
|
+
...(model ? { providerID: model.providerID, modelID: model.modelID } : {}),
|
|
1734
|
+
})
|
|
1735
|
+
.then((response) => {
|
|
1736
|
+
if (response.error) {
|
|
1737
|
+
this.finishForegroundTurn({
|
|
1738
|
+
type: "turn_failed",
|
|
1739
|
+
provider: "opencode",
|
|
1740
|
+
error: toDiagnosticErrorMessage(response.error),
|
|
1741
|
+
}, turnId);
|
|
1742
|
+
}
|
|
1743
|
+
else {
|
|
1744
|
+
this.finishForegroundTurn({ type: "turn_completed", provider: "opencode", usage: undefined }, turnId);
|
|
1745
|
+
}
|
|
1746
|
+
return;
|
|
1747
|
+
})
|
|
1748
|
+
.catch((error) => {
|
|
1749
|
+
this.finishForegroundTurn({
|
|
1750
|
+
type: "turn_failed",
|
|
1751
|
+
provider: "opencode",
|
|
1752
|
+
error: toDiagnosticErrorMessage(error),
|
|
1753
|
+
}, turnId);
|
|
1754
|
+
});
|
|
1755
|
+
return { turnId };
|
|
1756
|
+
}
|
|
1540
1757
|
// command() blocks until the server finishes processing. OpenCode's SSE
|
|
1541
1758
|
// endpoint does NOT replay past events, so if the command completes before
|
|
1542
1759
|
// our SSE reader connects, we miss `session.idle` and the turn hangs.
|
|
@@ -1584,41 +1801,44 @@ class OpenCodeAgentSession {
|
|
|
1584
1801
|
});
|
|
1585
1802
|
}
|
|
1586
1803
|
else {
|
|
1587
|
-
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1592
|
-
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1804
|
+
// Wrap in an async IIFE so a synchronous throw from promptAsync (e.g.
|
|
1805
|
+
// SDK input validation) is caught alongside async rejections. A plain
|
|
1806
|
+
// `.then().catch()` chain would let a sync throw escape unhandled.
|
|
1807
|
+
void (async () => {
|
|
1808
|
+
try {
|
|
1809
|
+
const promptResponse = await this.client.session.promptAsync({
|
|
1810
|
+
sessionID: this.sessionId,
|
|
1811
|
+
directory: this.config.cwd,
|
|
1812
|
+
parts,
|
|
1813
|
+
...(options?.outputSchema
|
|
1814
|
+
? {
|
|
1815
|
+
format: {
|
|
1816
|
+
type: "json_schema",
|
|
1817
|
+
schema: options.outputSchema,
|
|
1818
|
+
},
|
|
1819
|
+
}
|
|
1820
|
+
: {}),
|
|
1821
|
+
...(this.config.systemPrompt ? { system: this.config.systemPrompt } : {}),
|
|
1822
|
+
...(model ? { model } : {}),
|
|
1823
|
+
...(effectiveMode ? { agent: effectiveMode } : {}),
|
|
1824
|
+
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
|
1825
|
+
});
|
|
1826
|
+
if (promptResponse.error) {
|
|
1827
|
+
this.finishForegroundTurn({
|
|
1828
|
+
type: "turn_failed",
|
|
1829
|
+
provider: "opencode",
|
|
1830
|
+
error: toDiagnosticErrorMessage(promptResponse.error),
|
|
1831
|
+
}, turnId);
|
|
1598
1832
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
...(model ? { model } : {}),
|
|
1602
|
-
...(effectiveMode ? { agent: effectiveMode } : {}),
|
|
1603
|
-
...(effectiveVariant ? { variant: effectiveVariant } : {}),
|
|
1604
|
-
})
|
|
1605
|
-
.then((promptResponse) => {
|
|
1606
|
-
if (promptResponse.error) {
|
|
1833
|
+
}
|
|
1834
|
+
catch (error) {
|
|
1607
1835
|
this.finishForegroundTurn({
|
|
1608
1836
|
type: "turn_failed",
|
|
1609
1837
|
provider: "opencode",
|
|
1610
|
-
error: toDiagnosticErrorMessage(
|
|
1838
|
+
error: toDiagnosticErrorMessage(error),
|
|
1611
1839
|
}, turnId);
|
|
1612
1840
|
}
|
|
1613
|
-
|
|
1614
|
-
})
|
|
1615
|
-
.catch((error) => {
|
|
1616
|
-
this.finishForegroundTurn({
|
|
1617
|
-
type: "turn_failed",
|
|
1618
|
-
provider: "opencode",
|
|
1619
|
-
error: toDiagnosticErrorMessage(error),
|
|
1620
|
-
}, turnId);
|
|
1621
|
-
});
|
|
1841
|
+
})();
|
|
1622
1842
|
}
|
|
1623
1843
|
return { turnId };
|
|
1624
1844
|
}
|
|
@@ -1628,14 +1848,15 @@ class OpenCodeAgentSession {
|
|
|
1628
1848
|
this.subscribers.delete(callback);
|
|
1629
1849
|
};
|
|
1630
1850
|
}
|
|
1631
|
-
async consumeEventStream(turnId, turnAbortController) {
|
|
1851
|
+
async consumeEventStream(turnId, turnAbortController, subscriptionReady) {
|
|
1632
1852
|
try {
|
|
1633
1853
|
const result = await this.client.event.subscribe({ directory: this.config.cwd }, { signal: turnAbortController.signal, sseMaxRetryAttempts: 0 });
|
|
1854
|
+
subscriptionReady.resolve();
|
|
1634
1855
|
for await (const event of result.stream) {
|
|
1635
1856
|
if (turnAbortController.signal.aborted || this.activeForegroundTurnId !== turnId) {
|
|
1636
1857
|
break;
|
|
1637
1858
|
}
|
|
1638
|
-
const translated = this.translateEvent(event);
|
|
1859
|
+
const translated = await this.translateEvent(event);
|
|
1639
1860
|
for (const e of translated) {
|
|
1640
1861
|
if (this.activeForegroundTurnId !== turnId) {
|
|
1641
1862
|
return;
|
|
@@ -1660,6 +1881,7 @@ class OpenCodeAgentSession {
|
|
|
1660
1881
|
}
|
|
1661
1882
|
}
|
|
1662
1883
|
catch (error) {
|
|
1884
|
+
subscriptionReady.reject(error);
|
|
1663
1885
|
if (!turnAbortController.signal.aborted && this.activeForegroundTurnId === turnId) {
|
|
1664
1886
|
this.finishForegroundTurn({
|
|
1665
1887
|
type: "turn_failed",
|
|
@@ -1706,13 +1928,22 @@ class OpenCodeAgentSession {
|
|
|
1706
1928
|
}
|
|
1707
1929
|
synthesizeInterruptedToolCalls(turnId) {
|
|
1708
1930
|
for (const item of this.runningToolCalls.values()) {
|
|
1931
|
+
const error = { message: "Tool execution aborted" };
|
|
1709
1932
|
this.notifySubscribers({
|
|
1710
1933
|
type: "timeline",
|
|
1711
1934
|
provider: "opencode",
|
|
1712
1935
|
item: {
|
|
1713
1936
|
...item,
|
|
1714
1937
|
status: "failed",
|
|
1715
|
-
error
|
|
1938
|
+
error,
|
|
1939
|
+
detail: item.detail.type === "sub_agent"
|
|
1940
|
+
? {
|
|
1941
|
+
...item.detail,
|
|
1942
|
+
log: [item.detail.log, error.message]
|
|
1943
|
+
.filter((entry) => entry.trim().length > 0)
|
|
1944
|
+
.join("\n"),
|
|
1945
|
+
}
|
|
1946
|
+
: item.detail,
|
|
1716
1947
|
},
|
|
1717
1948
|
}, turnId);
|
|
1718
1949
|
}
|
|
@@ -1807,19 +2038,15 @@ class OpenCodeAgentSession {
|
|
|
1807
2038
|
const response = await this.client.app.agents({
|
|
1808
2039
|
directory: this.config.cwd,
|
|
1809
2040
|
});
|
|
1810
|
-
const
|
|
1811
|
-
|
|
1812
|
-
:
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
: DEFAULT_MODES.find((mode) => mode.id === agent.name)?.description,
|
|
1820
|
-
}));
|
|
1821
|
-
this.availableModesCache =
|
|
1822
|
-
discoveredModes.length > 0 ? sortOpenCodeModes(discoveredModes) : DEFAULT_MODES;
|
|
2041
|
+
const agents = response.error || !response.data ? [] : response.data;
|
|
2042
|
+
const discoveredModes = agents.filter(isSelectableOpenCodeAgent).map((agent) => ({
|
|
2043
|
+
id: agent.name,
|
|
2044
|
+
label: agent.name.charAt(0).toUpperCase() + agent.name.slice(1),
|
|
2045
|
+
description: typeof agent.description === "string" && agent.description.trim().length > 0
|
|
2046
|
+
? agent.description.trim()
|
|
2047
|
+
: DEFAULT_MODES.find((mode) => mode.id === agent.name)?.description,
|
|
2048
|
+
}));
|
|
2049
|
+
this.availableModesCache = mergeOpenCodeModes(discoveredModes);
|
|
1823
2050
|
return this.availableModesCache;
|
|
1824
2051
|
}
|
|
1825
2052
|
async getCurrentMode() {
|
|
@@ -1829,14 +2056,18 @@ class OpenCodeAgentSession {
|
|
|
1829
2056
|
const result = await this.client.command.list({
|
|
1830
2057
|
directory: this.config.cwd,
|
|
1831
2058
|
});
|
|
2059
|
+
const commandsByName = new Map(OPENCODE_HANDLED_BUILTIN_SLASH_COMMANDS.map((command) => [command.name, command]));
|
|
1832
2060
|
if (result.error || !result.data) {
|
|
1833
|
-
return
|
|
2061
|
+
return Array.from(commandsByName.values());
|
|
1834
2062
|
}
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
2063
|
+
for (const cmd of result.data) {
|
|
2064
|
+
commandsByName.set(cmd.name, {
|
|
2065
|
+
name: cmd.name,
|
|
2066
|
+
description: cmd.description ?? "",
|
|
2067
|
+
argumentHint: cmd.hints?.length ? cmd.hints.join(" ") : "",
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2070
|
+
return Array.from(commandsByName.values());
|
|
1840
2071
|
}
|
|
1841
2072
|
async setMode(modeId) {
|
|
1842
2073
|
this.currentMode = normalizeOpenCodeModeId(modeId);
|
|
@@ -2002,14 +2233,18 @@ class OpenCodeAgentSession {
|
|
|
2002
2233
|
}
|
|
2003
2234
|
throw new Error(`Failed to ${operation} OpenCode MCP server '${name}': ${toDiagnosticErrorMessage(error)}`);
|
|
2004
2235
|
}
|
|
2005
|
-
translateEvent(event) {
|
|
2236
|
+
async translateEvent(event) {
|
|
2006
2237
|
const translated = translateOpenCodeEvent(event, {
|
|
2007
2238
|
sessionId: this.sessionId,
|
|
2239
|
+
cwd: this.config.cwd,
|
|
2008
2240
|
messageRoles: this.messageRoles,
|
|
2009
2241
|
accumulatedUsage: this.accumulatedUsage,
|
|
2010
2242
|
streamedPartKeys: this.streamedPartKeys,
|
|
2011
2243
|
emittedStructuredMessageIds: this.emittedStructuredMessageIds,
|
|
2012
2244
|
partTypes: this.partTypes,
|
|
2245
|
+
subAgentsByCallId: this.subAgentsByCallId,
|
|
2246
|
+
subAgentCallIdByChildSessionId: this.subAgentCallIdByChildSessionId,
|
|
2247
|
+
pendingChildToolPartsBySessionId: this.pendingChildToolPartsBySessionId,
|
|
2013
2248
|
modelContextWindowsByModelKey: this.modelContextWindowsByModelKey,
|
|
2014
2249
|
onAssistantModelContextWindowResolved: (contextWindowMaxTokens) => {
|
|
2015
2250
|
this.accumulatedUsage.contextWindowMaxTokens = contextWindowMaxTokens;
|
|
@@ -2018,8 +2253,13 @@ class OpenCodeAgentSession {
|
|
|
2018
2253
|
}
|
|
2019
2254
|
},
|
|
2020
2255
|
});
|
|
2256
|
+
const events = [];
|
|
2021
2257
|
for (const translatedEvent of translated) {
|
|
2022
2258
|
if (translatedEvent.type === "permission_requested") {
|
|
2259
|
+
const autoApproved = await this.tryAutoApproveToolPermission(translatedEvent.request);
|
|
2260
|
+
if (autoApproved) {
|
|
2261
|
+
continue;
|
|
2262
|
+
}
|
|
2023
2263
|
this.pendingPermissions.set(translatedEvent.request.id, translatedEvent.request);
|
|
2024
2264
|
}
|
|
2025
2265
|
if (translatedEvent.type === "turn_completed") {
|
|
@@ -2030,8 +2270,26 @@ class OpenCodeAgentSession {
|
|
|
2030
2270
|
this.accumulatedUsage =
|
|
2031
2271
|
contextWindowMaxTokens !== undefined ? { contextWindowMaxTokens } : {};
|
|
2032
2272
|
}
|
|
2273
|
+
events.push(translatedEvent);
|
|
2274
|
+
}
|
|
2275
|
+
return events;
|
|
2276
|
+
}
|
|
2277
|
+
async tryAutoApproveToolPermission(request) {
|
|
2278
|
+
if (this.currentMode !== OPENCODE_FULL_ACCESS_MODE_ID || request.kind !== "tool") {
|
|
2279
|
+
return false;
|
|
2280
|
+
}
|
|
2281
|
+
try {
|
|
2282
|
+
await this.client.permission.reply({
|
|
2283
|
+
requestID: request.id,
|
|
2284
|
+
directory: this.config.cwd,
|
|
2285
|
+
reply: "once",
|
|
2286
|
+
});
|
|
2287
|
+
return true;
|
|
2288
|
+
}
|
|
2289
|
+
catch (error) {
|
|
2290
|
+
this.logger.warn({ err: error, requestId: request.id }, "Failed to auto-approve OpenCode tool permission");
|
|
2291
|
+
return false;
|
|
2033
2292
|
}
|
|
2034
|
-
return translated;
|
|
2035
2293
|
}
|
|
2036
2294
|
resolveSelectedModelContextWindowMaxTokens() {
|
|
2037
2295
|
return this.selectedModelContextWindowMaxTokens;
|