@sema-agent/core 7.56.0 → 7.57.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/CHANGELOG.md +541 -0
- package/LICENSE +1 -1
- package/dist/agents/org-delivery-gate.js +3 -4
- package/dist/agents/peer-held-queue.d.ts +69 -49
- package/dist/agents/peer-held-queue.js +255 -106
- package/dist/agents/peer-session-drain.js +63 -43
- package/dist/agents/send-message-tool.js +3 -2
- package/dist/agents/subagent.js +8 -8
- package/dist/brain/anthropic.js +16 -8
- package/dist/brain/open-responses.js +10 -8
- package/dist/brain/openai.js +11 -9
- package/dist/brain/provider-dialect.d.ts +3 -2
- package/dist/brain/provider-dialect.js +2 -2
- package/dist/brain/request-params.d.ts +6 -0
- package/dist/brain/request-params.js +14 -1
- package/dist/brain/stream-engine.d.ts +9 -0
- package/dist/brain/stream-engine.js +24 -10
- package/dist/brain/stream-shared.d.ts +5 -4
- package/dist/brain/stream-shared.js +4 -4
- package/dist/core/allow-entry.d.ts +3 -10
- package/dist/core/allow-entry.js +17 -25
- package/dist/core/approval-object.d.ts +21 -5
- package/dist/core/approval-object.js +44 -17
- package/dist/core/ask-origin.d.ts +2 -2
- package/dist/core/auto-compaction.d.ts +71 -6
- package/dist/core/auto-compaction.js +42 -26
- package/dist/core/background-agent-store.d.ts +6 -2
- package/dist/core/background-agent-store.js +1 -1
- package/dist/core/checkpoint-requirements.d.ts +7 -1
- package/dist/core/checkpoint-requirements.js +2 -0
- package/dist/core/checkpoint-store.d.ts +17 -29
- package/dist/core/checkpoint-store.js +19 -11
- package/dist/core/cross-boundary-taint.js +4 -2
- package/dist/core/engine-notice.d.ts +3 -2
- package/dist/core/engine-notice.js +6 -0
- package/dist/core/file-history-store.d.ts +14 -8
- package/dist/core/file-history-store.js +14 -4
- package/dist/core/gate-lanes.js +2 -3
- package/dist/core/hooks.d.ts +2 -2
- package/dist/core/mailbox-store.d.ts +62 -1
- package/dist/core/mailbox-store.js +59 -0
- package/dist/core/mcp-name-judge.d.ts +46 -0
- package/dist/core/mcp-name-judge.js +61 -0
- package/dist/core/mcp-probe.d.ts +1 -1
- package/dist/core/mcp-probe.js +2 -5
- package/dist/core/mcp.js +10 -30
- package/dist/core/memory-engine/consolidation-driver.js +4 -3
- package/dist/core/memory-engine/distiller.js +26 -17
- package/dist/core/memory-engine/layout.js +5 -2
- package/dist/core/park-selfcheck.js +2 -0
- package/dist/core/permission-rule-consent.d.ts +5 -3
- package/dist/core/permission-rule-consent.js +20 -15
- package/dist/core/permission-rule-model.d.ts +43 -2
- package/dist/core/permission-rule-model.js +52 -8
- package/dist/core/permission-rule-org.js +1 -1
- package/dist/core/protocol-http-auth.d.ts +16 -2
- package/dist/core/protocol-http-auth.js +42 -11
- package/dist/core/protocol-naming.d.ts +20 -0
- package/dist/core/protocol-naming.js +20 -3
- package/dist/core/read-only-shell.d.ts +20 -5
- package/dist/core/read-only-shell.js +29 -14
- package/dist/core/remote-env.d.ts +37 -1
- package/dist/core/remote-env.js +11 -0
- package/dist/core/resume-startup-cause.d.ts +24 -2
- package/dist/core/resume-startup-cause.js +20 -1
- package/dist/core/roles.js +50 -7
- package/dist/core/runner/compact-session.d.ts +10 -0
- package/dist/core/runner/compact-session.js +202 -0
- package/dist/core/runner/compaction-call-options.d.ts +2 -2
- package/dist/core/runner/compaction-seams.d.ts +21 -1
- package/dist/core/runner/compaction-seams.js +11 -8
- package/dist/core/runner/contracts.d.ts +23 -16
- package/dist/core/runner/derived-route-fallback.d.ts +13 -0
- package/dist/core/runner/derived-route-fallback.js +6 -0
- package/dist/core/runner/env-capability-census.d.ts +3 -2
- package/dist/core/runner/env-capability-census.js +9 -3
- package/dist/core/runner/permission-rule-lanes.d.ts +7 -7
- package/dist/core/runner/permission-rule-lanes.js +17 -11
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -0
- package/dist/core/runner/prepare-acquire-reconcile.js +2 -1
- package/dist/core/runner/prepare-config-doors.d.ts +6 -0
- package/dist/core/runner/prepare-config-doors.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -1
- package/dist/core/runner/prepare-hands-readface.js +2 -0
- package/dist/core/runner/prepare-park-ask.d.ts +2 -0
- package/dist/core/runner/prepare-park-ask.js +2 -2
- package/dist/core/runner/prepare-policy-chain.js +2 -4
- package/dist/core/runner/prepare-task.d.ts +4 -1
- package/dist/core/runner/prepare-task.js +23 -27
- package/dist/core/runner/prepare-tool-disclosure-mount.d.ts +13 -0
- package/dist/core/runner/prepare-tool-disclosure-mount.js +13 -7
- package/dist/core/runner/rewind-files.d.ts +2 -5
- package/dist/core/runner/rewind-files.js +9 -51
- package/dist/core/runner/run-leg.js +10 -21
- package/dist/core/runner/run-notification-lane.d.ts +2 -0
- package/dist/core/runner/run-notification-lane.js +2 -2
- package/dist/core/runner/run-recovery-lanes.js +3 -4
- package/dist/core/runner/run-settle-and-teardown.js +5 -11
- package/dist/core/runner/run-terminal-adoption.js +3 -4
- package/dist/core/runner/run-turn-boundary.js +3 -5
- package/dist/core/runner/runtask.d.ts +8 -1
- package/dist/core/runner/runtask.js +28 -34
- package/dist/core/runner/send-message-continuation.js +1 -1
- package/dist/core/runner/session-verb-doors.d.ts +28 -0
- package/dist/core/runner/session-verb-doors.js +48 -0
- package/dist/core/runner/session-write-ledger.d.ts +30 -0
- package/dist/core/runner/session-write-ledger.js +101 -0
- package/dist/core/runner/stream-settle-backstop.js +11 -14
- package/dist/core/runner/sub-agent-deny-lists.d.ts +25 -3
- package/dist/core/runner/sub-agent-deny-lists.js +21 -10
- package/dist/core/runner/teardown-bounded.d.ts +1 -0
- package/dist/core/runner/teardown-bounded.js +1 -0
- package/dist/core/runner-deps.d.ts +2 -2
- package/dist/core/secret-env.d.ts +4 -0
- package/dist/core/secret-env.js +3 -0
- package/dist/core/session-policy-store.d.ts +7 -2
- package/dist/core/session-policy-store.js +1 -1
- package/dist/core/shell-wrapper-projection.d.ts +1 -1
- package/dist/core/store-contracts/background-agent-store-contract.js +1 -0
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -1
- package/dist/core/store-contracts/file-history-store-contract.js +9 -0
- package/dist/core/store-contracts/mailbox-store-contract.js +49 -1
- package/dist/core/task-registry-agent.d.ts +8 -4
- package/dist/core/task-registry-agent.js +14 -8
- package/dist/core/task-registry-shared.d.ts +35 -6
- package/dist/core/task-registry-shared.js +11 -0
- package/dist/core/task-registry.d.ts +1 -1
- package/dist/core/task-registry.js +1 -1
- package/dist/core/tool-catalog-entries.d.ts +6 -0
- package/dist/core/tool-catalog-entries.js +1 -0
- package/dist/core/tool-name-aliases.d.ts +32 -2
- package/dist/core/tool-name-aliases.js +23 -0
- package/dist/core/tool-name-readings.d.ts +4 -0
- package/dist/core/tool-name-readings.js +1 -0
- package/dist/core/tool-policy.d.ts +10 -6
- package/dist/core/tool-policy.js +4 -7
- package/dist/core/trace.d.ts +4 -1
- package/dist/core/trace.js +2 -1
- package/dist/core/untrusted-egress.d.ts +20 -0
- package/dist/core/untrusted-egress.js +77 -3
- package/dist/engine/harness/agent-harness.d.ts +7 -5
- package/dist/engine/harness/agent-harness.js +11 -2
- package/dist/engine/loop/agent-loop.d.ts +1 -4
- package/dist/engine/loop/agent-loop.js +26 -4
- package/dist/index.d.ts +12 -7
- package/dist/index.js +7 -4
- package/dist/internal/harness.d.ts +2 -1
- package/dist/internal/harness.js +1 -0
- package/dist/primitives/credential-ref.d.ts +89 -0
- package/dist/primitives/credential-ref.js +125 -0
- package/dist/primitives/index.d.ts +2 -0
- package/dist/primitives/index.js +1 -0
- package/dist/stores/file/checkpoint-store.d.ts +0 -4
- package/dist/stores/file/checkpoint-store.js +0 -1
- package/dist/stores/file/file-history-store.js +12 -4
- package/dist/stores/file/mailbox-store.d.ts +2 -1
- package/dist/stores/file/mailbox-store.js +26 -1
- package/dist/tools/fs/bash-readonly-classifier.d.ts +15 -19
- package/dist/tools/fs/bash-readonly-classifier.js +5 -10
- package/dist/tools/fs/fs-bash.js +10 -3
- package/dist/tools/fs/pattern-kill-guard.d.ts +3 -2
- package/dist/tools/fs/pattern-kill-guard.js +68 -36
- package/dist/tools/fs/shell-read-check.d.ts +10 -0
- package/dist/tools/fs/shell-read-check.js +7 -1
- package/dist/tools/fs/shell-read-identity.d.ts +12 -9
- package/dist/tools/fs/shell-read-identity.js +9 -4
- package/dist/tools/web.js +9 -7
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +79 -3
- package/wire-changes/core-stores-sql@7.57.0.json +29 -0
- package/wire-changes/core@7.57.0.json +1487 -0
- package/wire-changes/mods-kernel@7.57.0.json +29 -0
- package/wire-changes/primitives@7.57.0.json +245 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { mailboxCrossProcessMountVerdict } from "../core/mailbox-store.js";
|
|
1
|
+
import { isMailboxDecisionFinal, mailboxCrossProcessMountVerdict, moveMailboxDecision } from "../core/mailbox-store.js";
|
|
2
2
|
import { decodeEngineFrame, ENGINE_FRAME_CODEC_VERSION, renderTaskNotificationXml, taskNotificationDedupKey } from "../core/task-notification.js";
|
|
3
3
|
import { createFrameSettlement, toolResultReceiptKey } from "../core/frame-settlement.js";
|
|
4
4
|
import { PRINCIPAL_INBOX_HANDLE } from "./cross-session-ref.js";
|
|
@@ -161,7 +161,7 @@ export function createPeerSessionDrain(opts) {
|
|
|
161
161
|
...(live
|
|
162
162
|
? {
|
|
163
163
|
inject: (entry) => {
|
|
164
|
-
if (currentRound === undefined)
|
|
164
|
+
if (currentRound === undefined || !currentRound.holds(lane))
|
|
165
165
|
return "deferred";
|
|
166
166
|
const payload = buildPeerMessagePayload(lane, entry);
|
|
167
167
|
if (currentRound.deliver(payload, "next") === "deferred")
|
|
@@ -169,9 +169,13 @@ export function createPeerSessionDrain(opts) {
|
|
|
169
169
|
noteDelivered(lane, entry.seq, 1, payload, currentRound.carrier);
|
|
170
170
|
return undefined;
|
|
171
171
|
},
|
|
172
|
+
canInject: () => currentRound !== undefined && currentRound.holds(lane) && !currentRound.spent,
|
|
172
173
|
}
|
|
173
174
|
: {}),
|
|
174
175
|
receipt: receipt(lane),
|
|
176
|
+
tellsSender: (entry) => receiptAddress(lane, entry) !== undefined,
|
|
177
|
+
decide: (entry, expect, next) => moveMailboxDecision(mailbox, scope, lane.boxHandle, entry.seq, expect, next),
|
|
178
|
+
onFault: (entry, e) => opts.onError?.(e, { phase: "degraded", sessionId, classification: `peer-decision-move:${entry.box}#${entry.seq}` }),
|
|
175
179
|
onHeld: (entry, count, cause, reannounce) => {
|
|
176
180
|
if (!reannounce && lane.disclosedHeld.has(entry.seq))
|
|
177
181
|
return;
|
|
@@ -179,12 +183,13 @@ export function createPeerSessionDrain(opts) {
|
|
|
179
183
|
disclose(lane, "held", cause, entry, reannounce ? `still held; its cause moved to ${cause} (${count} held)` : undefined);
|
|
180
184
|
},
|
|
181
185
|
onSettled: (entry, settlement, reason, count) => {
|
|
182
|
-
if (entry.box === lane.boxHandle && settlement !== "delivered")
|
|
186
|
+
if (entry.box === lane.boxHandle && settlement !== "delivered" && settlement !== "retired")
|
|
183
187
|
lane.ledger.set(entry.seq, { kind: "terminal", why: `held_${settlement}` });
|
|
184
188
|
const replyTo = receiptAddress(lane, entry);
|
|
189
|
+
const told = reason !== "decided_elsewhere" && settlement !== "retired" && replyTo !== undefined;
|
|
185
190
|
deliverEngineNotice(opts.onNotice, {
|
|
186
191
|
code: "peer.held_settled",
|
|
187
|
-
message: `held cross-session message seq ${entry.seq} left this session's held queue: ${settlement} (${reason}); ${count} still held${settlement === "expired" && reason === "evicted" ? " — the held queue was full, so the oldest entry was expired to make room" : ""}. The sender ${replyTo !== undefined ? "was sent a receipt" : "has no reply address and was not told"}.`,
|
|
192
|
+
message: `held cross-session message seq ${entry.seq} left this session's held queue: ${settlement} (${reason}); ${count} still held${settlement === "expired" && reason === "evicted" ? " — the held queue was full, so the oldest entry was expired to make room" : ""}${settlement === "retired" ? (reason === "superseded" ? " — its record is no longer in the box (another consumer settled it); nothing was decided here" : " — no decision was taken: it stays held in the box, and the next drain presents it again") : ""}${reason === "decided_elsewhere" ? " — another consumer of the box decided it first" : ""}. The sender ${told ? "was sent a receipt" : replyTo !== undefined ? "was not sent a receipt from here" : "has no reply address and was not told"}.`,
|
|
188
193
|
detail: { settlement, reason, seq: entry.seq, box: lane.boxHandle, ...(entry.peerMeta?.fromSession !== undefined ? { fromSession: entry.peerMeta.fromSession } : {}), heldCount: count, sessionId, runId },
|
|
189
194
|
});
|
|
190
195
|
},
|
|
@@ -216,28 +221,29 @@ export function createPeerSessionDrain(opts) {
|
|
|
216
221
|
idleMachine.requester.configure({
|
|
217
222
|
expired: (o) => void routePeerIdleNotice(route(), sessionId, { kind: "expired", label: o.label }),
|
|
218
223
|
});
|
|
219
|
-
const
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
for (const
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
224
|
+
const reconcileHeld = (lane, lease) => {
|
|
225
|
+
const live = lease.messages.filter((m) => lane.ackedUpTo === undefined || m.seq > lane.ackedUpTo);
|
|
226
|
+
lane.held.reconcile(new Map(live.map((m) => [m.seq, m.decision])));
|
|
227
|
+
adoptFinalDecisions(lane, lease);
|
|
228
|
+
for (const m of live) {
|
|
229
|
+
const d = lane.ledger.get(m.seq);
|
|
230
|
+
if (lane.held.has(m.seq)) {
|
|
231
|
+
if (d === undefined)
|
|
232
|
+
lane.ledger.set(m.seq, { kind: "held" });
|
|
233
|
+
}
|
|
234
|
+
else if (d?.kind === "held")
|
|
235
|
+
lane.ledger.delete(m.seq);
|
|
230
236
|
}
|
|
231
237
|
};
|
|
232
|
-
const
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
for (const [seq, d] of lane.ledger) {
|
|
236
|
-
if (d.kind !== "held")
|
|
238
|
+
const adoptFinalDecisions = (lane, lease) => {
|
|
239
|
+
for (const m of lease.messages) {
|
|
240
|
+
if (lane.ackedUpTo !== undefined && m.seq <= lane.ackedUpTo)
|
|
237
241
|
continue;
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
242
|
+
if (!isMailboxDecisionFinal(m.decision))
|
|
243
|
+
continue;
|
|
244
|
+
const d = lane.ledger.get(m.seq);
|
|
245
|
+
if (d === undefined || d.kind === "held" || d.kind === "invalidated")
|
|
246
|
+
lane.ledger.set(m.seq, { kind: "terminal", why: `held_${m.decision}` });
|
|
241
247
|
}
|
|
242
248
|
};
|
|
243
249
|
const wantsCompactionEffects = () => {
|
|
@@ -280,7 +286,6 @@ export function createPeerSessionDrain(opts) {
|
|
|
280
286
|
};
|
|
281
287
|
const settleLaneLocally = (lane, landed) => {
|
|
282
288
|
const { ledger, boxHandle } = lane;
|
|
283
|
-
adoptHeldDecisions(lane);
|
|
284
289
|
const hostWithheldSeqs = [];
|
|
285
290
|
if (seam.receipts.size > 0 || seam.withheld.size > 0 || seam.hostWithheld.size > 0) {
|
|
286
291
|
for (const [seq, d] of ledger) {
|
|
@@ -326,26 +331,17 @@ export function createPeerSessionDrain(opts) {
|
|
|
326
331
|
}
|
|
327
332
|
};
|
|
328
333
|
const ackSettledPrefix = async (lane, lease) => {
|
|
329
|
-
const {
|
|
330
|
-
|
|
331
|
-
if (decided.size > 0) {
|
|
332
|
-
const live = new Set(lease.messages.map((m) => m.seq));
|
|
333
|
-
held.forgetDecisions([...decided.keys()].filter((seq) => !live.has(seq)));
|
|
334
|
-
}
|
|
334
|
+
const { ledger, boxHandle } = lane;
|
|
335
|
+
adoptFinalDecisions(lane, lease);
|
|
335
336
|
const prefix = deriveAckPrefix(lane, lease.messages);
|
|
336
337
|
if (prefix !== undefined && (lane.ackedUpTo === undefined || prefix > lane.ackedUpTo)) {
|
|
337
338
|
try {
|
|
338
339
|
const result = await mailbox.ack(scope, boxHandle, drainOwner, prefix);
|
|
339
340
|
if (result.acked) {
|
|
340
341
|
lane.ackedUpTo = prefix;
|
|
341
|
-
const
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
continue;
|
|
345
|
-
gone.push(seq);
|
|
346
|
-
ledger.delete(seq);
|
|
347
|
-
}
|
|
348
|
-
held.forgetDecisions(gone);
|
|
342
|
+
for (const seq of [...ledger.keys()])
|
|
343
|
+
if (seq <= prefix)
|
|
344
|
+
ledger.delete(seq);
|
|
349
345
|
}
|
|
350
346
|
else {
|
|
351
347
|
opts.onError?.(new Error(`the ${lane.kind === "session" ? "session box" : "principal inbox"} ${boxHandle} refused this leg's ack up to seq ${prefix}: the drain lease is no longer held by ${drainOwner} (it expired and another cycle claimed it). The records stay parked and the lease holder re-serves them.`), { phase: "degraded", sessionId, classification: "peer-box-ack" });
|
|
@@ -451,6 +447,13 @@ export function createPeerSessionDrain(opts) {
|
|
|
451
447
|
lane.ledger.set(seq, { kind: "terminal", why });
|
|
452
448
|
}
|
|
453
449
|
batch = [];
|
|
450
|
+
leasedLanes = new Set();
|
|
451
|
+
lease(lanes) {
|
|
452
|
+
this.leasedLanes = new Set(lanes);
|
|
453
|
+
}
|
|
454
|
+
holds(lane) {
|
|
455
|
+
return this.leasedLanes.has(lane);
|
|
456
|
+
}
|
|
454
457
|
chars = 0;
|
|
455
458
|
constructor(limit, out, carrier, charBudget) {
|
|
456
459
|
this.limit = limit;
|
|
@@ -527,15 +530,17 @@ export function createPeerSessionDrain(opts) {
|
|
|
527
530
|
const leased = claims.filter((c) => c.lease !== null);
|
|
528
531
|
if (leased.length === 0)
|
|
529
532
|
return { pending: 0, urgent: 0 };
|
|
533
|
+
round.lease(leased.map((c) => c.lane));
|
|
530
534
|
for (const { lane, lease } of leased) {
|
|
531
535
|
bindHeld(lane, true);
|
|
532
536
|
reconcileHeld(lane, lease);
|
|
533
|
-
lane.held.rejudge();
|
|
537
|
+
await lane.held.rejudge();
|
|
534
538
|
}
|
|
535
539
|
try {
|
|
536
540
|
for (const { lane, lease } of leased) {
|
|
537
541
|
const { ledger, disclosedHeld, held, boxHandle } = lane;
|
|
538
542
|
const ackedUpTo = lane.ackedUpTo;
|
|
543
|
+
let adoptedThisPass = false;
|
|
539
544
|
for (const m of lease.messages) {
|
|
540
545
|
const prior = ledger.get(m.seq);
|
|
541
546
|
if (prior === undefined || prior.kind !== "invalidated")
|
|
@@ -545,7 +550,6 @@ export function createPeerSessionDrain(opts) {
|
|
|
545
550
|
const attempt = prior.attempt + 1;
|
|
546
551
|
round.batch.push({ lane, payload: { ...prior.payload, attempt, resupplied: true }, priority: "next", urgent: false, seq: m.seq, attempt });
|
|
547
552
|
}
|
|
548
|
-
adoptHeldDecisions(lane);
|
|
549
553
|
for (const m of lease.messages) {
|
|
550
554
|
if (ackedUpTo !== undefined && m.seq <= ackedUpTo)
|
|
551
555
|
continue;
|
|
@@ -597,15 +601,29 @@ export function createPeerSessionDrain(opts) {
|
|
|
597
601
|
continue;
|
|
598
602
|
}
|
|
599
603
|
const sameTree = meta?.fromRoot !== undefined && meta.fromRoot.toLowerCase() === sessionId.toLowerCase();
|
|
604
|
+
const known = m.decision;
|
|
600
605
|
if (!sameTree) {
|
|
601
606
|
const judged = judgeMeta(facts, meta);
|
|
602
|
-
|
|
607
|
+
const shown = known === "held" || known === "approved";
|
|
608
|
+
if (!shown && judged.verdict === "refuse") {
|
|
603
609
|
disclose(lane, "refused", judged.cause, m);
|
|
604
610
|
round.dispose(lane, m.seq, `refused:${judged.cause}`);
|
|
605
611
|
continue;
|
|
606
612
|
}
|
|
607
|
-
if (judged.verdict === "hold") {
|
|
608
|
-
held.hold({ seq: m.seq, box: boxHandle, content: m.content, ...(m.from !== undefined ? { from: m.from } : {}), sentAt: m.sentAt, ...(m.hopChain !== undefined ? { hopChain: [...m.hopChain] } : {}), ...(meta !== undefined ? { peerMeta: { ...meta } } : {}), cause: judged.cause });
|
|
613
|
+
if (shown || (judged.verdict === "hold" && known !== "delivered")) {
|
|
614
|
+
const outcome = await held.hold({ seq: m.seq, box: boxHandle, content: m.content, ...(m.from !== undefined ? { from: m.from } : {}), sentAt: m.sentAt, ...(m.hopChain !== undefined ? { hopChain: [...m.hopChain] } : {}), ...(meta !== undefined ? { peerMeta: { ...meta } } : {}), cause: judged.verdict === "hold" ? judged.cause : "explicit-setting" }, shown ? known : undefined);
|
|
615
|
+
if (outcome === "gone" || outcome === "fault")
|
|
616
|
+
continue;
|
|
617
|
+
if (outcome !== "held" && outcome !== "adopted" && outcome !== "uncarded") {
|
|
618
|
+
round.dispose(lane, m.seq, `held_${outcome}`);
|
|
619
|
+
continue;
|
|
620
|
+
}
|
|
621
|
+
if (shown && outcome === "adopted")
|
|
622
|
+
adoptedThisPass = true;
|
|
623
|
+
if (outcome === "uncarded" && !disclosedHeld.has(m.seq)) {
|
|
624
|
+
disclosedHeld.add(m.seq);
|
|
625
|
+
disclose(lane, "held", judged.verdict === "hold" ? judged.cause : "explicit-setting", m, "it is held in the box, but this session's held queue is full; it is shown when a card frees");
|
|
626
|
+
}
|
|
609
627
|
if (!ledger.has(m.seq))
|
|
610
628
|
ledger.set(m.seq, { kind: "held" });
|
|
611
629
|
continue;
|
|
@@ -622,6 +640,8 @@ export function createPeerSessionDrain(opts) {
|
|
|
622
640
|
}
|
|
623
641
|
round.batch.push({ lane, payload, priority: "next", urgent: meta?.urgent === true, seq: m.seq, attempt: 1 });
|
|
624
642
|
}
|
|
643
|
+
if (adoptedThisPass)
|
|
644
|
+
await held.rejudge();
|
|
625
645
|
}
|
|
626
646
|
}
|
|
627
647
|
finally {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Type } from "typebox";
|
|
2
2
|
import { isNotificationInjectionOutcome } from "../core/task-notification.js";
|
|
3
3
|
import { defineTool } from "../core/tools.js";
|
|
4
|
-
import { normalizeAgentName, DURABLE_AGENT_HANDLE_RE, DURABLE_AGENT_HEARTBEAT_MS } from "../core/task-registry.js";
|
|
4
|
+
import { normalizeAgentName, chosenAgentName, DURABLE_AGENT_HANDLE_RE, DURABLE_AGENT_HEARTBEAT_MS } from "../core/task-registry.js";
|
|
5
5
|
import { announceTranscriptIntegrityGapOnce, canAccessAgentRecord, clearRevivedRowTerminalPayload } from "../core/background-agent-store.js";
|
|
6
6
|
import { uuidv7 } from "../internal/harness.js";
|
|
7
7
|
import { MAILBOX_TOMBSTONED_RECIPIENT_CODE, mailboxCrossProcessMountVerdict } from "../core/mailbox-store.js";
|
|
@@ -1041,6 +1041,7 @@ export function createSendMessageTool(opts) {
|
|
|
1041
1041
|
if (!l3Verdict.ok)
|
|
1042
1042
|
return admissionRefusal(l3Verdict.reason, who);
|
|
1043
1043
|
assertParentSpecSeatCurrent(ctx.parentSpecSeat);
|
|
1044
|
+
const chosenRowName = chosenAgentName(targetId, row.name);
|
|
1044
1045
|
const resume = createSubagentResume({
|
|
1045
1046
|
ledger,
|
|
1046
1047
|
parentToolCallId: resumeToolUseId,
|
|
@@ -1055,7 +1056,7 @@ export function createSendMessageTool(opts) {
|
|
|
1055
1056
|
...((ctx.onBackgroundChildEvent ?? opts.onBackgroundChildEvent) ? { bgSink: ctx.onBackgroundChildEvent ?? opts.onBackgroundChildEvent } : {}),
|
|
1056
1057
|
sessionScoped: row.sessionScoped === true,
|
|
1057
1058
|
...(row.description !== undefined ? { rowDescription: row.description } : {}),
|
|
1058
|
-
...(
|
|
1059
|
+
...(chosenRowName !== undefined ? { rowName: chosenRowName } : {}),
|
|
1059
1060
|
...(row.agentType !== undefined ? { rowAgentType: row.agentType } : {}),
|
|
1060
1061
|
...(row.owner !== undefined ? { rowOwner: row.owner } : {}),
|
|
1061
1062
|
...(row.scope !== undefined ? { rowScope: row.scope } : {}),
|
package/dist/agents/subagent.js
CHANGED
|
@@ -41,7 +41,7 @@ import { boundedRedactedSummary } from "../core/untrusted-egress.js";
|
|
|
41
41
|
import { uuidv7 } from "../internal/harness.js";
|
|
42
42
|
import { addWorktree } from "../core/git-worktree-env.js";
|
|
43
43
|
import { shellQuote } from "../tools/fs/search.js";
|
|
44
|
-
import { BG_AGENT_REAP_STOP_ERROR } from "../core/task-registry.js";
|
|
44
|
+
import { BG_AGENT_REAP_STOP_ERROR, chosenAgentName } from "../core/task-registry.js";
|
|
45
45
|
import { readDurableOrgAdmission } from "../core/memory-admission.js";
|
|
46
46
|
import { governanceRetryClass } from "../core/governance-codes.js";
|
|
47
47
|
import { readSkillGrantCapture } from "../core/skill-grant.js";
|
|
@@ -1534,7 +1534,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
1534
1534
|
if (a.name !== undefined && typeof a.name !== "string") {
|
|
1535
1535
|
return notStartedResult({ isError: true, content: "Sub-agent not started: name must be a string.", details: { error: "name.invalid" } });
|
|
1536
1536
|
}
|
|
1537
|
-
const agentName = a.name;
|
|
1537
|
+
const agentName = reviveClaim !== undefined ? chosenAgentName(reviveClaim.row.handle, a.name) : a.name;
|
|
1538
1538
|
if (agentName !== undefined) {
|
|
1539
1539
|
if (!/^[A-Za-z0-9][A-Za-z0-9_-]{0,63}$/.test(agentName)) {
|
|
1540
1540
|
return notStartedResult({
|
|
@@ -1732,7 +1732,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
1732
1732
|
content: errorCodeOf(e) === WORKTREE_NOT_A_REPOSITORY
|
|
1733
1733
|
? "Sub-agent not started: worktree isolation failed — the working directory is not a git repository. Retry without the isolation parameter."
|
|
1734
1734
|
: "Sub-agent not started: worktree isolation failed. Retry without the isolation parameter, or fix the repository state.",
|
|
1735
|
-
details: { error: "isolation.failed", cause:
|
|
1735
|
+
details: { error: "isolation.failed", cause: childThrownText(e) },
|
|
1736
1736
|
});
|
|
1737
1737
|
}
|
|
1738
1738
|
}
|
|
@@ -1756,13 +1756,13 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
1756
1756
|
}
|
|
1757
1757
|
catch (e) {
|
|
1758
1758
|
worktreeKeptPath = worktreeDir;
|
|
1759
|
-
worktreeFault =
|
|
1759
|
+
worktreeFault = childThrownText(e);
|
|
1760
1760
|
return `worktree: ${worktreeDir} (cleanup check failed — the directory is kept on disk)`;
|
|
1761
1761
|
}
|
|
1762
1762
|
};
|
|
1763
1763
|
const reportedWorktreeLine = (line) => (line !== undefined && worktreeFault !== undefined ? `${line}: ${worktreeFault}` : line);
|
|
1764
1764
|
const faultDetails = (cause) => ({
|
|
1765
|
-
...(cause !== undefined ? { cause:
|
|
1765
|
+
...(cause !== undefined ? { cause: childThrownText(cause) } : {}),
|
|
1766
1766
|
...(worktreeFault !== undefined ? { worktreeCause: worktreeFault } : {}),
|
|
1767
1767
|
});
|
|
1768
1768
|
let injectedTools = [];
|
|
@@ -2499,7 +2499,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
2499
2499
|
}
|
|
2500
2500
|
}
|
|
2501
2501
|
if (!settled) {
|
|
2502
|
-
const detail =
|
|
2502
|
+
const detail = childThrownText(lastErr);
|
|
2503
2503
|
try {
|
|
2504
2504
|
enqueueMemoryAnnouncement(forkSettlementSeat.controlDir, {
|
|
2505
2505
|
kind: "gate",
|
|
@@ -3007,7 +3007,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
3007
3007
|
}
|
|
3008
3008
|
}
|
|
3009
3009
|
if (!settled) {
|
|
3010
|
-
const detail =
|
|
3010
|
+
const detail = childThrownText(lastErr);
|
|
3011
3011
|
try {
|
|
3012
3012
|
enqueueMemoryAnnouncement(settlementSeat.controlDir, {
|
|
3013
3013
|
kind: "gate",
|
|
@@ -3030,7 +3030,7 @@ function createSubagentToolNode(opts, depth, excluded, extraToolsBudget) {
|
|
|
3030
3030
|
...(reviveRow.sessionScoped ? { sessionScoped: true } : {}),
|
|
3031
3031
|
...(reviveRow.description !== undefined ? { description: reviveRow.description } : {}),
|
|
3032
3032
|
agentType: spawnAgentType,
|
|
3033
|
-
|
|
3033
|
+
name: reviveRow.name,
|
|
3034
3034
|
...(reviveRow.parentTaskId !== undefined ? { parentTaskId: reviveRow.parentTaskId } : {}),
|
|
3035
3035
|
...(reviveRow.parentSessionId !== undefined ? { parentSessionId: reviveRow.parentSessionId } : {}),
|
|
3036
3036
|
...((reviveRow.rootSessionId ?? reviveRow.parentSessionId) !== undefined
|
package/dist/brain/anthropic.js
CHANGED
|
@@ -6,7 +6,7 @@ import { STREAM_TORN_WARNING, createRepetitionPoll, createStreamEndLedger, model
|
|
|
6
6
|
import { admitToolCallId, providerResultIds, providerToolCallId, responseToolCallIds } from "./tool-call-id.js";
|
|
7
7
|
import { emitBrainTelemetry, reportReasoningWireFacts } from "./status-sink.js";
|
|
8
8
|
import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imageWithholdOf, reportImagesWithheld, sendableImages } from "./media-degrade.js";
|
|
9
|
-
import { ANTHROPIC_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders, takeHeaderSpellings } from "./request-params.js";
|
|
9
|
+
import { ANTHROPIC_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, declaredRequestValues, effectiveOutputCap, headerBagOnce, headerListEntries, lockHeader, mergeHeaders, takeHeaderSpellings } from "./request-params.js";
|
|
10
10
|
import { admitRouteRequest, applyRouteCredentialHeaders, assertServableRequestRoot, brainConfigSnapshot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential } from "./route-adjudicator.js";
|
|
11
11
|
import { requestRouteOf } from "./request-route.js";
|
|
12
12
|
import { NAMES_AS_WRITTEN, resolveProviderDialect, endpointToolNames } from "./provider-dialect.js";
|
|
@@ -296,6 +296,8 @@ export function createAnthropicBrain(given = {}) {
|
|
|
296
296
|
const headerLayers = [modelHeaders, config.headers, optionsHeaders];
|
|
297
297
|
const headers = mergeHeaders(...headerLayers);
|
|
298
298
|
applyRouteCredentialHeaders(headers, routeCredential);
|
|
299
|
+
const declaredBetas = headerLayers.flatMap((layer) => Object.entries(layer ?? {}).flatMap(([name, value]) => (name.toLowerCase() === "anthropic-beta" ? headerListEntries(value) : [])));
|
|
300
|
+
const declared = declaredRequestValues([...headerLayers, headers], [config.version, ...declaredBetas], apiKey);
|
|
299
301
|
takeHeaderSpellings(headers, "anthropic-beta");
|
|
300
302
|
for (const layer of headerLayers) {
|
|
301
303
|
for (const [name, value] of Object.entries(layer ?? {}))
|
|
@@ -320,6 +322,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
320
322
|
return {
|
|
321
323
|
url,
|
|
322
324
|
headers,
|
|
325
|
+
declared,
|
|
323
326
|
body: JSON.stringify(wire),
|
|
324
327
|
extraBodyDropped,
|
|
325
328
|
route: requestRouteOf(routeCredential, rootOrigin),
|
|
@@ -353,7 +356,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
353
356
|
let lastDegenCheckThinking = 0;
|
|
354
357
|
const detectRep = config.detectRepetition !== false;
|
|
355
358
|
let messageStopped = false;
|
|
356
|
-
const afterEnd = createStreamEndLedger();
|
|
359
|
+
const afterEnd = createStreamEndLedger(ctrl.providerWords);
|
|
357
360
|
const streamEnded = () => stopReason != null || messageStopped;
|
|
358
361
|
const mergeDeltaUsage = (u) => {
|
|
359
362
|
if (!u)
|
|
@@ -430,7 +433,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
430
433
|
else if (acc.type === "tool_use") {
|
|
431
434
|
const closed = acc.stopped === true || !endedCut;
|
|
432
435
|
if (!acc.toolName) {
|
|
433
|
-
(nameMissingCause(closed) === "truncated" ? malformed : unnamed).push(`id="${acc.toolId || "?"}"(${acc.toolJson.slice(0, 200)})`);
|
|
436
|
+
(nameMissingCause(closed) === "truncated" ? malformed : unnamed).push(`id="${ctrl.providerWords(acc.toolId || "?")}"(${ctrl.providerWords(acc.toolJson).slice(0, 200)})`);
|
|
434
437
|
}
|
|
435
438
|
else {
|
|
436
439
|
const tc = closeToolUseBlock(acc, responseIds, closed);
|
|
@@ -439,7 +442,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
439
442
|
finalContent.push(tc);
|
|
440
443
|
}
|
|
441
444
|
else {
|
|
442
|
-
malformed.push(`${acc.toolName}(${acc.toolJson.slice(0, 200)})`);
|
|
445
|
+
malformed.push(`${ctrl.providerWords(acc.toolName)}(${ctrl.providerWords(acc.toolJson).slice(0, 200)})`);
|
|
443
446
|
}
|
|
444
447
|
}
|
|
445
448
|
}
|
|
@@ -580,8 +583,13 @@ export function createAnthropicBrain(given = {}) {
|
|
|
580
583
|
const d = evt.delta;
|
|
581
584
|
if (d?.stop_reason)
|
|
582
585
|
stopReason = d.stop_reason;
|
|
583
|
-
if (d?.stop_details)
|
|
584
|
-
|
|
586
|
+
if (d?.stop_details) {
|
|
587
|
+
const raw = d.stop_details;
|
|
588
|
+
stopDetails = {
|
|
589
|
+
...(typeof raw.category === "string" ? { category: ctrl.providerWords(raw.category) } : {}),
|
|
590
|
+
...(typeof raw.explanation === "string" ? { explanation: ctrl.providerWords(raw.explanation) } : {}),
|
|
591
|
+
};
|
|
592
|
+
}
|
|
585
593
|
mergeDeltaUsage(evt.usage);
|
|
586
594
|
break;
|
|
587
595
|
}
|
|
@@ -596,7 +604,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
596
604
|
const inputTooLong = e?.type === "request_too_large" ||
|
|
597
605
|
(e?.type === "invalid_request_error" && typeof e.message === "string" && startsWithInputTooLongAnchor(e.message));
|
|
598
606
|
ctrl.keepOutput({ content: assembleTurn({}).content, ...reportedUsage() });
|
|
599
|
-
throw new BrainError(anthropicStreamErrorCode(e?.type), `anthropic stream error (${e?.type ?? "unknown"}): ${e?.message ?? ""}`, undefined, { apiError: true, ...(e === undefined ? {} : inputTooLong ? { inputTooLong: true } : { inputTooLongRuledOut: true }) });
|
|
607
|
+
throw new BrainError(anthropicStreamErrorCode(e?.type), `anthropic stream error ${ctrl.providerWords(`(${e?.type ?? "unknown"}): ${e?.message ?? ""}`)}`, undefined, { apiError: true, ...(e === undefined ? {} : inputTooLong ? { inputTooLong: true } : { inputTooLongRuledOut: true }) });
|
|
600
608
|
}
|
|
601
609
|
default:
|
|
602
610
|
break;
|
|
@@ -636,7 +644,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
636
644
|
}
|
|
637
645
|
catch {
|
|
638
646
|
malformedFrames++;
|
|
639
|
-
malformedSample ??= data.slice(0, 160);
|
|
647
|
+
malformedSample ??= ctrl.providerWords(data).slice(0, 160);
|
|
640
648
|
return;
|
|
641
649
|
}
|
|
642
650
|
handleEvent(evt);
|
|
@@ -5,7 +5,7 @@ import { STREAM_TORN_WARNING, createRepetitionPoll, modelOutputInvalidOf, noteRe
|
|
|
5
5
|
import { admitToolCallId, providerResultIds, providerToolCallId, responseToolCallIds } from "./tool-call-id.js";
|
|
6
6
|
import { emitBrainTelemetry } from "./status-sink.js";
|
|
7
7
|
import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imageWithholdOf, imagesOmittedNoVisionNote, reportImagesWithheld, sendableImages } from "./media-degrade.js";
|
|
8
|
-
import { OUTPUT_CAP_KEYS, RESPONSES_RESERVED, applyExtraBody, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders } from "./request-params.js";
|
|
8
|
+
import { OUTPUT_CAP_KEYS, RESPONSES_RESERVED, applyExtraBody, declaredRequestValues, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders } from "./request-params.js";
|
|
9
9
|
import { admitRouteRequest, applyRouteCredentialHeaders, assertServableRequestRoot, brainConfigSnapshot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential } from "./route-adjudicator.js";
|
|
10
10
|
import { requestRouteOf } from "./request-route.js";
|
|
11
11
|
import { NAMES_AS_WRITTEN, resolveProviderDialect, endpointToolNames } from "./provider-dialect.js";
|
|
@@ -281,6 +281,7 @@ export function createOpenResponsesBrain(given = {}) {
|
|
|
281
281
|
const { body: reasoningBody, effort } = applyReasoningToRequest({ api: "openai-responses", model, level: options?.reasoning, body });
|
|
282
282
|
const headers = mergeHeaders(modelHeaders, config.headers, optionsHeaders);
|
|
283
283
|
applyRouteCredentialHeaders(headers, routeCredential);
|
|
284
|
+
const declared = declaredRequestValues([modelHeaders, config.headers, optionsHeaders, headers], [], apiKey);
|
|
284
285
|
lockHeader(headers, "content-type", "application/json");
|
|
285
286
|
if (apiKey)
|
|
286
287
|
lockHeader(headers, OPEN_RESPONSES_KEY_HEADER, `Bearer ${apiKey}`);
|
|
@@ -288,6 +289,7 @@ export function createOpenResponsesBrain(given = {}) {
|
|
|
288
289
|
return {
|
|
289
290
|
url,
|
|
290
291
|
headers,
|
|
292
|
+
declared,
|
|
291
293
|
body: JSON.stringify(wire),
|
|
292
294
|
extraBodyDropped,
|
|
293
295
|
route: requestRouteOf(routeCredential, rootOrigin),
|
|
@@ -563,10 +565,10 @@ export function createOpenResponsesBrain(given = {}) {
|
|
|
563
565
|
case "response.failed": {
|
|
564
566
|
noteResponseModel(partial, frame.response?.model, model.id);
|
|
565
567
|
const err = frame.response?.error;
|
|
566
|
-
throw new BrainError(responsesErrorCode(err?.code), `responses stream failed (${err?.code ?? "unknown"}): ${err?.message ?? ""}`, undefined, { apiError: true });
|
|
568
|
+
throw new BrainError(responsesErrorCode(err?.code), `responses stream failed ${ctrl.providerWords(`(${err?.code ?? "unknown"}): ${err?.message ?? ""}`)}`, undefined, { apiError: true });
|
|
567
569
|
}
|
|
568
570
|
case "error": {
|
|
569
|
-
throw new BrainError(responsesErrorCode(frame.code), `responses stream error (${frame.code ?? "unknown"}): ${frame.message ?? ""}`, undefined, { apiError: true });
|
|
571
|
+
throw new BrainError(responsesErrorCode(frame.code), `responses stream error ${ctrl.providerWords(`(${frame.code ?? "unknown"}): ${frame.message ?? ""}`)}`, undefined, { apiError: true });
|
|
570
572
|
}
|
|
571
573
|
default:
|
|
572
574
|
return;
|
|
@@ -607,7 +609,7 @@ export function createOpenResponsesBrain(given = {}) {
|
|
|
607
609
|
}
|
|
608
610
|
catch {
|
|
609
611
|
malformedFrames++;
|
|
610
|
-
malformedSample ??= data.slice(0, MALFORMED_SAMPLE_CHARS);
|
|
612
|
+
malformedSample ??= ctrl.providerWords(data).slice(0, MALFORMED_SAMPLE_CHARS);
|
|
611
613
|
return;
|
|
612
614
|
}
|
|
613
615
|
handleFrame(frame);
|
|
@@ -660,10 +662,10 @@ export function createOpenResponsesBrain(given = {}) {
|
|
|
660
662
|
finalContent.push(tc);
|
|
661
663
|
}
|
|
662
664
|
else if (acc.name) {
|
|
663
|
-
malformed.push(`${acc.name}(${acc.args.slice(0, MALFORMED_ARGS_CHARS)})`);
|
|
665
|
+
malformed.push(`${ctrl.providerWords(acc.name)}(${ctrl.providerWords(acc.args).slice(0, MALFORMED_ARGS_CHARS)})`);
|
|
664
666
|
}
|
|
665
667
|
else {
|
|
666
|
-
(nameMissingCause(closed) === "truncated" ? malformed : unnamed).push(`call_id="${acc.callId || "?"}"(${acc.args.slice(0, MALFORMED_ARGS_CHARS)})`);
|
|
668
|
+
(nameMissingCause(closed) === "truncated" ? malformed : unnamed).push(`call_id="${ctrl.providerWords(acc.callId || "?")}"(${ctrl.providerWords(acc.args).slice(0, MALFORMED_ARGS_CHARS)})`);
|
|
667
669
|
}
|
|
668
670
|
}
|
|
669
671
|
}
|
|
@@ -708,14 +710,14 @@ export function createOpenResponsesBrain(given = {}) {
|
|
|
708
710
|
: safetyCut
|
|
709
711
|
? `[refusal] response cut by the provider content filter (incomplete_details.reason="${INCOMPLETE_CONTENT_FILTER}") — the output was censored/truncated for policy and is unreliable`
|
|
710
712
|
: refused
|
|
711
|
-
? `[refusal] response refused by the model for policy reasons: ${accumRefusal.trim()}`
|
|
713
|
+
? `[refusal] response refused by the model for policy reasons: ${ctrl.providerWords(accumRefusal.trim())}`
|
|
712
714
|
: (toolError ??
|
|
713
715
|
(truncatedEmpty && !dynamicCut && !staticReasoningCut
|
|
714
716
|
? reasoningSeen
|
|
715
717
|
? `[length_empty] response truncated at max_output_tokens (${maxTokensNote}) with no answer text — the model spent the whole budget on reasoning; raise the cap, or lower the reasoning effort for this task.`
|
|
716
718
|
: `[length_empty] response truncated at max_output_tokens (${maxTokensNote}) with no answer text — raise the cap`
|
|
717
719
|
: emptyNoFinish
|
|
718
|
-
? `[stream_torn] model stream ended with no content and ${terminalStatus === undefined ? "no terminal response event" : `a terminal status "${terminalStatus}" with no reason this client recognises (incomplete_details.reason=${incompleteReason
|
|
720
|
+
? `[stream_torn] model stream ended with no content and ${terminalStatus === undefined ? "no terminal response event" : `a terminal status "${ctrl.providerWords(terminalStatus)}" with no reason this client recognises (incomplete_details.reason=${incompleteReason === undefined ? "absent" : ctrl.providerWords(String(incompleteReason))})`} — the response was lost (a torn stream or an in-band provider error frame)${malformedFrames > 0 ? ` — ${malformedFrames} unparseable data frame(s) were dropped on this stream (first sample: ${JSON.stringify(malformedSample)})` : ""}`
|
|
719
721
|
: undefined));
|
|
720
722
|
const errored = degenerate ||
|
|
721
723
|
safetyCut ||
|
package/dist/brain/openai.js
CHANGED
|
@@ -6,7 +6,7 @@ import { admitToolCallId, providerResultIds, providerToolCallId, responseToolCal
|
|
|
6
6
|
import { emitBrainTelemetry } from "./status-sink.js";
|
|
7
7
|
import { errorResultMediaNote, IMAGE_OMITTED_NO_VISION, imageWithholdOf, imagesOmittedNoVisionNote, reportImagesWithheld, sendableImages } from "./media-degrade.js";
|
|
8
8
|
import { capabilityHeld } from "./model-capability.js";
|
|
9
|
-
import { OPENAI_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders } from "./request-params.js";
|
|
9
|
+
import { OPENAI_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, declaredRequestValues, effectiveOutputCap, headerBagOnce, lockHeader, mergeHeaders } from "./request-params.js";
|
|
10
10
|
import { BrainError, providerErrorWord } from "./errors.js";
|
|
11
11
|
import { NAMES_AS_WRITTEN, inBandProviderError, resolveProviderDialect, endpointToolNames } from "./provider-dialect.js";
|
|
12
12
|
import { admitRouteRequest, applyRouteCredentialHeaders, assertServableRequestRoot, brainConfigSnapshot, createBrainRouteJudge, joinRequestUrl, resolveRequestRootOf, resolveRouteCredential } from "./route-adjudicator.js";
|
|
@@ -320,6 +320,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
320
320
|
const { body: reasoningBody } = applyReasoningToRequest({ api: "openai-completions", model, level: options?.reasoning, body });
|
|
321
321
|
const headers = mergeHeaders(modelHeaders, config.headers, optionsHeaders);
|
|
322
322
|
applyRouteCredentialHeaders(headers, routeCredential);
|
|
323
|
+
const declaredValues = declaredRequestValues([modelHeaders, config.headers, optionsHeaders, headers], [], apiKey);
|
|
323
324
|
lockHeader(headers, "content-type", "application/json");
|
|
324
325
|
if (apiKey)
|
|
325
326
|
lockHeader(headers, OPENAI_KEY_HEADER, `Bearer ${apiKey}`);
|
|
@@ -327,6 +328,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
327
328
|
return {
|
|
328
329
|
url,
|
|
329
330
|
headers,
|
|
331
|
+
declared: declaredValues,
|
|
330
332
|
body: JSON.stringify(wire),
|
|
331
333
|
extraBodyDropped,
|
|
332
334
|
route: requestRouteOf(routeCredential, rootOrigin),
|
|
@@ -359,7 +361,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
359
361
|
const responseIds = responseToolCallIds();
|
|
360
362
|
let finishReason = null;
|
|
361
363
|
let inBandError;
|
|
362
|
-
const afterEnd = createStreamEndLedger();
|
|
364
|
+
const afterEnd = createStreamEndLedger(ctrl.providerWords);
|
|
363
365
|
const terminalFrameSeen = () => finishReason != null || inBandError !== undefined;
|
|
364
366
|
let usageRaw;
|
|
365
367
|
let malformedFrames = 0;
|
|
@@ -447,7 +449,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
447
449
|
}
|
|
448
450
|
catch {
|
|
449
451
|
malformedFrames++;
|
|
450
|
-
malformedSample ??= data.slice(0, 160);
|
|
452
|
+
malformedSample ??= ctrl.providerWords(data).slice(0, 160);
|
|
451
453
|
return;
|
|
452
454
|
}
|
|
453
455
|
const stated = chunk.error;
|
|
@@ -456,7 +458,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
456
458
|
afterEnd.note("error", providerErrorWord(stated) ?? "?");
|
|
457
459
|
return;
|
|
458
460
|
}
|
|
459
|
-
inBandError = inBandProviderError(ctrl.dialect, stated, "gateway");
|
|
461
|
+
inBandError = inBandProviderError(ctrl.dialect, stated, "gateway", ctrl.providerWords);
|
|
460
462
|
ctrl.cancel();
|
|
461
463
|
return;
|
|
462
464
|
}
|
|
@@ -537,7 +539,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
537
539
|
emptyPlaceholders++;
|
|
538
540
|
continue;
|
|
539
541
|
}
|
|
540
|
-
(nameMissingCause(!endedCut) === "truncated" ? malformed : unnamed).push(`id="${acc.id || "?"}"(${acc.args.slice(0, 200)})`);
|
|
542
|
+
(nameMissingCause(!endedCut) === "truncated" ? malformed : unnamed).push(`id="${ctrl.providerWords(acc.id || "?")}"(${ctrl.providerWords(acc.args).slice(0, 200)})`);
|
|
541
543
|
continue;
|
|
542
544
|
}
|
|
543
545
|
const tc = closeToolCallAccum(acc, responseIds, !endedCut);
|
|
@@ -546,7 +548,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
546
548
|
finalContent.push(tc);
|
|
547
549
|
}
|
|
548
550
|
else {
|
|
549
|
-
malformed.push(`${acc.name}(${acc.args.slice(0, 200)})`);
|
|
551
|
+
malformed.push(`${ctrl.providerWords(acc.name)}(${ctrl.providerWords(acc.args).slice(0, 200)})`);
|
|
550
552
|
}
|
|
551
553
|
}
|
|
552
554
|
if (config.repairTextToolCalls && toolCalls.length === 0 && textFace && context.tools && context.tools.length > 0) {
|
|
@@ -604,8 +606,8 @@ export function createOpenAIBrain(given = {}) {
|
|
|
604
606
|
const safetyCut = finishReading?.kind === "refusal";
|
|
605
607
|
const contextWindowExceeded = finishReading?.kind === "input_too_long";
|
|
606
608
|
const providerCut = finishReading?.kind === "provider_cut" ? finishReading : undefined;
|
|
607
|
-
const finishReasonUnknown = finishReading?.kind === "unrecognized" ? echoFoldedWord(finishReason ?? "") : undefined;
|
|
608
|
-
const finishQuoted = JSON.stringify((finishReason ?? "").slice(0, 64));
|
|
609
|
+
const finishReasonUnknown = finishReading?.kind === "unrecognized" ? echoFoldedWord(finishReason ?? "", ctrl.providerWords) : undefined;
|
|
610
|
+
const finishQuoted = JSON.stringify(ctrl.providerWords(finishReason ?? "").slice(0, 64));
|
|
609
611
|
const refused = accumRefusal.trim().length > 0;
|
|
610
612
|
const emptyNoFinish = noUsableContent && finishReason == null && !degenerate;
|
|
611
613
|
const maxTokensNote = sentMaxTokens !== undefined
|
|
@@ -620,7 +622,7 @@ export function createOpenAIBrain(given = {}) {
|
|
|
620
622
|
: safetyCut
|
|
621
623
|
? `[refusal] response cut by the provider content filter (finish_reason=${finishQuoted}) — the output was censored/truncated for policy and is unreliable`
|
|
622
624
|
: refused
|
|
623
|
-
? `[refusal] response refused by the model for policy reasons: ${accumRefusal.trim()}`
|
|
625
|
+
? `[refusal] response refused by the model for policy reasons: ${ctrl.providerWords(accumRefusal.trim())}`
|
|
624
626
|
: contextWindowExceeded
|
|
625
627
|
? `[invalid_request] model context window exceeded (finish_reason=${finishQuoted}) — the conversation no longer fits the model's context window`
|
|
626
628
|
: providerCut !== undefined
|
|
@@ -240,11 +240,12 @@ export declare function judgeInBandError(dialect: ProviderDialect | undefined, e
|
|
|
240
240
|
* The failure an in-band error frame states, as the brain error the stream's terminal carries: the code its
|
|
241
241
|
* condition reads as ({@link PROVIDER_CONDITION_TRAITS}), the provider's word and sentence in the message, the word
|
|
242
242
|
* on the echo seat, the verdict, and the context-limit reading of the same row. A frame the provider sent on its
|
|
243
|
-
* own stream is a provider failure by construction (`apiError`); it states no status.
|
|
243
|
+
* own stream is a provider failure by construction (`apiError`); it states no status. The message carries the
|
|
244
|
+
* provider's words as the stream's mint (`providerWords`) renders them; the verdict reads the frame as it came.
|
|
244
245
|
*/
|
|
245
246
|
export declare function inBandProviderError(dialect: ProviderDialect | undefined, envelope: {
|
|
246
247
|
message?: unknown;
|
|
247
248
|
code?: unknown;
|
|
248
249
|
type?: unknown;
|
|
249
|
-
}, label: string): BrainError;
|
|
250
|
+
}, label: string, providerWords: (words: string) => string): BrainError;
|
|
250
251
|
export {};
|
|
@@ -201,11 +201,11 @@ export function judgeHttpFailure(args) {
|
|
|
201
201
|
export function judgeInBandError(dialect, envelope) {
|
|
202
202
|
return verdictOf(dialect, undefined, statementOf(envelope), true);
|
|
203
203
|
}
|
|
204
|
-
export function inBandProviderError(dialect, envelope, label) {
|
|
204
|
+
export function inBandProviderError(dialect, envelope, label, providerWords) {
|
|
205
205
|
const v = judgeInBandError(dialect, envelope);
|
|
206
206
|
const word = carriedProviderWord(envelope);
|
|
207
207
|
const sentence = typeof envelope.message === "string" ? envelope.message : "";
|
|
208
|
-
return new BrainError(PROVIDER_CONDITION_TRAITS[v.condition].inBandCode, `${label} stream error (${word ?? "unknown"}): ${sentence}`, undefined, {
|
|
208
|
+
return new BrainError(PROVIDER_CONDITION_TRAITS[v.condition].inBandCode, `${label} stream error ${providerWords(`(${word ?? "unknown"}): ${sentence}`)}`, undefined, {
|
|
209
209
|
apiError: true,
|
|
210
210
|
...(v.inputTooLong === "yes" ? { inputTooLong: true } : v.inputTooLong === "no" ? { inputTooLongRuledOut: true } : {}),
|
|
211
211
|
...(word !== undefined ? { providerCode: word } : {}),
|
|
@@ -136,6 +136,12 @@ export declare function headerListEntries(value: unknown): string[];
|
|
|
136
136
|
* or keys answer differently on a second read cannot be judged as one bag and sent as another. */
|
|
137
137
|
export declare function headerBagOnce(bag: Readonly<Record<string, string>> | undefined): Record<string, string> | undefined;
|
|
138
138
|
export declare function mergeHeaders(...bags: Array<Record<string, string> | undefined>): Record<string, string>;
|
|
139
|
+
/** The values a request is DECLARED with ({@link import("./stream-engine.js").SSERequest.declared}): every value of the header bags it was
|
|
140
|
+
* built from — the route's credential headers included, as the merge after `applyRouteCredentialHeaders` holds them — the values the
|
|
141
|
+
* deployment or the call stated outside a bag (a configured protocol version, each entry of a list header the brain re-folds), and the
|
|
142
|
+
* key when it names a secret ({@link namesASecret}: a placeholder key is left in the words as it is left to every child). The values the
|
|
143
|
+
* brain writes itself (a structural lock, the default version, the beta entries it chose) are not among them. */
|
|
144
|
+
export declare function declaredRequestValues(bags: ReadonlyArray<Readonly<Record<string, string>> | undefined>, stated: ReadonlyArray<string | undefined>, key: string | undefined): string[];
|
|
139
145
|
/**
|
|
140
146
|
* The output-cap key(s) each lane's wire form uses. A lane's set is exactly the keys THAT lane's
|
|
141
147
|
* endpoint reads — a stray cap key belonging to another wire form is inert there and must not be
|