@bjoernrochel/sevro 0.1.0-rc.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 +159 -0
- package/README.md +71 -0
- package/docs/advisory-fixture.md +23 -0
- package/docs/builtin-graders-v1.md +77 -0
- package/docs/cache-ownership-validation.md +49 -0
- package/docs/claude-continuation-validation.md +47 -0
- package/docs/codex-host.md +134 -0
- package/docs/concurrency-validation.md +86 -0
- package/docs/configuration-root-validation.md +70 -0
- package/docs/development-cli.md +327 -0
- package/docs/engine-slice.md +114 -0
- package/docs/extension-protocol-v1.md +292 -0
- package/docs/fixture-cleanup-validation.md +70 -0
- package/docs/identity-v1.md +65 -0
- package/docs/native-controls.md +29 -0
- package/docs/releases.md +88 -0
- package/docs/report-v1.md +32 -0
- package/docs/results-v1.md +118 -0
- package/examples/basic/graded.json +13 -0
- package/examples/basic/host.ts +8 -0
- package/examples/basic/prompt-only.json +7 -0
- package/package.json +45 -0
- package/schemas/cli-result-v1.schema.json +184 -0
- package/schemas/extension-v1.schema.json +659 -0
- package/schemas/report-v1.schema.json +164 -0
- package/schemas/run-evidence-v1.schema.json +510 -0
- package/src/advisory-fixture.ts +282 -0
- package/src/advisory.ts +105 -0
- package/src/cli.ts +837 -0
- package/src/engine.ts +2341 -0
- package/src/extension-client.ts +257 -0
- package/src/extension-session.ts +335 -0
- package/src/fixture-bin.ts +87 -0
- package/src/fixture-cleanup.ts +38 -0
- package/src/fixture-setup.ts +163 -0
- package/src/generated-fixture.ts +220 -0
- package/src/git-hooks.ts +63 -0
- package/src/graders/git-head.ts +176 -0
- package/src/graders/output.ts +359 -0
- package/src/graders/semantic.ts +120 -0
- package/src/graders/shell.ts +277 -0
- package/src/hosts/claude-continuation.ts +94 -0
- package/src/hosts/claude-credential.ts +73 -0
- package/src/hosts/claude-events.ts +128 -0
- package/src/hosts/claude-nested-skills.ts +218 -0
- package/src/hosts/claude-repository-invocation.ts +239 -0
- package/src/hosts/claude-settings.ts +50 -0
- package/src/hosts/claude-tool-calls.ts +159 -0
- package/src/hosts/claude.ts +511 -0
- package/src/hosts/codex-configuration.ts +85 -0
- package/src/hosts/codex-events.ts +102 -0
- package/src/hosts/codex-native-calls.ts +702 -0
- package/src/hosts/codex-profile.ts +78 -0
- package/src/hosts/codex-skill-reads.ts +345 -0
- package/src/hosts/codex.ts +769 -0
- package/src/hosts/isolation-roots.ts +60 -0
- package/src/hosts/mac-sandbox.ts +108 -0
- package/src/hosts/native-controls.ts +124 -0
- package/src/hosts/protected-worktrees.ts +56 -0
- package/src/hosts/workspace-fingerprint.ts +55 -0
- package/src/identity.ts +156 -0
- package/src/instrumentation.ts +106 -0
- package/src/preparation.ts +211 -0
- package/src/provenance.ts +244 -0
- package/src/report.ts +351 -0
- package/src/repository-fixture.ts +286 -0
- package/src/results.ts +160 -0
- package/src/run-owner.ts +276 -0
- package/src/schema.ts +28 -0
- package/src/storage.ts +23 -0
- package/src/trial-scheduler.ts +27 -0
|
@@ -0,0 +1,702 @@
|
|
|
1
|
+
import type { Dirent } from "node:fs";
|
|
2
|
+
import { lstat, readFile, readdir, stat } from "node:fs/promises";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import {
|
|
5
|
+
codexNativeReadDiagnostic,
|
|
6
|
+
type NativeReadDiagnostic,
|
|
7
|
+
} from "./codex-skill-reads";
|
|
8
|
+
|
|
9
|
+
const MAX_SESSION_BYTES = 8 * 1024 * 1024;
|
|
10
|
+
const MAX_SESSION_ENTRIES = 10_000;
|
|
11
|
+
const MAX_SESSION_FILES = 1024;
|
|
12
|
+
const MAX_RETAINED_CALLS = 128;
|
|
13
|
+
const MAX_CHILD_SESSIONS = 8;
|
|
14
|
+
const THREAD_ID = /^[A-Za-z0-9._-]{1,128}$/;
|
|
15
|
+
const GOAL_CONTROLS = new Set(["create_goal", "get_goal", "update_goal"]);
|
|
16
|
+
const COLLABORATION_CONTROLS = new Set([
|
|
17
|
+
"spawn_agent",
|
|
18
|
+
"list_agents",
|
|
19
|
+
"wait_agent",
|
|
20
|
+
"followup_task",
|
|
21
|
+
"send_message",
|
|
22
|
+
"interrupt_agent",
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
interface NativeCall {
|
|
26
|
+
ordinal: number;
|
|
27
|
+
namespace: "functions" | "collaboration";
|
|
28
|
+
name: string;
|
|
29
|
+
evidence: "invocation_attempt";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
interface NativeToolCall {
|
|
33
|
+
ordinal: number;
|
|
34
|
+
namespace: "functions" | "collaboration" | "clock" | "other";
|
|
35
|
+
name: string;
|
|
36
|
+
target?: string;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface AcceptedSpawn {
|
|
40
|
+
callId: string;
|
|
41
|
+
agentRef: string;
|
|
42
|
+
threadId: string;
|
|
43
|
+
requestedOrdinal: number;
|
|
44
|
+
startedOrdinal: number;
|
|
45
|
+
acceptedOrdinal: number;
|
|
46
|
+
taskName?: string;
|
|
47
|
+
model?: string;
|
|
48
|
+
reasoningEffort?: string;
|
|
49
|
+
forkTurns?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
interface NativeFeedbackCall {
|
|
53
|
+
ordinal: number;
|
|
54
|
+
tool: "followup_task" | "send_message" | "interrupt_agent";
|
|
55
|
+
target: string | null;
|
|
56
|
+
responseObserved: boolean;
|
|
57
|
+
messageRepresentation: "plaintext" | "encrypted" | "unavailable";
|
|
58
|
+
messageMatchesFollowUpPrompt: boolean | null;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
interface ChildSession {
|
|
62
|
+
threadId: string;
|
|
63
|
+
status: "available" | "unavailable" | "ambiguous" | "partial";
|
|
64
|
+
resultStatus?: "completed" | "unavailable";
|
|
65
|
+
readDiagnostics?: NativeReadDiagnostic;
|
|
66
|
+
nestedSpawns?: NestedSpawn[];
|
|
67
|
+
requestsTruncated?: boolean;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
interface NestedSpawn {
|
|
71
|
+
requestedOrdinal: number;
|
|
72
|
+
status: "accepted" | "unaccepted";
|
|
73
|
+
taskName?: string;
|
|
74
|
+
model?: string;
|
|
75
|
+
reasoningEffort?: string;
|
|
76
|
+
forkTurns?: string;
|
|
77
|
+
agentRef?: string;
|
|
78
|
+
threadId?: string;
|
|
79
|
+
sessionStatus: ChildSession["status"];
|
|
80
|
+
readerResultStatus: "completed" | "unavailable";
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
interface NativeSkillContext {
|
|
84
|
+
workspace: string;
|
|
85
|
+
installedPluginRoots: string[];
|
|
86
|
+
followUpPrompt?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
interface NativeCallObservation {
|
|
90
|
+
id: "sevro.codex.native-calls";
|
|
91
|
+
completeness: "complete" | "partial" | "unavailable";
|
|
92
|
+
data: {
|
|
93
|
+
method: "native_session";
|
|
94
|
+
calls: NativeCall[];
|
|
95
|
+
toolCalls: NativeToolCall[];
|
|
96
|
+
submittedExecCalls: number;
|
|
97
|
+
acceptedSpawns: AcceptedSpawn[];
|
|
98
|
+
feedbackCalls: NativeFeedbackCall[];
|
|
99
|
+
parentReadDiagnostics?: NativeReadDiagnostic;
|
|
100
|
+
childSessions: ChildSession[];
|
|
101
|
+
childrenTruncated: boolean;
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function record(value: unknown): value is Record<string, unknown> {
|
|
106
|
+
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function unavailable(
|
|
110
|
+
completeness: NativeCallObservation["completeness"],
|
|
111
|
+
): NativeCallObservation {
|
|
112
|
+
return {
|
|
113
|
+
id: "sevro.codex.native-calls",
|
|
114
|
+
completeness,
|
|
115
|
+
data: {
|
|
116
|
+
method: "native_session",
|
|
117
|
+
calls: [],
|
|
118
|
+
toolCalls: [],
|
|
119
|
+
submittedExecCalls: 0,
|
|
120
|
+
acceptedSpawns: [],
|
|
121
|
+
feedbackCalls: [],
|
|
122
|
+
childSessions: [],
|
|
123
|
+
childrenTruncated: false,
|
|
124
|
+
},
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
async function sessionPath(home: string, threadId: string) {
|
|
129
|
+
if (!THREAD_ID.test(threadId)) return { status: "partial" as const };
|
|
130
|
+
const sessionsRoot = join(home, "sessions");
|
|
131
|
+
try {
|
|
132
|
+
const root = await lstat(sessionsRoot);
|
|
133
|
+
if (!root.isDirectory() || root.isSymbolicLink())
|
|
134
|
+
return { status: "partial" as const };
|
|
135
|
+
} catch (error) {
|
|
136
|
+
return {
|
|
137
|
+
status:
|
|
138
|
+
error instanceof Error && "code" in error && error.code === "ENOENT"
|
|
139
|
+
? ("unavailable" as const)
|
|
140
|
+
: ("partial" as const),
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
const pending = [sessionsRoot];
|
|
144
|
+
const suffix = `-${threadId}.jsonl`;
|
|
145
|
+
const matches: string[] = [];
|
|
146
|
+
let visited = 0;
|
|
147
|
+
while (pending.length) {
|
|
148
|
+
const directory = pending.pop()!;
|
|
149
|
+
let entries: Dirent<string>[];
|
|
150
|
+
try {
|
|
151
|
+
entries = await readdir(directory, { withFileTypes: true });
|
|
152
|
+
} catch {
|
|
153
|
+
return { status: "partial" as const };
|
|
154
|
+
}
|
|
155
|
+
for (const entry of entries) {
|
|
156
|
+
visited++;
|
|
157
|
+
if (visited > MAX_SESSION_FILES || entry.isSymbolicLink())
|
|
158
|
+
return { status: "partial" as const };
|
|
159
|
+
const path = join(directory, entry.name);
|
|
160
|
+
if (entry.isDirectory()) pending.push(path);
|
|
161
|
+
else if (entry.isFile() && entry.name.endsWith(suffix))
|
|
162
|
+
matches.push(path);
|
|
163
|
+
if (matches.length > 1) return { status: "ambiguous" as const };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return matches.length === 1
|
|
167
|
+
? { status: "found" as const, path: matches[0]! }
|
|
168
|
+
: { status: "unavailable" as const };
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function directCall(
|
|
172
|
+
ordinal: number,
|
|
173
|
+
payload: Record<string, unknown>,
|
|
174
|
+
): NativeCall | null {
|
|
175
|
+
if (payload.type !== "function_call" || typeof payload.name !== "string")
|
|
176
|
+
return null;
|
|
177
|
+
if (
|
|
178
|
+
(payload.namespace === "functions" || payload.namespace === undefined) &&
|
|
179
|
+
GOAL_CONTROLS.has(payload.name)
|
|
180
|
+
)
|
|
181
|
+
return {
|
|
182
|
+
ordinal,
|
|
183
|
+
namespace: "functions",
|
|
184
|
+
name: payload.name,
|
|
185
|
+
evidence: "invocation_attempt",
|
|
186
|
+
};
|
|
187
|
+
if (
|
|
188
|
+
payload.namespace === "collaboration" &&
|
|
189
|
+
COLLABORATION_CONTROLS.has(payload.name)
|
|
190
|
+
)
|
|
191
|
+
return {
|
|
192
|
+
ordinal,
|
|
193
|
+
namespace: "collaboration",
|
|
194
|
+
name: payload.name,
|
|
195
|
+
evidence: "invocation_attempt",
|
|
196
|
+
};
|
|
197
|
+
return null;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
const IDENTIFIER = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,127}$/;
|
|
201
|
+
const AGENT_REF =
|
|
202
|
+
/^(?:\/root(?:\/[a-z0-9_]+)+|[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/;
|
|
203
|
+
|
|
204
|
+
function bounded(value: unknown, pattern: RegExp): string | undefined {
|
|
205
|
+
return typeof value === "string" && value.length <= 128 && pattern.test(value)
|
|
206
|
+
? value
|
|
207
|
+
: undefined;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
function nativeToolCall(
|
|
211
|
+
ordinal: number,
|
|
212
|
+
payload: Record<string, unknown>,
|
|
213
|
+
): NativeToolCall | null {
|
|
214
|
+
if (payload.type !== "function_call" && payload.type !== "custom_tool_call")
|
|
215
|
+
return null;
|
|
216
|
+
const namespace =
|
|
217
|
+
payload.namespace === "functions" ||
|
|
218
|
+
payload.namespace === "collaboration" ||
|
|
219
|
+
payload.namespace === "clock"
|
|
220
|
+
? payload.namespace
|
|
221
|
+
: "other";
|
|
222
|
+
const name =
|
|
223
|
+
bounded(payload.name, /^[A-Za-z_][A-Za-z0-9_]{0,63}$/) ?? "other";
|
|
224
|
+
let target: string | undefined;
|
|
225
|
+
if (
|
|
226
|
+
namespace === "collaboration" &&
|
|
227
|
+
["followup_task", "send_message", "interrupt_agent"].includes(name) &&
|
|
228
|
+
typeof payload.arguments === "string"
|
|
229
|
+
) {
|
|
230
|
+
try {
|
|
231
|
+
const args: unknown = JSON.parse(payload.arguments);
|
|
232
|
+
if (record(args))
|
|
233
|
+
target =
|
|
234
|
+
bounded(args.target, AGENT_REF) ??
|
|
235
|
+
bounded(args.target, /^[a-z0-9][a-z0-9_]{0,63}$/);
|
|
236
|
+
} catch {
|
|
237
|
+
// An unreadable target stays unknown without exposing arguments.
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
return { ordinal, namespace, name, ...(target ? { target } : {}) };
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function acceptedSpawns(
|
|
244
|
+
entries: Array<{ ordinal: number; payload: Record<string, unknown> }>,
|
|
245
|
+
): AcceptedSpawn[] {
|
|
246
|
+
const requests = entries.filter(
|
|
247
|
+
({ payload }) =>
|
|
248
|
+
payload.type === "function_call" &&
|
|
249
|
+
payload.namespace === "collaboration" &&
|
|
250
|
+
payload.name === "spawn_agent",
|
|
251
|
+
);
|
|
252
|
+
const accepted: AcceptedSpawn[] = [];
|
|
253
|
+
for (const request of requests) {
|
|
254
|
+
const callId = bounded(request.payload.call_id, IDENTIFIER);
|
|
255
|
+
if (
|
|
256
|
+
!callId ||
|
|
257
|
+
requests.filter(({ payload }) => payload.call_id === callId).length !==
|
|
258
|
+
1 ||
|
|
259
|
+
typeof request.payload.arguments !== "string"
|
|
260
|
+
)
|
|
261
|
+
continue;
|
|
262
|
+
let args: unknown;
|
|
263
|
+
try {
|
|
264
|
+
args = JSON.parse(request.payload.arguments);
|
|
265
|
+
} catch {
|
|
266
|
+
continue;
|
|
267
|
+
}
|
|
268
|
+
if (!record(args)) continue;
|
|
269
|
+
const starts = entries.filter(({ payload }) => {
|
|
270
|
+
const item = record(payload.item) ? payload.item : undefined;
|
|
271
|
+
return (
|
|
272
|
+
payload.type === "item_completed" &&
|
|
273
|
+
item?.type === "SubAgentActivity" &&
|
|
274
|
+
item.id === callId &&
|
|
275
|
+
item.kind === "started"
|
|
276
|
+
);
|
|
277
|
+
});
|
|
278
|
+
const outputs = entries.filter(
|
|
279
|
+
({ payload }) =>
|
|
280
|
+
payload.type === "function_call_output" && payload.call_id === callId,
|
|
281
|
+
);
|
|
282
|
+
if (starts.length !== 1 || outputs.length !== 1) continue;
|
|
283
|
+
const start = starts[0]!;
|
|
284
|
+
const result = outputs[0]!;
|
|
285
|
+
const item = start.payload.item as Record<string, unknown>;
|
|
286
|
+
const agentRef = bounded(item.agent_path, AGENT_REF);
|
|
287
|
+
const threadId = bounded(item.agent_thread_id, IDENTIFIER);
|
|
288
|
+
if (
|
|
289
|
+
!agentRef ||
|
|
290
|
+
!threadId ||
|
|
291
|
+
!(request.ordinal < start.ordinal && start.ordinal < result.ordinal) ||
|
|
292
|
+
typeof result.payload.output !== "string"
|
|
293
|
+
)
|
|
294
|
+
continue;
|
|
295
|
+
let output: unknown;
|
|
296
|
+
try {
|
|
297
|
+
output = JSON.parse(result.payload.output);
|
|
298
|
+
} catch {
|
|
299
|
+
continue;
|
|
300
|
+
}
|
|
301
|
+
if (!record(output) || output.task_name !== agentRef) continue;
|
|
302
|
+
accepted.push({
|
|
303
|
+
callId,
|
|
304
|
+
agentRef,
|
|
305
|
+
threadId,
|
|
306
|
+
requestedOrdinal: request.ordinal,
|
|
307
|
+
startedOrdinal: start.ordinal,
|
|
308
|
+
acceptedOrdinal: result.ordinal,
|
|
309
|
+
...(bounded(args.task_name, /^[a-z0-9][a-z0-9_]{0,63}$/)
|
|
310
|
+
? { taskName: args.task_name as string }
|
|
311
|
+
: {}),
|
|
312
|
+
...(bounded(args.model, IDENTIFIER)
|
|
313
|
+
? { model: args.model as string }
|
|
314
|
+
: {}),
|
|
315
|
+
...(bounded(
|
|
316
|
+
args.reasoning_effort,
|
|
317
|
+
/^(?:low|medium|high|xhigh|max|ultra)$/,
|
|
318
|
+
)
|
|
319
|
+
? { reasoningEffort: args.reasoning_effort as string }
|
|
320
|
+
: {}),
|
|
321
|
+
...(bounded(args.fork_turns, /^(?:none|all|[1-9][0-9]*)$/)
|
|
322
|
+
? { forkTurns: args.fork_turns as string }
|
|
323
|
+
: {}),
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return accepted;
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function feedbackMessageEvidence(
|
|
330
|
+
payload: Record<string, unknown>,
|
|
331
|
+
followUpPrompt?: string,
|
|
332
|
+
) {
|
|
333
|
+
let message: unknown;
|
|
334
|
+
if (typeof payload.arguments === "string") {
|
|
335
|
+
try {
|
|
336
|
+
const args: unknown = JSON.parse(payload.arguments);
|
|
337
|
+
if (record(args)) message = args.message;
|
|
338
|
+
} catch {
|
|
339
|
+
// An unreadable message remains unavailable.
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
const messageRepresentation =
|
|
343
|
+
typeof message !== "string"
|
|
344
|
+
? ("unavailable" as const)
|
|
345
|
+
: /^gAAAAA[A-Za-z0-9_-]+={0,2}$/.test(message)
|
|
346
|
+
? ("encrypted" as const)
|
|
347
|
+
: ("plaintext" as const);
|
|
348
|
+
return {
|
|
349
|
+
messageRepresentation,
|
|
350
|
+
messageMatchesFollowUpPrompt:
|
|
351
|
+
messageRepresentation === "plaintext" && followUpPrompt !== undefined
|
|
352
|
+
? message === followUpPrompt
|
|
353
|
+
: null,
|
|
354
|
+
};
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
function nativeFeedbackCalls(
|
|
358
|
+
entries: Array<{ ordinal: number; payload: Record<string, unknown> }>,
|
|
359
|
+
followUpPrompt?: string,
|
|
360
|
+
): NativeFeedbackCall[] {
|
|
361
|
+
return entries.flatMap(({ ordinal, payload }) => {
|
|
362
|
+
if (
|
|
363
|
+
payload.type !== "function_call" ||
|
|
364
|
+
payload.namespace !== "collaboration" ||
|
|
365
|
+
!["followup_task", "send_message", "interrupt_agent"].includes(
|
|
366
|
+
String(payload.name),
|
|
367
|
+
)
|
|
368
|
+
)
|
|
369
|
+
return [];
|
|
370
|
+
const callId = bounded(payload.call_id, IDENTIFIER);
|
|
371
|
+
const outputs = callId
|
|
372
|
+
? entries.filter(
|
|
373
|
+
(entry) =>
|
|
374
|
+
entry.ordinal > ordinal &&
|
|
375
|
+
entry.payload.type === "function_call_output" &&
|
|
376
|
+
entry.payload.call_id === callId,
|
|
377
|
+
)
|
|
378
|
+
: [];
|
|
379
|
+
return [
|
|
380
|
+
{
|
|
381
|
+
ordinal,
|
|
382
|
+
tool: payload.name as NativeFeedbackCall["tool"],
|
|
383
|
+
target: nativeToolCall(ordinal, payload)?.target ?? null,
|
|
384
|
+
responseObserved:
|
|
385
|
+
outputs.length === 1 &&
|
|
386
|
+
typeof outputs[0]?.payload.output === "string",
|
|
387
|
+
...feedbackMessageEvidence(payload, followUpPrompt),
|
|
388
|
+
},
|
|
389
|
+
];
|
|
390
|
+
});
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
function parseSession(
|
|
394
|
+
text: string,
|
|
395
|
+
followUpPrompt?: string,
|
|
396
|
+
): {
|
|
397
|
+
observation: NativeCallObservation;
|
|
398
|
+
entries: Array<{ ordinal: number; payload: Record<string, unknown> }>;
|
|
399
|
+
} {
|
|
400
|
+
const calls: NativeCall[] = [];
|
|
401
|
+
const toolCalls: NativeToolCall[] = [];
|
|
402
|
+
const entries: Array<{ ordinal: number; payload: Record<string, unknown> }> =
|
|
403
|
+
[];
|
|
404
|
+
let submittedExecCalls = 0;
|
|
405
|
+
let lastOrdinal = -1;
|
|
406
|
+
let malformed = false;
|
|
407
|
+
let entryCount = 0;
|
|
408
|
+
for (const line of text.split("\n")) {
|
|
409
|
+
if (!line.trim()) continue;
|
|
410
|
+
entryCount++;
|
|
411
|
+
if (entryCount > MAX_SESSION_ENTRIES) {
|
|
412
|
+
malformed = true;
|
|
413
|
+
break;
|
|
414
|
+
}
|
|
415
|
+
let entry: unknown;
|
|
416
|
+
try {
|
|
417
|
+
entry = JSON.parse(line);
|
|
418
|
+
} catch {
|
|
419
|
+
malformed = true;
|
|
420
|
+
continue;
|
|
421
|
+
}
|
|
422
|
+
if (
|
|
423
|
+
!record(entry) ||
|
|
424
|
+
!Number.isSafeInteger(entry.ordinal) ||
|
|
425
|
+
(entry.ordinal as number) <= lastOrdinal ||
|
|
426
|
+
!record(entry.payload)
|
|
427
|
+
) {
|
|
428
|
+
malformed = true;
|
|
429
|
+
continue;
|
|
430
|
+
}
|
|
431
|
+
lastOrdinal = entry.ordinal as number;
|
|
432
|
+
entries.push({ ordinal: lastOrdinal, payload: entry.payload });
|
|
433
|
+
if (
|
|
434
|
+
entry.payload.type === "custom_tool_call" &&
|
|
435
|
+
entry.payload.name === "exec"
|
|
436
|
+
)
|
|
437
|
+
submittedExecCalls++;
|
|
438
|
+
const call = directCall(lastOrdinal, entry.payload);
|
|
439
|
+
if (call) calls.push(call);
|
|
440
|
+
const toolCall = nativeToolCall(lastOrdinal, entry.payload);
|
|
441
|
+
if (toolCall) toolCalls.push(toolCall);
|
|
442
|
+
if (
|
|
443
|
+
calls.length > MAX_RETAINED_CALLS ||
|
|
444
|
+
toolCalls.length > MAX_RETAINED_CALLS
|
|
445
|
+
) {
|
|
446
|
+
calls.length = MAX_RETAINED_CALLS;
|
|
447
|
+
toolCalls.length = MAX_RETAINED_CALLS;
|
|
448
|
+
malformed = true;
|
|
449
|
+
break;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
return {
|
|
453
|
+
entries,
|
|
454
|
+
observation: {
|
|
455
|
+
id: "sevro.codex.native-calls",
|
|
456
|
+
completeness: malformed || entryCount === 0 ? "partial" : "complete",
|
|
457
|
+
data: {
|
|
458
|
+
method: "native_session",
|
|
459
|
+
calls,
|
|
460
|
+
toolCalls,
|
|
461
|
+
submittedExecCalls,
|
|
462
|
+
acceptedSpawns:
|
|
463
|
+
malformed || entries.length === 0 ? [] : acceptedSpawns(entries),
|
|
464
|
+
feedbackCalls:
|
|
465
|
+
malformed || entries.length === 0
|
|
466
|
+
? []
|
|
467
|
+
: nativeFeedbackCalls(entries, followUpPrompt),
|
|
468
|
+
childSessions: [],
|
|
469
|
+
childrenTruncated: false,
|
|
470
|
+
},
|
|
471
|
+
},
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
/** Bind a private final answer to the same turn's later native completion. */
|
|
476
|
+
function childResultCompleted(
|
|
477
|
+
entries: Array<{ ordinal: number; payload: Record<string, unknown> }>,
|
|
478
|
+
): boolean {
|
|
479
|
+
const finals = entries.filter(({ payload }) => {
|
|
480
|
+
const item = record(payload.item) ? payload.item : null;
|
|
481
|
+
return (
|
|
482
|
+
payload.type === "item_completed" &&
|
|
483
|
+
item?.type === "AgentMessage" &&
|
|
484
|
+
item.phase === "final_answer"
|
|
485
|
+
);
|
|
486
|
+
});
|
|
487
|
+
const completions = entries.filter(
|
|
488
|
+
({ payload }) => payload.type === "task_complete",
|
|
489
|
+
);
|
|
490
|
+
if (
|
|
491
|
+
finals.length !== 1 ||
|
|
492
|
+
completions.length !== 1 ||
|
|
493
|
+
entries.some(
|
|
494
|
+
({ payload }) =>
|
|
495
|
+
payload.type === "turn_aborted" || payload.type === "turn_failed",
|
|
496
|
+
)
|
|
497
|
+
)
|
|
498
|
+
return false;
|
|
499
|
+
const final = finals[0]!;
|
|
500
|
+
const complete = completions[0]!;
|
|
501
|
+
const item = final.payload.item as Record<string, unknown>;
|
|
502
|
+
const content = item.content;
|
|
503
|
+
if (
|
|
504
|
+
!bounded(final.payload.turn_id, IDENTIFIER) ||
|
|
505
|
+
complete.payload.turn_id !== final.payload.turn_id ||
|
|
506
|
+
final.ordinal >= complete.ordinal ||
|
|
507
|
+
!Array.isArray(content) ||
|
|
508
|
+
content.length === 0 ||
|
|
509
|
+
!content.every(
|
|
510
|
+
(part) =>
|
|
511
|
+
record(part) && part.type === "Text" && typeof part.text === "string",
|
|
512
|
+
)
|
|
513
|
+
)
|
|
514
|
+
return false;
|
|
515
|
+
const message = content.map((part) => part.text as string).join("");
|
|
516
|
+
return (
|
|
517
|
+
message.trim().length > 0 && complete.payload.last_agent_message === message
|
|
518
|
+
);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function nestedRequestFields(payload: Record<string, unknown>) {
|
|
522
|
+
let args: unknown;
|
|
523
|
+
try {
|
|
524
|
+
args = JSON.parse(payload.arguments as string);
|
|
525
|
+
} catch {
|
|
526
|
+
return {};
|
|
527
|
+
}
|
|
528
|
+
if (!record(args)) return {};
|
|
529
|
+
return {
|
|
530
|
+
...(bounded(args.task_name, /^[a-z0-9][a-z0-9_]{0,63}$/)
|
|
531
|
+
? { taskName: args.task_name as string }
|
|
532
|
+
: {}),
|
|
533
|
+
...(bounded(args.model, IDENTIFIER) ? { model: args.model as string } : {}),
|
|
534
|
+
...(bounded(args.reasoning_effort, /^(?:low|medium|high|xhigh|max|ultra)$/)
|
|
535
|
+
? { reasoningEffort: args.reasoning_effort as string }
|
|
536
|
+
: {}),
|
|
537
|
+
...(bounded(args.fork_turns, /^(?:none|all|[1-9][0-9]*)$/)
|
|
538
|
+
? { forkTurns: args.fork_turns as string }
|
|
539
|
+
: {}),
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
async function nestedSpawnReceipts(
|
|
544
|
+
home: string,
|
|
545
|
+
rootThread: string,
|
|
546
|
+
parentThread: string,
|
|
547
|
+
entries: Array<{ ordinal: number; payload: Record<string, unknown> }>,
|
|
548
|
+
) {
|
|
549
|
+
const requests = entries.filter(
|
|
550
|
+
({ payload }) =>
|
|
551
|
+
payload.type === "function_call" &&
|
|
552
|
+
payload.namespace === "collaboration" &&
|
|
553
|
+
payload.name === "spawn_agent",
|
|
554
|
+
);
|
|
555
|
+
const accepted = acceptedSpawns(entries);
|
|
556
|
+
const nestedSpawns: NestedSpawn[] = await Promise.all(
|
|
557
|
+
requests.slice(0, MAX_CHILD_SESSIONS).map(async ({ ordinal, payload }) => {
|
|
558
|
+
const receipt = accepted.find(
|
|
559
|
+
(spawn) => spawn.requestedOrdinal === ordinal,
|
|
560
|
+
);
|
|
561
|
+
const session: ChildSession | null = receipt
|
|
562
|
+
? receipt.threadId === rootThread
|
|
563
|
+
? { threadId: receipt.threadId, status: "partial" }
|
|
564
|
+
: await childSessionStatus(home, parentThread, receipt.threadId)
|
|
565
|
+
: null;
|
|
566
|
+
return {
|
|
567
|
+
requestedOrdinal: ordinal,
|
|
568
|
+
status: receipt ? ("accepted" as const) : ("unaccepted" as const),
|
|
569
|
+
...nestedRequestFields(payload),
|
|
570
|
+
...(receipt
|
|
571
|
+
? { agentRef: receipt.agentRef, threadId: receipt.threadId }
|
|
572
|
+
: {}),
|
|
573
|
+
sessionStatus: session?.status ?? "unavailable",
|
|
574
|
+
readerResultStatus: session?.resultStatus ?? "unavailable",
|
|
575
|
+
};
|
|
576
|
+
}),
|
|
577
|
+
);
|
|
578
|
+
return {
|
|
579
|
+
nestedSpawns,
|
|
580
|
+
requestsTruncated: requests.length > MAX_CHILD_SESSIONS,
|
|
581
|
+
};
|
|
582
|
+
}
|
|
583
|
+
|
|
584
|
+
async function childSessionStatus(
|
|
585
|
+
home: string,
|
|
586
|
+
parentThread: string,
|
|
587
|
+
threadId: string,
|
|
588
|
+
skillContext?: NativeSkillContext,
|
|
589
|
+
rootThread?: string,
|
|
590
|
+
): Promise<ChildSession> {
|
|
591
|
+
if (threadId === parentThread) return { threadId, status: "partial" };
|
|
592
|
+
const located = await sessionPath(home, threadId);
|
|
593
|
+
if (located.status !== "found") return { threadId, status: located.status };
|
|
594
|
+
try {
|
|
595
|
+
const size = (await stat(located.path)).size;
|
|
596
|
+
if (size > MAX_SESSION_BYTES) return { threadId, status: "partial" };
|
|
597
|
+
const bytes = await readFile(located.path);
|
|
598
|
+
if (bytes.byteLength > MAX_SESSION_BYTES)
|
|
599
|
+
return { threadId, status: "partial" };
|
|
600
|
+
const parsed = parseSession(
|
|
601
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
602
|
+
);
|
|
603
|
+
if (parsed.observation.completeness !== "complete")
|
|
604
|
+
return { threadId, status: "partial" };
|
|
605
|
+
const readDiagnostics = skillContext
|
|
606
|
+
? await codexNativeReadDiagnostic(
|
|
607
|
+
parsed.entries,
|
|
608
|
+
skillContext.workspace,
|
|
609
|
+
skillContext.installedPluginRoots,
|
|
610
|
+
)
|
|
611
|
+
: undefined;
|
|
612
|
+
const nested = rootThread
|
|
613
|
+
? await nestedSpawnReceipts(home, rootThread, threadId, parsed.entries)
|
|
614
|
+
: undefined;
|
|
615
|
+
return {
|
|
616
|
+
threadId,
|
|
617
|
+
status: "available",
|
|
618
|
+
resultStatus: childResultCompleted(parsed.entries)
|
|
619
|
+
? "completed"
|
|
620
|
+
: "unavailable",
|
|
621
|
+
...(readDiagnostics ? { readDiagnostics } : {}),
|
|
622
|
+
...nested,
|
|
623
|
+
};
|
|
624
|
+
} catch {
|
|
625
|
+
return { threadId, status: "partial" };
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
|
|
629
|
+
/** Last validated native event before a follow-up prompt enters this thread. */
|
|
630
|
+
export async function codexNativeSessionLastOrdinal(
|
|
631
|
+
home: string,
|
|
632
|
+
threadId: string,
|
|
633
|
+
): Promise<number | null> {
|
|
634
|
+
const located = await sessionPath(home, threadId);
|
|
635
|
+
if (located.status !== "found") return null;
|
|
636
|
+
try {
|
|
637
|
+
if ((await stat(located.path)).size > MAX_SESSION_BYTES) return null;
|
|
638
|
+
const bytes = await readFile(located.path);
|
|
639
|
+
if (bytes.byteLength > MAX_SESSION_BYTES) return null;
|
|
640
|
+
const parsed = parseSession(
|
|
641
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
642
|
+
);
|
|
643
|
+
if (parsed.observation.completeness !== "complete") return null;
|
|
644
|
+
return parsed.entries.at(-1)?.ordinal ?? null;
|
|
645
|
+
} catch {
|
|
646
|
+
return null;
|
|
647
|
+
}
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
/** Bind one private native session to the completed public thread. */
|
|
651
|
+
export async function codexNativeCallObservation(
|
|
652
|
+
home: string,
|
|
653
|
+
threadId: string,
|
|
654
|
+
skillContext?: NativeSkillContext,
|
|
655
|
+
): Promise<NativeCallObservation> {
|
|
656
|
+
const located = await sessionPath(home, threadId);
|
|
657
|
+
if (located.status !== "found")
|
|
658
|
+
return unavailable(
|
|
659
|
+
located.status === "ambiguous" ? "partial" : located.status,
|
|
660
|
+
);
|
|
661
|
+
try {
|
|
662
|
+
const size = (await stat(located.path)).size;
|
|
663
|
+
if (size > MAX_SESSION_BYTES) return unavailable("partial");
|
|
664
|
+
const bytes = await readFile(located.path);
|
|
665
|
+
if (bytes.byteLength > MAX_SESSION_BYTES) return unavailable("partial");
|
|
666
|
+
const { observation, entries } = parseSession(
|
|
667
|
+
new TextDecoder("utf-8", { fatal: true }).decode(bytes),
|
|
668
|
+
skillContext?.followUpPrompt,
|
|
669
|
+
);
|
|
670
|
+
if (observation.completeness !== "complete") return observation;
|
|
671
|
+
const parentReadDiagnostics = skillContext
|
|
672
|
+
? await codexNativeReadDiagnostic(
|
|
673
|
+
entries,
|
|
674
|
+
skillContext.workspace,
|
|
675
|
+
skillContext.installedPluginRoots,
|
|
676
|
+
)
|
|
677
|
+
: undefined;
|
|
678
|
+
const children = [
|
|
679
|
+
...new Set(
|
|
680
|
+
observation.data.acceptedSpawns.map((spawn) => spawn.threadId),
|
|
681
|
+
),
|
|
682
|
+
];
|
|
683
|
+
const childSessions = await Promise.all(
|
|
684
|
+
children
|
|
685
|
+
.slice(0, MAX_CHILD_SESSIONS)
|
|
686
|
+
.map((child) =>
|
|
687
|
+
childSessionStatus(home, threadId, child, skillContext, threadId),
|
|
688
|
+
),
|
|
689
|
+
);
|
|
690
|
+
return {
|
|
691
|
+
...observation,
|
|
692
|
+
data: {
|
|
693
|
+
...observation.data,
|
|
694
|
+
...(parentReadDiagnostics ? { parentReadDiagnostics } : {}),
|
|
695
|
+
childSessions,
|
|
696
|
+
childrenTruncated: children.length > MAX_CHILD_SESSIONS,
|
|
697
|
+
},
|
|
698
|
+
};
|
|
699
|
+
} catch {
|
|
700
|
+
return unavailable("partial");
|
|
701
|
+
}
|
|
702
|
+
}
|