@pasko70/pibo 1.16.6 → 2.0.0
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/agent-runtime/auth.js +28 -0
- package/dist/agent-runtime/capabilities.js +221 -0
- package/dist/agent-runtime/context-build.js +313 -0
- package/dist/agent-runtime/contract.js +45 -0
- package/dist/agent-runtime/errors.js +57 -0
- package/dist/agent-runtime/events.js +1 -0
- package/dist/agent-runtime/history.js +1 -0
- package/dist/agent-runtime/profile-validation.js +109 -0
- package/dist/agent-runtime/registry.js +608 -0
- package/dist/agent-runtime/resource-files.js +87 -0
- package/dist/agent-runtime/resource-service.js +635 -0
- package/dist/agent-runtime/resources.js +1 -0
- package/dist/agent-runtime/routed-session.js +931 -0
- package/dist/agent-runtime/testing/contract.js +51 -0
- package/dist/agent-runtime/testing/fake-adapter.js +192 -0
- package/dist/agent-runtime/types.js +3 -0
- package/dist/agent-runtimes/codex-native/adapter.js +905 -0
- package/dist/agent-runtimes/codex-native/auth.js +476 -0
- package/dist/agent-runtimes/codex-native/client.js +734 -0
- package/dist/agent-runtimes/codex-native/config.js +152 -0
- package/dist/agent-runtimes/codex-native/history.js +283 -0
- package/dist/agent-runtimes/codex-native/mcp-stdio-launcher.js +89 -0
- package/dist/agent-runtimes/codex-native/models.js +581 -0
- package/dist/agent-runtimes/codex-native/process.js +459 -0
- package/dist/agent-runtimes/codex-native/protocol-types.js +1 -0
- package/dist/agent-runtimes/codex-native/protocol-version.js +7 -0
- package/dist/agent-runtimes/codex-native/redaction.js +31 -0
- package/dist/agent-runtimes/codex-native/requests.js +378 -0
- package/dist/agent-runtimes/codex-native/resource-delivery.js +445 -0
- package/dist/agent-runtimes/codex-native/thread.js +388 -0
- package/dist/agent-runtimes/codex-native/turn.js +849 -0
- package/dist/agent-runtimes/pi/adapter.js +653 -0
- package/dist/agent-runtimes/pi/auth.js +455 -0
- package/dist/agent-runtimes/pi/history.js +640 -0
- package/dist/agent-runtimes/pi/model-catalog.js +87 -0
- package/dist/agent-runtimes/pi/routed-session.js +1464 -0
- package/dist/agent-runtimes/pi/runtime.js +534 -0
- package/dist/agent-runtimes/pi/tool-compiler.js +69 -0
- package/dist/apps/chat/agent-profiles.js +40 -23
- package/dist/apps/chat/agent-store.js +111 -64
- package/dist/apps/chat/chat-api-routes.js +1 -1
- package/dist/apps/chat/chat-request-normalizers.js +47 -0
- package/dist/apps/chat/data/chat-data-mappers.js +25 -9
- package/dist/apps/chat/data/history-query-service.js +108 -0
- package/dist/apps/chat/data/session-query-service.js +24 -3
- package/dist/apps/chat/data/timeline-query-service.js +3 -3
- package/dist/apps/chat/model-catalog.js +1 -55
- package/dist/apps/chat/provider-auth-actions.js +171 -23
- package/dist/apps/chat/stream.js +12 -0
- package/dist/apps/chat/trace-v2.js +1 -0
- package/dist/apps/chat/trace.js +126 -415
- package/dist/apps/chat/web-app.js +582 -157
- package/dist/apps/chat-ui/assets/{dist-BTLtT_Vf.js → dist-9v2ZXT6V.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CMk1aPug.js → dist-B1LVAytl.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-CcwA_IWN.js → dist-C6LPDFXU.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DKOthbxr.js → dist-DVtXxfHc.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-ls2I6BIw.js → dist-DW4Qrfbd.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D1rAtRWs.js → dist-DmbsHdMC.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-C1JQRskW.js → dist-DyvwuSFO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-DfpaylQ-.js → dist-I26VB0QO.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-D10bTFD5.js → dist-RtHbJRPV.js} +1 -1
- package/dist/apps/chat-ui/assets/{dist-5KpmmBBZ.js → dist-sZgJkWZb.js} +1 -1
- package/dist/apps/chat-ui/assets/index-BPbNvcZe.css +1 -0
- package/dist/apps/chat-ui/assets/index-CIOf2uL2.js +237 -0
- package/dist/apps/chat-ui/index.html +2 -2
- package/dist/apps/chat-vscode-web/assets/index-1ivRyjFs.js +41 -0
- package/dist/apps/chat-vscode-web/index.html +1 -1
- package/dist/apps/vscode-artifacts/latest.vsix +0 -0
- package/dist/apps/vscode-artifacts/pibo-vscode-ext-2.0.0.vsix +0 -0
- package/dist/auth/login-actions.js +5 -251
- package/dist/cli-session/localSessionSource.js +8 -1
- package/dist/core/context-build.js +124 -20
- package/dist/core/default-profile.js +8 -0
- package/dist/core/profiles.js +30 -3
- package/dist/core/routed-session.js +5 -1446
- package/dist/core/runtime.js +5 -561
- package/dist/core/session-router.js +637 -83
- package/dist/data/cli.js +20 -3
- package/dist/data/schema.js +104 -1
- package/dist/data/session-store.js +24 -1
- package/dist/debug/events.js +25 -10
- package/dist/debug/failures.js +23 -3
- package/dist/debug/index.js +24 -6
- package/dist/debug/messages.js +87 -7
- package/dist/debug/persisted-payloads.js +31 -0
- package/dist/debug/pty.js +7 -6
- package/dist/debug/runtime-binding.js +29 -0
- package/dist/debug/session.js +137 -0
- package/dist/debug/summary.js +12 -0
- package/dist/debug/telemetry.js +28 -0
- package/dist/debug/tools.js +12 -2
- package/dist/debug/trace.js +154 -76
- package/dist/gateway/server.js +87 -2
- package/dist/gateway/tool.js +5 -5
- package/dist/index.js +21 -2
- package/dist/loops/tools.js +13 -12
- package/dist/mcp/agent-context.js +13 -4
- package/dist/mcp/client.js +10 -6
- package/dist/mcp/config.js +5 -2
- package/dist/mcp/runtime-session.js +166 -0
- package/dist/plugins/builtin.js +191 -53
- package/dist/plugins/codex-native.js +29 -0
- package/dist/plugins/registry.js +66 -2
- package/dist/runs/tools.js +26 -25
- package/dist/session-ui/terminalRows.js +2 -2
- package/dist/sessions/pibo-data-store.js +125 -16
- package/dist/sessions/runtime-binding.js +107 -0
- package/dist/sessions/sqlite-store.js +239 -18
- package/dist/sessions/store.js +86 -7
- package/dist/shared/trace-engine.js +18 -9
- package/dist/shared/trace-event-projection.js +29 -11
- package/dist/shared/{trace-transcript.js → trace-history.js} +193 -195
- package/dist/shared/trace-order.js +9 -4
- package/dist/shared/trace-page-merge.js +1 -1
- package/dist/signals/projector.js +20 -2
- package/dist/signals/registry.js +11 -0
- package/dist/subagents/tool.js +8 -6
- package/dist/tools/codex-browser.js +20 -19
- package/dist/tools/codex-compat.js +10 -9
- package/dist/tools/codex-image-generation.js +8 -6
- package/dist/tools/contract.js +45 -0
- package/dist/tools/credential-registry.js +182 -0
- package/dist/tools/mcp-bridge.js +511 -0
- package/dist/tools/payload-writer.js +17 -0
- package/dist/tools/runtime/tool.js +10 -9
- package/dist/tools/schema.js +9 -0
- package/dist/tools/session-service.js +193 -0
- package/dist/tools/session-tool-set.js +85 -0
- package/dist/web-annotations/tools.js +17 -16
- package/docs/README.md +11 -0
- package/package.json +3 -2
- package/skills/builtin/pibo-agent-runtime-adapter/SKILL.md +183 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/README.md +10 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/evals.json +45 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/orion-full-harness.md +60 -0
- package/skills/builtin/pibo-agent-runtime-adapter/evals/fixtures/relay-partial-harness.md +52 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/capabilities-and-designer.md +194 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/history-debug-and-security.md +213 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/interfaces-and-registration.md +214 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/lifecycle-bindings-and-events.md +193 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/portable-delivery-and-native-behavior.md +226 -0
- package/skills/builtin/pibo-agent-runtime-adapter/references/testing-migration-and-validation.md +256 -0
- package/dist/apps/chat-ui/assets/index-C2YI0xfw.js +0 -237
- package/dist/apps/chat-ui/assets/index-E0RmuCkY.css +0 -1
- package/dist/apps/chat-vscode-web/assets/index-D-tSsXLG.js +0 -41
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { CodexAppServerRpcResponseError, } from "./client.js";
|
|
2
|
+
import { redactCodexNativeSensitiveText } from "./redaction.js";
|
|
3
|
+
export const CODEX_NATIVE_ADAPTER_ID = "codex-native";
|
|
4
|
+
const THREAD_LIST_LIMIT = 100;
|
|
5
|
+
const THREAD_LIST_SOURCE_KINDS = [
|
|
6
|
+
"cli",
|
|
7
|
+
"vscode",
|
|
8
|
+
"exec",
|
|
9
|
+
"appServer",
|
|
10
|
+
"subAgent",
|
|
11
|
+
"subAgentReview",
|
|
12
|
+
"subAgentCompact",
|
|
13
|
+
"subAgentThreadSpawn",
|
|
14
|
+
"subAgentOther",
|
|
15
|
+
"unknown",
|
|
16
|
+
];
|
|
17
|
+
const THREAD_MISSING_PATTERN = /\b(?:thread(?:\s+\S+)?\s+(?:not found|not loaded)|no rollout found for (?:thread|conversation) id|failed to resolve rollout path[^\r\n]{0,2048}(?:file does not exist|no such file or directory))\b/i;
|
|
18
|
+
const TURN_STATUSES = new Set(["completed", "interrupted", "failed", "inProgress"]);
|
|
19
|
+
const THREAD_STATUS_TYPES = new Set(["notLoaded", "idle", "systemError", "active"]);
|
|
20
|
+
export class CodexNativeThreadMissingError extends Error {
|
|
21
|
+
threadId;
|
|
22
|
+
constructor(threadId) {
|
|
23
|
+
super("The bound Codex thread is not available in this configured runtime instance.");
|
|
24
|
+
this.threadId = threadId;
|
|
25
|
+
this.name = "CodexNativeThreadMissingError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export class CodexNativeThreadProtocolError extends Error {
|
|
29
|
+
constructor(message) {
|
|
30
|
+
super(message);
|
|
31
|
+
this.name = "CodexNativeThreadProtocolError";
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function isRecord(value) {
|
|
35
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
36
|
+
}
|
|
37
|
+
function finiteInteger(value, label) {
|
|
38
|
+
if (!Number.isSafeInteger(value))
|
|
39
|
+
throw new CodexNativeThreadProtocolError(`Codex ${label} is invalid.`);
|
|
40
|
+
return Number(value);
|
|
41
|
+
}
|
|
42
|
+
function optionalInteger(value, label) {
|
|
43
|
+
if (value === undefined || value === null)
|
|
44
|
+
return value;
|
|
45
|
+
return finiteInteger(value, label);
|
|
46
|
+
}
|
|
47
|
+
function requiredString(value, label) {
|
|
48
|
+
if (typeof value !== "string" || !value.trim())
|
|
49
|
+
throw new CodexNativeThreadProtocolError(`Codex ${label} is missing.`);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
function optionalString(value, label) {
|
|
53
|
+
if (value === undefined || value === null)
|
|
54
|
+
return value;
|
|
55
|
+
if (typeof value !== "string")
|
|
56
|
+
throw new CodexNativeThreadProtocolError(`Codex ${label} is invalid.`);
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
export function validateCodexAppServerThreadStatus(value) {
|
|
60
|
+
if (!isRecord(value) || typeof value.type !== "string" || !THREAD_STATUS_TYPES.has(value.type)) {
|
|
61
|
+
throw new CodexNativeThreadProtocolError("Codex thread status is invalid.");
|
|
62
|
+
}
|
|
63
|
+
if (value.type === "active") {
|
|
64
|
+
if (!Array.isArray(value.activeFlags) || value.activeFlags.some((flag) => typeof flag !== "string")) {
|
|
65
|
+
throw new CodexNativeThreadProtocolError("Codex active thread flags are invalid.");
|
|
66
|
+
}
|
|
67
|
+
return { type: "active", activeFlags: [...value.activeFlags] };
|
|
68
|
+
}
|
|
69
|
+
return { type: value.type };
|
|
70
|
+
}
|
|
71
|
+
export function validateCodexAppServerThreadItem(value) {
|
|
72
|
+
if (!isRecord(value))
|
|
73
|
+
throw new CodexNativeThreadProtocolError("Codex thread item is invalid.");
|
|
74
|
+
const id = requiredString(value.id, "thread item id");
|
|
75
|
+
const type = requiredString(value.type, "thread item type");
|
|
76
|
+
return structuredClone({ ...value, id, type });
|
|
77
|
+
}
|
|
78
|
+
export function validateCodexAppServerTurn(value) {
|
|
79
|
+
if (!isRecord(value))
|
|
80
|
+
throw new CodexNativeThreadProtocolError("Codex turn is invalid.");
|
|
81
|
+
const id = requiredString(value.id, "turn id");
|
|
82
|
+
if (typeof value.status !== "string" || !TURN_STATUSES.has(value.status)) {
|
|
83
|
+
throw new CodexNativeThreadProtocolError("Codex turn status is invalid.");
|
|
84
|
+
}
|
|
85
|
+
if (!Array.isArray(value.items))
|
|
86
|
+
throw new CodexNativeThreadProtocolError("Codex turn items are invalid.");
|
|
87
|
+
const itemsView = optionalString(value.itemsView, "turn items view");
|
|
88
|
+
if (itemsView !== undefined && itemsView !== null && !["notLoaded", "summary", "full"].includes(itemsView)) {
|
|
89
|
+
throw new CodexNativeThreadProtocolError("Codex turn items view is invalid.");
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
id,
|
|
93
|
+
status: value.status,
|
|
94
|
+
items: value.items.map(validateCodexAppServerThreadItem),
|
|
95
|
+
...(itemsView ? { itemsView: itemsView } : {}),
|
|
96
|
+
...((value.startedAt !== undefined) ? { startedAt: optionalInteger(value.startedAt, "turn start timestamp") } : {}),
|
|
97
|
+
...((value.completedAt !== undefined) ? { completedAt: optionalInteger(value.completedAt, "turn completion timestamp") } : {}),
|
|
98
|
+
...((value.durationMs !== undefined) ? { durationMs: optionalInteger(value.durationMs, "turn duration") } : {}),
|
|
99
|
+
...(value.error !== undefined ? { error: structuredClone(value.error) } : {}),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
export function validateCodexAppServerThread(value) {
|
|
103
|
+
if (!isRecord(value))
|
|
104
|
+
throw new CodexNativeThreadProtocolError("Codex thread response is invalid.");
|
|
105
|
+
if (!Array.isArray(value.turns))
|
|
106
|
+
throw new CodexNativeThreadProtocolError("Codex thread turns are invalid.");
|
|
107
|
+
return {
|
|
108
|
+
id: requiredString(value.id, "thread id"),
|
|
109
|
+
preview: typeof value.preview === "string" ? value.preview : "",
|
|
110
|
+
modelProvider: requiredString(value.modelProvider, "thread model provider"),
|
|
111
|
+
createdAt: finiteInteger(value.createdAt, "thread creation timestamp"),
|
|
112
|
+
updatedAt: finiteInteger(value.updatedAt, "thread update timestamp"),
|
|
113
|
+
...((value.recencyAt !== undefined) ? { recencyAt: optionalInteger(value.recencyAt, "thread recency timestamp") } : {}),
|
|
114
|
+
cwd: requiredString(value.cwd, "thread workspace"),
|
|
115
|
+
cliVersion: requiredString(value.cliVersion, "thread CLI version"),
|
|
116
|
+
source: structuredClone(value.source),
|
|
117
|
+
...(value.threadSource !== undefined ? { threadSource: structuredClone(value.threadSource) } : {}),
|
|
118
|
+
status: validateCodexAppServerThreadStatus(value.status),
|
|
119
|
+
ephemeral: value.ephemeral === true,
|
|
120
|
+
turns: value.turns.map(validateCodexAppServerTurn),
|
|
121
|
+
sessionId: requiredString(value.sessionId, "thread session id"),
|
|
122
|
+
...((value.name !== undefined) ? { name: optionalString(value.name, "thread name") } : {}),
|
|
123
|
+
...((value.forkedFromId !== undefined) ? { forkedFromId: optionalString(value.forkedFromId, "fork source id") } : {}),
|
|
124
|
+
...((value.parentThreadId !== undefined) ? { parentThreadId: optionalString(value.parentThreadId, "parent thread id") } : {}),
|
|
125
|
+
...((value.path !== undefined) ? { path: optionalString(value.path, "thread path") } : {}),
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function threadFromResponse(value, operation) {
|
|
129
|
+
if (!isRecord(value) || !Object.hasOwn(value, "thread")) {
|
|
130
|
+
throw new CodexNativeThreadProtocolError(`Codex ${operation} response is missing its thread.`);
|
|
131
|
+
}
|
|
132
|
+
return validateCodexAppServerThread(value.thread);
|
|
133
|
+
}
|
|
134
|
+
function threadSessionFromResponse(value, operation) {
|
|
135
|
+
const record = isRecord(value) ? value : undefined;
|
|
136
|
+
const thread = threadFromResponse(value, operation);
|
|
137
|
+
if (!record)
|
|
138
|
+
throw new CodexNativeThreadProtocolError(`Codex ${operation} response is invalid.`);
|
|
139
|
+
const reasoningEffort = optionalString(record.reasoningEffort, `${operation} reasoning effort`);
|
|
140
|
+
const serviceTier = optionalString(record.serviceTier, `${operation} service tier`);
|
|
141
|
+
return {
|
|
142
|
+
thread,
|
|
143
|
+
configuration: {
|
|
144
|
+
model: requiredString(record.model, `${operation} model`),
|
|
145
|
+
modelProvider: requiredString(record.modelProvider, `${operation} model provider`),
|
|
146
|
+
...(reasoningEffort !== undefined ? { reasoningEffort } : {}),
|
|
147
|
+
...(serviceTier !== undefined ? { serviceTier } : {}),
|
|
148
|
+
},
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
export function isCodexNativeThreadMissingError(error) {
|
|
152
|
+
return error instanceof CodexNativeThreadMissingError
|
|
153
|
+
|| (error instanceof CodexAppServerRpcResponseError
|
|
154
|
+
&& error.rpcCode === -32600
|
|
155
|
+
&& THREAD_MISSING_PATTERN.test(error.message));
|
|
156
|
+
}
|
|
157
|
+
function normalizeThreadError(error, threadId) {
|
|
158
|
+
if (isCodexNativeThreadMissingError(error))
|
|
159
|
+
throw new CodexNativeThreadMissingError(threadId);
|
|
160
|
+
throw error;
|
|
161
|
+
}
|
|
162
|
+
function secondsToIso(seconds) {
|
|
163
|
+
if (!Number.isSafeInteger(seconds))
|
|
164
|
+
return undefined;
|
|
165
|
+
const date = new Date(Number(seconds) * 1_000);
|
|
166
|
+
return Number.isNaN(date.getTime()) ? undefined : date.toISOString();
|
|
167
|
+
}
|
|
168
|
+
function itemText(item) {
|
|
169
|
+
if (item.type === "agentMessage" && typeof item.text === "string")
|
|
170
|
+
return redactCodexNativeSensitiveText(item.text);
|
|
171
|
+
if (item.type === "userMessage" && Array.isArray(item.content)) {
|
|
172
|
+
const text = item.content
|
|
173
|
+
.filter((part) => isRecord(part) && part.type === "text" && typeof part.text === "string")
|
|
174
|
+
.map((part) => redactCodexNativeSensitiveText(part.text))
|
|
175
|
+
.join("\n");
|
|
176
|
+
return text || undefined;
|
|
177
|
+
}
|
|
178
|
+
return undefined;
|
|
179
|
+
}
|
|
180
|
+
function threadLeafId(thread) {
|
|
181
|
+
return thread.turns.at(-1)?.id ?? null;
|
|
182
|
+
}
|
|
183
|
+
export function codexThreadSnapshot(runtimeInstanceId, thread) {
|
|
184
|
+
return {
|
|
185
|
+
adapterId: CODEX_NATIVE_ADAPTER_ID,
|
|
186
|
+
runtimeInstanceId,
|
|
187
|
+
nativeSessionId: thread.id,
|
|
188
|
+
locator: { kind: "adapter-resolved" },
|
|
189
|
+
leafId: threadLeafId(thread),
|
|
190
|
+
cwd: thread.cwd,
|
|
191
|
+
name: thread.name ? redactCodexNativeSensitiveText(thread.name) : undefined,
|
|
192
|
+
metadata: {
|
|
193
|
+
cliVersion: thread.cliVersion,
|
|
194
|
+
modelProvider: thread.modelProvider,
|
|
195
|
+
status: thread.status.type,
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
}
|
|
199
|
+
export function codexThreadInfo(runtimeInstanceId, thread) {
|
|
200
|
+
return {
|
|
201
|
+
...codexThreadSnapshot(runtimeInstanceId, thread),
|
|
202
|
+
createdAt: secondsToIso(thread.createdAt),
|
|
203
|
+
updatedAt: secondsToIso(thread.updatedAt),
|
|
204
|
+
firstMessage: thread.preview ? redactCodexNativeSensitiveText(thread.preview) : undefined,
|
|
205
|
+
};
|
|
206
|
+
}
|
|
207
|
+
export function codexThreadForkCandidates(thread) {
|
|
208
|
+
return thread.turns.map((turn) => {
|
|
209
|
+
const text = [...turn.items].reverse().map(itemText).find((candidate) => candidate?.trim()) ?? `Codex turn ${turn.id}`;
|
|
210
|
+
return { entryId: turn.id, text };
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
export class CodexNativeThreadController {
|
|
214
|
+
client;
|
|
215
|
+
currentThread;
|
|
216
|
+
currentConfiguration;
|
|
217
|
+
resourceSelection;
|
|
218
|
+
knownThreads = new Map();
|
|
219
|
+
constructor(client, currentThread, currentConfiguration, resourceSelection) {
|
|
220
|
+
this.client = client;
|
|
221
|
+
this.currentThread = currentThread;
|
|
222
|
+
this.currentConfiguration = currentConfiguration;
|
|
223
|
+
this.resourceSelection = resourceSelection;
|
|
224
|
+
this.knownThreads.set(currentThread.id, structuredClone(currentThread));
|
|
225
|
+
}
|
|
226
|
+
static async start(client, workspace, selection = {}) {
|
|
227
|
+
const response = await client.request("thread/start", {
|
|
228
|
+
cwd: workspace,
|
|
229
|
+
ephemeral: false,
|
|
230
|
+
...(selection.model ? { model: selection.model } : {}),
|
|
231
|
+
...(selection.serviceTier !== undefined ? { serviceTier: selection.serviceTier } : {}),
|
|
232
|
+
...(selection.personality !== undefined ? { personality: selection.personality } : {}),
|
|
233
|
+
...(selection.config ? { config: selection.config } : {}),
|
|
234
|
+
...(selection.developerInstructions ? { developerInstructions: selection.developerInstructions } : {}),
|
|
235
|
+
});
|
|
236
|
+
const selected = threadSessionFromResponse(response, "thread/start");
|
|
237
|
+
return new CodexNativeThreadController(client, selected.thread, selected.configuration, {
|
|
238
|
+
...(selection.config ? { config: structuredClone(selection.config) } : {}),
|
|
239
|
+
...(selection.developerInstructions ? { developerInstructions: selection.developerInstructions } : {}),
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
static async resume(client, threadId, workspace, selection = {}) {
|
|
243
|
+
try {
|
|
244
|
+
const response = await client.request("thread/resume", {
|
|
245
|
+
threadId,
|
|
246
|
+
cwd: workspace,
|
|
247
|
+
...(selection.model ? { model: selection.model } : {}),
|
|
248
|
+
...(selection.serviceTier !== undefined ? { serviceTier: selection.serviceTier } : {}),
|
|
249
|
+
...(selection.personality !== undefined ? { personality: selection.personality } : {}),
|
|
250
|
+
...(selection.config ? { config: selection.config } : {}),
|
|
251
|
+
...(selection.developerInstructions ? { developerInstructions: selection.developerInstructions } : {}),
|
|
252
|
+
});
|
|
253
|
+
const selected = threadSessionFromResponse(response, "thread/resume");
|
|
254
|
+
const thread = selected.thread;
|
|
255
|
+
if (thread.id !== threadId)
|
|
256
|
+
throw new CodexNativeThreadProtocolError("Codex resumed a different thread than requested.");
|
|
257
|
+
return new CodexNativeThreadController(client, thread, selected.configuration, {
|
|
258
|
+
...(selection.config ? { config: structuredClone(selection.config) } : {}),
|
|
259
|
+
...(selection.developerInstructions ? { developerInstructions: selection.developerInstructions } : {}),
|
|
260
|
+
});
|
|
261
|
+
}
|
|
262
|
+
catch (error) {
|
|
263
|
+
return normalizeThreadError(error, threadId);
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
static async read(client, threadId, includeTurns) {
|
|
267
|
+
try {
|
|
268
|
+
const response = await client.request("thread/read", { threadId, includeTurns });
|
|
269
|
+
const thread = threadFromResponse(response, "thread/read");
|
|
270
|
+
if (thread.id !== threadId)
|
|
271
|
+
throw new CodexNativeThreadProtocolError("Codex read a different thread than requested.");
|
|
272
|
+
return thread;
|
|
273
|
+
}
|
|
274
|
+
catch (error) {
|
|
275
|
+
return normalizeThreadError(error, threadId);
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
get thread() {
|
|
279
|
+
return structuredClone(this.currentThread);
|
|
280
|
+
}
|
|
281
|
+
get configuration() {
|
|
282
|
+
return structuredClone(this.currentConfiguration);
|
|
283
|
+
}
|
|
284
|
+
getSnapshot(runtimeInstanceId) {
|
|
285
|
+
return codexThreadSnapshot(runtimeInstanceId, this.currentThread);
|
|
286
|
+
}
|
|
287
|
+
getForkCandidates() {
|
|
288
|
+
return codexThreadForkCandidates(this.currentThread);
|
|
289
|
+
}
|
|
290
|
+
setStatus(status) {
|
|
291
|
+
this.currentThread = { ...this.currentThread, status: structuredClone(status) };
|
|
292
|
+
this.knownThreads.set(this.currentThread.id, structuredClone(this.currentThread));
|
|
293
|
+
}
|
|
294
|
+
recordTurn(turn) {
|
|
295
|
+
const turns = this.currentThread.turns.map((entry) => structuredClone(entry));
|
|
296
|
+
const existingIndex = turns.findIndex((entry) => entry.id === turn.id);
|
|
297
|
+
if (existingIndex >= 0)
|
|
298
|
+
turns[existingIndex] = structuredClone(turn);
|
|
299
|
+
else
|
|
300
|
+
turns.push(structuredClone(turn));
|
|
301
|
+
const terminal = turn.status !== "inProgress";
|
|
302
|
+
const updatedAt = Math.max(this.currentThread.updatedAt, turn.completedAt ?? turn.startedAt ?? Math.floor(Date.now() / 1_000));
|
|
303
|
+
this.currentThread = {
|
|
304
|
+
...this.currentThread,
|
|
305
|
+
turns,
|
|
306
|
+
updatedAt,
|
|
307
|
+
recencyAt: updatedAt,
|
|
308
|
+
status: terminal ? { type: "idle" } : { type: "active", activeFlags: [] },
|
|
309
|
+
};
|
|
310
|
+
this.knownThreads.set(this.currentThread.id, structuredClone(this.currentThread));
|
|
311
|
+
}
|
|
312
|
+
async list(runtimeInstanceId, workspace) {
|
|
313
|
+
const params = {
|
|
314
|
+
cwd: workspace,
|
|
315
|
+
limit: THREAD_LIST_LIMIT,
|
|
316
|
+
sortKey: "updated_at",
|
|
317
|
+
sortDirection: "desc",
|
|
318
|
+
archived: false,
|
|
319
|
+
sourceKinds: THREAD_LIST_SOURCE_KINDS,
|
|
320
|
+
};
|
|
321
|
+
const response = await this.client.request("thread/list", params);
|
|
322
|
+
if (!isRecord(response) || !Array.isArray(response.data)) {
|
|
323
|
+
throw new CodexNativeThreadProtocolError("Codex thread/list response is invalid.");
|
|
324
|
+
}
|
|
325
|
+
const threads = new Map();
|
|
326
|
+
for (const value of response.data) {
|
|
327
|
+
const thread = validateCodexAppServerThread(value);
|
|
328
|
+
threads.set(thread.id, thread);
|
|
329
|
+
this.knownThreads.set(thread.id, structuredClone(thread));
|
|
330
|
+
}
|
|
331
|
+
for (const thread of this.knownThreads.values()) {
|
|
332
|
+
if (thread.cwd === workspace && !threads.has(thread.id)) {
|
|
333
|
+
threads.set(thread.id, structuredClone(thread));
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
return [...threads.values()]
|
|
337
|
+
.sort((left, right) => right.updatedAt - left.updatedAt || right.createdAt - left.createdAt)
|
|
338
|
+
.map((thread) => codexThreadInfo(runtimeInstanceId, thread));
|
|
339
|
+
}
|
|
340
|
+
async fork(runtimeInstanceId, workspace, lastTurnId, validateThread) {
|
|
341
|
+
if (!lastTurnId.trim())
|
|
342
|
+
throw new Error("Codex thread fork requires a native turn id.");
|
|
343
|
+
return await this.forkAt(runtimeInstanceId, workspace, lastTurnId, validateThread);
|
|
344
|
+
}
|
|
345
|
+
async clone(runtimeInstanceId, workspace, validateThread) {
|
|
346
|
+
return await this.forkAt(runtimeInstanceId, workspace, undefined, validateThread);
|
|
347
|
+
}
|
|
348
|
+
async forkAt(runtimeInstanceId, workspace, lastTurnId, validateThread) {
|
|
349
|
+
const previousThread = this.currentThread;
|
|
350
|
+
const previous = codexThreadSnapshot(runtimeInstanceId, previousThread);
|
|
351
|
+
const params = {
|
|
352
|
+
threadId: previousThread.id,
|
|
353
|
+
...(lastTurnId ? { lastTurnId } : {}),
|
|
354
|
+
cwd: workspace,
|
|
355
|
+
ephemeral: false,
|
|
356
|
+
...(this.resourceSelection.config ? { config: structuredClone(this.resourceSelection.config) } : {}),
|
|
357
|
+
...(this.resourceSelection.developerInstructions
|
|
358
|
+
? { developerInstructions: this.resourceSelection.developerInstructions }
|
|
359
|
+
: {}),
|
|
360
|
+
};
|
|
361
|
+
try {
|
|
362
|
+
const response = await this.client.request("thread/fork", params);
|
|
363
|
+
const selected = threadSessionFromResponse(response, "thread/fork");
|
|
364
|
+
const forked = selected.thread;
|
|
365
|
+
if (forked.id === previousThread.id) {
|
|
366
|
+
throw new CodexNativeThreadProtocolError("Codex thread/fork returned the source thread id.");
|
|
367
|
+
}
|
|
368
|
+
await validateThread?.(forked.id);
|
|
369
|
+
const selectedText = lastTurnId
|
|
370
|
+
? codexThreadForkCandidates(previousThread).find((candidate) => candidate.entryId === lastTurnId)?.text
|
|
371
|
+
: undefined;
|
|
372
|
+
this.knownThreads.set(previousThread.id, structuredClone(previousThread));
|
|
373
|
+
this.knownThreads.set(forked.id, structuredClone(forked));
|
|
374
|
+
this.currentThread = forked;
|
|
375
|
+
this.currentConfiguration = selected.configuration;
|
|
376
|
+
return {
|
|
377
|
+
previous,
|
|
378
|
+
current: codexThreadSnapshot(runtimeInstanceId, forked),
|
|
379
|
+
cancelled: false,
|
|
380
|
+
...(selectedText ? { selectedText } : {}),
|
|
381
|
+
...(lastTurnId ? { summaryEntryId: lastTurnId } : {}),
|
|
382
|
+
};
|
|
383
|
+
}
|
|
384
|
+
catch (error) {
|
|
385
|
+
return normalizeThreadError(error, previousThread.id);
|
|
386
|
+
}
|
|
387
|
+
}
|
|
388
|
+
}
|