@darkhunt-security/endpoint-codex 0.9.9 → 0.9.11
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/.codex-plugin/plugin.json +1 -1
- package/dist/bin/backfill.mjs +326 -19
- package/dist/bin/forwarder.mjs +326 -19
- package/dist/bin/status.mjs +237 -15
- package/package.json +3 -3
package/dist/bin/forwarder.mjs
CHANGED
|
@@ -18308,6 +18308,7 @@ function attachmentLabel(record) {
|
|
|
18308
18308
|
return `[${record.mediaType ?? "attachment"}${size}]`;
|
|
18309
18309
|
}
|
|
18310
18310
|
var RESUMED_USER_TEXT_LIMIT = 4e3;
|
|
18311
|
+
var USAGE_WIRE_NAMES = { thinking_tokens: "reasoning" };
|
|
18311
18312
|
var SessionEmitter = class {
|
|
18312
18313
|
client;
|
|
18313
18314
|
options;
|
|
@@ -18331,6 +18332,8 @@ var SessionEmitter = class {
|
|
|
18331
18332
|
/** Attachments seen before the trace could be opened knowing the prompt. */
|
|
18332
18333
|
deferred = [];
|
|
18333
18334
|
pendingUsage;
|
|
18335
|
+
/** Set when the model call this generation stands for failed. Cleared with it. */
|
|
18336
|
+
generationError;
|
|
18334
18337
|
outputText = [];
|
|
18335
18338
|
/** The last thing the assistant said in this pass — the trace's result. */
|
|
18336
18339
|
lastAssistantText;
|
|
@@ -18386,9 +18389,10 @@ var SessionEmitter = class {
|
|
|
18386
18389
|
this.count++;
|
|
18387
18390
|
if (record.kind === "attachment")
|
|
18388
18391
|
this.pendingAttachments.push(attachmentLabel(record));
|
|
18389
|
-
if (record.kind === "user_message")
|
|
18392
|
+
if (record.kind === "user_message" && !record.isError && !record.synthetic) {
|
|
18390
18393
|
this.absorbUserTurn(record);
|
|
18391
|
-
|
|
18394
|
+
}
|
|
18395
|
+
if (!this.trace && (record.kind === "attachment" || record.synthetic === true)) {
|
|
18392
18396
|
this.deferred.push(record);
|
|
18393
18397
|
return;
|
|
18394
18398
|
}
|
|
@@ -18426,6 +18430,15 @@ var SessionEmitter = class {
|
|
|
18426
18430
|
this.owners.set(record.uuid, owner);
|
|
18427
18431
|
switch (record.kind) {
|
|
18428
18432
|
case "user_message":
|
|
18433
|
+
if (record.synthetic) {
|
|
18434
|
+
this.seeded(["injected", record.uuid], () => owner.span("context_injection", {
|
|
18435
|
+
startTime: record.ts,
|
|
18436
|
+
...record.text !== void 0 ? { output: summarize(record.text) } : {}
|
|
18437
|
+
})).end({ endTime: record.ts });
|
|
18438
|
+
break;
|
|
18439
|
+
}
|
|
18440
|
+
if (record.isError)
|
|
18441
|
+
this.generationError = record.errorKind ?? "error";
|
|
18429
18442
|
this.endGeneration();
|
|
18430
18443
|
break;
|
|
18431
18444
|
case "attachment": {
|
|
@@ -18442,7 +18455,9 @@ var SessionEmitter = class {
|
|
|
18442
18455
|
}
|
|
18443
18456
|
case "assistant_message":
|
|
18444
18457
|
this.openGeneration(record, owner);
|
|
18445
|
-
if (record.
|
|
18458
|
+
if (record.isError)
|
|
18459
|
+
this.generationError = record.errorKind ?? "error";
|
|
18460
|
+
else if (record.text)
|
|
18446
18461
|
this.outputText.push(record.text);
|
|
18447
18462
|
break;
|
|
18448
18463
|
case "thinking": {
|
|
@@ -18471,15 +18486,44 @@ var SessionEmitter = class {
|
|
|
18471
18486
|
case "tool_result": {
|
|
18472
18487
|
const span = record.toolCallId ? this.toolSpans.get(record.toolCallId) : void 0;
|
|
18473
18488
|
if (span) {
|
|
18474
|
-
span.end({
|
|
18489
|
+
span.end({
|
|
18490
|
+
output: record.output,
|
|
18491
|
+
endTime: record.ts,
|
|
18492
|
+
...record.isError ? { level: "ERROR" } : {},
|
|
18493
|
+
...record.errorKind !== void 0 ? { statusMessage: record.errorKind } : {}
|
|
18494
|
+
});
|
|
18475
18495
|
this.toolSpans.delete(record.toolCallId);
|
|
18476
18496
|
}
|
|
18477
18497
|
this.pendingToolResults.push(summarize(record.output));
|
|
18478
18498
|
break;
|
|
18479
18499
|
}
|
|
18500
|
+
case "compaction":
|
|
18501
|
+
this.endGeneration();
|
|
18502
|
+
this.seeded(["compaction", record.uuid], () => owner.span("compaction", {
|
|
18503
|
+
startTime: record.ts,
|
|
18504
|
+
...record.text ? { output: record.text } : {}
|
|
18505
|
+
})).end({ endTime: record.ts });
|
|
18506
|
+
break;
|
|
18507
|
+
case "permission_grant": {
|
|
18508
|
+
const snapshot = record.input && typeof record.input === "object" ? record.input : void 0;
|
|
18509
|
+
const steps = Array.isArray(snapshot?.steps) ? snapshot.steps : [];
|
|
18510
|
+
this.seeded(["permission", record.uuid], () => owner.span("permission_grant", {
|
|
18511
|
+
startTime: record.ts,
|
|
18512
|
+
// `input`, not `output`: the list is what this record IS, not a result it
|
|
18513
|
+
// produced.
|
|
18514
|
+
input: steps,
|
|
18515
|
+
metadata: {
|
|
18516
|
+
// The true count, which is larger than `steps.length` when the mapper
|
|
18517
|
+
// truncated the snapshot to its byte budget.
|
|
18518
|
+
count: String(snapshot?.count ?? steps.length),
|
|
18519
|
+
full: String(snapshot?.full === true)
|
|
18520
|
+
}
|
|
18521
|
+
})).end({ endTime: record.ts });
|
|
18522
|
+
break;
|
|
18523
|
+
}
|
|
18480
18524
|
case "usage":
|
|
18481
18525
|
if (record.usage) {
|
|
18482
|
-
this.pendingUsage = Object.fromEntries(Object.entries(record.usage).filter(([, v]) => typeof v === "number"));
|
|
18526
|
+
this.pendingUsage = Object.fromEntries(Object.entries(record.usage).filter(([, v]) => typeof v === "number").map(([key, value]) => [USAGE_WIRE_NAMES[key] ?? key, value]));
|
|
18483
18527
|
}
|
|
18484
18528
|
if (record.model)
|
|
18485
18529
|
this.model = record.model;
|
|
@@ -18557,6 +18601,9 @@ var SessionEmitter = class {
|
|
|
18557
18601
|
return this.options.parentAgentId ?? this.meta["parentSessionId"];
|
|
18558
18602
|
}
|
|
18559
18603
|
defaultTraceName() {
|
|
18604
|
+
const label = this.options.workflow?.label;
|
|
18605
|
+
if (label)
|
|
18606
|
+
return label;
|
|
18560
18607
|
const agentType = this.agentType();
|
|
18561
18608
|
if (agentType)
|
|
18562
18609
|
return `subagent: ${agentType}`;
|
|
@@ -18565,6 +18612,27 @@ var SessionEmitter = class {
|
|
|
18565
18612
|
}
|
|
18566
18613
|
return this.options.agentType ? `subagent: ${this.options.agentType}` : `subagent ${this.options.agentId}`;
|
|
18567
18614
|
}
|
|
18615
|
+
/**
|
|
18616
|
+
* The run this agent belongs to, flattened onto the trace.
|
|
18617
|
+
*
|
|
18618
|
+
* Flat scalars rather than a nested object: metadata is lifted onto the span one
|
|
18619
|
+
* attribute at a time downstream, so a nested value would arrive as a JSON blob that
|
|
18620
|
+
* nothing can group or filter on. `workflow_id` is the one that matters — it is what
|
|
18621
|
+
* lets a consumer collect the agents of one run out of a session that ran several.
|
|
18622
|
+
*/
|
|
18623
|
+
workflowMetadata() {
|
|
18624
|
+
const workflow = this.options.workflow;
|
|
18625
|
+
if (!workflow)
|
|
18626
|
+
return {};
|
|
18627
|
+
return {
|
|
18628
|
+
workflow_id: workflow.id,
|
|
18629
|
+
...workflow.name !== void 0 ? { workflow_name: workflow.name } : {},
|
|
18630
|
+
...workflow.label !== void 0 ? { workflow_label: workflow.label } : {},
|
|
18631
|
+
...workflow.phase !== void 0 ? { workflow_phase: workflow.phase } : {},
|
|
18632
|
+
...workflow.phaseIndex !== void 0 ? { workflow_phase_index: workflow.phaseIndex } : {},
|
|
18633
|
+
...workflow.attempt !== void 0 ? { workflow_attempt: workflow.attempt } : {}
|
|
18634
|
+
};
|
|
18635
|
+
}
|
|
18568
18636
|
/** The session traces group under. Set from the path, or from `session_meta`. */
|
|
18569
18637
|
grouping;
|
|
18570
18638
|
ensureTrace(ts) {
|
|
@@ -18589,7 +18657,10 @@ var SessionEmitter = class {
|
|
|
18589
18657
|
...this.agentId() !== void 0 ? { agent_id: this.agentId() } : {},
|
|
18590
18658
|
...this.agentType() !== void 0 ? { agent_type: this.agentType() } : {},
|
|
18591
18659
|
...this.parentAgentId() !== void 0 ? { parent_agent_id: this.parentAgentId() } : {},
|
|
18592
|
-
...this.options.spawnDepth !== void 0 ? { spawn_depth: this.options.spawnDepth } : {}
|
|
18660
|
+
...this.options.spawnDepth !== void 0 ? { spawn_depth: this.options.spawnDepth } : {},
|
|
18661
|
+
// snake_case for the same reason as `agent_id` above: trace-hub lifts each
|
|
18662
|
+
// key through unchanged, and these are read alongside it.
|
|
18663
|
+
...this.workflowMetadata()
|
|
18593
18664
|
},
|
|
18594
18665
|
...this.options.userId !== void 0 ? { userId: this.options.userId } : {},
|
|
18595
18666
|
...this.options.userEmail !== void 0 ? { userEmail: this.options.userEmail } : {},
|
|
@@ -18609,7 +18680,18 @@ var SessionEmitter = class {
|
|
|
18609
18680
|
this.model = record.model;
|
|
18610
18681
|
this.generation = this.seeded(["generation", id], () => owner.generation("assistant", {
|
|
18611
18682
|
startTime: record.ts,
|
|
18612
|
-
...this.model !== void 0 ? { model: this.model } : {}
|
|
18683
|
+
...this.model !== void 0 ? { model: this.model } : {},
|
|
18684
|
+
// What drove this model call — an installed skill, an MCP server's output, a
|
|
18685
|
+
// plugin. A flat scalar like every other metadata value emitted here, because
|
|
18686
|
+
// trace-hub lifts each key onto the span unchanged and a nested value would
|
|
18687
|
+
// arrive as a blob nothing can group or filter on. One lowercase word, so unlike
|
|
18688
|
+
// `agent_id` there is no camelCase to convert.
|
|
18689
|
+
//
|
|
18690
|
+
// Set once, at open, and never through update(): this method early-returns when
|
|
18691
|
+
// the generation is already open, so the value has to be constant across a
|
|
18692
|
+
// message group. Measured over the claude-code corpus, 0 of 1,381 attributed
|
|
18693
|
+
// groups carry two different tokens.
|
|
18694
|
+
...record.attribution !== void 0 ? { metadata: { attribution: record.attribution } } : {}
|
|
18613
18695
|
}));
|
|
18614
18696
|
const input = this.buildInputMessages();
|
|
18615
18697
|
if (input.inputMessages)
|
|
@@ -18649,12 +18731,14 @@ var SessionEmitter = class {
|
|
|
18649
18731
|
this.generation.end({
|
|
18650
18732
|
...output ? { outputMessages: [{ role: "assistant", content: output }] } : {},
|
|
18651
18733
|
...this.model !== void 0 ? { model: this.model } : {},
|
|
18652
|
-
...this.pendingUsage !== void 0 ? { usage: this.pendingUsage } : {}
|
|
18734
|
+
...this.pendingUsage !== void 0 ? { usage: this.pendingUsage } : {},
|
|
18735
|
+
...this.generationError !== void 0 ? { level: "ERROR", statusMessage: this.generationError } : {}
|
|
18653
18736
|
});
|
|
18654
18737
|
this.generation = void 0;
|
|
18655
18738
|
this.generationId = void 0;
|
|
18656
18739
|
this.outputText = [];
|
|
18657
18740
|
this.pendingUsage = void 0;
|
|
18741
|
+
this.generationError = void 0;
|
|
18658
18742
|
}
|
|
18659
18743
|
};
|
|
18660
18744
|
|
|
@@ -21746,6 +21830,7 @@ async function runForwarder(mapper, options = {}) {
|
|
|
21746
21830
|
...sub?.agentType !== void 0 ? { agentType: sub.agentType } : {},
|
|
21747
21831
|
...sub?.parentAgentId !== void 0 ? { parentAgentId: sub.parentAgentId } : {},
|
|
21748
21832
|
...sub?.spawnDepth !== void 0 ? { spawnDepth: sub.spawnDepth } : {},
|
|
21833
|
+
...sub?.workflow !== void 0 ? { workflow: sub.workflow } : {},
|
|
21749
21834
|
...ids !== void 0 ? { ids } : {},
|
|
21750
21835
|
...userId !== void 0 ? { userId } : {},
|
|
21751
21836
|
...carried !== void 0 ? { resumeTurn: carried } : {}
|
|
@@ -21861,6 +21946,7 @@ import { join as join9 } from "node:path";
|
|
|
21861
21946
|
var CLI_CREDENTIALS_PATH = join9(homedir3(), ".darkhunt", "credentials.json");
|
|
21862
21947
|
|
|
21863
21948
|
// adapters/codex/dist/transcript.js
|
|
21949
|
+
import { readFileSync as readFileSync6 } from "node:fs";
|
|
21864
21950
|
import { basename, join as join10 } from "node:path";
|
|
21865
21951
|
import { homedir as homedir4 } from "node:os";
|
|
21866
21952
|
function str(value) {
|
|
@@ -21897,17 +21983,128 @@ function textOf(content) {
|
|
|
21897
21983
|
const parts = content.map((b) => b && typeof b === "object" ? str(b["text"]) : void 0).filter((t) => !!t);
|
|
21898
21984
|
return parts.length > 0 ? parts.join("\n") : void 0;
|
|
21899
21985
|
}
|
|
21986
|
+
var CODEX_APPROVAL_MODES = {
|
|
21987
|
+
never: "auto",
|
|
21988
|
+
"on-request": "ask"
|
|
21989
|
+
};
|
|
21990
|
+
var CODEX_SANDBOX_MODES = {
|
|
21991
|
+
"workspace-write": "workspace-write",
|
|
21992
|
+
"read-only": "read-only",
|
|
21993
|
+
"danger-full-access": "danger-full-access"
|
|
21994
|
+
};
|
|
21995
|
+
var PERMISSION_SNAPSHOT_LIMIT = 32e3;
|
|
21996
|
+
function budgeted(steps) {
|
|
21997
|
+
const kept = [];
|
|
21998
|
+
let bytes = 0;
|
|
21999
|
+
for (const step of steps) {
|
|
22000
|
+
bytes += JSON.stringify(step ?? null).length + 1;
|
|
22001
|
+
if (bytes > PERMISSION_SNAPSHOT_LIMIT)
|
|
22002
|
+
break;
|
|
22003
|
+
kept.push(step);
|
|
22004
|
+
}
|
|
22005
|
+
return kept;
|
|
22006
|
+
}
|
|
22007
|
+
function unwrapExecOutput(value) {
|
|
22008
|
+
if (typeof value !== "string")
|
|
22009
|
+
return { output: value };
|
|
22010
|
+
let parsed;
|
|
22011
|
+
try {
|
|
22012
|
+
parsed = JSON.parse(value);
|
|
22013
|
+
} catch {
|
|
22014
|
+
return { output: value };
|
|
22015
|
+
}
|
|
22016
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
22017
|
+
return { output: value };
|
|
22018
|
+
const bag = parsed;
|
|
22019
|
+
if (!Object.prototype.hasOwnProperty.call(bag, "output"))
|
|
22020
|
+
return { output: value };
|
|
22021
|
+
const metadata = bag["metadata"];
|
|
22022
|
+
if (!metadata || typeof metadata !== "object")
|
|
22023
|
+
return { output: value };
|
|
22024
|
+
const exitCode = num(metadata["exit_code"]);
|
|
22025
|
+
if (exitCode === void 0)
|
|
22026
|
+
return { output: value };
|
|
22027
|
+
return { output: bag["output"], exitCode };
|
|
22028
|
+
}
|
|
22029
|
+
function jwtClaims(token) {
|
|
22030
|
+
const parts = token.split(".");
|
|
22031
|
+
if (parts.length !== 3 || !parts[1])
|
|
22032
|
+
return void 0;
|
|
22033
|
+
try {
|
|
22034
|
+
const json = Buffer.from(parts[1], "base64url").toString("utf8");
|
|
22035
|
+
const claims = JSON.parse(json);
|
|
22036
|
+
return claims && typeof claims === "object" ? claims : void 0;
|
|
22037
|
+
} catch {
|
|
22038
|
+
return void 0;
|
|
22039
|
+
}
|
|
22040
|
+
}
|
|
22041
|
+
function emailFromAuth(raw) {
|
|
22042
|
+
let parsed;
|
|
22043
|
+
try {
|
|
22044
|
+
parsed = JSON.parse(raw);
|
|
22045
|
+
} catch {
|
|
22046
|
+
return void 0;
|
|
22047
|
+
}
|
|
22048
|
+
const tokens = parsed?.tokens;
|
|
22049
|
+
const token = tokens?.id_token;
|
|
22050
|
+
if (typeof token !== "string" || token === "")
|
|
22051
|
+
return void 0;
|
|
22052
|
+
const email = jwtClaims(token)?.["email"];
|
|
22053
|
+
return typeof email === "string" && email !== "" ? email : void 0;
|
|
22054
|
+
}
|
|
22055
|
+
function repositoryIdentity(url) {
|
|
22056
|
+
if (url === void 0)
|
|
22057
|
+
return void 0;
|
|
22058
|
+
const trimmed = url.trim();
|
|
22059
|
+
if (trimmed === "")
|
|
22060
|
+
return void 0;
|
|
22061
|
+
const scp = /^(?:[^@/\s]+@)?([^:/\s]+):(?!\/)(\S+)$/.exec(trimmed);
|
|
22062
|
+
if (scp)
|
|
22063
|
+
return `${scp[1]}/${stripSuffix(scp[2])}`;
|
|
22064
|
+
const withScheme = /^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) ? trimmed : `ssh://${trimmed}`;
|
|
22065
|
+
try {
|
|
22066
|
+
const parsed = new URL(withScheme);
|
|
22067
|
+
if (!parsed.hostname)
|
|
22068
|
+
return trimmed;
|
|
22069
|
+
const path = stripSuffix(parsed.pathname.replace(/^\/+/, ""));
|
|
22070
|
+
return path === "" ? parsed.hostname : `${parsed.hostname}/${path}`;
|
|
22071
|
+
} catch {
|
|
22072
|
+
return trimmed;
|
|
22073
|
+
}
|
|
22074
|
+
}
|
|
22075
|
+
function stripSuffix(path) {
|
|
22076
|
+
return path.replace(/\/+$/, "").replace(/\.git$/i, "");
|
|
22077
|
+
}
|
|
21900
22078
|
var codexTranscript = {
|
|
21901
22079
|
vendor: "codex",
|
|
21902
22080
|
sessionRoots() {
|
|
21903
22081
|
return [join10(homedir4(), ".codex", "sessions")];
|
|
21904
22082
|
},
|
|
21905
|
-
|
|
21906
|
-
|
|
21907
|
-
|
|
21908
|
-
|
|
21909
|
-
|
|
21910
|
-
|
|
22083
|
+
/**
|
|
22084
|
+
* `~/.codex/auth.json` -> the `email` claim of `tokens.id_token`.
|
|
22085
|
+
*
|
|
22086
|
+
* Codex records no identity in the rollout itself and none in plain text anywhere
|
|
22087
|
+
* else: `tokens.account_id` is a UUID, not a person. The address is a claim inside the
|
|
22088
|
+
* OAuth id_token, so reading it means decoding that token — hence {@link jwtClaims}.
|
|
22089
|
+
*
|
|
22090
|
+
* The token's own `exp` is deliberately not enforced. It is an hour long and the file
|
|
22091
|
+
* is only rewritten on sign-in and on refresh, so gating on expiry would leave most
|
|
22092
|
+
* sessions unattributed while answering a question nobody asked: an expired id_token
|
|
22093
|
+
* is evidence that a token needs refreshing, never evidence that a different person is
|
|
22094
|
+
* now signed in. Signing in as someone else rewrites this file, which is what makes
|
|
22095
|
+
* the stale-address worry unfounded — the claim always names the last account to
|
|
22096
|
+
* authenticate on this machine, which is the account that wrote these rollouts.
|
|
22097
|
+
*
|
|
22098
|
+
* `undefined` for API-key auth (`OPENAI_API_KEY` with no tokens), for a signed-out
|
|
22099
|
+
* agent, and for anything unreadable; the caller then falls back to configuration.
|
|
22100
|
+
*/
|
|
22101
|
+
resolveUserId() {
|
|
22102
|
+
try {
|
|
22103
|
+
return emailFromAuth(readFileSync6(join10(homedir4(), ".codex", "auth.json"), "utf8"));
|
|
22104
|
+
} catch {
|
|
22105
|
+
return void 0;
|
|
22106
|
+
}
|
|
22107
|
+
},
|
|
21911
22108
|
sessionIdFor(path) {
|
|
21912
22109
|
const name = basename(path, ".jsonl");
|
|
21913
22110
|
const match = /([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/i.exec(name);
|
|
@@ -21930,12 +22127,20 @@ var codexTranscript = {
|
|
|
21930
22127
|
const uuid = `codex:${offset}`;
|
|
21931
22128
|
const base = { vendor: "codex", ts, uuid };
|
|
21932
22129
|
if (raw.type === "session_meta") {
|
|
22130
|
+
const rawGit = payload["git"];
|
|
22131
|
+
const git = rawGit && typeof rawGit === "object" ? rawGit : void 0;
|
|
22132
|
+
const gitBranch = str(git?.["branch"]);
|
|
22133
|
+
const gitRepositoryUrl = repositoryIdentity(str(git?.["repository_url"]));
|
|
21933
22134
|
return [
|
|
21934
22135
|
{
|
|
21935
22136
|
...base,
|
|
21936
22137
|
kind: "session_meta",
|
|
21937
22138
|
meta: {
|
|
21938
22139
|
...str(payload["cwd"]) !== void 0 ? { cwd: str(payload["cwd"]) } : {},
|
|
22140
|
+
// Conditional spread rather than a plain assignment: the 7 `{}` blocks and
|
|
22141
|
+
// the 92 absent ones must leave the key absent, not present-and-undefined.
|
|
22142
|
+
...gitBranch !== void 0 ? { gitBranch } : {},
|
|
22143
|
+
...gitRepositoryUrl !== void 0 ? { gitRepositoryUrl } : {},
|
|
21939
22144
|
...str(payload["cli_version"]) !== void 0 ? { version: str(payload["cli_version"]) } : {},
|
|
21940
22145
|
...str(payload["originator"]) !== void 0 ? { entrypoint: str(payload["originator"]) } : {},
|
|
21941
22146
|
// A Codex subagent is a rollout of its own, a peer of its parent in the
|
|
@@ -21951,15 +22156,61 @@ var codexTranscript = {
|
|
|
21951
22156
|
}
|
|
21952
22157
|
if (raw.type === "turn_context") {
|
|
21953
22158
|
const model = str(payload["model"]);
|
|
21954
|
-
|
|
22159
|
+
const approval = str(payload["approval_policy"]);
|
|
22160
|
+
const sandbox = payload["sandbox_policy"];
|
|
22161
|
+
const sandboxMode = (() => {
|
|
22162
|
+
if (!sandbox || typeof sandbox !== "object")
|
|
22163
|
+
return void 0;
|
|
22164
|
+
const bag = sandbox;
|
|
22165
|
+
return str(bag["mode"]) ?? str(bag["type"]);
|
|
22166
|
+
})();
|
|
22167
|
+
const meta = {
|
|
22168
|
+
...model !== void 0 ? { model } : {},
|
|
22169
|
+
...approval !== void 0 ? { approvalMode: CODEX_APPROVAL_MODES[approval] ?? approval } : {},
|
|
22170
|
+
...sandboxMode !== void 0 ? { sandboxMode: CODEX_SANDBOX_MODES[sandboxMode] ?? sandboxMode } : {}
|
|
22171
|
+
};
|
|
22172
|
+
if (Object.keys(meta).length === 0)
|
|
21955
22173
|
return [];
|
|
21956
|
-
return [{ ...base, kind: "session_meta", meta
|
|
22174
|
+
return [{ ...base, kind: "session_meta", meta }];
|
|
21957
22175
|
}
|
|
21958
22176
|
const kind = str(payload["type"]);
|
|
21959
22177
|
if (raw.type === "event_msg" && kind === "token_count") {
|
|
21960
22178
|
const usage = mapTokenCount(payload["info"]);
|
|
21961
22179
|
return usage ? [{ ...base, kind: "usage", usage }] : [];
|
|
21962
22180
|
}
|
|
22181
|
+
if (raw.type === "compacted") {
|
|
22182
|
+
const note = str(payload["message"]);
|
|
22183
|
+
return [{ ...base, kind: "compaction", ...note ? { text: note } : {} }];
|
|
22184
|
+
}
|
|
22185
|
+
if (raw.type === "world_state") {
|
|
22186
|
+
const state = payload["state"];
|
|
22187
|
+
const perms = state && typeof state === "object" ? state["permissions"] : void 0;
|
|
22188
|
+
if (!perms || typeof perms !== "object")
|
|
22189
|
+
return [];
|
|
22190
|
+
const list = perms["approved_command_prefixes"];
|
|
22191
|
+
const steps = Array.isArray(list) ? list : [];
|
|
22192
|
+
return [
|
|
22193
|
+
{
|
|
22194
|
+
...base,
|
|
22195
|
+
kind: "permission_grant",
|
|
22196
|
+
input: {
|
|
22197
|
+
steps: budgeted(steps),
|
|
22198
|
+
count: steps.length,
|
|
22199
|
+
...payload["full"] === true ? { full: true } : {}
|
|
22200
|
+
}
|
|
22201
|
+
}
|
|
22202
|
+
];
|
|
22203
|
+
}
|
|
22204
|
+
if (raw.type === "event_msg" && kind === "turn_aborted") {
|
|
22205
|
+
return [
|
|
22206
|
+
{
|
|
22207
|
+
...base,
|
|
22208
|
+
kind: "user_message",
|
|
22209
|
+
isError: true,
|
|
22210
|
+
errorKind: `aborted:${str(payload["reason"]) ?? "unknown"}`
|
|
22211
|
+
}
|
|
22212
|
+
];
|
|
22213
|
+
}
|
|
21963
22214
|
if (raw.type !== "response_item")
|
|
21964
22215
|
return [];
|
|
21965
22216
|
switch (kind) {
|
|
@@ -21973,18 +22224,74 @@ var codexTranscript = {
|
|
|
21973
22224
|
...str(payload["call_id"]) !== void 0 ? { toolCallId: str(payload["call_id"]) } : {}
|
|
21974
22225
|
}
|
|
21975
22226
|
];
|
|
21976
|
-
case "function_call_output":
|
|
22227
|
+
case "function_call_output": {
|
|
22228
|
+
const flattened = textOf(payload["output"]) ?? payload["output"];
|
|
22229
|
+
const { output, exitCode } = unwrapExecOutput(flattened);
|
|
21977
22230
|
return [
|
|
21978
22231
|
{
|
|
21979
22232
|
...base,
|
|
21980
22233
|
kind: "tool_result",
|
|
21981
|
-
output
|
|
22234
|
+
output,
|
|
22235
|
+
// Only where an exit status was actually found. On the 993 string outputs
|
|
22236
|
+
// that are not envelopes and the 144 array ones the key stays ABSENT rather
|
|
22237
|
+
// than `false`: the emitter tests `record.isError`, and "this tool reported
|
|
22238
|
+
// success" is a different claim from "nothing here reported an outcome".
|
|
22239
|
+
...exitCode !== void 0 ? { isError: exitCode !== 0 } : {},
|
|
21982
22240
|
...str(payload["call_id"]) !== void 0 ? { toolCallId: str(payload["call_id"]) } : {}
|
|
21983
22241
|
}
|
|
21984
22242
|
];
|
|
22243
|
+
}
|
|
22244
|
+
// Codex's OTHER tool-call shape, and the one it actually uses: `exec` and
|
|
22245
|
+
// `apply_patch` arrive as `custom_tool_call`, never as `function_call`. Measured
|
|
22246
|
+
// across 251 rollouts, 2179 of 5382 tool calls — 40% — took this shape, so
|
|
22247
|
+
// handling only `function_call` left every shell command and every file write
|
|
22248
|
+
// this endpoint made invisible to both the trace and anything reading it.
|
|
22249
|
+
case "custom_tool_call":
|
|
22250
|
+
return [
|
|
22251
|
+
{
|
|
22252
|
+
...base,
|
|
22253
|
+
kind: "tool_call",
|
|
22254
|
+
toolName: str(payload["name"]) ?? "tool",
|
|
22255
|
+
input: payload["input"],
|
|
22256
|
+
...str(payload["call_id"]) !== void 0 ? { toolCallId: str(payload["call_id"]) } : {}
|
|
22257
|
+
}
|
|
22258
|
+
];
|
|
22259
|
+
case "custom_tool_call_output": {
|
|
22260
|
+
const flattened = textOf(payload["output"]) ?? payload["output"];
|
|
22261
|
+
const { output, exitCode } = unwrapExecOutput(flattened);
|
|
22262
|
+
return [
|
|
22263
|
+
{
|
|
22264
|
+
...base,
|
|
22265
|
+
kind: "tool_result",
|
|
22266
|
+
output,
|
|
22267
|
+
...exitCode !== void 0 ? { isError: exitCode !== 0 } : {},
|
|
22268
|
+
...str(payload["call_id"]) !== void 0 ? { toolCallId: str(payload["call_id"]) } : {}
|
|
22269
|
+
}
|
|
22270
|
+
];
|
|
22271
|
+
}
|
|
22272
|
+
// The model's own web reads. 49 across the corpus in 9 rollouts — `search` 31,
|
|
22273
|
+
// `open_page` 16, `find_in_page` 2 — every one of which mapped to nothing, so a
|
|
22274
|
+
// session where the agent searched and opened pages rendered as reasoning
|
|
22275
|
+
// followed by an answer with no source anywhere in it. The queries and the URLs
|
|
22276
|
+
// are the whole point of the record: they are the evidence of what the agent
|
|
22277
|
+
// read from outside the machine.
|
|
22278
|
+
//
|
|
22279
|
+
// `action` is passed through whole. It is already a vendor-neutral argument bag
|
|
22280
|
+
// ({type, query?, queries?, url?, pattern?}) and it is small — 322 bytes at the
|
|
22281
|
+
// worst, 121 on average across all 49.
|
|
22282
|
+
//
|
|
22283
|
+
// Deliberately unpaired: no `toolCallId`. Only 1 of the 49 lines carries an
|
|
22284
|
+
// `id`, `call_id` is the pairing key everywhere else in this stream, and no
|
|
22285
|
+
// response_item output line ever pairs with a search — so setting one would
|
|
22286
|
+
// register a span in the emitter's pairing table that nothing ever closes, and
|
|
22287
|
+
// `finish()` would end it at pass end and stamp a multi-minute duration on a
|
|
22288
|
+
// search that took seconds. Left unpaired, the emitter closes it at the call
|
|
22289
|
+
// timestamp, which is the truthful reading.
|
|
22290
|
+
case "web_search_call":
|
|
22291
|
+
return [{ ...base, kind: "tool_call", toolName: "web_search", input: payload["action"] }];
|
|
21985
22292
|
case "reasoning": {
|
|
21986
22293
|
const text = textOf(payload["summary"]) ?? textOf(payload["content"]);
|
|
21987
|
-
return
|
|
22294
|
+
return [{ ...base, kind: "thinking", ...text !== void 0 ? { text } : {} }];
|
|
21988
22295
|
}
|
|
21989
22296
|
case "message": {
|
|
21990
22297
|
const text = textOf(payload["content"]);
|