@sema-agent/core 7.37.1 → 7.38.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 +135 -0
- package/dist/agents/observer.js +1 -1
- package/dist/agents/peer-notices.js +4 -4
- package/dist/agents/subagent.js +1 -1
- package/dist/agents/team-role.js +2 -2
- package/dist/brain/anthropic.js +10 -9
- package/dist/brain/errors.d.ts +26 -0
- package/dist/brain/errors.js +34 -0
- package/dist/brain/input-too-long.d.ts +0 -31
- package/dist/brain/input-too-long.js +1 -18
- package/dist/brain/open-responses.js +10 -9
- package/dist/brain/openai.js +10 -9
- package/dist/brain/status-sink.d.ts +1 -1
- package/dist/brain/stream-engine.js +10 -2
- package/dist/brain/stream-shared.d.ts +11 -3
- package/dist/brain/stream-shared.js +4 -2
- package/dist/brain/tool-call-id.d.ts +29 -8
- package/dist/brain/tool-call-id.js +36 -6
- package/dist/core/a2a-task-state.js +2 -2
- package/dist/core/artifact-host.js +6 -6
- package/dist/core/ask-origin.js +6 -6
- package/dist/core/ask-unresolvable-notice.js +1 -1
- package/dist/core/auto-mode.js +4 -4
- package/dist/core/background-agent-store.js +2 -2
- package/dist/core/checkpoint-execution-record.js +1 -1
- package/dist/core/checkpoint-store.d.ts +2 -2
- package/dist/core/checkpoint-store.js +2 -2
- package/dist/core/child-clamp-seats.js +3 -3
- package/dist/core/compliance.js +1 -1
- package/dist/core/context-edit.js +1 -1
- package/dist/core/context-guard.d.ts +0 -19
- package/dist/core/context-guard.js +0 -38
- package/dist/core/decision-receipt.d.ts +27 -1
- package/dist/core/decision-receipt.js +176 -1
- package/dist/core/engine-notice.d.ts +59 -8
- package/dist/core/engine-notice.js +2 -1
- package/dist/core/gate-fold.js +3 -2
- package/dist/core/gate-outcome.js +4 -4
- package/dist/core/governance-codes.d.ts +221 -13
- package/dist/core/governance-codes.js +104 -4
- package/dist/core/hook-seats.js +2 -2
- package/dist/core/hooks.d.ts +21 -2
- package/dist/core/hooks.js +4 -1
- package/dist/core/mailbox-store.js +3 -3
- package/dist/core/mcp-failure.js +4 -4
- package/dist/core/mcp-injection-drop.js +1 -1
- package/dist/core/memory-engine/consolidation.js +1 -1
- package/dist/core/memory-engine/delegation-settlement.d.ts +8 -0
- package/dist/core/memory-engine/delegation-settlement.js +7 -0
- package/dist/core/memory-engine/engine.d.ts +12 -2
- package/dist/core/memory-engine/engine.js +10 -6
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/layout.d.ts +6 -6
- package/dist/core/memory-engine/layout.js +6 -8
- package/dist/core/memory-engine/session-write-home.d.ts +30 -0
- package/dist/core/memory-engine/session-write-home.js +34 -0
- package/dist/core/memory-engine/tools.js +1 -1
- package/dist/core/memory-engine/types.js +1 -1
- package/dist/core/memory.js +1 -1
- package/dist/core/mode-policy.d.ts +10 -1
- package/dist/core/mode-policy.js +15 -7
- package/dist/core/model-seat.js +1 -1
- package/dist/core/permission-rule-model.js +3 -3
- package/dist/core/permission-rule-store.js +2 -2
- package/dist/core/read-only-shell-table.js +8 -8
- package/dist/core/retention.js +2 -2
- package/dist/core/runner/assemble-result.js +15 -5
- package/dist/core/runner/classifier-ladder.js +1 -1
- package/dist/core/runner/denial-limit-arms.d.ts +2 -0
- package/dist/core/runner/denial-limit-arms.js +6 -2
- package/dist/core/runner/inherited-ask-grants.d.ts +6 -5
- package/dist/core/runner/inherited-ask-grants.js +3 -2
- package/dist/core/runner/prepare-context-lane.d.ts +19 -15
- package/dist/core/runner/prepare-context-lane.js +11 -15
- package/dist/core/runner/prepare-gate-stations.js +5 -5
- package/dist/core/runner/prepare-inherited-gate.js +1 -1
- package/dist/core/runner/prepare-policy-chain.js +10 -10
- package/dist/core/runner/run-harness-handlers.js +3 -0
- package/dist/core/runner/run-identity-wiring.d.ts +1 -1
- package/dist/core/runner/run-identity-wiring.js +0 -2
- package/dist/core/runner/run-leg.js +2 -2
- package/dist/core/runner/run-stop-and-final-verify.js +1 -0
- package/dist/core/runner/run-turn-boundary.js +1 -1
- package/dist/core/runner/session-mode-seats.d.ts +11 -3
- package/dist/core/runner/session-mode-seats.js +6 -0
- package/dist/core/runner/session-rule-policy.js +2 -3
- package/dist/core/runner/stream-steer-verb.js +1 -1
- package/dist/core/runner/tool-call-id-fold-seat.js +16 -9
- package/dist/core/runner/tool-turn-repair-seat.d.ts +11 -1
- package/dist/core/runner/tool-turn-repair-seat.js +35 -0
- package/dist/core/runner/turn-attachments.js +1 -1
- package/dist/core/runtime-caps.js +1 -1
- package/dist/core/safety-axis-vocab.d.ts +5 -0
- package/dist/core/safety-axis-vocab.js +5 -0
- package/dist/core/session-reconcile.d.ts +9 -7
- package/dist/core/session-reconcile.js +21 -1
- package/dist/core/shared-memory/types.js +1 -1
- package/dist/core/side-query.d.ts +6 -1
- package/dist/core/store-contracts/read-back-shape-contract.js +1 -1
- package/dist/core/swappable-deps.js +1 -1
- package/dist/core/task-notification.js +4 -4
- package/dist/core/task-registry-shared.js +1 -1
- package/dist/core/terminal-cause.d.ts +19 -0
- package/dist/core/tool-face.js +6 -6
- package/dist/core/tool-policy.d.ts +17 -11
- package/dist/core/tool-policy.js +38 -72
- package/dist/core/tool-roster.js +1 -1
- package/dist/core/tool-search-setting.js +1 -1
- package/dist/core/trace.d.ts +5 -4
- package/dist/core/types.d.ts +2 -2
- package/dist/core/types.js +1 -1
- package/dist/core/wiring-manifest.js +2 -2
- package/dist/core/write-protect.js +1 -1
- package/dist/engine/harness/agent-harness.js +10 -6
- package/dist/engine/llm/tool-turns.d.ts +93 -4
- package/dist/engine/llm/tool-turns.js +63 -9
- package/dist/engine/llm/types.d.ts +11 -0
- package/dist/index.d.ts +5 -3
- package/dist/index.js +4 -2
- package/dist/internal/llm.d.ts +2 -2
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/workflow-governance.js +2 -2
- package/dist/orchestration/workflow-types.js +2 -2
- package/dist/shell/lex.js +7 -7
- package/dist/tools/fs/bash-program-position.js +2 -2
- package/dist/tools/fs/read-deny.js +2 -2
- package/dist/tools/fs/safety.js +1 -1
- package/dist/tools/fs/shell-read-judge.js +2 -2
- package/dist/tools/fs/shell-read-plan.js +2 -2
- package/dist/tools/fs/shell-read-write-targets.js +1 -1
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +17 -1
- package/wire-changes/core@7.38.0.json +664 -0
package/dist/brain/openai.js
CHANGED
|
@@ -2,7 +2,7 @@ import {} from "../internal/llm.js";
|
|
|
2
2
|
import { repairTextToolCalls } from "./tool-call-repair.js";
|
|
3
3
|
import { DEGENERATE_MESSAGE, trimDegenerateTail } from "./repetition.js";
|
|
4
4
|
import { STREAM_TORN_WARNING, createRepetitionPoll, noteResponseModel, parseStreamedToolArgs, placeTurnNotes, truncationCauseClause } from "./stream-shared.js";
|
|
5
|
-
import { admitToolCallId, providerResultIds, providerToolCallId } from "./tool-call-id.js";
|
|
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, imagesOmittedNoVisionNote, modelSupportsVision, sendableImages } from "./media-degrade.js";
|
|
8
8
|
import { OPENAI_RESERVED, OUTPUT_CAP_KEYS, applyExtraBody, effectiveOutputCap, lockHeader, mergeHeaders } from "./request-params.js";
|
|
@@ -12,7 +12,7 @@ import { declaredOffSpelling, mintEffortWireValue, reasoningRequestCarried } fro
|
|
|
12
12
|
import { runStreamingBrain } from "./stream-engine.js";
|
|
13
13
|
import { refuseRetiredTimeoutKnobs } from "./timeout.js";
|
|
14
14
|
import { resolveFetch } from "./transport.js";
|
|
15
|
-
function closeToolCallAccum(acc) {
|
|
15
|
+
function closeToolCallAccum(acc, responseIds) {
|
|
16
16
|
if (acc.closedTc)
|
|
17
17
|
return acc.closedTc;
|
|
18
18
|
if (!acc.name)
|
|
@@ -20,7 +20,7 @@ function closeToolCallAccum(acc) {
|
|
|
20
20
|
const args = parseStreamedToolArgs(acc.args);
|
|
21
21
|
if (args === undefined)
|
|
22
22
|
return undefined;
|
|
23
|
-
const { engineId, wireId } = admitToolCallId(acc.id, "call_");
|
|
23
|
+
const { engineId, wireId } = admitToolCallId(acc.id, "call_", responseIds);
|
|
24
24
|
acc.closedTc = { type: "toolCall", id: engineId, ...(wireId !== engineId ? { wireId } : {}), name: acc.name, arguments: args };
|
|
25
25
|
return acc.closedTc;
|
|
26
26
|
}
|
|
@@ -377,6 +377,7 @@ export function createOpenAIBrain(config = {}) {
|
|
|
377
377
|
let thinkingClosed = false;
|
|
378
378
|
let textIndex = 0;
|
|
379
379
|
const toolAccum = new Map();
|
|
380
|
+
const responseIds = responseToolCallIds();
|
|
380
381
|
let finishReason = null;
|
|
381
382
|
const terminalFrameSeen = () => finishReason != null;
|
|
382
383
|
let usageRaw;
|
|
@@ -495,7 +496,7 @@ export function createOpenAIBrain(config = {}) {
|
|
|
495
496
|
continue;
|
|
496
497
|
if (prevAcc.args === "")
|
|
497
498
|
continue;
|
|
498
|
-
const closed = closeToolCallAccum(prevAcc);
|
|
499
|
+
const closed = closeToolCallAccum(prevAcc, responseIds);
|
|
499
500
|
if (closed) {
|
|
500
501
|
out.push({ type: "toolcall_end", contentIndex: prevIdx, toolCall: closed, partial: { ...partial } });
|
|
501
502
|
}
|
|
@@ -536,7 +537,7 @@ export function createOpenAIBrain(config = {}) {
|
|
|
536
537
|
unnamed.push(`id="${acc.id || "?"}"(${acc.args.slice(0, 200)})`);
|
|
537
538
|
continue;
|
|
538
539
|
}
|
|
539
|
-
const tc = closeToolCallAccum(acc);
|
|
540
|
+
const tc = closeToolCallAccum(acc, responseIds);
|
|
540
541
|
if (tc) {
|
|
541
542
|
toolCalls.push(tc);
|
|
542
543
|
finalContent.push(tc);
|
|
@@ -579,15 +580,15 @@ export function createOpenAIBrain(config = {}) {
|
|
|
579
580
|
const noUsableContent = toolCalls.length === 0 && !accumText.trim();
|
|
580
581
|
const notes = [];
|
|
581
582
|
if (malformed.length > 0) {
|
|
582
|
-
notes.push(`\n[note: ${malformed.length} tool call(s) were truncated (finish_reason="${finishReason ?? "?"}") and dropped — re-issue them next turn: ${malformed.join("; ")}]`);
|
|
583
|
+
notes.push({ cause: "truncated", count: malformed.length, text: `\n[note: ${malformed.length} tool call(s) were truncated (finish_reason="${finishReason ?? "?"}") and dropped — re-issue them next turn: ${malformed.join("; ")}]` });
|
|
583
584
|
}
|
|
584
585
|
if (unnamed.length > 0) {
|
|
585
|
-
notes.push(`\n[note: ${unnamed.length} tool call(s) arrived with no tool name and were dropped — re-issue them next turn with an explicit tool name: ${unnamed.join("; ")}]`);
|
|
586
|
+
notes.push({ cause: "unnamed", count: unnamed.length, text: `\n[note: ${unnamed.length} tool call(s) arrived with no tool name and were dropped — re-issue them next turn with an explicit tool name: ${unnamed.join("; ")}]` });
|
|
586
587
|
}
|
|
587
588
|
if (malformedFrames > 0) {
|
|
588
|
-
notes.push(`\n[note: ${malformedFrames} provider stream frame(s) were not valid JSON and were dropped — the streamed output may be missing content (first sample: ${JSON.stringify(malformedSample)})]`);
|
|
589
|
+
notes.push({ cause: "bad_frame", count: malformedFrames, text: `\n[note: ${malformedFrames} provider stream frame(s) were not valid JSON and were dropped — the streamed output may be missing content (first sample: ${JSON.stringify(malformedSample)})]` });
|
|
589
590
|
}
|
|
590
|
-
placeTurnNotes(finalContent, notes);
|
|
591
|
+
placeTurnNotes(partial, finalContent, notes);
|
|
591
592
|
const truncatedEmpty = finishReason === "length" && noUsableContent && !toolError;
|
|
592
593
|
const dynamicCut = truncatedEmpty && options?.maxTokensDynamic === true;
|
|
593
594
|
const safetyCut = finishReason === "content_filter";
|
|
@@ -71,7 +71,7 @@ export type BrainTelemetry = {
|
|
|
71
71
|
* and the field is absent. One event per provider response per field. */
|
|
72
72
|
| {
|
|
73
73
|
kind: "echo_dropped";
|
|
74
|
-
field: "requestId" | "responseModel";
|
|
74
|
+
field: "requestId" | "responseModel" | "apiErrorCode";
|
|
75
75
|
};
|
|
76
76
|
/** Run `fn` with a per-task brain-telemetry sink in scope (Runner-side; compose with runWithStatusSink). */
|
|
77
77
|
export declare function runWithBrainTelemetry<T>(emit: (t: BrainTelemetry) => void, fn: () => Promise<T>): Promise<T>;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { createAssistantMessageEventStream, } from "../internal/llm.js";
|
|
2
2
|
import { STREAM_TORN_WARNING } from "./stream-shared.js";
|
|
3
3
|
import { FLOOR_OUTPUT_TOKENS, parseContextOverflow, planOutputCapAdjustment } from "./context-overflow.js";
|
|
4
|
-
import { abortLikeName, BrainError, brainErrorCodeOf, classifyConnectFailure, classifyFetchThrow, classifyHttp, describeNetworkError, namesTheFailure, readProviderRequestId } from "./errors.js";
|
|
4
|
+
import { abortLikeName, BrainError, brainErrorCodeOf, classifyConnectFailure, classifyFetchThrow, classifyHttp, describeNetworkError, isProviderEchoShape, namesTheFailure, readProviderErrorCode, readProviderRequestId, refusedTheRequest } from "./errors.js";
|
|
5
5
|
import { stripUrlCredentials } from "./route-adjudicator.js";
|
|
6
6
|
import { classifyInputTooLong } from "./input-too-long.js";
|
|
7
7
|
import { FAST_MAX_BACKOFF_MS, providerWaitHint, retryBackoffMs } from "./retry.js";
|
|
@@ -304,6 +304,9 @@ export function runStreamingBrain(args) {
|
|
|
304
304
|
errorMsg.apiErrorStatus = statusNum;
|
|
305
305
|
if (requestIdSeen !== undefined)
|
|
306
306
|
errorMsg.requestId = requestIdSeen;
|
|
307
|
+
const providerCode = readMember(err, "providerCode");
|
|
308
|
+
if (refusedTheRequest(statusNum) && typeof providerCode === "string" && isProviderEchoShape(providerCode))
|
|
309
|
+
errorMsg.apiErrorCode = providerCode;
|
|
307
310
|
}
|
|
308
311
|
}
|
|
309
312
|
errorMsg.usageMissing = true;
|
|
@@ -582,7 +585,12 @@ export function runStreamingBrain(args) {
|
|
|
582
585
|
const detail = overflowBody ?? (r ? (await readErrorBody(r, signal)).text : "");
|
|
583
586
|
const status = r?.status ?? 0;
|
|
584
587
|
const itl = classifyInputTooLong(status, detail);
|
|
585
|
-
|
|
588
|
+
const providerCode = refusedTheRequest(status) ? readProviderErrorCode(detail) : undefined;
|
|
589
|
+
throw new BrainError(classifyHttp(status), `${httpLabel} HTTP ${status || "ERR"}: ${detail.slice(0, 500)}${overflowDeclineNote}`, status, {
|
|
590
|
+
apiError: true,
|
|
591
|
+
...(itl === "yes" ? { inputTooLong: true } : itl === "no" ? { inputTooLongRuledOut: true } : {}),
|
|
592
|
+
...(providerCode !== undefined ? { providerCode } : {}),
|
|
593
|
+
});
|
|
586
594
|
}
|
|
587
595
|
finally {
|
|
588
596
|
cc.abort();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type RepetitionEvent } from "./repetition.js";
|
|
2
|
-
import type
|
|
2
|
+
import { type AssistantMessage, type StreamDropCause } from "../internal/llm.js";
|
|
3
3
|
/**
|
|
4
4
|
* design/157 A10 — stream-parser pieces that the anthropic and openai SSE lanes carried BYTE-IDENTICALLY
|
|
5
5
|
* (verified by diff at 1469481: a 16-line repetition-telemetry closure). Provider-agnostic policy, so it
|
|
@@ -29,14 +29,22 @@ import type { AssistantMessage } from "../internal/llm.js";
|
|
|
29
29
|
* mid-stream promotion (the body threw) and by the parsers' own finalize (content arrived, no finish frame). */
|
|
30
30
|
export declare const STREAM_TORN_WARNING = "Connection closed mid-response. The response above may be incomplete.";
|
|
31
31
|
export declare function parseStreamedToolArgs(json: string): Record<string, unknown> | undefined;
|
|
32
|
+
/** One drop note of a turn: what was dropped, how many, and the sentence the model reads. */
|
|
33
|
+
export interface TurnNote {
|
|
34
|
+
readonly cause: StreamDropCause;
|
|
35
|
+
readonly count: number;
|
|
36
|
+
readonly text: string;
|
|
37
|
+
}
|
|
32
38
|
/**
|
|
33
39
|
* Place a turn's engine notes in its final content: AHEAD of the first tool call, in order, or at the end of a turn
|
|
34
40
|
* that has none. Every dropped call (cut arguments, no tool name) and dropped stream frames are stated so the model
|
|
35
41
|
* re-issues them — also when text survived and no call did; a partial batch still executes its valid calls (a brain
|
|
36
42
|
* `error` is a terminal task failure, not a re-prompt). No block may follow the calls: the Anthropic Messages API
|
|
37
|
-
* rejects a `tool_use` followed by anything but another `tool_use`.
|
|
43
|
+
* rejects a `tool_use` followed by anything but another `tool_use`. The same notes are stamped on the turn's message as
|
|
44
|
+
* its stream drops (`stampStreamDrops`), the run's source for the person's line (`task.tool_turn_incomplete`): the
|
|
45
|
+
* model's sentence and the person's line come from one list. One rule for the three lanes.
|
|
38
46
|
*/
|
|
39
|
-
export declare function placeTurnNotes(content: AssistantMessage["content"], notes: readonly
|
|
47
|
+
export declare function placeTurnNotes(message: Pick<AssistantMessage, "diagnostics">, content: AssistantMessage["content"], notes: readonly TurnNote[]): void;
|
|
40
48
|
/**
|
|
41
49
|
* The cause clause of a dropped call's "not valid JSON" message. The output cap is named only when the stream says
|
|
42
50
|
* the cap cut it — the lane's own cap stop, or a counted output at or over the cap on the wire; a stream that ended
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isProviderEchoShape, providerEchoReading } from "./errors.js";
|
|
2
2
|
import { inspectDegenerate } from "./repetition.js";
|
|
3
3
|
import { emitBrainTelemetry } from "./status-sink.js";
|
|
4
|
+
import { stampStreamDrops } from "../internal/llm.js";
|
|
4
5
|
export const STREAM_TORN_WARNING = "Connection closed mid-response. The response above may be incomplete.";
|
|
5
6
|
export function parseStreamedToolArgs(json) {
|
|
6
7
|
if (!json)
|
|
@@ -16,11 +17,12 @@ export function parseStreamedToolArgs(json) {
|
|
|
16
17
|
return undefined;
|
|
17
18
|
return parsed;
|
|
18
19
|
}
|
|
19
|
-
export function placeTurnNotes(content, notes) {
|
|
20
|
+
export function placeTurnNotes(message, content, notes) {
|
|
20
21
|
if (notes.length === 0)
|
|
21
22
|
return;
|
|
22
23
|
const at = content.findIndex((block) => block.type === "toolCall");
|
|
23
|
-
content.splice(at === -1 ? content.length : at, 0, ...notes.map((text) => ({ type: "text", text })));
|
|
24
|
+
content.splice(at === -1 ? content.length : at, 0, ...notes.map(({ text }) => ({ type: "text", text })));
|
|
25
|
+
stampStreamDrops(message, notes);
|
|
24
26
|
}
|
|
25
27
|
export function truncationCauseClause(facts) {
|
|
26
28
|
const { capStop, outputTokens, capTokens, terminalFrameSeen } = facts;
|
|
@@ -12,14 +12,35 @@ export interface AdmittedToolCallId {
|
|
|
12
12
|
readonly engineId: string;
|
|
13
13
|
readonly wireId: string;
|
|
14
14
|
}
|
|
15
|
-
/** Why a
|
|
16
|
-
* a non-ASCII unit, or the fold separator); `"length"` — every character is admitted and it is longer than
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
export
|
|
20
|
-
/**
|
|
21
|
-
*
|
|
22
|
-
export declare function
|
|
15
|
+
/** Why a call's id was folded: `"charset"` — the raw holds a character outside the admitted alphabet (a control byte,
|
|
16
|
+
* a space, a non-ASCII unit, or the fold separator); `"length"` — every character is admitted and it is longer than
|
|
17
|
+
* 128; `"duplicate"` — an earlier call in the same response carried the same raw id, so this one was renamed. */
|
|
18
|
+
export declare const TOOL_CALL_ID_FOLD_REASONS: readonly ["charset", "length", "duplicate"];
|
|
19
|
+
export type ToolCallIdFoldReason = (typeof TOOL_CALL_ID_FOLD_REASONS)[number];
|
|
20
|
+
/** The fold reading of one non-empty raw id on its own: `undefined` ⇒ admitted verbatim; otherwise why its shape is
|
|
21
|
+
* folded (`"duplicate"` is a reading of the response, never of one id). */
|
|
22
|
+
export declare function toolCallIdFoldReason(raw: string): Exclude<ToolCallIdFoldReason, "duplicate"> | undefined;
|
|
23
|
+
/** Why a call carries two ids, read off the call itself (a built-in brain's call and a host brain's alike):
|
|
24
|
+
* `undefined` ⇒ one id, or an in-shape pair the admission did not mint (a host brain's own spelling); a provider id
|
|
25
|
+
* outside the admitted shape ⇒ its shape reason; an in-shape provider id beside an engine id of the rename arm's
|
|
26
|
+
* form ⇒ `"duplicate"`. */
|
|
27
|
+
export declare function toolCallFoldReason(call: {
|
|
28
|
+
readonly id: string;
|
|
29
|
+
readonly wireId?: unknown;
|
|
30
|
+
}): ToolCallIdFoldReason | undefined;
|
|
31
|
+
/** What ONE provider response has admitted so far — the state the rename arm reads: every provider id handed out
|
|
32
|
+
* (`handedOut`) and how many calls each raw id arrived on (`arrivals`). A brain holds one per response attempt
|
|
33
|
+
* ({@link responseToolCallIds}; a retried response starts a new one). */
|
|
34
|
+
export interface ResponseToolCallIds {
|
|
35
|
+
readonly handedOut: Set<string>;
|
|
36
|
+
readonly arrivals: Map<string, number>;
|
|
37
|
+
}
|
|
38
|
+
/** A fresh {@link ResponseToolCallIds} for one response attempt. */
|
|
39
|
+
export declare function responseToolCallIds(): ResponseToolCallIds;
|
|
40
|
+
/** Admit a provider-minted tool-call id (see the module header for the four arms). `response` = the response's
|
|
41
|
+
* {@link ResponseToolCallIds}; absent ⇒ the single-call reading (no rename). Pure apart from recording the call in
|
|
42
|
+
* `response`: announcing a fold is the run's job, read off the call ({@link toolCallFoldReason}). */
|
|
43
|
+
export declare function admitToolCallId(raw: unknown, prefix: string, response?: ResponseToolCallIds): AdmittedToolCallId;
|
|
23
44
|
/** The id a provider is handed for this call: its `wireId` when it carries one (a non-empty string), else its `id`. */
|
|
24
45
|
export declare function providerToolCallId(call: {
|
|
25
46
|
readonly id: string;
|
|
@@ -6,25 +6,55 @@ const FOLD_DIGEST_HEX = 32;
|
|
|
6
6
|
export function mintFallbackToolCallId(prefix) {
|
|
7
7
|
return `${prefix}${Math.random().toString(36).slice(2)}`;
|
|
8
8
|
}
|
|
9
|
+
export const TOOL_CALL_ID_FOLD_REASONS = Object.freeze(["charset", "length", "duplicate"]);
|
|
9
10
|
export function toolCallIdFoldReason(raw) {
|
|
10
11
|
const separated = raw.includes(TOOL_CALL_ID_FOLD_SEPARATOR);
|
|
11
12
|
if (!separated && isProviderEchoShape(raw))
|
|
12
13
|
return undefined;
|
|
13
14
|
return !separated && fitsProviderEchoCharset(raw) ? "length" : "charset";
|
|
14
15
|
}
|
|
15
|
-
export function
|
|
16
|
+
export function toolCallFoldReason(call) {
|
|
17
|
+
const wireId = providerToolCallId(call);
|
|
18
|
+
if (wireId === call.id)
|
|
19
|
+
return undefined;
|
|
20
|
+
return toolCallIdFoldReason(wireId) ?? (RENAMED_ENGINE_ID.test(call.id) ? "duplicate" : undefined);
|
|
21
|
+
}
|
|
22
|
+
const RENAMED_ENGINE_ID = new RegExp(`^[\\x21-\\x7D]{1,${FOLD_BASE_CHARS}}${TOOL_CALL_ID_FOLD_SEPARATOR}[1-9][0-9]*${TOOL_CALL_ID_FOLD_SEPARATOR}[0-9a-f]{${FOLD_DIGEST_HEX}}$`);
|
|
23
|
+
export function responseToolCallIds() {
|
|
24
|
+
return { handedOut: new Set(), arrivals: new Map() };
|
|
25
|
+
}
|
|
26
|
+
export function admitToolCallId(raw, prefix, response) {
|
|
16
27
|
if (typeof raw !== "string" || raw === "") {
|
|
17
|
-
|
|
28
|
+
let id = mintFallbackToolCallId(prefix);
|
|
29
|
+
while (response?.handedOut.has(id) === true)
|
|
30
|
+
id = mintFallbackToolCallId(prefix);
|
|
31
|
+
response?.handedOut.add(id);
|
|
18
32
|
return { engineId: id, wireId: id };
|
|
19
33
|
}
|
|
20
|
-
|
|
34
|
+
if (response === undefined)
|
|
35
|
+
return { engineId: engineIdOf(raw), wireId: raw };
|
|
36
|
+
const arrival = (response.arrivals.get(raw) ?? 0) + 1;
|
|
37
|
+
response.arrivals.set(raw, arrival);
|
|
38
|
+
if (!response.handedOut.has(raw)) {
|
|
39
|
+
response.handedOut.add(raw);
|
|
40
|
+
return { engineId: engineIdOf(raw), wireId: raw };
|
|
41
|
+
}
|
|
42
|
+
let wireId = `${prefix}${digestOf(`${arrival}\u0000${raw}`)}`;
|
|
43
|
+
for (let attempt = 1; response.handedOut.has(wireId); attempt++)
|
|
44
|
+
wireId = `${prefix}${digestOf(`${arrival}\u0000${raw}\u0000${attempt}`)}`;
|
|
45
|
+
response.handedOut.add(wireId);
|
|
46
|
+
return { engineId: `${foldBase(raw)}${TOOL_CALL_ID_FOLD_SEPARATOR}${arrival}${TOOL_CALL_ID_FOLD_SEPARATOR}${digestOf(wireId)}`, wireId };
|
|
21
47
|
}
|
|
22
48
|
function engineIdOf(raw) {
|
|
23
49
|
if (toolCallIdFoldReason(raw) === undefined)
|
|
24
50
|
return raw;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
51
|
+
return `${foldBase(raw)}${TOOL_CALL_ID_FOLD_SEPARATOR}${digestOf(raw)}`;
|
|
52
|
+
}
|
|
53
|
+
function foldBase(raw) {
|
|
54
|
+
return raw.slice(0, FOLD_BASE_CHARS).replace(/[^\x21-\x7D]/g, "-");
|
|
55
|
+
}
|
|
56
|
+
function digestOf(value) {
|
|
57
|
+
return createHash("sha256").update(Buffer.from(value, "utf16le")).digest("hex").slice(0, FOLD_DIGEST_HEX);
|
|
28
58
|
}
|
|
29
59
|
export function providerToolCallId(call) {
|
|
30
60
|
return typeof call.wireId === "string" && call.wireId !== "" ? call.wireId : call.id;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const A2A_TASK_STATES = [
|
|
1
|
+
export const A2A_TASK_STATES = Object.freeze([
|
|
2
2
|
"submitted",
|
|
3
3
|
"working",
|
|
4
4
|
"input-required",
|
|
@@ -8,7 +8,7 @@ export const A2A_TASK_STATES = [
|
|
|
8
8
|
"rejected",
|
|
9
9
|
"auth-required",
|
|
10
10
|
"unknown",
|
|
11
|
-
];
|
|
11
|
+
]);
|
|
12
12
|
const CANCELLING_STOP_SOURCES = new Set(["user", "parent"]);
|
|
13
13
|
export function toA2ATaskState(record) {
|
|
14
14
|
switch (record.status) {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { isAbsoluteForFamily, pathFamilyOf } from "../tools/fs/safety.js";
|
|
2
2
|
import { thrownText } from "./thrown-value.js";
|
|
3
|
-
export const ARTIFACT_ACTIONS = ["publish", "list", "read", "list_files", "read_file"];
|
|
4
|
-
export const ARTIFACT_PLANES = ["hosted", "local-stub"];
|
|
5
|
-
export const ARTIFACT_COMMIT_CERTAINTIES = ["throw_means_uncommitted", "uncertain"];
|
|
3
|
+
export const ARTIFACT_ACTIONS = Object.freeze(["publish", "list", "read", "list_files", "read_file"]);
|
|
4
|
+
export const ARTIFACT_PLANES = Object.freeze(["hosted", "local-stub"]);
|
|
5
|
+
export const ARTIFACT_COMMIT_CERTAINTIES = Object.freeze(["throw_means_uncommitted", "uncertain"]);
|
|
6
6
|
export const ARTIFACT_COMMIT_THROW_OUTCOME = {
|
|
7
7
|
throw_means_uncommitted: "not_executed",
|
|
8
8
|
uncertain: "unknown",
|
|
9
9
|
};
|
|
10
|
-
export const ARTIFACT_PUBLISH_CONTEXTS = ["pr_review", "workshop", "whiteboard", "prototype", "plain"];
|
|
11
|
-
export const ARTIFACT_LIST_SCOPES = ["mine", "shared", "all"];
|
|
10
|
+
export const ARTIFACT_PUBLISH_CONTEXTS = Object.freeze(["pr_review", "workshop", "whiteboard", "prototype", "plain"]);
|
|
11
|
+
export const ARTIFACT_LIST_SCOPES = Object.freeze(["mine", "shared", "all"]);
|
|
12
12
|
export const ARTIFACT_PLANE_CONTENT_ORIGIN = {
|
|
13
13
|
hosted: "external",
|
|
14
14
|
"local-stub": "local",
|
|
@@ -27,7 +27,7 @@ export const ARTIFACT_ACTION_CONCURRENCY_SAFE = {
|
|
|
27
27
|
list_files: true,
|
|
28
28
|
read_file: true,
|
|
29
29
|
};
|
|
30
|
-
export const ARTIFACT_HOST_FAILURE_CODES = ["conflict", "url_foreign", "forbidden", "payload_too_large", "not_found", "force_refused", "refused"];
|
|
30
|
+
export const ARTIFACT_HOST_FAILURE_CODES = Object.freeze(["conflict", "url_foreign", "forbidden", "payload_too_large", "not_found", "force_refused", "refused"]);
|
|
31
31
|
export const ARTIFACT_FAILURE_RESULT_CODE = {
|
|
32
32
|
conflict: "artifact.publish_conflict",
|
|
33
33
|
url_foreign: "artifact.url_foreign",
|
package/dist/core/ask-origin.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const ASK_ORIGINS = ["content_question", "ancestor_marked", "org_unavailable", "org_rule", "rule_store_unavailable", "hook", "ask_rule", "denial_limit_fallback", "shell_gate_tighten", "safety_tighten", "policy"];
|
|
1
|
+
export const ASK_ORIGINS = Object.freeze(["content_question", "ancestor_marked", "org_unavailable", "org_rule", "rule_store_unavailable", "hook", "ask_rule", "denial_limit_fallback", "shell_gate_tighten", "safety_tighten", "policy"]);
|
|
2
2
|
const ASK_ORIGIN_SET = new Set(ASK_ORIGINS);
|
|
3
3
|
export function isAskOrigin(v) {
|
|
4
4
|
return ASK_ORIGIN_SET.has(v);
|
|
@@ -103,7 +103,7 @@ export const ORIGIN_IMPLIES_REAL_APPROVAL = {
|
|
|
103
103
|
safety_tighten: false,
|
|
104
104
|
policy: false,
|
|
105
105
|
};
|
|
106
|
-
export const PERSISTED_RULE_MANDATES = ["operator_always", "tool_marks", "probe_mandate", "probe_unanswered", "write_protection", "write_protection_unresolved"];
|
|
106
|
+
export const PERSISTED_RULE_MANDATES = Object.freeze(["operator_always", "tool_marks", "probe_mandate", "probe_unanswered", "write_protection", "write_protection_unresolved"]);
|
|
107
107
|
const PERSISTED_RULE_MANDATE_SET = new Set(PERSISTED_RULE_MANDATES);
|
|
108
108
|
export function isPersistedRuleMandate(v) {
|
|
109
109
|
return PERSISTED_RULE_MANDATE_SET.has(v);
|
|
@@ -149,7 +149,7 @@ export function safetyAxisOf(marks) {
|
|
|
149
149
|
const shell = raised && marks.shellGated === true;
|
|
150
150
|
return egress || raised ? { egress, irreversible: raised && !shell, ...(shell ? { shell: true } : {}) } : undefined;
|
|
151
151
|
}
|
|
152
|
-
export const PERMISSION_MODES = ["default", "acceptEdits", "plan", "auto", "bypassPermissions", "dontAsk"];
|
|
152
|
+
export const PERMISSION_MODES = Object.freeze(["default", "acceptEdits", "plan", "auto", "bypassPermissions", "dontAsk"]);
|
|
153
153
|
const PERMISSION_MODE_SET = new Set(PERMISSION_MODES);
|
|
154
154
|
export function isPermissionMode(v) {
|
|
155
155
|
return PERMISSION_MODE_SET.has(v);
|
|
@@ -166,7 +166,7 @@ export function clampPermissionMode(declared, ceiling) {
|
|
|
166
166
|
return { effective: ceiling, clamped: true };
|
|
167
167
|
return PERMISSION_MODE_RANK[declared] <= PERMISSION_MODE_RANK[ceiling] ? { effective: declared, clamped: false } : { effective: ceiling, clamped: true };
|
|
168
168
|
}
|
|
169
|
-
export const ASK_CLASSES = [
|
|
169
|
+
export const ASK_CLASSES = Object.freeze([
|
|
170
170
|
"content_question",
|
|
171
171
|
"hook",
|
|
172
172
|
"ancestor",
|
|
@@ -187,7 +187,7 @@ export const ASK_CLASSES = [
|
|
|
187
187
|
"artifact_shared_read",
|
|
188
188
|
"mode",
|
|
189
189
|
"ordinary",
|
|
190
|
-
];
|
|
190
|
+
]);
|
|
191
191
|
const ASK_CLASS_SET = new Set(ASK_CLASSES);
|
|
192
192
|
export function isAskClass(v) {
|
|
193
193
|
return ASK_CLASS_SET.has(v);
|
|
@@ -216,7 +216,7 @@ export const MODE_ARBITRATION = {
|
|
|
216
216
|
};
|
|
217
217
|
export const RRA_EXPLAINERS = new Set(["unverifiable_delete", "transcript_write", "org_rule", "governance_unavailable", "rule_unreadable", "denial_limit_fallback", "ancestor", "artifact_shared_read"]);
|
|
218
218
|
export const RELEASABLE_ASK_CLASSES = ASK_CLASSES.filter((c) => !MODE_ARBITRATION[c].bypassImmune);
|
|
219
|
-
export const MODE_RELEASE_REASONS = ["rule_unreadable"];
|
|
219
|
+
export const MODE_RELEASE_REASONS = Object.freeze(["rule_unreadable"]);
|
|
220
220
|
const MODE_RELEASE_REASON_SET = new Set(MODE_RELEASE_REASONS);
|
|
221
221
|
export function isModeReleaseReason(v) {
|
|
222
222
|
return MODE_RELEASE_REASON_SET.has(v);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const ASK_UNRESOLVABLE_CAUSES = ["approver_unavailable", "no_approver_wired", "mandate_unreconstructible"];
|
|
1
|
+
export const ASK_UNRESOLVABLE_CAUSES = Object.freeze(["approver_unavailable", "no_approver_wired", "mandate_unreconstructible"]);
|
|
2
2
|
Object.freeze(ASK_UNRESOLVABLE_CAUSES);
|
|
3
3
|
const ASK_UNRESOLVABLE_CAUSE_SET = new Set(ASK_UNRESOLVABLE_CAUSES);
|
|
4
4
|
export function isAskUnresolvableCause(v) {
|
package/dist/core/auto-mode.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import { AUTO_MODE_DEFAULT_TIMEOUT_MS, AUTO_MODE_DENIAL_AUTO_DENY_DEFAULT_MS, AUTO_MODE_DENIAL_LIMIT_DEFAULTS } from "./auto-mode-defaults.js";
|
|
2
2
|
import { thrownIs } from "./thrown-value.js";
|
|
3
3
|
import { describeRejectedValue } from "./tool-search-setting.js";
|
|
4
|
-
export const AUTO_MODE_UNAVAILABLE_CAUSES = ["error", "timeout"];
|
|
4
|
+
export const AUTO_MODE_UNAVAILABLE_CAUSES = Object.freeze(["error", "timeout"]);
|
|
5
5
|
const AUTO_MODE_UNAVAILABLE_CAUSE_SET = new Set(AUTO_MODE_UNAVAILABLE_CAUSES);
|
|
6
6
|
export function isAutoModeUnavailableCause(v) {
|
|
7
7
|
return AUTO_MODE_UNAVAILABLE_CAUSE_SET.has(v);
|
|
8
8
|
}
|
|
9
|
-
export const AUTO_MODE_PARSE_FAILURES = ["missing", "conflict"];
|
|
9
|
+
export const AUTO_MODE_PARSE_FAILURES = Object.freeze(["missing", "conflict"]);
|
|
10
10
|
const AUTO_MODE_PARSE_FAILURE_SET = new Set(AUTO_MODE_PARSE_FAILURES);
|
|
11
11
|
export function isAutoModeParseFailure(v) {
|
|
12
12
|
return AUTO_MODE_PARSE_FAILURE_SET.has(v);
|
|
13
13
|
}
|
|
14
|
-
export const AUTO_MODE_FALLBACK_CAUSES = ["error", "timeout", "parse_error"];
|
|
14
|
+
export const AUTO_MODE_FALLBACK_CAUSES = Object.freeze(["error", "timeout", "parse_error"]);
|
|
15
15
|
const AUTO_MODE_FALLBACK_CAUSE_SET = new Set(AUTO_MODE_FALLBACK_CAUSES);
|
|
16
16
|
export function isAutoModeFallbackCause(v) {
|
|
17
17
|
return AUTO_MODE_FALLBACK_CAUSE_SET.has(v);
|
|
18
18
|
}
|
|
19
|
-
export const AUTO_MODE_CLASSIFIER_FALLBACKS = ["main", "none"];
|
|
19
|
+
export const AUTO_MODE_CLASSIFIER_FALLBACKS = Object.freeze(["main", "none"]);
|
|
20
20
|
const AUTO_MODE_CLASSIFIER_FALLBACK_SET = new Set(AUTO_MODE_CLASSIFIER_FALLBACKS);
|
|
21
21
|
export function isAutoModeClassifierFallback(v) {
|
|
22
22
|
return AUTO_MODE_CLASSIFIER_FALLBACK_SET.has(v);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { uuidv7 } from "../internal/harness.js";
|
|
2
2
|
import { assertRetentionPolicy } from "./retention-policy.js";
|
|
3
|
-
export const REVIVED_ROW_CLEARED_FIELDS = [
|
|
3
|
+
export const REVIVED_ROW_CLEARED_FIELDS = Object.freeze([
|
|
4
4
|
"settledAt",
|
|
5
5
|
"stoppedBy",
|
|
6
6
|
"completionId",
|
|
@@ -16,7 +16,7 @@ export const REVIVED_ROW_CLEARED_FIELDS = [
|
|
|
16
16
|
"recentSteps",
|
|
17
17
|
"editedFiles",
|
|
18
18
|
"usage",
|
|
19
|
-
];
|
|
19
|
+
]);
|
|
20
20
|
export function clearRevivedRowTerminalPayload(record) {
|
|
21
21
|
for (const field of REVIVED_ROW_CLEARED_FIELDS)
|
|
22
22
|
delete record[field];
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {} from "./ask-origin.js";
|
|
2
|
-
export const EXECUTION_OUTCOME_RECORD_WORDS = ["recorded", "already_recorded", "not_resolved", "absent"];
|
|
2
|
+
export const EXECUTION_OUTCOME_RECORD_WORDS = Object.freeze(["recorded", "already_recorded", "not_resolved", "absent"]);
|
|
3
3
|
export const EXECUTION_RECORD_LEAVES_ROW_UNRECORDED = {
|
|
4
4
|
recorded: false,
|
|
5
5
|
already_recorded: false,
|
|
@@ -1135,7 +1135,7 @@ export interface CheckpointState {
|
|
|
1135
1135
|
* revive the mode where the redeeming deployment denies it, and an `auto` row arms only where a face is
|
|
1136
1136
|
* wired. Absent on a task that declared nothing and inherited nothing (`default`). Rows written before this
|
|
1137
1137
|
* member carried `autoModeRequested` / `approverPosture` / a doctrine `shellGate`; the resume leg migrates
|
|
1138
|
-
* them once, announced (`resume.legacy_mode_seed_migrated`), and the next suspend writes this member. The migration is kept through 7.
|
|
1138
|
+
* them once, announced (`resume.legacy_mode_seed_migrated`), and the next suspend writes this member. The migration is kept through 7.38.x and removed in 7.39.0, which refuses a row still carrying these keys. */
|
|
1139
1139
|
permissionMode?: PermissionMode;
|
|
1140
1140
|
/** Beside a recorded `plan`: the declared word the leg had when a steer or the model's `EnterPlanMode` moved it into
|
|
1141
1141
|
* plan — the mode an approved or edited `plan_review` resumes under ({@link import("./mode-policy.js").modeRequestAfterResume}). */
|
|
@@ -3055,6 +3055,6 @@ export interface LegacyModeSeedMigration {
|
|
|
3055
3055
|
* - `shellGate`: absent ⇒ none; `"always"` ⇒ kept (a live key, not a retired encoding); `"off"` / `"classify"` ⇒
|
|
3056
3056
|
* dropped (no floor); anything else ⇒ refused (`resume.legacy_mode_seed`).
|
|
3057
3057
|
* Idempotent: a row the resume leg writes back carries `permissionMode` and the floor only, so a second read migrates nothing ("once" is per row).
|
|
3058
|
-
* Migration precedes any retired-key door, so a window row is read rather than refused. The window: this migration is kept through 7.
|
|
3058
|
+
* Migration precedes any retired-key door, so a window row is read rather than refused. The window: this migration is kept through 7.38.x and removed in 7.39.0, which refuses a row still carrying these keys — resume or abandon a row parked before 7.34.0 before upgrading to 7.39.0.
|
|
3059
3059
|
*/
|
|
3060
3060
|
export declare function migrateLegacyModeSeed(gate: object | undefined): LegacyModeSeedMigration;
|
|
@@ -74,7 +74,7 @@ const BIDI_BACKFILL_MAX_NODES = 512;
|
|
|
74
74
|
export const MAX_PENDING_STEER_CHARS = 16_000;
|
|
75
75
|
export const PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES = 48_000;
|
|
76
76
|
export const MAX_PENDING_STEER_ENTRIES = Math.floor(PENDING_STEER_QUEUE_BYTE_BUDGET_BYTES / MAX_PENDING_STEER_CHARS);
|
|
77
|
-
export const PENDING_STEER_FROZEN_FIELDS = ["text", "trusted", "actor", "seq", "inputId", "priority"];
|
|
77
|
+
export const PENDING_STEER_FROZEN_FIELDS = Object.freeze(["text", "trusted", "actor", "seq", "inputId", "priority"]);
|
|
78
78
|
export function isPlainRecord(x) {
|
|
79
79
|
try {
|
|
80
80
|
if (x === null || typeof x !== "object" || Array.isArray(x))
|
|
@@ -500,7 +500,7 @@ export function validatePendingSteer(steer) {
|
|
|
500
500
|
}
|
|
501
501
|
export const MAX_ACTOR_FIELD_CHARS = 256;
|
|
502
502
|
export const MAX_STEER_INPUT_ID_CHARS = 128;
|
|
503
|
-
export const ACTOR_ASSERTION_FROZEN_FIELDS = ["id", "hostAsserted", "issuer"];
|
|
503
|
+
export const ACTOR_ASSERTION_FROZEN_FIELDS = Object.freeze(["id", "hostAsserted", "issuer"]);
|
|
504
504
|
function captureActorAssertion(actor) {
|
|
505
505
|
if (actor === null || typeof actor !== "object") {
|
|
506
506
|
throw new CheckpointError("steering.invalid_content", `actor must be an object carrying the attribution fields (got ${actor === null ? "null" : typeof actor})`);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const CHILD_CLAMP_SEATS = ["handsReadOnly", "interactiveTools", "readFace", "writeFace", "readDenyPatterns"];
|
|
1
|
+
export const CHILD_CLAMP_SEATS = Object.freeze(["handsReadOnly", "interactiveTools", "readFace", "writeFace", "readDenyPatterns"]);
|
|
2
2
|
export const CHILD_CLAMP_SEATS_NOT_CARRIED = Object.freeze({
|
|
3
3
|
toolPolicy: "not a clamp a child spec copies: a parent's denies reach its children through the ancestor-constraint chain the child's own prepare folds, not by putting the parent's policy object on the child seat",
|
|
4
4
|
shellGate: "travels on the inherited-gate lane (`InheritedGate.shellGate`, a trusted internals seat), not on the child spec — a spec-level copy would be a second source for the same clamp",
|
|
@@ -8,7 +8,7 @@ export const CHILD_CLAMP_SEATS_NOT_CARRIED = Object.freeze({
|
|
|
8
8
|
excludeTools: "roster control rather than containment: the lanes that copy a parent's roster do so beside these seats, and the workflow lane authors its child roster from the governance baseline instead of the host's",
|
|
9
9
|
deferTools: "roster control, same reading as `excludeTools` above",
|
|
10
10
|
});
|
|
11
|
-
export const ENGINE_CHILD_SPEC_CONSTRUCTORS = [
|
|
11
|
+
export const ENGINE_CHILD_SPEC_CONSTRUCTORS = Object.freeze([
|
|
12
12
|
"src/agents/subagent.ts#buildChildSpec",
|
|
13
13
|
"src/agents/subagent.ts#observerSpec",
|
|
14
14
|
"src/agents/subagent.ts#resumeSpec",
|
|
@@ -16,7 +16,7 @@ export const ENGINE_CHILD_SPEC_CONSTRUCTORS = [
|
|
|
16
16
|
"src/agents/verify.ts#verifierSpec",
|
|
17
17
|
"src/agents/verify.ts#fixLegSpec",
|
|
18
18
|
"src/orchestration/workflow-primitives.ts#workflowChildClamps",
|
|
19
|
-
];
|
|
19
|
+
]);
|
|
20
20
|
export function childClampSeats(source) {
|
|
21
21
|
return {
|
|
22
22
|
...(source.handsReadOnly === true ? { handsReadOnly: true } : {}),
|
package/dist/core/compliance.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const COMPLIANCE_CAPABILITIES = ["mcp_servers", "workflows", "web_fetch", "org_memory_mount"];
|
|
1
|
+
export const COMPLIANCE_CAPABILITIES = Object.freeze(["mcp_servers", "workflows", "web_fetch", "org_memory_mount"]);
|
|
2
2
|
export const BUILTIN_COMPLIANCE_DENIES = {
|
|
3
3
|
hipaa: ["web_fetch", "org_memory_mount"],
|
|
4
4
|
zdr: ["org_memory_mount"],
|
|
@@ -33,7 +33,7 @@ export const COMPACTION_TRIGGER_BUFFER_TOKENS = 13000;
|
|
|
33
33
|
export function contextEditFrontier(window) {
|
|
34
34
|
return Math.max(window - (CONTEXT_OUTPUT_RESERVE_TOKENS + COMPACTION_TRIGGER_BUFFER_TOKENS), Math.floor(window * EDIT_FRACTION));
|
|
35
35
|
}
|
|
36
|
-
export const MICRO_COMPACT_MACHINES = ["off", "cc"];
|
|
36
|
+
export const MICRO_COMPACT_MACHINES = Object.freeze(["off", "cc"]);
|
|
37
37
|
export const CC_DEFAULT_KEEP_RECENT_TOOL_RESULTS = 5;
|
|
38
38
|
export const MIN_CLEAR_SAVINGS_TOKENS = 20000;
|
|
39
39
|
const MEDIA_BLOCK_SAVINGS_TOKENS = 2000;
|
|
@@ -35,25 +35,6 @@ export declare const CONTEXT_TRIM_NOTICE: string;
|
|
|
35
35
|
* (fixed timestamp keeps it fully deterministic).
|
|
36
36
|
*/
|
|
37
37
|
export declare function insertTrimNotice(trimmed: AgentMessage[]): AgentMessage[];
|
|
38
|
-
/**
|
|
39
|
-
* design/123 D3 belt (invariant-level, live-caught 16k 400s): the FINAL request view must never
|
|
40
|
-
* contain a toolResult whose tool-call assistant is absent — strict gateways hard-400 on it
|
|
41
|
-
* ("Messages with role 'tool' must be a response to a preceding message with 'tool_calls'"). Every
|
|
42
|
-
* individual producer is turn-aligned (findCutPoint never cuts on a toolResult; trimToBudget
|
|
43
|
-
* turn-aligns its floor), but NO pipeline combination may ship an orphan, so the prepare-task
|
|
44
|
-
* context hook sweeps its output through this last. Deterministic ⇒ byte-stable per request ⇒
|
|
45
|
-
* prefix-cache safe. Returns the SAME array when clean (zero-cost fast path); `dropped` carries a
|
|
46
|
-
* diagnostic per removed orphan (toolCallId + neighbor roles) for onError attribution.
|
|
47
|
-
*/
|
|
48
|
-
export declare function dropOrphanToolResults(messages: AgentMessage[]): {
|
|
49
|
-
messages: AgentMessage[];
|
|
50
|
-
dropped: Array<{
|
|
51
|
-
toolCallId: string;
|
|
52
|
-
index: number;
|
|
53
|
-
prevRole: string;
|
|
54
|
-
nextRole: string;
|
|
55
|
-
}>;
|
|
56
|
-
};
|
|
57
38
|
/** R2-3 (falsification round 2) — does the message's ENGINE-AUTHORED region cover [start, start+len)?
|
|
58
39
|
* The carrier scan must never crown a counterfeit: a tool result or a user paste can reproduce the
|
|
59
40
|
* wrapped frame bytes verbatim, but only ENGINE metadata (engineMinted whole-message, the
|
|
@@ -77,44 +77,6 @@ export function insertTrimNotice(trimmed) {
|
|
|
77
77
|
at++;
|
|
78
78
|
return [...trimmed.slice(0, at), notice, ...trimmed.slice(at)];
|
|
79
79
|
}
|
|
80
|
-
export function dropOrphanToolResults(messages) {
|
|
81
|
-
const seenCallIds = new Set();
|
|
82
|
-
let orphanAt = -1;
|
|
83
|
-
for (let i = 0; i < messages.length; i++) {
|
|
84
|
-
const m = messages[i];
|
|
85
|
-
if (m.role === "assistant" && Array.isArray(m.content)) {
|
|
86
|
-
for (const c of m.content) {
|
|
87
|
-
if (c?.type === "toolCall" && typeof c.id === "string")
|
|
88
|
-
seenCallIds.add(c.id);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
else if (m.role === "toolResult" && !seenCallIds.has(m.toolCallId ?? "")) {
|
|
92
|
-
orphanAt = i;
|
|
93
|
-
break;
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
if (orphanAt === -1) {
|
|
97
|
-
return { messages, dropped: [] };
|
|
98
|
-
}
|
|
99
|
-
const dropped = [];
|
|
100
|
-
const out = messages.slice(0, orphanAt);
|
|
101
|
-
const roleOf = (i) => i < 0 || i >= messages.length ? "(none)" : (messages[i].role ?? "(unknown)");
|
|
102
|
-
for (let i = orphanAt; i < messages.length; i++) {
|
|
103
|
-
const m = messages[i];
|
|
104
|
-
if (m.role === "assistant" && Array.isArray(m.content)) {
|
|
105
|
-
for (const c of m.content) {
|
|
106
|
-
if (c?.type === "toolCall" && typeof c.id === "string")
|
|
107
|
-
seenCallIds.add(c.id);
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else if (m.role === "toolResult" && !seenCallIds.has(m.toolCallId ?? "")) {
|
|
111
|
-
dropped.push({ toolCallId: m.toolCallId ?? "(missing)", index: i, prevRole: roleOf(i - 1), nextRole: roleOf(i + 1) });
|
|
112
|
-
continue;
|
|
113
|
-
}
|
|
114
|
-
out.push(messages[i]);
|
|
115
|
-
}
|
|
116
|
-
return { messages: out, dropped };
|
|
117
|
-
}
|
|
118
80
|
export function engineRegionCovers(m, start, len) {
|
|
119
81
|
const meta = m;
|
|
120
82
|
if (meta.engineMinted === true)
|