@adecore/agents 0.0.1 → 0.17.0-beta.1
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/LICENSE +110 -0
- package/README.md +33 -0
- package/dist/async.d.ts +2 -0
- package/dist/async.js +31 -0
- package/dist/chat/attachment-store.d.ts +10 -0
- package/dist/chat/attachment-store.js +93 -0
- package/dist/chat/backend.d.ts +214 -0
- package/dist/chat/backend.js +1 -0
- package/dist/chat/background-work.d.ts +8 -0
- package/dist/chat/background-work.js +33 -0
- package/dist/chat/bookmark-store.d.ts +25 -0
- package/dist/chat/bookmark-store.js +141 -0
- package/dist/chat/chat-core.d.ts +311 -0
- package/dist/chat/chat-core.js +1025 -0
- package/dist/chat/chat-log.d.ts +33 -0
- package/dist/chat/chat-log.js +163 -0
- package/dist/chat/chat-process.d.ts +46 -0
- package/dist/chat/chat-process.js +190 -0
- package/dist/chat/chat-session.d.ts +209 -0
- package/dist/chat/chat-session.js +1511 -0
- package/dist/chat/chat-store.d.ts +37 -0
- package/dist/chat/chat-store.js +202 -0
- package/dist/chat/chat-title.d.ts +10 -0
- package/dist/chat/chat-title.js +74 -0
- package/dist/chat/claude-backend.d.ts +35 -0
- package/dist/chat/claude-backend.js +214 -0
- package/dist/chat/claude-protocol.d.ts +41 -0
- package/dist/chat/claude-protocol.js +642 -0
- package/dist/chat/claude-title.d.ts +11 -0
- package/dist/chat/claude-title.js +97 -0
- package/dist/chat/claude-transcript.d.ts +28 -0
- package/dist/chat/claude-transcript.js +211 -0
- package/dist/chat/codex-backend.d.ts +51 -0
- package/dist/chat/codex-backend.js +364 -0
- package/dist/chat/codex-protocol.d.ts +56 -0
- package/dist/chat/codex-protocol.js +767 -0
- package/dist/chat/codex-thread.d.ts +32 -0
- package/dist/chat/codex-thread.js +131 -0
- package/dist/chat/codex-transport.d.ts +42 -0
- package/dist/chat/codex-transport.js +188 -0
- package/dist/chat/composer-preferences.d.ts +15 -0
- package/dist/chat/composer-preferences.js +46 -0
- package/dist/chat/context-breakdown.d.ts +2 -0
- package/dist/chat/context-breakdown.js +74 -0
- package/dist/chat/delta-coalescer.d.ts +12 -0
- package/dist/chat/delta-coalescer.js +55 -0
- package/dist/chat/errors.d.ts +4 -0
- package/dist/chat/errors.js +4 -0
- package/dist/chat/fake-claude.d.ts +3 -0
- package/dist/chat/fake-claude.js +982 -0
- package/dist/chat/fake-cli.d.ts +25 -0
- package/dist/chat/fake-cli.js +157 -0
- package/dist/chat/fake-codex.d.ts +10 -0
- package/dist/chat/fake-codex.js +502 -0
- package/dist/chat/fixtures/claude-2.1.285-auto-fallback.json +24 -0
- package/dist/chat/fixtures/claude-2.1.285-native-children.json +6600 -0
- package/dist/chat/fixtures/claude-2.1.285-resume-direct-compact.json +202 -0
- package/dist/chat/fixtures/claude-2.1.285-resume-task-notification.json +57 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.jsonl +10 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.meta.json +1 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.jsonl +2 -0
- package/dist/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.meta.json +1 -0
- package/dist/chat/fixtures/codex-0.159.2-native-approval.json +119 -0
- package/dist/chat/fixtures/codex-0.159.2-native-file-approval.json +136 -0
- package/dist/chat/fixtures/codex-0.159.2-native-interacted.json +220 -0
- package/dist/chat/fixtures/codex-0.159.2-usage-windows.json +74 -0
- package/dist/chat/input.d.ts +19 -0
- package/dist/chat/input.js +71 -0
- package/dist/chat/limit-resume.d.ts +11 -0
- package/dist/chat/limit-resume.js +68 -0
- package/dist/chat/projector.d.ts +60 -0
- package/dist/chat/projector.js +860 -0
- package/dist/chat/request-summary.d.ts +3 -0
- package/dist/chat/request-summary.js +143 -0
- package/dist/chat/subagent-projection.d.ts +8 -0
- package/dist/chat/subagent-projection.js +40 -0
- package/dist/chat/subagent-reader.d.ts +66 -0
- package/dist/chat/subagent-reader.js +396 -0
- package/dist/chat/subagent-settlement.d.ts +6 -0
- package/dist/chat/subagent-settlement.js +103 -0
- package/dist/chat/thread.d.ts +30 -0
- package/dist/chat/thread.js +147 -0
- package/dist/chat/wake-chat.d.ts +20 -0
- package/dist/chat/wake-chat.js +27 -0
- package/dist/client-sinks.d.ts +9 -0
- package/dist/client-sinks.js +34 -0
- package/dist/coded-error.d.ts +5 -0
- package/dist/coded-error.js +17 -0
- package/dist/context/argv.d.ts +11 -0
- package/dist/context/argv.js +58 -0
- package/dist/context/refusal.d.ts +9 -0
- package/dist/context/refusal.js +38 -0
- package/dist/context/verb.d.ts +85 -0
- package/dist/context/verb.js +233 -0
- package/dist/error-text.d.ts +5 -0
- package/dist/error-text.js +24 -0
- package/dist/events.d.ts +12 -0
- package/dist/events.js +1 -0
- package/dist/fs.d.ts +9 -0
- package/dist/fs.js +107 -0
- package/dist/host/agent-host.d.ts +28 -0
- package/dist/host/agent-host.js +105 -0
- package/dist/host/environment.d.ts +7 -0
- package/dist/host/environment.js +22 -0
- package/dist/host/handlers.d.ts +30 -0
- package/dist/host/handlers.js +111 -0
- package/dist/host/memory-port.d.ts +2 -0
- package/dist/host/memory-port.js +25 -0
- package/dist/host/wiring.d.ts +40 -0
- package/dist/host/wiring.js +120 -0
- package/dist/lineage.d.ts +44 -0
- package/dist/lineage.js +134 -0
- package/dist/messages/deliver-message.d.ts +21 -0
- package/dist/messages/deliver-message.js +42 -0
- package/dist/messages/deliver-notice.d.ts +25 -0
- package/dist/messages/deliver-notice.js +75 -0
- package/dist/messages/notice-notes.d.ts +15 -0
- package/dist/messages/notice-notes.js +26 -0
- package/dist/messages/notice-store.d.ts +30 -0
- package/dist/messages/notice-store.js +120 -0
- package/dist/modes.d.ts +11 -0
- package/dist/modes.js +28 -0
- package/dist/outbox/manual-clock.d.ts +10 -0
- package/dist/outbox/manual-clock.js +25 -0
- package/dist/outbox/outbox-worker.d.ts +44 -0
- package/dist/outbox/outbox-worker.js +173 -0
- package/dist/outbox/outbox.d.ts +37 -0
- package/dist/outbox/outbox.js +76 -0
- package/dist/providers/accounts/accounts.d.ts +20 -0
- package/dist/providers/accounts/accounts.js +158 -0
- package/dist/providers/accounts/launch.d.ts +17 -0
- package/dist/providers/accounts/launch.js +30 -0
- package/dist/providers/accounts/service.d.ts +87 -0
- package/dist/providers/accounts/service.js +538 -0
- package/dist/providers/accounts/shadow-home.d.ts +8 -0
- package/dist/providers/accounts/shadow-home.js +70 -0
- package/dist/providers/accounts/status.d.ts +12 -0
- package/dist/providers/accounts/status.js +85 -0
- package/dist/providers/accounts/store.d.ts +14 -0
- package/dist/providers/accounts/store.js +112 -0
- package/dist/providers/accounts/test-accounts.d.ts +12 -0
- package/dist/providers/accounts/test-accounts.js +38 -0
- package/dist/providers/accounts/variables.d.ts +27 -0
- package/dist/providers/accounts/variables.js +94 -0
- package/dist/providers/catalog.d.ts +17 -0
- package/dist/providers/catalog.js +76 -0
- package/dist/providers/claude-models.json +114 -0
- package/dist/providers/claude-provider.d.ts +4 -0
- package/dist/providers/claude-provider.js +29 -0
- package/dist/providers/claude.d.ts +15 -0
- package/dist/providers/claude.js +105 -0
- package/dist/providers/codex-models.json +135 -0
- package/dist/providers/codex-provider.d.ts +4 -0
- package/dist/providers/codex-provider.js +27 -0
- package/dist/providers/codex-rules.d.ts +9 -0
- package/dist/providers/codex-rules.js +35 -0
- package/dist/providers/codex.d.ts +14 -0
- package/dist/providers/codex.js +52 -0
- package/dist/providers/detect.d.ts +6 -0
- package/dist/providers/detect.js +30 -0
- package/dist/providers/provider.d.ts +25 -0
- package/dist/providers/provider.js +1 -0
- package/dist/providers/registry.d.ts +28 -0
- package/dist/providers/registry.js +118 -0
- package/dist/record-directory.d.ts +27 -0
- package/dist/record-directory.js +114 -0
- package/dist/run-process.d.ts +13 -0
- package/dist/run-process.js +42 -0
- package/dist/serializer.d.ts +9 -0
- package/dist/serializer.js +34 -0
- package/dist/skills.d.ts +21 -0
- package/dist/skills.js +174 -0
- package/dist/tasks/background-limit.d.ts +16 -0
- package/dist/tasks/background-limit.js +55 -0
- package/dist/tasks/end-children.d.ts +34 -0
- package/dist/tasks/end-children.js +53 -0
- package/dist/tasks/give-task.d.ts +14 -0
- package/dist/tasks/give-task.js +33 -0
- package/dist/tasks/task-coordinator.d.ts +52 -0
- package/dist/tasks/task-coordinator.js +323 -0
- package/dist/tasks/task-store.d.ts +49 -0
- package/dist/tasks/task-store.js +197 -0
- package/dist/tasks/task-work.d.ts +47 -0
- package/dist/tasks/task-work.js +28 -0
- package/dist/tasks/waiting-child.d.ts +51 -0
- package/dist/tasks/waiting-child.js +143 -0
- package/dist/tasks/wake-parent.d.ts +19 -0
- package/dist/tasks/wake-parent.js +109 -0
- package/dist/tasks/wiring.d.ts +51 -0
- package/dist/tasks/wiring.js +151 -0
- package/dist/title-file.d.ts +2 -0
- package/dist/title-file.js +55 -0
- package/dist/usage/accounts.d.ts +15 -0
- package/dist/usage/accounts.js +64 -0
- package/dist/usage/aggregate.d.ts +12 -0
- package/dist/usage/aggregate.js +154 -0
- package/dist/usage/exchange.d.ts +16 -0
- package/dist/usage/exchange.js +84 -0
- package/dist/usage/index-file.d.ts +15 -0
- package/dist/usage/index-file.js +123 -0
- package/dist/usage/limits/monitor.d.ts +50 -0
- package/dist/usage/limits/monitor.js +179 -0
- package/dist/usage/limits/normalize.d.ts +21 -0
- package/dist/usage/limits/normalize.js +160 -0
- package/dist/usage/limits/probe.d.ts +9 -0
- package/dist/usage/limits/probe.js +113 -0
- package/dist/usage/prices-snapshot.json +1071 -0
- package/dist/usage/pricing.d.ts +34 -0
- package/dist/usage/pricing.js +186 -0
- package/dist/usage/projects.d.ts +17 -0
- package/dist/usage/projects.js +49 -0
- package/dist/usage/readers/claude.d.ts +3 -0
- package/dist/usage/readers/claude.js +59 -0
- package/dist/usage/readers/codex.d.ts +23 -0
- package/dist/usage/readers/codex.js +155 -0
- package/dist/usage/record.d.ts +15 -0
- package/dist/usage/record.js +39 -0
- package/dist/usage/roots.d.ts +12 -0
- package/dist/usage/roots.js +29 -0
- package/dist/usage/scanner.d.ts +30 -0
- package/dist/usage/scanner.js +234 -0
- package/dist/usage/usage-service.d.ts +35 -0
- package/dist/usage/usage-service.js +130 -0
- package/dist/watch-seam.d.ts +29 -0
- package/dist/watch-seam.js +78 -0
- package/dist/watch-test-helpers.d.ts +28 -0
- package/dist/watch-test-helpers.js +86 -0
- package/package.json +42 -3
- package/src/async.ts +40 -0
- package/src/chat/attachment-store.ts +108 -0
- package/src/chat/backend.ts +199 -0
- package/src/chat/background-work.ts +42 -0
- package/src/chat/bookmark-store.ts +166 -0
- package/src/chat/chat-core.ts +1228 -0
- package/src/chat/chat-log.ts +187 -0
- package/src/chat/chat-process.ts +237 -0
- package/src/chat/chat-session.ts +1723 -0
- package/src/chat/chat-store.ts +261 -0
- package/src/chat/chat-title.ts +90 -0
- package/src/chat/claude-backend.ts +235 -0
- package/src/chat/claude-protocol.ts +684 -0
- package/src/chat/claude-title.ts +106 -0
- package/src/chat/claude-transcript.ts +233 -0
- package/src/chat/codex-backend.ts +397 -0
- package/src/chat/codex-protocol.ts +872 -0
- package/src/chat/codex-thread.ts +162 -0
- package/src/chat/codex-transport.ts +224 -0
- package/src/chat/composer-preferences.ts +67 -0
- package/src/chat/context-breakdown.ts +80 -0
- package/src/chat/delta-coalescer.ts +62 -0
- package/src/chat/errors.ts +25 -0
- package/src/chat/fake-claude.ts +1006 -0
- package/src/chat/fake-cli.ts +199 -0
- package/src/chat/fake-codex.ts +534 -0
- package/src/chat/fixtures/claude-2.1.285-auto-fallback.json +24 -0
- package/src/chat/fixtures/claude-2.1.285-native-children.json +6600 -0
- package/src/chat/fixtures/claude-2.1.285-resume-direct-compact.json +202 -0
- package/src/chat/fixtures/claude-2.1.285-resume-task-notification.json +57 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.jsonl +10 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a4c2e8f10b3d5a7e9.meta.json +1 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.jsonl +2 -0
- package/src/chat/fixtures/claude-projects/-work-demo/5f1c2a9e-0b7d-4c1e-9a53-3e2f8d6b7a10/subagents/agent-a9b8c7d6e5f4a3b21.meta.json +1 -0
- package/src/chat/fixtures/codex-0.159.2-native-approval.json +119 -0
- package/src/chat/fixtures/codex-0.159.2-native-file-approval.json +136 -0
- package/src/chat/fixtures/codex-0.159.2-native-interacted.json +220 -0
- package/src/chat/fixtures/codex-0.159.2-usage-windows.json +74 -0
- package/src/chat/input.ts +89 -0
- package/src/chat/limit-resume.ts +74 -0
- package/src/chat/projector.ts +969 -0
- package/src/chat/request-summary.ts +168 -0
- package/src/chat/subagent-projection.ts +45 -0
- package/src/chat/subagent-reader.ts +469 -0
- package/src/chat/subagent-settlement.ts +111 -0
- package/src/chat/thread.ts +167 -0
- package/src/chat/wake-chat.ts +45 -0
- package/src/client-sinks.ts +39 -0
- package/src/coded-error.ts +18 -0
- package/src/context/argv.ts +61 -0
- package/src/context/refusal.ts +50 -0
- package/src/context/verb.ts +392 -0
- package/src/error-text.ts +28 -0
- package/src/events.ts +9 -0
- package/src/fs.ts +118 -0
- package/src/host/agent-host.ts +124 -0
- package/src/host/environment.ts +31 -0
- package/src/host/handlers.ts +142 -0
- package/src/host/memory-port.ts +27 -0
- package/src/host/wiring.ts +164 -0
- package/src/lineage.ts +159 -0
- package/src/messages/deliver-message.ts +61 -0
- package/src/messages/deliver-notice.ts +120 -0
- package/src/messages/notice-notes.ts +34 -0
- package/src/messages/notice-store.ts +142 -0
- package/src/modes.ts +38 -0
- package/src/outbox/manual-clock.ts +31 -0
- package/src/outbox/outbox-worker.ts +214 -0
- package/src/outbox/outbox.ts +106 -0
- package/src/providers/accounts/accounts.ts +192 -0
- package/src/providers/accounts/launch.ts +55 -0
- package/src/providers/accounts/service.ts +632 -0
- package/src/providers/accounts/shadow-home.ts +85 -0
- package/src/providers/accounts/status.ts +106 -0
- package/src/providers/accounts/store.ts +158 -0
- package/src/providers/accounts/test-accounts.ts +48 -0
- package/src/providers/accounts/variables.ts +132 -0
- package/src/providers/catalog.ts +90 -0
- package/src/providers/claude-models.json +114 -0
- package/src/providers/claude-provider.ts +32 -0
- package/src/providers/claude.ts +123 -0
- package/src/providers/codex-models.json +135 -0
- package/src/providers/codex-provider.ts +30 -0
- package/src/providers/codex-rules.ts +54 -0
- package/src/providers/codex.ts +69 -0
- package/src/providers/detect.ts +40 -0
- package/src/providers/provider.ts +46 -0
- package/src/providers/registry.ts +150 -0
- package/src/record-directory.ts +136 -0
- package/src/run-process.ts +61 -0
- package/src/serializer.ts +41 -0
- package/src/skills.ts +199 -0
- package/src/tasks/background-limit.ts +72 -0
- package/src/tasks/end-children.ts +100 -0
- package/src/tasks/give-task.ts +52 -0
- package/src/tasks/task-coordinator.ts +384 -0
- package/src/tasks/task-store.ts +236 -0
- package/src/tasks/task-work.ts +62 -0
- package/src/tasks/waiting-child.ts +203 -0
- package/src/tasks/wake-parent.ts +142 -0
- package/src/tasks/wiring.ts +231 -0
- package/src/title-file.ts +57 -0
- package/src/usage/accounts.ts +86 -0
- package/src/usage/aggregate.ts +220 -0
- package/src/usage/exchange.ts +93 -0
- package/src/usage/index-file.ts +178 -0
- package/src/usage/limits/monitor.ts +239 -0
- package/src/usage/limits/normalize.ts +188 -0
- package/src/usage/limits/probe.ts +120 -0
- package/src/usage/prices-snapshot.json +1071 -0
- package/src/usage/pricing.ts +236 -0
- package/src/usage/projects.ts +65 -0
- package/src/usage/readers/claude.ts +60 -0
- package/src/usage/readers/codex.ts +196 -0
- package/src/usage/record.ts +60 -0
- package/src/usage/roots.ts +39 -0
- package/src/usage/scanner.ts +265 -0
- package/src/usage/usage-service.ts +161 -0
- package/src/watch-seam.ts +111 -0
- package/src/watch-test-helpers.ts +102 -0
|
@@ -0,0 +1,534 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Network-free `codex app-server` fake. Prompt commands exercise approvals, edits, questions,
|
|
3
|
+
* interrupts, failures, names, subagents, pagination and forks through the real JSON-RPC shapes.
|
|
4
|
+
*/
|
|
5
|
+
import { runOverStdio, type FakeCli } from './fake-cli.ts';
|
|
6
|
+
|
|
7
|
+
type Frame = Record<string, unknown>;
|
|
8
|
+
|
|
9
|
+
type PendingApproval = { rpcId: number; entry: Frame; kind: 'command' | 'fileChange' };
|
|
10
|
+
|
|
11
|
+
// How many steps a spawned agent takes: more than a thread row keeps, so only its own thread has them all.
|
|
12
|
+
export const FAKE_CHILD_STEPS = 250;
|
|
13
|
+
|
|
14
|
+
// The threads of spawned agents, outside any one process: the real ones are on disk, so a process that never ran them reads them too.
|
|
15
|
+
const childThreads = new Map<string, Frame[]>();
|
|
16
|
+
|
|
17
|
+
// The turn ids per thread, outside any one process for the same reason.
|
|
18
|
+
const threadTurns = new Map<string, string[]>();
|
|
19
|
+
|
|
20
|
+
// The developer instructions per thread, kept from its start the way Codex keeps them in the rollout.
|
|
21
|
+
const threadInstructions = new Map<string, string | null>();
|
|
22
|
+
|
|
23
|
+
// Every `thread/fork` a fake was asked, oldest first, so a test can see what the daemon forked at.
|
|
24
|
+
export const fakeCodexForks: Frame[] = [];
|
|
25
|
+
|
|
26
|
+
export interface FakeCodexOptions {
|
|
27
|
+
// How the note a host repeats in front of a resumed thread's first prompt starts; `pasted?` answers it back.
|
|
28
|
+
resumeLead?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function fakeCodexWith(options: FakeCodexOptions): FakeCli {
|
|
32
|
+
return (io) => {
|
|
33
|
+
const out = io.out;
|
|
34
|
+
|
|
35
|
+
let serverRequestId = 0;
|
|
36
|
+
let itemCounter = 0;
|
|
37
|
+
let threadId = '';
|
|
38
|
+
let threadModel = 'fake-model';
|
|
39
|
+
let threadName: string | null = null;
|
|
40
|
+
let threadSandbox = '';
|
|
41
|
+
let threadApproval = '';
|
|
42
|
+
let turnId = '';
|
|
43
|
+
let turnEffort: string | null = null;
|
|
44
|
+
let pasted: string | null = null;
|
|
45
|
+
|
|
46
|
+
const notify = (method: string, params: unknown): void => {
|
|
47
|
+
out({ method, params, emittedAtMs: Date.now() });
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Codex item ids are unique across processes (UUIDs and response ids); a nonce keeps the fake honest.
|
|
51
|
+
const nonce = Math.random().toString(36).slice(2, 6);
|
|
52
|
+
|
|
53
|
+
const item = (type: string, fields: Frame): Frame => ({ type, id: `${type}-${nonce}-${++itemCounter}`, ...fields });
|
|
54
|
+
|
|
55
|
+
const started = (entry: Frame): void => {
|
|
56
|
+
notify('item/started', { item: entry, threadId, turnId, startedAtMs: Date.now() });
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
const completed = (entry: Frame): void => {
|
|
60
|
+
notify('item/completed', { item: entry, threadId, turnId, completedAtMs: Date.now() });
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
const usage = (): void => {
|
|
64
|
+
notify('thread/tokenUsage/updated', {
|
|
65
|
+
threadId,
|
|
66
|
+
turnId,
|
|
67
|
+
tokenUsage: {
|
|
68
|
+
total: {
|
|
69
|
+
totalTokens: 25090,
|
|
70
|
+
inputTokens: 25085,
|
|
71
|
+
cachedInputTokens: 12928,
|
|
72
|
+
cacheWriteInputTokens: 0,
|
|
73
|
+
outputTokens: 5,
|
|
74
|
+
reasoningOutputTokens: 0
|
|
75
|
+
},
|
|
76
|
+
last: {
|
|
77
|
+
totalTokens: 25090,
|
|
78
|
+
inputTokens: 25085,
|
|
79
|
+
cachedInputTokens: 12928,
|
|
80
|
+
cacheWriteInputTokens: 0,
|
|
81
|
+
outputTokens: 5,
|
|
82
|
+
reasoningOutputTokens: 0
|
|
83
|
+
},
|
|
84
|
+
// Codex reports the window of the model the thread runs on, which spark makes smaller.
|
|
85
|
+
modelContextWindow: threadModel.includes('spark') ? 121600 : 258400
|
|
86
|
+
}
|
|
87
|
+
});
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const agentMessage = (text: string): void => {
|
|
91
|
+
const entry = item('agentMessage', { text: '', phase: 'final_answer', memoryCitation: null, delivery: null, questions: null });
|
|
92
|
+
started(entry);
|
|
93
|
+
const half = Math.ceil(text.length / 2);
|
|
94
|
+
notify('item/agentMessage/delta', { threadId, turnId, itemId: entry.id, delta: text.slice(0, half) });
|
|
95
|
+
notify('item/agentMessage/delta', { threadId, turnId, itemId: entry.id, delta: text.slice(half) });
|
|
96
|
+
completed({ ...entry, text });
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
const turnStarted = (): void => {
|
|
100
|
+
turnId = `turn-${nonce}-${++itemCounter}`;
|
|
101
|
+
threadTurns.set(threadId, [...(threadTurns.get(threadId) ?? []), turnId]);
|
|
102
|
+
notify('thread/status/changed', { threadId, status: { type: 'active', activeFlags: [] } });
|
|
103
|
+
notify('turn/started', { threadId, turn: { id: turnId, items: [], itemsView: 'notLoaded', status: 'inProgress', error: null } });
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
const turnCompleted = (status: 'completed' | 'interrupted' | 'failed', error: string | null = null, codexErrorInfo: string | null = null): void => {
|
|
107
|
+
usage();
|
|
108
|
+
notify('thread/status/changed', { threadId, status: { type: 'idle' } });
|
|
109
|
+
notify('turn/completed', {
|
|
110
|
+
threadId,
|
|
111
|
+
turn: {
|
|
112
|
+
id: turnId,
|
|
113
|
+
items: [],
|
|
114
|
+
itemsView: 'summary',
|
|
115
|
+
status,
|
|
116
|
+
error: error ? { message: error, codexErrorInfo, additionalDetails: null } : null
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
turnId = '';
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
let pendingApproval: PendingApproval | null = null;
|
|
123
|
+
let pendingQuestion: { rpcId: number; questionId: string } | null = null;
|
|
124
|
+
let pendingSteer = false;
|
|
125
|
+
let slow = false;
|
|
126
|
+
|
|
127
|
+
const askApproval = (kind: 'command' | 'fileChange', entry: Frame, params: Frame): void => {
|
|
128
|
+
pendingApproval = { rpcId: serverRequestId, entry, kind };
|
|
129
|
+
notify('thread/status/changed', { threadId, status: { type: 'active', activeFlags: ['waitingOnApproval'] } });
|
|
130
|
+
out({
|
|
131
|
+
method: kind === 'command' ? 'item/commandExecution/requestApproval' : 'item/fileChange/requestApproval',
|
|
132
|
+
id: serverRequestId++,
|
|
133
|
+
params: { threadId, turnId, itemId: entry.id, startedAtMs: Date.now(), ...params }
|
|
134
|
+
});
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const handleTurnStart = (params: Frame): void => {
|
|
138
|
+
turnEffort = typeof params.effort === 'string' ? params.effort : null;
|
|
139
|
+
const input = Array.isArray(params.input) ? (params.input[0] as { text?: string } | undefined) : undefined;
|
|
140
|
+
const raw = input?.text ?? '';
|
|
141
|
+
const gap = raw.indexOf('\n\n');
|
|
142
|
+
const noted = options.resumeLead !== undefined && raw.startsWith(options.resumeLead) && gap !== -1;
|
|
143
|
+
if (noted) {
|
|
144
|
+
pasted = raw.slice(0, gap);
|
|
145
|
+
}
|
|
146
|
+
const text = noted ? raw.slice(gap + 2) : raw;
|
|
147
|
+
if (text === 'name?') {
|
|
148
|
+
turnStarted();
|
|
149
|
+
agentMessage(threadName ?? 'unnamed');
|
|
150
|
+
turnCompleted('completed');
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
if (text === 'note?' || text === 'pasted?') {
|
|
154
|
+
turnStarted();
|
|
155
|
+
agentMessage((text === 'note?' ? threadInstructions.get(threadId) : pasted) ?? 'nothing');
|
|
156
|
+
turnCompleted('completed');
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
turnStarted();
|
|
160
|
+
const user = item('userMessage', { clientId: null, content: [{ type: 'text', text, text_elements: [] }] });
|
|
161
|
+
started(user);
|
|
162
|
+
completed(user);
|
|
163
|
+
if (text === 'crash') {
|
|
164
|
+
io.exit(1);
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
167
|
+
if (text === 'crash loudly') {
|
|
168
|
+
io.err('Error: the fake lost its thread\n');
|
|
169
|
+
io.exit(1);
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
if (text === 'fail') {
|
|
173
|
+
turnCompleted('failed', 'The model is overloaded');
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
// Lines of their own, so a task brief around them still fails the way Codex 0.156.1 does.
|
|
177
|
+
const lines = text.split('\n');
|
|
178
|
+
// A dev server Codex leaves running past the turn; its process ends once the test says later is.
|
|
179
|
+
if (lines.includes('serve')) {
|
|
180
|
+
const command = item('commandExecution', { command: "/bin/zsh -lc 'bun dev'", cwd: io.cwd, processId: `pty-${nonce}`, status: 'inProgress' });
|
|
181
|
+
started(command);
|
|
182
|
+
io.later(() => completed({ ...command, status: 'completed', aggregatedOutput: '', exitCode: 0 }));
|
|
183
|
+
}
|
|
184
|
+
if (lines.includes('overloaded')) {
|
|
185
|
+
turnCompleted('failed', 'Selected model is at capacity. Please try a different model.', 'serverOverloaded');
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
const limit = lines.find((line) => line.startsWith('limit:'));
|
|
189
|
+
if (limit !== undefined) {
|
|
190
|
+
notify('account/rateLimits/updated', {
|
|
191
|
+
rateLimits: {
|
|
192
|
+
limitId: 'codex',
|
|
193
|
+
primary: { usedPercent: 100, windowDurationMins: 300, resetsAt: Number(limit.slice(6)) },
|
|
194
|
+
secondary: { usedPercent: 40, windowDurationMins: 10080, resetsAt: Number(limit.slice(6)) + 86_400 }
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
turnCompleted('failed', "You've hit your usage limit.", 'usageLimitExceeded');
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (text === 'slow') {
|
|
201
|
+
slow = true;
|
|
202
|
+
started(item('agentMessage', { text: '', phase: 'final_answer', memoryCitation: null, delivery: null, questions: null }));
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (text.startsWith('tool:')) {
|
|
206
|
+
const command = text.slice(5).trim();
|
|
207
|
+
const entry = item('commandExecution', {
|
|
208
|
+
command: `/bin/zsh -lc ${command}`,
|
|
209
|
+
cwd: io.cwd,
|
|
210
|
+
status: 'inProgress',
|
|
211
|
+
aggregatedOutput: null,
|
|
212
|
+
exitCode: null
|
|
213
|
+
});
|
|
214
|
+
started(entry);
|
|
215
|
+
askApproval('command', entry, {
|
|
216
|
+
kind: 'command',
|
|
217
|
+
command: `/bin/zsh -lc ${command}`,
|
|
218
|
+
cwd: io.cwd,
|
|
219
|
+
reason: 'Run a command',
|
|
220
|
+
proposedExecpolicyAmendment: [command.split(' ')[0]],
|
|
221
|
+
availableDecisions: ['accept', { acceptWithExecpolicyAmendment: { execpolicy_amendment: [command.split(' ')[0]] } }, 'cancel']
|
|
222
|
+
});
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
if (text.startsWith('edit:')) {
|
|
226
|
+
const path = text.slice(5).trim();
|
|
227
|
+
const entry = item('fileChange', { changes: [{ path, kind: { type: 'add' }, diff: `+++ ${path}\n+hello\n` }], status: 'inProgress' });
|
|
228
|
+
started(entry);
|
|
229
|
+
askApproval('fileChange', entry, { reason: 'Write outside the sandbox' });
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
const finish = text.startsWith('spawn and finish:');
|
|
233
|
+
if (finish || text.startsWith('spawn:')) {
|
|
234
|
+
const prompt = text.slice(text.indexOf(':') + 1).trim();
|
|
235
|
+
const childId = `child-${nonce}-${++itemCounter}`;
|
|
236
|
+
const steps: Frame[] = [{ type: 'userMessage', id: `${childId}-prompt`, content: [{ type: 'text', text: prompt, text_elements: [] }] }];
|
|
237
|
+
for (let step = 1; step <= FAKE_CHILD_STEPS; step++) {
|
|
238
|
+
steps.push({
|
|
239
|
+
type: 'commandExecution',
|
|
240
|
+
id: `${childId}-step-${step}`,
|
|
241
|
+
command: `/bin/zsh -lc 'echo ${step}'`,
|
|
242
|
+
cwd: io.cwd,
|
|
243
|
+
status: 'completed',
|
|
244
|
+
aggregatedOutput: `${step}\n`,
|
|
245
|
+
exitCode: 0
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
childThreads.set(childId, steps);
|
|
249
|
+
const spawn = item('collabAgentToolCall', {
|
|
250
|
+
tool: 'spawnAgent',
|
|
251
|
+
prompt,
|
|
252
|
+
model: 'fake-model',
|
|
253
|
+
senderThreadId: threadId,
|
|
254
|
+
receiverThreadIds: [],
|
|
255
|
+
agentsStates: {},
|
|
256
|
+
status: 'inProgress'
|
|
257
|
+
});
|
|
258
|
+
started(spawn);
|
|
259
|
+
const running = { ...spawn, receiverThreadIds: [childId], agentsStates: { [childId]: { status: 'running', message: null } } };
|
|
260
|
+
if (!finish) {
|
|
261
|
+
completed(running);
|
|
262
|
+
agentMessage('spawned');
|
|
263
|
+
turnCompleted('completed');
|
|
264
|
+
return;
|
|
265
|
+
}
|
|
266
|
+
completed({ ...running, status: 'completed', agentsStates: { [childId]: { status: 'completed', message: 'the docs are read' } } });
|
|
267
|
+
agentMessage('spawned');
|
|
268
|
+
const spawnedIn = turnId;
|
|
269
|
+
turnCompleted('completed');
|
|
270
|
+
// A snapshot of the call from while its agent still ran, delivered after the agent finished.
|
|
271
|
+
io.later(() => notify('item/completed', { item: running, threadId, turnId: spawnedIn, completedAtMs: Date.now() }));
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
/*
|
|
275
|
+
* A spawn the way Codex 0.156.1 reports it: no spawnAgent call, a `subAgentActivity` that started under
|
|
276
|
+
* the call id, the agent's own thread streaming over the same connection, and a `completed` activity
|
|
277
|
+
* with an id of its own once the agent is done, here after the parent's turn ended.
|
|
278
|
+
*/
|
|
279
|
+
if (text.startsWith('spawn agent:')) {
|
|
280
|
+
const prompt = text.slice(text.indexOf(':') + 1).trim();
|
|
281
|
+
const childId = `child-${nonce}-${++itemCounter}`;
|
|
282
|
+
const childTurn = `turn-${nonce}-${++itemCounter}`;
|
|
283
|
+
childThreads.set(childId, [{ type: 'userMessage', id: `${childId}-prompt`, content: [{ type: 'text', text: prompt, text_elements: [] }] }]);
|
|
284
|
+
const activity = (id: string, kind: string): void => {
|
|
285
|
+
const entry = { type: 'subAgentActivity', id, kind, agentThreadId: childId, agentPath: '/root/survey' };
|
|
286
|
+
started(entry);
|
|
287
|
+
completed(entry);
|
|
288
|
+
};
|
|
289
|
+
const inChild = (method: string, params: Frame): void => {
|
|
290
|
+
notify(method, { threadId: childId, ...params });
|
|
291
|
+
};
|
|
292
|
+
activity(`call-spawn-${nonce}-${++itemCounter}`, 'started');
|
|
293
|
+
inChild('thread/status/changed', { status: { type: 'active', activeFlags: [] } });
|
|
294
|
+
inChild('turn/started', { turn: { id: childTurn, items: [], itemsView: 'notLoaded', status: 'inProgress', error: null } });
|
|
295
|
+
const step = { type: 'commandExecution', id: `${childId}-step`, command: "/bin/zsh -lc 'echo PONG'", cwd: io.cwd, status: 'completed' };
|
|
296
|
+
inChild('item/started', { turnId: childTurn, item: { ...step, status: 'inProgress' } });
|
|
297
|
+
inChild('item/completed', { turnId: childTurn, item: { ...step, aggregatedOutput: 'PONG\n', exitCode: 0 } });
|
|
298
|
+
inChild('item/completed', { turnId: childTurn, item: { type: 'agentMessage', id: `${childId}-answer`, text: 'PONG', phase: 'final_answer' } });
|
|
299
|
+
inChild('turn/completed', { turn: { id: childTurn, items: [], itemsView: 'summary', status: 'completed', error: null } });
|
|
300
|
+
agentMessage('spawned');
|
|
301
|
+
turnCompleted('completed');
|
|
302
|
+
io.later(() => activity(`subagent-completed-${childTurn}`, 'completed'));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
if (text.startsWith('ask:')) {
|
|
306
|
+
const question = text.slice(4).trim();
|
|
307
|
+
pendingQuestion = { rpcId: serverRequestId, questionId: 'color' };
|
|
308
|
+
out({
|
|
309
|
+
method: 'item/tool/requestUserInput',
|
|
310
|
+
id: serverRequestId++,
|
|
311
|
+
params: {
|
|
312
|
+
threadId,
|
|
313
|
+
turnId,
|
|
314
|
+
itemId: 'tool-q',
|
|
315
|
+
isBlocking: true,
|
|
316
|
+
questions: [
|
|
317
|
+
{
|
|
318
|
+
id: 'color',
|
|
319
|
+
header: 'Choice',
|
|
320
|
+
question,
|
|
321
|
+
isOther: false,
|
|
322
|
+
isSecret: false,
|
|
323
|
+
options: [
|
|
324
|
+
{ label: 'Red', description: 'Warm' },
|
|
325
|
+
{ label: 'Blue', description: 'Cool' }
|
|
326
|
+
]
|
|
327
|
+
}
|
|
328
|
+
]
|
|
329
|
+
}
|
|
330
|
+
});
|
|
331
|
+
return;
|
|
332
|
+
}
|
|
333
|
+
if (text.startsWith('async:')) {
|
|
334
|
+
const question = text.slice(6).trim();
|
|
335
|
+
pendingSteer = true;
|
|
336
|
+
const entry = item('agentMessage', {
|
|
337
|
+
text: `${question}\n- Red\n- Blue`,
|
|
338
|
+
phase: 'final_answer',
|
|
339
|
+
memoryCitation: null,
|
|
340
|
+
delivery: 'async',
|
|
341
|
+
questions: [{ title: question, options: ['Red', 'Blue'] }]
|
|
342
|
+
});
|
|
343
|
+
started(entry);
|
|
344
|
+
completed(entry);
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
agentMessage(`echo: ${text}${turnEffort ? ` (${turnEffort})` : ''}`);
|
|
348
|
+
turnCompleted('completed');
|
|
349
|
+
};
|
|
350
|
+
|
|
351
|
+
const handleApprovalResponse = (approval: PendingApproval, result: Frame): void => {
|
|
352
|
+
pendingApproval = null;
|
|
353
|
+
notify('serverRequest/resolved', { threadId, requestId: approval.rpcId });
|
|
354
|
+
const decision = result.decision;
|
|
355
|
+
const accepted = decision === 'accept' || decision === 'acceptForSession' || (typeof decision === 'object' && decision !== null);
|
|
356
|
+
const always = decision === 'acceptForSession' || (typeof decision === 'object' && decision !== null);
|
|
357
|
+
if (approval.kind === 'command') {
|
|
358
|
+
const command = String(approval.entry.command).replace('/bin/zsh -lc ', '');
|
|
359
|
+
completed({
|
|
360
|
+
...approval.entry,
|
|
361
|
+
status: accepted ? 'completed' : 'declined',
|
|
362
|
+
aggregatedOutput: accepted ? `ran: ${command}\n` : null,
|
|
363
|
+
exitCode: accepted ? 0 : null
|
|
364
|
+
});
|
|
365
|
+
} else {
|
|
366
|
+
completed({ ...approval.entry, status: accepted ? 'completed' : 'declined' });
|
|
367
|
+
}
|
|
368
|
+
agentMessage(accepted ? (always ? 'done, remembered' : 'done') : 'denied');
|
|
369
|
+
turnCompleted('completed');
|
|
370
|
+
};
|
|
371
|
+
|
|
372
|
+
const handleQuestionResponse = (question: { questionId: string }, result: Frame): void => {
|
|
373
|
+
pendingQuestion = null;
|
|
374
|
+
const answers = result.answers as Record<string, { answers?: string[] }> | undefined;
|
|
375
|
+
agentMessage(`you chose ${answers?.[question.questionId]?.answers?.[0] ?? 'no answer'}`);
|
|
376
|
+
turnCompleted('completed');
|
|
377
|
+
};
|
|
378
|
+
|
|
379
|
+
const handleRequest = (id: unknown, method: string, params: Frame): void => {
|
|
380
|
+
switch (method) {
|
|
381
|
+
case 'initialize':
|
|
382
|
+
out({ id, result: { userAgent: 'fake-codex/0.0.0', codexHome: io.cwd, platformFamily: 'unix', platformOs: 'test' } });
|
|
383
|
+
return;
|
|
384
|
+
case 'model/list':
|
|
385
|
+
out({
|
|
386
|
+
id,
|
|
387
|
+
result: {
|
|
388
|
+
data: [{ model: threadModel, inputModalities: threadModel.includes('spark') ? ['text'] : ['text', 'image'] }],
|
|
389
|
+
nextCursor: null
|
|
390
|
+
}
|
|
391
|
+
});
|
|
392
|
+
return;
|
|
393
|
+
case 'thread/start':
|
|
394
|
+
case 'thread/resume': {
|
|
395
|
+
const resumed = method === 'thread/resume' ? String(params.threadId) : null;
|
|
396
|
+
if (resumed === 'gone') {
|
|
397
|
+
out({ id, error: { code: -32600, message: 'no thread gone' } });
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
threadId = resumed ?? `fake-${Math.random().toString(36).slice(2, 8)}`;
|
|
401
|
+
// Codex 0.154 ignores developer instructions on a resume; only a start sets them.
|
|
402
|
+
if (resumed === null) {
|
|
403
|
+
threadInstructions.set(threadId, typeof params.developerInstructions === 'string' ? params.developerInstructions : null);
|
|
404
|
+
}
|
|
405
|
+
threadModel = typeof params.model === 'string' ? params.model : 'fake-model';
|
|
406
|
+
threadSandbox = typeof params.sandbox === 'string' ? params.sandbox : '';
|
|
407
|
+
threadApproval = typeof params.approvalPolicy === 'string' ? params.approvalPolicy : '';
|
|
408
|
+
threadName = threadId.startsWith('named-') ? 'Named before' : null;
|
|
409
|
+
const thread = { id: threadId, model: threadModel, cwd: params.cwd, turns: [], name: threadName };
|
|
410
|
+
out({
|
|
411
|
+
id,
|
|
412
|
+
result: {
|
|
413
|
+
thread,
|
|
414
|
+
model: `${threadModel} ${threadApproval} ${threadSandbox}`,
|
|
415
|
+
modelProvider: 'fake',
|
|
416
|
+
cwd: params.cwd,
|
|
417
|
+
approvalPolicy: threadApproval,
|
|
418
|
+
sandbox: { type: threadSandbox }
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
notify('thread/started', { thread });
|
|
422
|
+
return;
|
|
423
|
+
}
|
|
424
|
+
case 'thread/fork': {
|
|
425
|
+
const source = String(params.threadId);
|
|
426
|
+
const turns = threadTurns.get(source) ?? [];
|
|
427
|
+
const last = typeof params.lastTurnId === 'string' ? turns.indexOf(params.lastTurnId) : turns.length - 1;
|
|
428
|
+
if (!threadTurns.has(source) || (typeof params.lastTurnId === 'string' && last < 0)) {
|
|
429
|
+
out({ id, error: { code: -32600, message: `no rollout found for thread id ${source}` } });
|
|
430
|
+
return;
|
|
431
|
+
}
|
|
432
|
+
fakeCodexForks.push(params);
|
|
433
|
+
const forked = `fork-${Math.random().toString(36).slice(2, 8)}`;
|
|
434
|
+
threadTurns.set(forked, turns.slice(0, last + 1));
|
|
435
|
+
threadInstructions.set(forked, threadInstructions.get(source) ?? null);
|
|
436
|
+
out({ id, result: { thread: { id: forked, forkedFromId: source, cwd: params.cwd, turns: [] }, model: params.model ?? 'fake-model' } });
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
case 'thread/turns/list': {
|
|
440
|
+
const turns = threadTurns.get(String(params.threadId)) ?? [];
|
|
441
|
+
out({ id, result: { data: turns.map((turn) => ({ id: turn, items: [], status: 'completed', error: null })), nextCursor: null } });
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
case 'thread/items/list': {
|
|
445
|
+
const steps = childThreads.get(String(params.threadId));
|
|
446
|
+
if (!steps) {
|
|
447
|
+
out({ id, error: { code: -32600, message: `no rollout found for thread id ${String(params.threadId)}` } });
|
|
448
|
+
return;
|
|
449
|
+
}
|
|
450
|
+
// The cursor is where the next page starts, counted from the end the list is sorted from.
|
|
451
|
+
const ordered = params.sortDirection === 'asc' ? steps : [...steps].reverse();
|
|
452
|
+
const start = typeof params.cursor === 'string' ? Number(params.cursor) : 0;
|
|
453
|
+
const limit = typeof params.limit === 'number' ? params.limit : 50;
|
|
454
|
+
const page = ordered.slice(start, start + limit);
|
|
455
|
+
const next = start + limit < ordered.length ? String(start + limit) : null;
|
|
456
|
+
out({ id, result: { data: page.map((entry) => ({ item: entry, turnId: 'child-turn' })), nextCursor: next, backwardsCursor: null } });
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
case 'thread/name/set':
|
|
460
|
+
threadName = String(params.name);
|
|
461
|
+
out({ id, result: {} });
|
|
462
|
+
notify('thread/name/updated', { threadId, threadName });
|
|
463
|
+
return;
|
|
464
|
+
case 'turn/start':
|
|
465
|
+
out({ id, result: { turn: { id: `turn-${nonce}-${itemCounter + 1}`, items: [], status: 'inProgress', error: null } } });
|
|
466
|
+
handleTurnStart(params);
|
|
467
|
+
return;
|
|
468
|
+
case 'turn/steer': {
|
|
469
|
+
// The real app-server refuses a steer that does not name the turn it is meant for.
|
|
470
|
+
if (params.expectedTurnId !== turnId) {
|
|
471
|
+
out({ id, error: { code: -32602, message: 'Invalid request: missing field `expectedTurnId`' } });
|
|
472
|
+
// The real turn would go on polling; ending it here makes a test fail on its
|
|
473
|
+
// assertion rather than on a timeout.
|
|
474
|
+
pendingSteer = false;
|
|
475
|
+
turnCompleted('failed');
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
out({ id, result: { turnId } });
|
|
479
|
+
if (pendingSteer) {
|
|
480
|
+
pendingSteer = false;
|
|
481
|
+
const input = Array.isArray(params.input) ? (params.input[0] as { text?: string } | undefined) : undefined;
|
|
482
|
+
agentMessage(`you chose ${input?.text ?? 'no answer'}`);
|
|
483
|
+
turnCompleted('completed');
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
case 'turn/interrupt':
|
|
488
|
+
out({ id, result: {} });
|
|
489
|
+
if (slow) {
|
|
490
|
+
slow = false;
|
|
491
|
+
turnCompleted('interrupted');
|
|
492
|
+
}
|
|
493
|
+
return;
|
|
494
|
+
case 'thread/compact/start':
|
|
495
|
+
out({ id, result: {} });
|
|
496
|
+
turnStarted();
|
|
497
|
+
started(item('contextCompaction', {}));
|
|
498
|
+
completed(item('contextCompaction', {}));
|
|
499
|
+
turnCompleted('completed');
|
|
500
|
+
return;
|
|
501
|
+
default:
|
|
502
|
+
out({ id, error: { code: -32601, message: `unknown method ${method}` } });
|
|
503
|
+
}
|
|
504
|
+
};
|
|
505
|
+
|
|
506
|
+
return {
|
|
507
|
+
onLine: (line) => {
|
|
508
|
+
const frame = JSON.parse(line) as Frame;
|
|
509
|
+
const params = (frame.params ?? {}) as Frame;
|
|
510
|
+
if (typeof frame.method === 'string' && frame.id !== undefined) {
|
|
511
|
+
handleRequest(frame.id, frame.method, params);
|
|
512
|
+
return;
|
|
513
|
+
}
|
|
514
|
+
if (frame.id === undefined || frame.result === undefined) {
|
|
515
|
+
return;
|
|
516
|
+
}
|
|
517
|
+
const result = frame.result as Frame;
|
|
518
|
+
const approval = pendingApproval;
|
|
519
|
+
const question = pendingQuestion;
|
|
520
|
+
if (approval && approval.rpcId === frame.id) {
|
|
521
|
+
handleApprovalResponse(approval, result);
|
|
522
|
+
} else if (question && question.rpcId === frame.id) {
|
|
523
|
+
handleQuestionResponse(question, result);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
};
|
|
527
|
+
};
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
export const fakeCodex: FakeCli = fakeCodexWith({});
|
|
531
|
+
|
|
532
|
+
if (import.meta.main) {
|
|
533
|
+
await runOverStdio(fakeCodex);
|
|
534
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "Claude Code 2.1.285",
|
|
3
|
+
"capturedAt": "2026-09-30",
|
|
4
|
+
"requestedMode": "auto",
|
|
5
|
+
"model": "claude-haiku-4-5",
|
|
6
|
+
"source": "Live Claude stream-json in an isolated temporary folder. Init reports auto; after one native Write attempt the status frame reports default. Only permission metadata is retained.",
|
|
7
|
+
"frames": [
|
|
8
|
+
{
|
|
9
|
+
"type": "system",
|
|
10
|
+
"subtype": "init",
|
|
11
|
+
"session_id": "6e4ac93f-9fd7-466b-bef4-bae6303cf342",
|
|
12
|
+
"model": "claude-haiku-4-5",
|
|
13
|
+
"permissionMode": "auto",
|
|
14
|
+
"fast_mode_state": "off"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"type": "system",
|
|
18
|
+
"subtype": "status",
|
|
19
|
+
"status": null,
|
|
20
|
+
"permissionMode": "default",
|
|
21
|
+
"session_id": "6e4ac93f-9fd7-466b-bef4-bae6303cf342"
|
|
22
|
+
}
|
|
23
|
+
]
|
|
24
|
+
}
|