@darkhunt-security/endpoint-codex 0.9.8 → 0.9.9
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 +64 -14
- package/dist/bin/forwarder.mjs +64 -14
- package/package.json +1 -1
package/dist/bin/backfill.mjs
CHANGED
|
@@ -18303,6 +18303,10 @@ function summarize(output) {
|
|
|
18303
18303
|
return text;
|
|
18304
18304
|
return `${text.slice(0, TOOL_SUMMARY_LIMIT)}\u2026 [truncated, ${text.length} chars]`;
|
|
18305
18305
|
}
|
|
18306
|
+
function attachmentLabel(record) {
|
|
18307
|
+
const size = record.bytes ? `, ${Math.round(record.bytes / 1024)} KB` : "";
|
|
18308
|
+
return `[${record.mediaType ?? "attachment"}${size}]`;
|
|
18309
|
+
}
|
|
18306
18310
|
var RESUMED_USER_TEXT_LIMIT = 4e3;
|
|
18307
18311
|
var SessionEmitter = class {
|
|
18308
18312
|
client;
|
|
@@ -18324,8 +18328,12 @@ var SessionEmitter = class {
|
|
|
18324
18328
|
/** True while consecutive user records still belong to the same turn. */
|
|
18325
18329
|
userTurnOpen = false;
|
|
18326
18330
|
pendingAttachments = [];
|
|
18331
|
+
/** Attachments seen before the trace could be opened knowing the prompt. */
|
|
18332
|
+
deferred = [];
|
|
18327
18333
|
pendingUsage;
|
|
18328
18334
|
outputText = [];
|
|
18335
|
+
/** The last thing the assistant said in this pass — the trace's result. */
|
|
18336
|
+
lastAssistantText;
|
|
18329
18337
|
count = 0;
|
|
18330
18338
|
constructor(client, options) {
|
|
18331
18339
|
this.client = client;
|
|
@@ -18376,6 +18384,28 @@ var SessionEmitter = class {
|
|
|
18376
18384
|
return;
|
|
18377
18385
|
}
|
|
18378
18386
|
this.count++;
|
|
18387
|
+
if (record.kind === "attachment")
|
|
18388
|
+
this.pendingAttachments.push(attachmentLabel(record));
|
|
18389
|
+
if (record.kind === "user_message")
|
|
18390
|
+
this.absorbUserTurn(record);
|
|
18391
|
+
if (!this.trace && record.kind === "attachment") {
|
|
18392
|
+
this.deferred.push(record);
|
|
18393
|
+
return;
|
|
18394
|
+
}
|
|
18395
|
+
this.flushDeferred();
|
|
18396
|
+
this.place(record);
|
|
18397
|
+
}
|
|
18398
|
+
/** Open the trace on the turn held back, then replay it. No-op once the trace exists. */
|
|
18399
|
+
flushDeferred() {
|
|
18400
|
+
if (this.deferred.length === 0)
|
|
18401
|
+
return;
|
|
18402
|
+
const held = this.deferred.splice(0);
|
|
18403
|
+
this.ensureTrace(held[0].ts);
|
|
18404
|
+
for (const record of held)
|
|
18405
|
+
this.place(record);
|
|
18406
|
+
}
|
|
18407
|
+
/** Route one record onto its owning trace and emit whatever it is worth. */
|
|
18408
|
+
place(record) {
|
|
18379
18409
|
const root = this.ensureTrace(record.ts);
|
|
18380
18410
|
const parentTrace = record.parentUuid ? this.owners.get(record.parentUuid) : void 0;
|
|
18381
18411
|
let owner = parentTrace ?? root;
|
|
@@ -18385,28 +18415,21 @@ var SessionEmitter = class {
|
|
|
18385
18415
|
sessionId: this.options.sessionId,
|
|
18386
18416
|
handoffFrom: [root.handoffToken()],
|
|
18387
18417
|
startTime: record.ts,
|
|
18418
|
+
// A subagent's first record is the task it was given, and it has already been
|
|
18419
|
+
// absorbed by the time this fires — so the child trace opens with its brief
|
|
18420
|
+
// rather than empty.
|
|
18421
|
+
...this.lastUserText ? { input: this.lastUserText } : {},
|
|
18388
18422
|
...this.options.userId !== void 0 ? { userId: this.options.userId } : {}
|
|
18389
18423
|
}));
|
|
18390
18424
|
this.sidechains.push(owner);
|
|
18391
18425
|
}
|
|
18392
18426
|
this.owners.set(record.uuid, owner);
|
|
18393
18427
|
switch (record.kind) {
|
|
18394
|
-
case "user_message":
|
|
18428
|
+
case "user_message":
|
|
18395
18429
|
this.endGeneration();
|
|
18396
|
-
const part = [this.pendingAttachments.join(" "), record.text].filter(Boolean).join(" ");
|
|
18397
|
-
this.pendingAttachments = [];
|
|
18398
|
-
if (this.userTurnOpen) {
|
|
18399
|
-
this.lastUserText = [this.lastUserText, part].filter(Boolean).join(" ");
|
|
18400
|
-
} else {
|
|
18401
|
-
this.lastUserText = part;
|
|
18402
|
-
this.userTurnOpen = true;
|
|
18403
|
-
this.pendingToolResults = [];
|
|
18404
|
-
}
|
|
18405
18430
|
break;
|
|
18406
|
-
}
|
|
18407
18431
|
case "attachment": {
|
|
18408
|
-
const label =
|
|
18409
|
-
this.pendingAttachments.push(label);
|
|
18432
|
+
const label = attachmentLabel(record);
|
|
18410
18433
|
this.seeded(["attachment", record.uuid], () => owner.span("attachment", {
|
|
18411
18434
|
startTime: record.ts,
|
|
18412
18435
|
metadata: {
|
|
@@ -18463,8 +18486,26 @@ var SessionEmitter = class {
|
|
|
18463
18486
|
break;
|
|
18464
18487
|
}
|
|
18465
18488
|
}
|
|
18489
|
+
/**
|
|
18490
|
+
* Fold a user record into the turn in flight.
|
|
18491
|
+
*
|
|
18492
|
+
* Split out of the `user_message` case so it can run before the trace is opened —
|
|
18493
|
+
* see the call site in {@link ingest}.
|
|
18494
|
+
*/
|
|
18495
|
+
absorbUserTurn(record) {
|
|
18496
|
+
const part = [this.pendingAttachments.join(" "), record.text].filter(Boolean).join(" ");
|
|
18497
|
+
this.pendingAttachments = [];
|
|
18498
|
+
if (this.userTurnOpen) {
|
|
18499
|
+
this.lastUserText = [this.lastUserText, part].filter(Boolean).join(" ");
|
|
18500
|
+
} else {
|
|
18501
|
+
this.lastUserText = part;
|
|
18502
|
+
this.userTurnOpen = true;
|
|
18503
|
+
this.pendingToolResults = [];
|
|
18504
|
+
}
|
|
18505
|
+
}
|
|
18466
18506
|
/** Ends everything still open and flushes. Safe to call twice. */
|
|
18467
18507
|
async finish() {
|
|
18508
|
+
this.flushDeferred();
|
|
18468
18509
|
this.endGeneration();
|
|
18469
18510
|
for (const span of this.toolSpans.values())
|
|
18470
18511
|
span.end();
|
|
@@ -18475,7 +18516,10 @@ var SessionEmitter = class {
|
|
|
18475
18516
|
if (this.trace) {
|
|
18476
18517
|
this.trace.update({
|
|
18477
18518
|
metadata: this.meta,
|
|
18478
|
-
...this.title !== void 0 ? { name: this.title } : {}
|
|
18519
|
+
...this.title !== void 0 ? { name: this.title } : {},
|
|
18520
|
+
// The pass's result. Paired with the `input` set when the trace opened, this is
|
|
18521
|
+
// what stops the consumer inferring the trace's I/O from a descendant.
|
|
18522
|
+
...this.lastAssistantText !== void 0 ? { output: this.lastAssistantText } : {}
|
|
18479
18523
|
});
|
|
18480
18524
|
this.trace.end();
|
|
18481
18525
|
this.trace = void 0;
|
|
@@ -18531,6 +18575,10 @@ var SessionEmitter = class {
|
|
|
18531
18575
|
name: this.title ?? this.defaultTraceName(),
|
|
18532
18576
|
sessionId: this.grouping ?? this.options.sessionId,
|
|
18533
18577
|
startTime: ts,
|
|
18578
|
+
// What the agent was asked. `TraceArgs.input` is construction-only — the SDK's
|
|
18579
|
+
// `update()` carries output alone — which is why `ingest` absorbs the user turn
|
|
18580
|
+
// before it calls this.
|
|
18581
|
+
...this.lastUserText ? { input: this.lastUserText } : {},
|
|
18534
18582
|
tags: [this.options.vendor, ...this.options.agentId ? ["subagent"] : []],
|
|
18535
18583
|
metadata: {
|
|
18536
18584
|
...this.meta,
|
|
@@ -18596,6 +18644,8 @@ var SessionEmitter = class {
|
|
|
18596
18644
|
if (!this.generation)
|
|
18597
18645
|
return;
|
|
18598
18646
|
const output = this.outputText.join("\n");
|
|
18647
|
+
if (output)
|
|
18648
|
+
this.lastAssistantText = output;
|
|
18599
18649
|
this.generation.end({
|
|
18600
18650
|
...output ? { outputMessages: [{ role: "assistant", content: output }] } : {},
|
|
18601
18651
|
...this.model !== void 0 ? { model: this.model } : {},
|
package/dist/bin/forwarder.mjs
CHANGED
|
@@ -18303,6 +18303,10 @@ function summarize(output) {
|
|
|
18303
18303
|
return text;
|
|
18304
18304
|
return `${text.slice(0, TOOL_SUMMARY_LIMIT)}\u2026 [truncated, ${text.length} chars]`;
|
|
18305
18305
|
}
|
|
18306
|
+
function attachmentLabel(record) {
|
|
18307
|
+
const size = record.bytes ? `, ${Math.round(record.bytes / 1024)} KB` : "";
|
|
18308
|
+
return `[${record.mediaType ?? "attachment"}${size}]`;
|
|
18309
|
+
}
|
|
18306
18310
|
var RESUMED_USER_TEXT_LIMIT = 4e3;
|
|
18307
18311
|
var SessionEmitter = class {
|
|
18308
18312
|
client;
|
|
@@ -18324,8 +18328,12 @@ var SessionEmitter = class {
|
|
|
18324
18328
|
/** True while consecutive user records still belong to the same turn. */
|
|
18325
18329
|
userTurnOpen = false;
|
|
18326
18330
|
pendingAttachments = [];
|
|
18331
|
+
/** Attachments seen before the trace could be opened knowing the prompt. */
|
|
18332
|
+
deferred = [];
|
|
18327
18333
|
pendingUsage;
|
|
18328
18334
|
outputText = [];
|
|
18335
|
+
/** The last thing the assistant said in this pass — the trace's result. */
|
|
18336
|
+
lastAssistantText;
|
|
18329
18337
|
count = 0;
|
|
18330
18338
|
constructor(client, options) {
|
|
18331
18339
|
this.client = client;
|
|
@@ -18376,6 +18384,28 @@ var SessionEmitter = class {
|
|
|
18376
18384
|
return;
|
|
18377
18385
|
}
|
|
18378
18386
|
this.count++;
|
|
18387
|
+
if (record.kind === "attachment")
|
|
18388
|
+
this.pendingAttachments.push(attachmentLabel(record));
|
|
18389
|
+
if (record.kind === "user_message")
|
|
18390
|
+
this.absorbUserTurn(record);
|
|
18391
|
+
if (!this.trace && record.kind === "attachment") {
|
|
18392
|
+
this.deferred.push(record);
|
|
18393
|
+
return;
|
|
18394
|
+
}
|
|
18395
|
+
this.flushDeferred();
|
|
18396
|
+
this.place(record);
|
|
18397
|
+
}
|
|
18398
|
+
/** Open the trace on the turn held back, then replay it. No-op once the trace exists. */
|
|
18399
|
+
flushDeferred() {
|
|
18400
|
+
if (this.deferred.length === 0)
|
|
18401
|
+
return;
|
|
18402
|
+
const held = this.deferred.splice(0);
|
|
18403
|
+
this.ensureTrace(held[0].ts);
|
|
18404
|
+
for (const record of held)
|
|
18405
|
+
this.place(record);
|
|
18406
|
+
}
|
|
18407
|
+
/** Route one record onto its owning trace and emit whatever it is worth. */
|
|
18408
|
+
place(record) {
|
|
18379
18409
|
const root = this.ensureTrace(record.ts);
|
|
18380
18410
|
const parentTrace = record.parentUuid ? this.owners.get(record.parentUuid) : void 0;
|
|
18381
18411
|
let owner = parentTrace ?? root;
|
|
@@ -18385,28 +18415,21 @@ var SessionEmitter = class {
|
|
|
18385
18415
|
sessionId: this.options.sessionId,
|
|
18386
18416
|
handoffFrom: [root.handoffToken()],
|
|
18387
18417
|
startTime: record.ts,
|
|
18418
|
+
// A subagent's first record is the task it was given, and it has already been
|
|
18419
|
+
// absorbed by the time this fires — so the child trace opens with its brief
|
|
18420
|
+
// rather than empty.
|
|
18421
|
+
...this.lastUserText ? { input: this.lastUserText } : {},
|
|
18388
18422
|
...this.options.userId !== void 0 ? { userId: this.options.userId } : {}
|
|
18389
18423
|
}));
|
|
18390
18424
|
this.sidechains.push(owner);
|
|
18391
18425
|
}
|
|
18392
18426
|
this.owners.set(record.uuid, owner);
|
|
18393
18427
|
switch (record.kind) {
|
|
18394
|
-
case "user_message":
|
|
18428
|
+
case "user_message":
|
|
18395
18429
|
this.endGeneration();
|
|
18396
|
-
const part = [this.pendingAttachments.join(" "), record.text].filter(Boolean).join(" ");
|
|
18397
|
-
this.pendingAttachments = [];
|
|
18398
|
-
if (this.userTurnOpen) {
|
|
18399
|
-
this.lastUserText = [this.lastUserText, part].filter(Boolean).join(" ");
|
|
18400
|
-
} else {
|
|
18401
|
-
this.lastUserText = part;
|
|
18402
|
-
this.userTurnOpen = true;
|
|
18403
|
-
this.pendingToolResults = [];
|
|
18404
|
-
}
|
|
18405
18430
|
break;
|
|
18406
|
-
}
|
|
18407
18431
|
case "attachment": {
|
|
18408
|
-
const label =
|
|
18409
|
-
this.pendingAttachments.push(label);
|
|
18432
|
+
const label = attachmentLabel(record);
|
|
18410
18433
|
this.seeded(["attachment", record.uuid], () => owner.span("attachment", {
|
|
18411
18434
|
startTime: record.ts,
|
|
18412
18435
|
metadata: {
|
|
@@ -18463,8 +18486,26 @@ var SessionEmitter = class {
|
|
|
18463
18486
|
break;
|
|
18464
18487
|
}
|
|
18465
18488
|
}
|
|
18489
|
+
/**
|
|
18490
|
+
* Fold a user record into the turn in flight.
|
|
18491
|
+
*
|
|
18492
|
+
* Split out of the `user_message` case so it can run before the trace is opened —
|
|
18493
|
+
* see the call site in {@link ingest}.
|
|
18494
|
+
*/
|
|
18495
|
+
absorbUserTurn(record) {
|
|
18496
|
+
const part = [this.pendingAttachments.join(" "), record.text].filter(Boolean).join(" ");
|
|
18497
|
+
this.pendingAttachments = [];
|
|
18498
|
+
if (this.userTurnOpen) {
|
|
18499
|
+
this.lastUserText = [this.lastUserText, part].filter(Boolean).join(" ");
|
|
18500
|
+
} else {
|
|
18501
|
+
this.lastUserText = part;
|
|
18502
|
+
this.userTurnOpen = true;
|
|
18503
|
+
this.pendingToolResults = [];
|
|
18504
|
+
}
|
|
18505
|
+
}
|
|
18466
18506
|
/** Ends everything still open and flushes. Safe to call twice. */
|
|
18467
18507
|
async finish() {
|
|
18508
|
+
this.flushDeferred();
|
|
18468
18509
|
this.endGeneration();
|
|
18469
18510
|
for (const span of this.toolSpans.values())
|
|
18470
18511
|
span.end();
|
|
@@ -18475,7 +18516,10 @@ var SessionEmitter = class {
|
|
|
18475
18516
|
if (this.trace) {
|
|
18476
18517
|
this.trace.update({
|
|
18477
18518
|
metadata: this.meta,
|
|
18478
|
-
...this.title !== void 0 ? { name: this.title } : {}
|
|
18519
|
+
...this.title !== void 0 ? { name: this.title } : {},
|
|
18520
|
+
// The pass's result. Paired with the `input` set when the trace opened, this is
|
|
18521
|
+
// what stops the consumer inferring the trace's I/O from a descendant.
|
|
18522
|
+
...this.lastAssistantText !== void 0 ? { output: this.lastAssistantText } : {}
|
|
18479
18523
|
});
|
|
18480
18524
|
this.trace.end();
|
|
18481
18525
|
this.trace = void 0;
|
|
@@ -18531,6 +18575,10 @@ var SessionEmitter = class {
|
|
|
18531
18575
|
name: this.title ?? this.defaultTraceName(),
|
|
18532
18576
|
sessionId: this.grouping ?? this.options.sessionId,
|
|
18533
18577
|
startTime: ts,
|
|
18578
|
+
// What the agent was asked. `TraceArgs.input` is construction-only — the SDK's
|
|
18579
|
+
// `update()` carries output alone — which is why `ingest` absorbs the user turn
|
|
18580
|
+
// before it calls this.
|
|
18581
|
+
...this.lastUserText ? { input: this.lastUserText } : {},
|
|
18534
18582
|
tags: [this.options.vendor, ...this.options.agentId ? ["subagent"] : []],
|
|
18535
18583
|
metadata: {
|
|
18536
18584
|
...this.meta,
|
|
@@ -18596,6 +18644,8 @@ var SessionEmitter = class {
|
|
|
18596
18644
|
if (!this.generation)
|
|
18597
18645
|
return;
|
|
18598
18646
|
const output = this.outputText.join("\n");
|
|
18647
|
+
if (output)
|
|
18648
|
+
this.lastAssistantText = output;
|
|
18599
18649
|
this.generation.end({
|
|
18600
18650
|
...output ? { outputMessages: [{ role: "assistant", content: output }] } : {},
|
|
18601
18651
|
...this.model !== void 0 ? { model: this.model } : {},
|
package/package.json
CHANGED