@myagentroam/node 0.1.3 → 0.1.6
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/README.md +9 -1
- package/dist/capabilities.d.ts +2 -0
- package/dist/capabilities.js +15 -4
- package/dist/claude-agent-sdk.d.ts +4 -16
- package/dist/claude-agent-sdk.js +18 -79
- package/dist/claude-channel.js +0 -1
- package/dist/codex-app-server.d.ts +5 -0
- package/dist/codex-app-server.js +26 -5
- package/dist/config.d.ts +3 -0
- package/dist/config.js +18 -2
- package/dist/connector/node-connector-options.d.ts +26 -0
- package/dist/connector/node-connector-options.js +1 -0
- package/dist/connector/node-operation-router.d.ts +9 -0
- package/dist/connector/node-operation-router.js +22 -0
- package/dist/connector.d.ts +62 -356
- package/dist/connector.js +714 -6176
- package/dist/control-outbound-scheduler.d.ts +26 -0
- package/dist/control-outbound-scheduler.js +121 -0
- package/dist/database.d.ts +4 -0
- package/dist/database.js +15 -10
- package/dist/event-buffer.js +0 -1
- package/dist/fake-runner.js +0 -1
- package/dist/health.js +0 -1
- package/dist/main.js +6 -1
- package/dist/migrations/v001.js +0 -1
- package/dist/migrations/v002.js +0 -1
- package/dist/migrations/v003.d.ts +4 -0
- package/dist/migrations/v003.js +44 -0
- package/dist/native-jsonl-reader.d.ts +14 -0
- package/dist/native-jsonl-reader.js +97 -0
- package/dist/native-session-history.d.ts +41 -4
- package/dist/native-session-history.js +340 -159
- package/dist/opencode-runtime.d.ts +33 -0
- package/dist/opencode-runtime.js +80 -0
- package/dist/opencode-server.d.ts +47 -0
- package/dist/opencode-server.js +250 -0
- package/dist/operational.js +10 -3
- package/dist/process-tree.js +0 -1
- package/dist/runner/abstract-runner.d.ts +153 -0
- package/dist/runner/abstract-runner.js +154 -0
- package/dist/runner/claude/managed-run-controller.d.ts +52 -0
- package/dist/runner/claude/managed-run-controller.js +326 -0
- package/dist/runner/claude-code-runner.d.ts +70 -0
- package/dist/runner/claude-code-runner.js +286 -0
- package/dist/runner/codex/conversation-parser.d.ts +59 -0
- package/dist/runner/codex/conversation-parser.js +816 -0
- package/dist/runner/codex/managed-run-controller.d.ts +80 -0
- package/dist/runner/codex/managed-run-controller.js +388 -0
- package/dist/runner/codex-runner.d.ts +85 -0
- package/dist/runner/codex-runner.js +365 -0
- package/dist/runner/fake-test-runner.d.ts +26 -0
- package/dist/runner/fake-test-runner.js +47 -0
- package/dist/runner/opencode/conversation-parser.d.ts +27 -0
- package/dist/runner/opencode/conversation-parser.js +217 -0
- package/dist/runner/opencode/managed-run-controller.d.ts +76 -0
- package/dist/runner/opencode/managed-run-controller.js +451 -0
- package/dist/runner/opencode-runner.d.ts +60 -0
- package/dist/runner/opencode-runner.js +330 -0
- package/dist/runner/runner-registry.d.ts +19 -0
- package/dist/runner/runner-registry.js +75 -0
- package/dist/runner-command-engine.js +0 -1
- package/dist/runner-profiles.d.ts +4 -0
- package/dist/runner-profiles.js +76 -3
- package/dist/runner-usage.d.ts +2 -2
- package/dist/runner-usage.js +3 -6
- package/dist/runtime-state.js +26 -14
- package/dist/service/attachment-domain-state.d.ts +5 -0
- package/dist/service/attachment-domain-state.js +5 -0
- package/dist/service/conversation-history-service.d.ts +34 -0
- package/dist/service/conversation-history-service.js +158 -0
- package/dist/service/external-session-resume-service.d.ts +32 -0
- package/dist/service/external-session-resume-service.js +98 -0
- package/dist/service/fake-managed-run-service.d.ts +29 -0
- package/dist/service/fake-managed-run-service.js +62 -0
- package/dist/service/managed-runner-session-service.d.ts +12 -0
- package/dist/service/managed-runner-session-service.js +35 -0
- package/dist/service/native-session-projection-service.d.ts +51 -0
- package/dist/service/native-session-projection-service.js +271 -0
- package/dist/service/native-session-watch-service.d.ts +37 -0
- package/dist/service/native-session-watch-service.js +150 -0
- package/dist/service/node-connection-lifecycle-service.d.ts +37 -0
- package/dist/service/node-connection-lifecycle-service.js +85 -0
- package/dist/service/node-control-channel.d.ts +32 -0
- package/dist/service/node-control-channel.js +85 -0
- package/dist/service/node-control-message-service.d.ts +28 -0
- package/dist/service/node-control-message-service.js +104 -0
- package/dist/service/node-request-service.d.ts +14 -0
- package/dist/service/node-request-service.js +50 -0
- package/dist/service/node-run-event-bridge.d.ts +40 -0
- package/dist/service/node-run-event-bridge.js +83 -0
- package/dist/service/node-terminal-channel.d.ts +29 -0
- package/dist/service/node-terminal-channel.js +182 -0
- package/dist/service/node-upgrade-coordinator.d.ts +29 -0
- package/dist/service/node-upgrade-coordinator.js +137 -0
- package/dist/service/node-workspace-coordinator.d.ts +32 -0
- package/dist/service/node-workspace-coordinator.js +80 -0
- package/dist/service/run-attachment-service.d.ts +37 -0
- package/dist/service/run-attachment-service.js +160 -0
- package/dist/service/run-domain-state.d.ts +4 -0
- package/dist/service/run-domain-state.js +4 -0
- package/dist/service/run-event-service.d.ts +31 -0
- package/dist/service/run-event-service.js +102 -0
- package/dist/service/run-workbench-service.d.ts +27 -0
- package/dist/service/run-workbench-service.js +113 -0
- package/dist/service/runner-channel-message-service.d.ts +13 -0
- package/dist/service/runner-channel-message-service.js +20 -0
- package/dist/service/runner-interaction-service.d.ts +40 -0
- package/dist/service/runner-interaction-service.js +246 -0
- package/dist/service/runner-service.d.ts +44 -0
- package/dist/service/runner-service.js +68 -0
- package/dist/service/session-catalog-service.d.ts +45 -0
- package/dist/service/session-catalog-service.js +224 -0
- package/dist/service/session-command-service.d.ts +23 -0
- package/dist/service/session-command-service.js +69 -0
- package/dist/service/session-context-service.d.ts +34 -0
- package/dist/service/session-context-service.js +87 -0
- package/dist/service/session-domain-state.d.ts +8 -0
- package/dist/service/session-domain-state.js +8 -0
- package/dist/service/session-identity-service.d.ts +24 -0
- package/dist/service/session-identity-service.js +86 -0
- package/dist/service/session-lifecycle-service.d.ts +31 -0
- package/dist/service/session-lifecycle-service.js +242 -0
- package/dist/service/session-message-service.d.ts +33 -0
- package/dist/service/session-message-service.js +157 -0
- package/dist/service/session-presentation-service.d.ts +33 -0
- package/dist/service/session-presentation-service.js +36 -0
- package/dist/service/session-query-service.d.ts +31 -0
- package/dist/service/session-query-service.js +77 -0
- package/dist/service/terminal-relay-state.d.ts +6 -0
- package/dist/service/terminal-relay-state.js +3 -0
- package/dist/service/terminal-service.d.ts +12 -0
- package/dist/service/terminal-service.js +52 -0
- package/dist/service/workbench-event-service.d.ts +21 -0
- package/dist/service/workbench-event-service.js +53 -0
- package/dist/service/workbench-manifest-service.d.ts +89 -0
- package/dist/service/workbench-manifest-service.js +70 -0
- package/dist/service/workspace-change-service.d.ts +9 -0
- package/dist/service/workspace-change-service.js +86 -0
- package/dist/service/workspace-content-search-service.d.ts +14 -0
- package/dist/service/workspace-content-search-service.js +477 -0
- package/dist/service/workspace-domain-state.d.ts +75 -0
- package/dist/service/workspace-domain-state.js +40 -0
- package/dist/service/workspace-file-service.d.ts +17 -0
- package/dist/service/workspace-file-service.js +109 -0
- package/dist/service/workspace-queue-workbench-service.d.ts +55 -0
- package/dist/service/workspace-queue-workbench-service.js +226 -0
- package/dist/service/workspace-service.d.ts +15 -0
- package/dist/service/workspace-service.js +67 -0
- package/dist/service/workspace-session-service.d.ts +23 -0
- package/dist/service/workspace-session-service.js +139 -0
- package/dist/service/workspace-upload-service.d.ts +37 -0
- package/dist/service/workspace-upload-service.js +240 -0
- package/dist/service/workspace-watch-service.d.ts +18 -0
- package/dist/service/workspace-watch-service.js +120 -0
- package/dist/service/workspace-workbench-service.d.ts +47 -0
- package/dist/service/workspace-workbench-service.js +223 -0
- package/dist/service.js +2 -3
- package/dist/storage.js +0 -1
- package/dist/supervisor.d.ts +1 -0
- package/dist/supervisor.js +154 -0
- package/dist/terminal.d.ts +1 -0
- package/dist/terminal.js +1 -2
- package/dist/util/node-operation-parsers.d.ts +92 -0
- package/dist/util/node-operation-parsers.js +382 -0
- package/dist/util/runner-native-session-parsers.d.ts +72 -0
- package/dist/util/runner-native-session-parsers.js +381 -0
- package/dist/util/secret-environment.d.ts +1 -0
- package/dist/util/secret-environment.js +25 -0
- package/dist/workspace.d.ts +62 -2
- package/dist/workspace.js +539 -57
- package/package.json +3 -2
- package/dist/capabilities.js.map +0 -1
- package/dist/claude-agent-sdk.js.map +0 -1
- package/dist/claude-channel.js.map +0 -1
- package/dist/codex-app-server.js.map +0 -1
- package/dist/config.js.map +0 -1
- package/dist/connector.js.map +0 -1
- package/dist/database.js.map +0 -1
- package/dist/event-buffer.js.map +0 -1
- package/dist/fake-runner.js.map +0 -1
- package/dist/health.js.map +0 -1
- package/dist/main.js.map +0 -1
- package/dist/migrations/v001.js.map +0 -1
- package/dist/migrations/v002.js.map +0 -1
- package/dist/native-session-history.js.map +0 -1
- package/dist/operational.js.map +0 -1
- package/dist/process-tree.js.map +0 -1
- package/dist/runner-command-engine.js.map +0 -1
- package/dist/runner-profiles.js.map +0 -1
- package/dist/runner-usage.js.map +0 -1
- package/dist/runtime-state.js.map +0 -1
- package/dist/service.js.map +0 -1
- package/dist/storage.js.map +0 -1
- package/dist/terminal.js.map +0 -1
- package/dist/workspace.js.map +0 -1
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { NodeEnvelope, RunnerCommandDescriptor, RunnerCommandState } from '@myagentroam/protocol';
|
|
2
|
+
import type { NodeAgentSession, NodeMessageAttachmentInput } from '../../database.js';
|
|
3
|
+
import type { CodexComposerInput } from '../../codex-app-server.js';
|
|
4
|
+
import type { FakeRunnerStatus } from '../../fake-runner.js';
|
|
5
|
+
import { CodexRunner } from '../codex-runner.js';
|
|
6
|
+
type CodexImageInput = Extract<CodexComposerInput, {
|
|
7
|
+
readonly type: 'localImage';
|
|
8
|
+
}>;
|
|
9
|
+
export interface CodexManagedRunHost<TAttachment> {
|
|
10
|
+
readonly available: () => boolean;
|
|
11
|
+
readonly intercepted: () => boolean;
|
|
12
|
+
readonly active: ReadonlySet<string>;
|
|
13
|
+
addActive(runId: string): void;
|
|
14
|
+
removeActive(runId: string): void;
|
|
15
|
+
adopt(input: {
|
|
16
|
+
runId: string;
|
|
17
|
+
sessionId: string;
|
|
18
|
+
runner: 'codex';
|
|
19
|
+
cwd: string;
|
|
20
|
+
externalSessionId?: string;
|
|
21
|
+
}): void;
|
|
22
|
+
session(sessionId: string): NodeAgentSession | undefined;
|
|
23
|
+
runStatus(runId: string): string | undefined;
|
|
24
|
+
run(runId: string): unknown;
|
|
25
|
+
interrupted(runId: string): boolean;
|
|
26
|
+
parseAttachments(value: unknown): readonly TAttachment[];
|
|
27
|
+
materialize(runId: string, attachments: readonly TAttachment[]): Promise<readonly CodexImageInput[]>;
|
|
28
|
+
completeCancelled(runId: string, cwd: string): boolean;
|
|
29
|
+
promoteSession(sessionId: string, nativeSessionId: string): void;
|
|
30
|
+
send(type: string, payload: unknown): void;
|
|
31
|
+
emit(runId: string, eventType: string, payload: unknown, status?: FakeRunnerStatus): void;
|
|
32
|
+
cancel(runId: string, threadId: string, turnId: string, cwd: string, status: 'INTERRUPTED' | 'CANCELLED'): Promise<void>;
|
|
33
|
+
createApproval(input: {
|
|
34
|
+
runId: string;
|
|
35
|
+
approvalId: string;
|
|
36
|
+
payload: unknown;
|
|
37
|
+
expiresAt: number;
|
|
38
|
+
}): void;
|
|
39
|
+
publishApproval(input: {
|
|
40
|
+
runId: string;
|
|
41
|
+
approvalId: string;
|
|
42
|
+
payload: unknown;
|
|
43
|
+
expiresAt: number;
|
|
44
|
+
}): void;
|
|
45
|
+
emitItem(runId: string, item: {
|
|
46
|
+
readonly itemId: string;
|
|
47
|
+
readonly kind: 'reasoning_summary' | 'tool_call' | 'command_execution' | 'user_input_request' | 'plan' | 'context_compaction' | 'file_change' | 'unknown';
|
|
48
|
+
readonly status: 'PENDING' | 'IN_PROGRESS' | 'COMPLETED' | 'FAILED' | 'DECLINED';
|
|
49
|
+
readonly payload: Record<string, unknown>;
|
|
50
|
+
readonly merge?: boolean;
|
|
51
|
+
readonly append?: 'sections' | 'outputPreview' | 'outputSummary';
|
|
52
|
+
}): void;
|
|
53
|
+
appendImages(runId: string, images: readonly NodeMessageAttachmentInput[]): readonly Record<string, unknown>[];
|
|
54
|
+
captureSnapshot(runId: string, cwd: string): Promise<void>;
|
|
55
|
+
syncTitle(sessionId: string, nativeSessionId: string, cwd: string): Promise<void>;
|
|
56
|
+
commandState(sessionId: string, commandId: string): RunnerCommandState | undefined;
|
|
57
|
+
setCommandState(sessionId: string, state: RunnerCommandState): void;
|
|
58
|
+
clearCommandState(sessionId: string, commandId: string): void;
|
|
59
|
+
commandStates(sessionId: string): readonly RunnerCommandState[];
|
|
60
|
+
fast(input: string): Promise<unknown>;
|
|
61
|
+
}
|
|
62
|
+
export declare class CodexManagedRunController<TAttachment> {
|
|
63
|
+
private readonly runner;
|
|
64
|
+
private readonly host;
|
|
65
|
+
constructor(runner: CodexRunner, host: CodexManagedRunHost<TAttachment>);
|
|
66
|
+
executeCommand(session: NodeAgentSession, command: RunnerCommandDescriptor, input: string, context: {
|
|
67
|
+
readonly secretEnvironment: Readonly<Record<string, string>>;
|
|
68
|
+
}): Promise<unknown>;
|
|
69
|
+
private compact;
|
|
70
|
+
handleNotification(notification: {
|
|
71
|
+
readonly method: string;
|
|
72
|
+
readonly params: unknown;
|
|
73
|
+
readonly requestId?: string | number;
|
|
74
|
+
}): void;
|
|
75
|
+
private requestApproval;
|
|
76
|
+
private requestUserInput;
|
|
77
|
+
start(envelope: NodeEnvelope): void;
|
|
78
|
+
private run;
|
|
79
|
+
}
|
|
80
|
+
export {};
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { extractId } from '../../util/runner-native-session-parsers.js';
|
|
2
|
+
import { parseSecretEnvironment } from '../../util/secret-environment.js';
|
|
3
|
+
import { boundedConversationItemId, codexImageAttachments, codexLiveConversationItem, codexUserInputQuestions, compactRunnerText, isPlainRecord } from './conversation-parser.js';
|
|
4
|
+
export class CodexManagedRunController {
|
|
5
|
+
runner;
|
|
6
|
+
host;
|
|
7
|
+
constructor(runner, host) {
|
|
8
|
+
this.runner = runner;
|
|
9
|
+
this.host = host;
|
|
10
|
+
}
|
|
11
|
+
async executeCommand(session, command, input, context) {
|
|
12
|
+
if (command.id === 'plan') {
|
|
13
|
+
const environmentLeaseId = crypto.randomUUID();
|
|
14
|
+
this.runner.prepareEnvironment(context.secretEnvironment, environmentLeaseId);
|
|
15
|
+
let modes;
|
|
16
|
+
try {
|
|
17
|
+
await this.runner.start();
|
|
18
|
+
modes = await this.runner.listCollaborationModes();
|
|
19
|
+
}
|
|
20
|
+
finally {
|
|
21
|
+
this.runner.releaseEnvironment(environmentLeaseId);
|
|
22
|
+
}
|
|
23
|
+
if (!isPlainRecord(modes) ||
|
|
24
|
+
!Array.isArray(modes.data) ||
|
|
25
|
+
!modes.data.some((mode) => isPlainRecord(mode) && mode.mode === 'plan'))
|
|
26
|
+
throw new Error('RUNNER_COMMAND_UNAVAILABLE');
|
|
27
|
+
const current = this.host.commandState(session.id, 'plan');
|
|
28
|
+
if (current?.active)
|
|
29
|
+
this.host.clearCommandState(session.id, 'plan');
|
|
30
|
+
else
|
|
31
|
+
this.host.setCommandState(session.id, {
|
|
32
|
+
commandId: 'plan',
|
|
33
|
+
active: true,
|
|
34
|
+
label: 'Plan Mode',
|
|
35
|
+
detail: '后续消息将以协作规划模式运行。',
|
|
36
|
+
closable: true,
|
|
37
|
+
closeInput: '/plan',
|
|
38
|
+
continuation: { label: 'Implement', prompt: '请根据上述计划开始实施。' }
|
|
39
|
+
});
|
|
40
|
+
return { command: command.id, states: this.host.commandStates(session.id) };
|
|
41
|
+
}
|
|
42
|
+
const threadId = session.externalSessionId;
|
|
43
|
+
if (threadId === null || session.nativeControl !== 'MAR_MANAGED')
|
|
44
|
+
throw new Error('RUNNER_COMMAND_UNAVAILABLE');
|
|
45
|
+
if (command.id === 'compact') {
|
|
46
|
+
const runId = crypto.randomUUID();
|
|
47
|
+
this.runner.prepareEnvironment(context.secretEnvironment, runId);
|
|
48
|
+
try {
|
|
49
|
+
await this.runner.start();
|
|
50
|
+
return await this.compact(session, threadId, runId);
|
|
51
|
+
}
|
|
52
|
+
catch (error) {
|
|
53
|
+
this.runner.releaseEnvironment(runId);
|
|
54
|
+
throw error;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (command.id === 'fast')
|
|
58
|
+
return this.host.fast(input);
|
|
59
|
+
throw new Error('RUNNER_COMMAND_UNAVAILABLE');
|
|
60
|
+
}
|
|
61
|
+
async compact(session, threadId, runId) {
|
|
62
|
+
this.host.adopt({
|
|
63
|
+
runId,
|
|
64
|
+
sessionId: session.id,
|
|
65
|
+
runner: 'codex',
|
|
66
|
+
cwd: session.cwd,
|
|
67
|
+
externalSessionId: threadId
|
|
68
|
+
});
|
|
69
|
+
this.host.addActive(runId);
|
|
70
|
+
this.runner.execution.runs.set(runId, {
|
|
71
|
+
sessionId: session.id,
|
|
72
|
+
threadId,
|
|
73
|
+
cwd: session.cwd,
|
|
74
|
+
refreshTitle: false
|
|
75
|
+
});
|
|
76
|
+
this.host.emit(runId, 'run.started', { command: 'compact' }, 'STARTING');
|
|
77
|
+
try {
|
|
78
|
+
await this.runner.request('thread/compact/start', { threadId });
|
|
79
|
+
return {
|
|
80
|
+
command: 'compact',
|
|
81
|
+
run: this.host.run(runId),
|
|
82
|
+
states: this.host.commandStates(session.id)
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
catch (error) {
|
|
86
|
+
this.host.emit(runId, 'run.failed', { code: error instanceof Error ? error.message : 'CODEX_COMPACT_FAILED' }, 'FAILED');
|
|
87
|
+
this.runner.execution.runs.delete(runId);
|
|
88
|
+
this.runner.releaseEnvironment(runId);
|
|
89
|
+
this.host.removeActive(runId);
|
|
90
|
+
throw error;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
handleNotification(notification) {
|
|
94
|
+
const params = isPlainRecord(notification.params) ? notification.params : {};
|
|
95
|
+
const turn = isPlainRecord(params.turn) ? params.turn : undefined;
|
|
96
|
+
const turnId = typeof params.turnId === 'string'
|
|
97
|
+
? params.turnId
|
|
98
|
+
: typeof turn?.id === 'string'
|
|
99
|
+
? turn.id
|
|
100
|
+
: undefined;
|
|
101
|
+
const threadId = typeof params.threadId === 'string' ? params.threadId : undefined;
|
|
102
|
+
if (turnId === undefined && threadId === undefined)
|
|
103
|
+
return;
|
|
104
|
+
const run = [...this.runner.execution.runs.entries()].find(([, value]) => (turnId !== undefined && value.turnId === turnId) ||
|
|
105
|
+
(threadId !== undefined && value.threadId === threadId));
|
|
106
|
+
if (run === undefined)
|
|
107
|
+
return;
|
|
108
|
+
const [runId] = run;
|
|
109
|
+
if (notification.method === 'turn/started' && turnId !== undefined) {
|
|
110
|
+
const active = this.runner.execution.runs.get(runId);
|
|
111
|
+
if (active !== undefined)
|
|
112
|
+
this.runner.execution.runs.set(runId, { ...active, turnId });
|
|
113
|
+
this.host.emit(runId, 'run.running', { threadId, turnId }, 'RUNNING');
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
if (notification.requestId !== undefined &&
|
|
117
|
+
(notification.method === 'item/commandExecution/requestApproval' ||
|
|
118
|
+
notification.method === 'item/fileChange/requestApproval')) {
|
|
119
|
+
this.requestApproval(runId, {
|
|
120
|
+
...notification,
|
|
121
|
+
requestId: notification.requestId
|
|
122
|
+
});
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (notification.requestId !== undefined &&
|
|
126
|
+
notification.method === 'item/tool/requestUserInput') {
|
|
127
|
+
this.requestUserInput(runId, notification.requestId, params);
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
if (notification.method === 'item/agentMessage/delta' && typeof params.delta === 'string') {
|
|
131
|
+
this.host.emit(runId, 'text.delta', { text: params.delta });
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
if (notification.method === 'item/reasoning/summaryTextDelta' &&
|
|
135
|
+
typeof params.itemId === 'string' &&
|
|
136
|
+
typeof params.delta === 'string') {
|
|
137
|
+
const index = typeof params.summaryIndex === 'number' && Number.isInteger(params.summaryIndex)
|
|
138
|
+
? params.summaryIndex
|
|
139
|
+
: 0;
|
|
140
|
+
this.host.emitItem(runId, {
|
|
141
|
+
itemId: boundedConversationItemId('codex', params.itemId),
|
|
142
|
+
kind: 'reasoning_summary',
|
|
143
|
+
status: 'IN_PROGRESS',
|
|
144
|
+
payload: { sections: [{ index, text: compactRunnerText(params.delta, 10_000) }] },
|
|
145
|
+
merge: true,
|
|
146
|
+
append: 'sections'
|
|
147
|
+
});
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
if (notification.method === 'item/commandExecution/outputDelta' &&
|
|
151
|
+
typeof params.itemId === 'string' &&
|
|
152
|
+
typeof params.delta === 'string') {
|
|
153
|
+
this.host.emitItem(runId, {
|
|
154
|
+
itemId: boundedConversationItemId('codex', params.itemId),
|
|
155
|
+
kind: 'command_execution',
|
|
156
|
+
status: 'IN_PROGRESS',
|
|
157
|
+
payload: { outputPreview: compactRunnerText(params.delta, 10_000) },
|
|
158
|
+
merge: true,
|
|
159
|
+
append: 'outputPreview'
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
if (notification.method === 'item/mcpToolCall/progress' &&
|
|
164
|
+
typeof params.itemId === 'string' &&
|
|
165
|
+
typeof params.message === 'string') {
|
|
166
|
+
this.host.emitItem(runId, {
|
|
167
|
+
itemId: boundedConversationItemId('codex', params.itemId),
|
|
168
|
+
kind: 'tool_call',
|
|
169
|
+
status: 'IN_PROGRESS',
|
|
170
|
+
payload: { progressLabel: compactRunnerText(params.message, 500) },
|
|
171
|
+
merge: true
|
|
172
|
+
});
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
if ((notification.method === 'item/started' || notification.method === 'item/completed') &&
|
|
176
|
+
isPlainRecord(params.item)) {
|
|
177
|
+
const attachments = this.host.appendImages(runId, codexImageAttachments(params.item));
|
|
178
|
+
const item = codexLiveConversationItem(params.item, notification.method === 'item/completed', attachments);
|
|
179
|
+
if (item !== undefined)
|
|
180
|
+
this.host.emitItem(runId, item);
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
if (notification.method === 'turn/completed') {
|
|
184
|
+
const status = turn?.status;
|
|
185
|
+
const terminal = status === 'completed' ? 'SUCCEEDED' : status === 'interrupted' ? 'INTERRUPTED' : 'FAILED';
|
|
186
|
+
this.host.emit(runId, 'run.completed', { status: status ?? 'unknown' }, terminal);
|
|
187
|
+
const active = this.runner.execution.runs.get(runId);
|
|
188
|
+
const titleRefresh = active === undefined ||
|
|
189
|
+
active.refreshTitle === false ||
|
|
190
|
+
this.host.session(active.sessionId)?.titleSource !== 'AUTO'
|
|
191
|
+
? undefined
|
|
192
|
+
: this.host.syncTitle(active.sessionId, active.threadId, active.cwd);
|
|
193
|
+
if (active !== undefined) {
|
|
194
|
+
void this.host.captureSnapshot(runId, active.cwd);
|
|
195
|
+
}
|
|
196
|
+
this.runner.execution.runs.delete(runId);
|
|
197
|
+
if (titleRefresh === undefined)
|
|
198
|
+
this.runner.releaseEnvironment(runId);
|
|
199
|
+
else
|
|
200
|
+
void titleRefresh.finally(() => this.runner.releaseEnvironment(runId));
|
|
201
|
+
this.host.removeActive(runId);
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
requestApproval(runId, notification) {
|
|
205
|
+
const approvalId = `codex:${notification.requestId}`;
|
|
206
|
+
const expiresAt = Date.now() + 10 * 60_000;
|
|
207
|
+
this.runner.execution.approvals.set(approvalId, notification.requestId);
|
|
208
|
+
try {
|
|
209
|
+
this.host.createApproval({
|
|
210
|
+
runId,
|
|
211
|
+
approvalId,
|
|
212
|
+
payload: { method: notification.method, params: notification.params },
|
|
213
|
+
expiresAt
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
catch {
|
|
217
|
+
this.runner.execution.approvals.delete(approvalId);
|
|
218
|
+
return;
|
|
219
|
+
}
|
|
220
|
+
this.host.publishApproval({
|
|
221
|
+
runId,
|
|
222
|
+
approvalId,
|
|
223
|
+
payload: { method: notification.method, params: notification.params },
|
|
224
|
+
expiresAt
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
requestUserInput(runId, nativeRequestId, params) {
|
|
228
|
+
const questions = codexUserInputQuestions(params.questions);
|
|
229
|
+
if (questions.length === 0) {
|
|
230
|
+
try {
|
|
231
|
+
this.runner.respond(nativeRequestId, { answers: {} });
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// A disconnected App Server cannot receive a malformed-request response.
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
const requestId = String(nativeRequestId);
|
|
239
|
+
this.runner.execution.userInputs.set(requestId, {
|
|
240
|
+
runId,
|
|
241
|
+
requestId: nativeRequestId,
|
|
242
|
+
questions: questions.map((question) => ({
|
|
243
|
+
id: question.id,
|
|
244
|
+
options: question.options.map((option) => option.value),
|
|
245
|
+
allowOther: question.allowOther
|
|
246
|
+
}))
|
|
247
|
+
});
|
|
248
|
+
this.host.emitItem(runId, {
|
|
249
|
+
itemId: boundedConversationItemId('codex-input', requestId),
|
|
250
|
+
kind: 'user_input_request',
|
|
251
|
+
status: 'PENDING',
|
|
252
|
+
payload: {
|
|
253
|
+
requestId,
|
|
254
|
+
questions: questions.map((question) => ({
|
|
255
|
+
id: question.id,
|
|
256
|
+
prompt: question.prompt,
|
|
257
|
+
input: question.options.length === 0 ? 'SHORT_TEXT' : 'SINGLE_SELECT',
|
|
258
|
+
options: question.options.map((option) => ({
|
|
259
|
+
value: option.value,
|
|
260
|
+
label: option.label,
|
|
261
|
+
description: option.description
|
|
262
|
+
})),
|
|
263
|
+
allowOther: question.allowOther
|
|
264
|
+
}))
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
start(envelope) {
|
|
269
|
+
const payload = envelope.payload;
|
|
270
|
+
if (payload.runner !== 'codex' ||
|
|
271
|
+
typeof payload.runId !== 'string' ||
|
|
272
|
+
typeof payload.sessionId !== 'string' ||
|
|
273
|
+
typeof payload.input !== 'string' ||
|
|
274
|
+
typeof payload.cwd !== 'string' ||
|
|
275
|
+
this.host.intercepted() ||
|
|
276
|
+
this.host.active.has(payload.runId))
|
|
277
|
+
return;
|
|
278
|
+
const { runId, sessionId, input, cwd } = payload;
|
|
279
|
+
let attachments;
|
|
280
|
+
let secretEnvironment;
|
|
281
|
+
try {
|
|
282
|
+
attachments = this.host.parseAttachments(payload.attachments);
|
|
283
|
+
secretEnvironment = parseSecretEnvironment(payload.secretEnvironment);
|
|
284
|
+
}
|
|
285
|
+
catch (error) {
|
|
286
|
+
this.host.emit(runId, 'run.rejected', { code: error instanceof Error ? error.message : 'MESSAGE_ATTACHMENTS_INVALID' }, 'FAILED');
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
this.host.adopt({
|
|
290
|
+
runId,
|
|
291
|
+
sessionId,
|
|
292
|
+
runner: 'codex',
|
|
293
|
+
cwd,
|
|
294
|
+
...(typeof payload.externalSessionId === 'string'
|
|
295
|
+
? { externalSessionId: payload.externalSessionId }
|
|
296
|
+
: {})
|
|
297
|
+
});
|
|
298
|
+
if (this.host.completeCancelled(runId, cwd))
|
|
299
|
+
return;
|
|
300
|
+
const session = this.host.session(sessionId);
|
|
301
|
+
if (!this.host.available()) {
|
|
302
|
+
this.host.emit(runId, 'run.rejected', { code: 'CODEX_UNAVAILABLE' }, 'FAILED');
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (typeof payload.externalSessionId === 'string' &&
|
|
306
|
+
(session === undefined || session.nativeControl !== 'MAR_MANAGED')) {
|
|
307
|
+
this.host.emit(runId, 'run.rejected', { code: 'EXTERNAL_THREAD_OBSERVE_ONLY' }, 'FAILED');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
this.runner.prepareEnvironment(secretEnvironment, runId);
|
|
312
|
+
}
|
|
313
|
+
catch (error) {
|
|
314
|
+
this.host.emit(runId, 'run.rejected', { code: error instanceof Error ? error.message : 'SECRET_ENVIRONMENT_INVALID' }, 'FAILED');
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
this.host.addActive(runId);
|
|
318
|
+
void this.run({
|
|
319
|
+
runId,
|
|
320
|
+
sessionId,
|
|
321
|
+
input,
|
|
322
|
+
cwd,
|
|
323
|
+
externalSessionId: payload.externalSessionId,
|
|
324
|
+
model: payload.model,
|
|
325
|
+
effort: payload.effort,
|
|
326
|
+
access: payload.access,
|
|
327
|
+
collaborationMode: payload.collaborationMode,
|
|
328
|
+
serviceTier: payload.serviceTier
|
|
329
|
+
}, attachments);
|
|
330
|
+
}
|
|
331
|
+
async run(payload, attachments) {
|
|
332
|
+
const { runId, sessionId, input, cwd } = payload;
|
|
333
|
+
try {
|
|
334
|
+
await this.runner.start();
|
|
335
|
+
if (this.host.completeCancelled(runId, cwd)) {
|
|
336
|
+
this.runner.releaseEnvironment(runId);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
this.host.emit(runId, 'run.started', {}, 'STARTING');
|
|
340
|
+
const configuration = {
|
|
341
|
+
...(typeof payload.model === 'string' ? { model: payload.model } : {}),
|
|
342
|
+
...(typeof payload.effort === 'string' ? { effort: payload.effort } : {}),
|
|
343
|
+
...(typeof payload.access === 'string' ? { access: payload.access } : {})
|
|
344
|
+
};
|
|
345
|
+
const threadResult = typeof payload.externalSessionId === 'string'
|
|
346
|
+
? await this.runner.resumeThread(payload.externalSessionId, cwd, configuration)
|
|
347
|
+
: await this.runner.startThread(cwd, configuration);
|
|
348
|
+
if (this.host.completeCancelled(runId, cwd)) {
|
|
349
|
+
this.runner.releaseEnvironment(runId);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
const threadId = extractId(threadResult, 'thread');
|
|
353
|
+
let publicSessionId = sessionId;
|
|
354
|
+
if (typeof payload.externalSessionId !== 'string') {
|
|
355
|
+
this.host.promoteSession(sessionId, threadId);
|
|
356
|
+
publicSessionId = threadId;
|
|
357
|
+
this.host.send('session.external-id', { sessionId, externalSessionId: threadId });
|
|
358
|
+
}
|
|
359
|
+
this.runner.execution.runs.set(runId, { sessionId: publicSessionId, threadId, cwd });
|
|
360
|
+
const turnResult = await this.runner.startTurn(threadId, input, cwd, {
|
|
361
|
+
...configuration,
|
|
362
|
+
...(payload.collaborationMode === 'plan' || payload.collaborationMode === 'default'
|
|
363
|
+
? { collaborationMode: payload.collaborationMode }
|
|
364
|
+
: {}),
|
|
365
|
+
...(payload.serviceTier === 'fast' ? { serviceTier: 'fast' } : {})
|
|
366
|
+
}, await this.host.materialize(runId, attachments));
|
|
367
|
+
const turnId = extractId(turnResult, 'turn');
|
|
368
|
+
this.runner.execution.runs.set(runId, { sessionId: publicSessionId, threadId, turnId, cwd });
|
|
369
|
+
this.runner.execution.managedTurns.set(turnId, { sessionId: publicSessionId, runId });
|
|
370
|
+
if (this.host.runStatus(runId) === 'CANCELLING') {
|
|
371
|
+
await this.host.cancel(runId, threadId, turnId, cwd, this.host.interrupted(runId) ? 'INTERRUPTED' : 'CANCELLED');
|
|
372
|
+
this.runner.releaseEnvironment(runId);
|
|
373
|
+
return;
|
|
374
|
+
}
|
|
375
|
+
this.host.emit(runId, 'run.running', { threadId, turnId }, 'RUNNING');
|
|
376
|
+
}
|
|
377
|
+
catch (error) {
|
|
378
|
+
if (this.host.completeCancelled(runId, cwd)) {
|
|
379
|
+
this.runner.releaseEnvironment(runId);
|
|
380
|
+
return;
|
|
381
|
+
}
|
|
382
|
+
this.host.emit(runId, 'run.failed', { code: error instanceof Error ? error.message : 'CODEX_RUN_FAILED' }, 'FAILED');
|
|
383
|
+
this.runner.execution.runs.delete(runId);
|
|
384
|
+
this.runner.releaseEnvironment(runId);
|
|
385
|
+
this.host.removeActive(runId);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { CodexAppServerClient, type CodexComposerInput, type CodexRunConfiguration, type JsonRpcNotification } from '../codex-app-server.js';
|
|
2
|
+
import { AbstractRunner, type ExternalResumeContext, type ExternalResumeResult, type RunnerDiscoveryContext, type RunnerSessionPresentationContext, type RunnerSessionPresentation, type RunnerProjectionTitleInput } from './abstract-runner.js';
|
|
3
|
+
import type { NodeCapabilities, RunnerDefaultConfiguration, RunnerProfile } from '@myagentroam/protocol';
|
|
4
|
+
import type { NodeAgentSession, NodeDatabase } from '../database.js';
|
|
5
|
+
import type { NodeWorkspace } from '../database.js';
|
|
6
|
+
export declare class CodexRunner extends AbstractRunner<'codex'> {
|
|
7
|
+
private readonly client;
|
|
8
|
+
readonly name: "codex";
|
|
9
|
+
readonly discoveryScope: "ALL_WORKSPACES";
|
|
10
|
+
readonly execution: CodexExecutionState;
|
|
11
|
+
private fastEnabled;
|
|
12
|
+
private environmentFingerprint;
|
|
13
|
+
private readonly environmentRuns;
|
|
14
|
+
constructor(client?: CodexAppServerClient);
|
|
15
|
+
profile(capabilities: NodeCapabilities): RunnerProfile;
|
|
16
|
+
available(capabilities: NodeCapabilities): boolean;
|
|
17
|
+
executeGlobalCommand(commandId: string, input: string): unknown;
|
|
18
|
+
serviceTier(): 'fast' | undefined;
|
|
19
|
+
usesRunnerTitleForRename(): boolean;
|
|
20
|
+
renameNative(session: NodeAgentSession, input: {
|
|
21
|
+
readonly title?: string | null;
|
|
22
|
+
readonly pinned?: boolean;
|
|
23
|
+
}, database: NodeDatabase): Promise<void>;
|
|
24
|
+
projectedRunnerTitle(metadata: ReturnType<NodeDatabase['getNativeSessionMetadata']>, input: RunnerProjectionTitleInput, database: NodeDatabase | undefined): string | null;
|
|
25
|
+
readOfficialConversation(session: NodeAgentSession, input: {
|
|
26
|
+
readonly cursor?: string;
|
|
27
|
+
readonly limit?: number;
|
|
28
|
+
}, managedTurn: (nativeTurnId: string) => import('../database.js').NodeConversationTurn | undefined): Promise<{
|
|
29
|
+
readonly turns: readonly import("../database.js").NodeConversationTurn[];
|
|
30
|
+
readonly nextCursor: string | null;
|
|
31
|
+
} | undefined>;
|
|
32
|
+
readExternalActivity(session: NodeAgentSession): Promise<"UNAVAILABLE" | "MANAGED_ACTIVE" | "EXTERNAL_ACTIVE" | "IDLE" | undefined>;
|
|
33
|
+
acceptsTruncatedNativeHistory(): boolean;
|
|
34
|
+
readManagedRunnerTitle(session: NodeAgentSession, nativeSessionId: string): Promise<string | undefined>;
|
|
35
|
+
nativeImageRoot(session: NodeAgentSession): string | undefined;
|
|
36
|
+
managedRunForNativeTurn(nativeTurnId: string): string | undefined;
|
|
37
|
+
protected profileForValidation(): RunnerProfile;
|
|
38
|
+
defaultConfiguration(): RunnerDefaultConfiguration;
|
|
39
|
+
resumeExternal(external: NodeAgentSession, context: ExternalResumeContext, force?: boolean): Promise<ExternalResumeResult>;
|
|
40
|
+
discoverSessions(context: RunnerDiscoveryContext, workspace?: NodeWorkspace): Promise<readonly NodeAgentSession[]>;
|
|
41
|
+
readContextUsage(session: NodeAgentSession): Promise<import("../native-session-history.js").NativeCodexContextUsage | undefined>;
|
|
42
|
+
presentSession(session: NodeAgentSession, capabilities: NodeCapabilities, context: RunnerSessionPresentationContext): RunnerSessionPresentation;
|
|
43
|
+
onNotification(listener: (notification: JsonRpcNotification) => void): () => void;
|
|
44
|
+
start(): Promise<void>;
|
|
45
|
+
prepareEnvironment(environment: Readonly<Record<string, string>>, runId: string): void;
|
|
46
|
+
releaseEnvironment(runId: string): void;
|
|
47
|
+
stop(): void;
|
|
48
|
+
request(method: string, params: unknown): Promise<unknown>;
|
|
49
|
+
respond(requestId: string | number, result: unknown): void;
|
|
50
|
+
listThreads(): Promise<unknown>;
|
|
51
|
+
readThread(threadId: string, includeTurns?: boolean): Promise<unknown>;
|
|
52
|
+
startThread(cwd: string, configuration?: CodexRunConfiguration): Promise<unknown>;
|
|
53
|
+
forkThread(threadId: string, cwd: string, lastTurnId: string, configuration?: CodexRunConfiguration): Promise<unknown>;
|
|
54
|
+
forkNative(session: NodeAgentSession, boundary: string | null, title: string): Promise<string>;
|
|
55
|
+
resumeThread(threadId: string, cwd: string, configuration?: CodexRunConfiguration): Promise<unknown>;
|
|
56
|
+
startTurn(threadId: string, text: string, cwd: string, configuration?: CodexRunConfiguration, attachments?: readonly Extract<CodexComposerInput, {
|
|
57
|
+
readonly type: 'localImage';
|
|
58
|
+
}>[]): Promise<unknown>;
|
|
59
|
+
interruptTurn(threadId: string, turnId: string): Promise<unknown>;
|
|
60
|
+
setThreadName(threadId: string, name: string): Promise<unknown>;
|
|
61
|
+
listCollaborationModes(): Promise<unknown>;
|
|
62
|
+
}
|
|
63
|
+
export declare class CodexExecutionState {
|
|
64
|
+
readonly runs: Map<string, {
|
|
65
|
+
sessionId: string;
|
|
66
|
+
threadId: string;
|
|
67
|
+
turnId?: string;
|
|
68
|
+
cwd: string;
|
|
69
|
+
refreshTitle?: boolean;
|
|
70
|
+
}>;
|
|
71
|
+
readonly managedTurns: Map<string, {
|
|
72
|
+
sessionId: string;
|
|
73
|
+
runId: string;
|
|
74
|
+
}>;
|
|
75
|
+
readonly approvals: Map<string, string | number>;
|
|
76
|
+
readonly userInputs: Map<string, {
|
|
77
|
+
readonly runId: string;
|
|
78
|
+
readonly requestId: string | number;
|
|
79
|
+
readonly questions: readonly {
|
|
80
|
+
readonly id: string;
|
|
81
|
+
readonly options: readonly string[];
|
|
82
|
+
readonly allowOther: boolean;
|
|
83
|
+
}[];
|
|
84
|
+
}>;
|
|
85
|
+
}
|