@sema-agent/core 7.23.5 → 7.24.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 +77 -0
- package/dist/agents/list-agents-tool.d.ts +7 -4
- package/dist/agents/list-agents-tool.js +12 -1
- package/dist/agents/observer.js +5 -8
- package/dist/agents/subagent.js +2 -2
- package/dist/agents/team.js +9 -0
- package/dist/brain/degrading.js +8 -9
- package/dist/brain/route-adjudicator.d.ts +25 -12
- package/dist/brain/route-adjudicator.js +89 -23
- package/dist/brain/route-conformance.js +9 -0
- package/dist/brain/stream-engine.js +11 -9
- package/dist/core/arg-summary.js +17 -6
- package/dist/core/auto-compaction.d.ts +42 -1
- package/dist/core/auto-compaction.js +21 -1
- package/dist/core/auto-mode.js +2 -8
- package/dist/core/exec-gate.js +3 -5
- package/dist/core/file-history-store.js +11 -10
- package/dist/core/hooks.d.ts +7 -0
- package/dist/core/mcp.js +7 -5
- package/dist/core/memory-engine/distiller.d.ts +7 -4
- package/dist/core/memory-engine/distiller.js +11 -3
- package/dist/core/memory.js +1 -0
- package/dist/core/runner/assemble-result.js +12 -19
- package/dist/core/runner/contracts.d.ts +1 -0
- package/dist/core/runner/prepare-file-history.js +19 -0
- package/dist/core/runner/run-recovery-lanes.js +4 -20
- package/dist/core/runner/run-settle-and-teardown.js +2 -16
- package/dist/core/runner/run-turn-boundary.js +4 -20
- package/dist/core/runner/runtask.js +3 -5
- package/dist/core/runner/stream-settle-backstop.js +5 -5
- package/dist/core/runner/tool-end-body.js +5 -4
- package/dist/core/runner/tool-output-projection.js +3 -2
- package/dist/core/runner/turn-attachments.d.ts +0 -20
- package/dist/core/runner/turn-attachments.js +41 -36
- package/dist/core/session-store.js +2 -4
- package/dist/core/session.d.ts +4 -1
- package/dist/core/session.js +2 -1
- package/dist/core/task-event.d.ts +19 -9
- package/dist/core/task-registry-shared.js +1 -0
- package/dist/core/thrown-value.d.ts +24 -13
- package/dist/core/thrown-value.js +13 -1
- package/dist/core/tool-errors.d.ts +6 -0
- package/dist/core/tool-errors.js +6 -14
- package/dist/core/tools.js +8 -9
- package/dist/engine/llm/types.d.ts +4 -4
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/orchestration/workflow.js +44 -23
- package/dist/stores/file/file-history-store.js +12 -11
- package/package.json +1 -1
- package/test/export-surface.snapshot.json +7 -3
- package/wire-changes/core@7.24.0.json +249 -0
package/dist/index.js
CHANGED
|
@@ -279,7 +279,7 @@ export { createCircuitBreakerBrain, CIRCUIT_OPEN_MARKER, } from "./brain/circuit
|
|
|
279
279
|
export { createDegradingBrain, readDegradation, DEGRADED_DIAGNOSTIC_TYPE, } from "./brain/degrading.js";
|
|
280
280
|
export { retryBackoffMs, parseRetryAfter } from "./brain/retry.js";
|
|
281
281
|
export { WAITING_FIRST_TOKEN_AFTER_MS, WAITING_FIRST_TOKEN_EVERY_MS } from "./brain/stream-engine.js";
|
|
282
|
-
export { adjudicateModelRoute, resolveRouteCredential, routeRefusalText, routePairingStatus,
|
|
282
|
+
export { adjudicateModelRoute, resolveRouteCredential, routeRefusalText, routePairingStatus, routeKeyOf, displayUrlOf, resolveRequestRoot, hasAuthCarrier, } from "./brain/route-adjudicator.js";
|
|
283
283
|
export { ROUTE_ADJUDICATION_CONFORMANCE_CORPUS } from "./brain/route-conformance.js";
|
|
284
284
|
export {} from "./brain/timeout.js";
|
|
285
285
|
export { createAssistantMessageEventStream } from "./internal/llm.js";
|
|
@@ -23,7 +23,7 @@ import { compileOutputSchema } from "../core/runner/strict-output-schema.js";
|
|
|
23
23
|
import { WorkflowBudgetExceededError, WorkflowNestingError, WorkflowAgentBlockedError, WorkflowAgentParkedError, WorkflowAgentSchemaError, WorkflowAgentStalledError, WorkflowMaxAgentsError, WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } from "./workflow-types.js";
|
|
24
24
|
import { WorkflowScriptError } from "./workflow-meta.js";
|
|
25
25
|
import { STALL_CONNECT_MS, STALL_FIRST_TOKEN_MS } from "../brain/timeout.js";
|
|
26
|
-
import { asThrownError, thrownText } from "../core/thrown-value.js";
|
|
26
|
+
import { asThrownError, isErrorLike, readMember, thrownIs, thrownName, thrownText } from "../core/thrown-value.js";
|
|
27
27
|
export * from "./workflow-types.js";
|
|
28
28
|
const MAX_TRANSCRIPT_CHARS = 4000;
|
|
29
29
|
const WORKFLOW_RESULT_MAX = 4000;
|
|
@@ -176,7 +176,7 @@ export function assertSupportedAgentIsolation(isolation) {
|
|
|
176
176
|
}
|
|
177
177
|
}
|
|
178
178
|
function rethrowIfMaxAgents(e) {
|
|
179
|
-
if (e
|
|
179
|
+
if (thrownIs(e, WorkflowMaxAgentsError))
|
|
180
180
|
throw e;
|
|
181
181
|
return null;
|
|
182
182
|
}
|
|
@@ -186,7 +186,7 @@ function foldFanOutSettled(settled, lane, errorsOut, emitRunLog) {
|
|
|
186
186
|
const results = settled.map((s) => {
|
|
187
187
|
if (s.ok)
|
|
188
188
|
return s.v;
|
|
189
|
-
if (s.e
|
|
189
|
+
if (thrownIs(s.e, WorkflowBudgetExceededError)) {
|
|
190
190
|
dropped++;
|
|
191
191
|
droppedSlots.push(s.i);
|
|
192
192
|
errorsOut?.push(workflowFanOutSlotError(s.i, s.e));
|
|
@@ -201,9 +201,19 @@ function foldFanOutSettled(settled, lane, errorsOut, emitRunLog) {
|
|
|
201
201
|
emitRunLog(`${lane}: ${dropped} ${dropped === 1 ? "slot" : "slots"} dropped — token budget exceeded (${dropped === 1 ? "slot" : "slots"} ${droppedSlots.join(", ")})`);
|
|
202
202
|
return results;
|
|
203
203
|
}
|
|
204
|
+
function thrownMessageOf(err) {
|
|
205
|
+
if (!isErrorLike(err))
|
|
206
|
+
return undefined;
|
|
207
|
+
const message = readMember(err, "message");
|
|
208
|
+
return typeof message === "string" && message !== "" ? message : undefined;
|
|
209
|
+
}
|
|
210
|
+
function thrownNameOf(err) {
|
|
211
|
+
const name = thrownName(err);
|
|
212
|
+
return name !== undefined && name !== "" ? name : undefined;
|
|
213
|
+
}
|
|
204
214
|
function workflowFanOutSlotError(index, e) {
|
|
205
|
-
const code = e
|
|
206
|
-
const kind = typeof code === "string" && code.length > 0 ? code : e
|
|
215
|
+
const code = readMember(e, "code");
|
|
216
|
+
const kind = typeof code === "string" && code.length > 0 ? code : thrownNameOf(e) ?? "Error";
|
|
207
217
|
return { index, kind, message: boundedRedactedSummary(thrownText(e), 300) };
|
|
208
218
|
}
|
|
209
219
|
export class WorkflowResultTooLargeError extends Error {
|
|
@@ -247,12 +257,20 @@ export const MAX_WORKFLOW_ITEMS = 4096;
|
|
|
247
257
|
function describeFanOutValue(v) {
|
|
248
258
|
if (v === null)
|
|
249
259
|
return "null";
|
|
250
|
-
if (
|
|
260
|
+
if (isFanOutArray(v))
|
|
251
261
|
return "array";
|
|
252
|
-
if (v
|
|
262
|
+
if (thrownIs(v, Promise))
|
|
253
263
|
return "a Promise (an already-CALLED agent(...) — wrap it: () => agent(...))";
|
|
254
264
|
return typeof v;
|
|
255
265
|
}
|
|
266
|
+
function isFanOutArray(v) {
|
|
267
|
+
try {
|
|
268
|
+
return Array.isArray(v);
|
|
269
|
+
}
|
|
270
|
+
catch {
|
|
271
|
+
return false;
|
|
272
|
+
}
|
|
273
|
+
}
|
|
256
274
|
function assertFanOutCallables(lane, member, list) {
|
|
257
275
|
for (let i = 0; i < list.length; i++) {
|
|
258
276
|
if (typeof list[i] !== "function") {
|
|
@@ -263,7 +281,7 @@ function assertFanOutCallables(lane, member, list) {
|
|
|
263
281
|
}
|
|
264
282
|
}
|
|
265
283
|
function assertFanOutArray(lane, what, v) {
|
|
266
|
-
if (!
|
|
284
|
+
if (!isFanOutArray(v)) {
|
|
267
285
|
throw new WorkflowScriptError(`${lane}(): ${what} must be an ARRAY (got ${describeFanOutValue(v)}). Nothing was run.`);
|
|
268
286
|
}
|
|
269
287
|
}
|
|
@@ -1740,14 +1758,14 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1740
1758
|
}
|
|
1741
1759
|
}
|
|
1742
1760
|
catch (err) {
|
|
1743
|
-
if (drive !== undefined && !finalized && !(err
|
|
1761
|
+
if (drive !== undefined && !finalized && !thrownIs(err, WorkflowAgentParkedError)) {
|
|
1744
1762
|
emitRunLog(`[park] the parked leg "${label}" could not be driven — the resume was refused before the checkpoint was consumed (${withoutToken(errText(err), drive.token)}); the park stands.`);
|
|
1745
1763
|
return await parkAgentLeg(rec, drive.paused, activityTail, false);
|
|
1746
1764
|
}
|
|
1747
1765
|
if (!finalized) {
|
|
1748
1766
|
rec.status = "failed";
|
|
1749
1767
|
rec.endedAt = now();
|
|
1750
|
-
const salvaged = err
|
|
1768
|
+
const salvaged = thrownIs(err, WorkflowAgentStalledError) ? err.lastResult : undefined;
|
|
1751
1769
|
if (salvaged?.runId === undefined)
|
|
1752
1770
|
delete rec.taskRunId;
|
|
1753
1771
|
if (salvaged !== undefined) {
|
|
@@ -1763,17 +1781,18 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1763
1781
|
rec.output = boundedRedactedSummary(salvaged.structuredOutput ?? salvaged.result, MAX_TRANSCRIPT_CHARS) || (rec.errorMessage ?? "");
|
|
1764
1782
|
rec.stats = { tokens: salvaged.stats.tokens ?? 0, turns: salvaged.stats.turns ?? 0, costMicroUsd: salvaged.stats.costMicroUsd };
|
|
1765
1783
|
}
|
|
1766
|
-
if (err
|
|
1784
|
+
if (thrownIs(err, WorkflowAgentBlockedError)) {
|
|
1767
1785
|
rec.errorCode = WORKFLOW_SPAWN_BLOCKED_ERROR_CODE;
|
|
1768
1786
|
rec.errorMessage = boundedRedactedSummary(err.message, MAX_TRANSCRIPT_CHARS);
|
|
1769
1787
|
}
|
|
1770
|
-
if (err
|
|
1788
|
+
if (thrownIs(err, WorkflowBudgetExceededError)) {
|
|
1771
1789
|
rec.errorCode = err.code;
|
|
1772
1790
|
rec.errorMessage = boundedRedactedSummary(err.message, MAX_TRANSCRIPT_CHARS);
|
|
1773
1791
|
}
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1792
|
+
const preLaunchMessage = thrownMessageOf(err);
|
|
1793
|
+
if (rec.errorMessage === undefined && preLaunchMessage !== undefined)
|
|
1794
|
+
rec.errorMessage = boundedRedactedSummary(preLaunchMessage, MAX_TRANSCRIPT_CHARS);
|
|
1795
|
+
if (thrownIs(err, WorkflowAgentStalledError) && err.attempts > 1) {
|
|
1777
1796
|
rec.attempts = err.attempts;
|
|
1778
1797
|
rec.lastAttemptReason = "stalled";
|
|
1779
1798
|
}
|
|
@@ -1785,12 +1804,12 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1785
1804
|
result: boundedRedactedSummary(thrownText(err), 500),
|
|
1786
1805
|
terminal: {
|
|
1787
1806
|
kind: "failed",
|
|
1788
|
-
...(err
|
|
1807
|
+
...(thrownIs(err, WorkflowAgentBlockedError) ? { code: WORKFLOW_SPAWN_BLOCKED_ERROR_CODE } : thrownIs(err, WorkflowBudgetExceededError) ? { code: err.code } : {}),
|
|
1789
1808
|
message: boundedRedactedSummary(thrownText(err), 500),
|
|
1790
1809
|
},
|
|
1791
1810
|
stats: { turns: 0, tokens: 0, costMicroUsd: 0, usageMissing: true },
|
|
1792
1811
|
}, label).catch(() => undefined);
|
|
1793
|
-
if (!((err
|
|
1812
|
+
if (!((thrownIs(err, WorkflowBudgetExceededError) || thrownIs(err, WorkflowAgentParkedError)) && rec.startedAt === undefined))
|
|
1794
1813
|
await journaled;
|
|
1795
1814
|
bceTerminal(callKey, "failed", rec.output ?? (thrownText(err)), rec.sessionId, rec.stats);
|
|
1796
1815
|
}
|
|
@@ -1955,9 +1974,10 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
1955
1974
|
releaseLeg();
|
|
1956
1975
|
return await parkAgentLeg(rec, drive.paused, [], false);
|
|
1957
1976
|
}
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1977
|
+
const spawnMessage = thrownMessageOf(err);
|
|
1978
|
+
if (!finalized && rec.errorMessage === undefined && spawnMessage !== undefined)
|
|
1979
|
+
rec.errorMessage = boundedRedactedSummary(spawnMessage, MAX_TRANSCRIPT_CHARS);
|
|
1980
|
+
if (!finalized && thrownIs(err, WorkflowAgentBlockedError)) {
|
|
1961
1981
|
rec.errorCode = WORKFLOW_SPAWN_BLOCKED_ERROR_CODE;
|
|
1962
1982
|
rec.errorMessage = boundedRedactedSummary(err.message, MAX_TRANSCRIPT_CHARS);
|
|
1963
1983
|
void journalAppend(callKey, {
|
|
@@ -2210,8 +2230,9 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
2210
2230
|
prior = await opts.store.get(opts.resumeFromRunId);
|
|
2211
2231
|
}
|
|
2212
2232
|
catch (err) {
|
|
2213
|
-
const
|
|
2214
|
-
const
|
|
2233
|
+
const errName = thrownNameOf(err);
|
|
2234
|
+
const errCode = errName !== undefined ? readMember(err, "code") : undefined;
|
|
2235
|
+
const errClass = errName !== undefined ? `${errName}${typeof errCode === "string" ? `/${errCode}` : ""}` : typeof err;
|
|
2215
2236
|
throw new WorkflowParkRefusal("workflow.park_truth_unreadable", `startWorkflow: resume from "${fromRunId}" was REFUSED — the prior run's record could not be read from the run store (${errClass}), so its parks cannot be proven.`, { reason: "store_threw" });
|
|
2216
2237
|
}
|
|
2217
2238
|
if (prior !== null && prior.scope !== scope)
|
|
@@ -2376,7 +2397,7 @@ export function startWorkflow(runner, fn, opts = {}, internals) {
|
|
|
2376
2397
|
run.status = "failed";
|
|
2377
2398
|
run.completionId ??= uuidv7();
|
|
2378
2399
|
run.endedAt = now();
|
|
2379
|
-
if (parkedLeg !== undefined && !(err
|
|
2400
|
+
if (parkedLeg !== undefined && !thrownIs(err, WorkflowAgentParkedError))
|
|
2380
2401
|
err = parkedError();
|
|
2381
2402
|
run.error = thrownText(err);
|
|
2382
2403
|
closeAbandonedAgents(run.endedAt);
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createHash, randomBytes } from "node:crypto";
|
|
2
2
|
import { appendFileSync, closeSync, existsSync, fsyncSync, openSync, readdirSync, readFileSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { thrownText } from "../../core/thrown-value.js";
|
|
4
5
|
import { applyFileRestoreViaEnv, boundaryPublishVerdict, worldStillMatchesMint, captureFileBackupViaEnv, modeProvenDifferent, previewFileDelta, describeTrackKey, fileHistoryExportDigest, resolveTrackKey, trackKeyOf, validateFileHistoryExport, } from "../../core/file-history-store.js";
|
|
5
6
|
import { fileHistoryBoundariesToKeep, resolveFileHistoryRetention } from "../../core/file-history-retention.js";
|
|
6
7
|
import { atomicWriteFile, ensureDir, sanitizePathComponent, sanitizeScope, writeThenLink } from "./fs-atomic.js";
|
|
@@ -456,7 +457,7 @@ export class FileFileHistoryStore {
|
|
|
456
457
|
return { ok: true, minted: true };
|
|
457
458
|
}
|
|
458
459
|
catch (err) {
|
|
459
|
-
return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${err
|
|
460
|
+
return { ok: false, error: { code: "track_failed", message: `first-touch record for ${absPath} could not be persisted: ${thrownText(err)}` } };
|
|
460
461
|
}
|
|
461
462
|
}
|
|
462
463
|
async annulTrack(scope, absPath, root, verify) {
|
|
@@ -511,7 +512,7 @@ export class FileFileHistoryStore {
|
|
|
511
512
|
return { ok: true };
|
|
512
513
|
}
|
|
513
514
|
catch (err) {
|
|
514
|
-
return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${err
|
|
515
|
+
return { ok: false, error: { code: "track_failed", message: `annulling the first-touch record for ${absPath} failed: ${thrownText(err)}` } };
|
|
515
516
|
}
|
|
516
517
|
}
|
|
517
518
|
scopeIsEmptySync(scope) {
|
|
@@ -677,7 +678,7 @@ export class FileFileHistoryStore {
|
|
|
677
678
|
}
|
|
678
679
|
catch (err) {
|
|
679
680
|
nestedSetAdd(this.spentAttempts, scope, entryId);
|
|
680
|
-
return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${err
|
|
681
|
+
return { ok: false, error: { code: "snapshot_failed", message: `boundary for entry "${entryId}" could not be committed: ${thrownText(err)}` } };
|
|
681
682
|
}
|
|
682
683
|
finally {
|
|
683
684
|
this.activeCaptures.get(scope)?.delete(entryId);
|
|
@@ -754,7 +755,7 @@ export class FileFileHistoryStore {
|
|
|
754
755
|
});
|
|
755
756
|
}
|
|
756
757
|
catch (err) {
|
|
757
|
-
applied = { outcome: "failed", reason: err
|
|
758
|
+
applied = { outcome: "failed", reason: thrownText(err) };
|
|
758
759
|
}
|
|
759
760
|
if (applied.outcome === "applied")
|
|
760
761
|
ledger.filesChanged.push(key);
|
|
@@ -771,7 +772,7 @@ export class FileFileHistoryStore {
|
|
|
771
772
|
}
|
|
772
773
|
catch (err) {
|
|
773
774
|
const touched = ledger.filesChanged.length > 0 || ledger.identicalSkipped.length > 0 || ledger.refused.length > 0 || ledger.failed.length > 0;
|
|
774
|
-
return { outcome: touched ? "partial" : "failed", ...ledger, error: { code: "restore_failed", message: err
|
|
775
|
+
return { outcome: touched ? "partial" : "failed", ...ledger, error: { code: "restore_failed", message: thrownText(err) } };
|
|
775
776
|
}
|
|
776
777
|
}
|
|
777
778
|
async canRestore(scope, entryId) {
|
|
@@ -889,7 +890,7 @@ export class FileFileHistoryStore {
|
|
|
889
890
|
this.writeTracked(scope, tracked);
|
|
890
891
|
}
|
|
891
892
|
catch (err) {
|
|
892
|
-
this.disclose(this.trackedPath(scope), `version-chain trim could not be committed (${err
|
|
893
|
+
this.disclose(this.trackedPath(scope), `version-chain trim could not be committed (${thrownText(err)}) — trim skipped this pass; untrimmed versions keep their blobs live`);
|
|
893
894
|
}
|
|
894
895
|
}
|
|
895
896
|
this.collectBlobs();
|
|
@@ -1091,7 +1092,7 @@ export class FileFileHistoryStore {
|
|
|
1091
1092
|
return { ok: true };
|
|
1092
1093
|
}
|
|
1093
1094
|
catch (err) {
|
|
1094
|
-
return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${err
|
|
1095
|
+
return { ok: false, error: { code: "adopt_failed", message: `adoptScope failed: ${thrownText(err)}` } };
|
|
1095
1096
|
}
|
|
1096
1097
|
}
|
|
1097
1098
|
async exportHistory(scope) {
|
|
@@ -1151,7 +1152,7 @@ export class FileFileHistoryStore {
|
|
|
1151
1152
|
return await this.runImport(scope, data, srcGetBlob, importJournal, identicalRepublish);
|
|
1152
1153
|
}
|
|
1153
1154
|
catch (err) {
|
|
1154
|
-
return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${err
|
|
1155
|
+
return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${thrownText(err)}` } };
|
|
1155
1156
|
}
|
|
1156
1157
|
}
|
|
1157
1158
|
async runImport(scope, data, srcGetBlob, importJournal, identicalRepublish) {
|
|
@@ -1178,7 +1179,7 @@ export class FileFileHistoryStore {
|
|
|
1178
1179
|
bytes = await srcGetBlob(v.blobHash);
|
|
1179
1180
|
}
|
|
1180
1181
|
catch (err) {
|
|
1181
|
-
return { ok: false, error: { code: "unsupported_format", message: `source blob ${v.blobHash} fetch failed: ${err
|
|
1182
|
+
return { ok: false, error: { code: "unsupported_format", message: `source blob ${v.blobHash} fetch failed: ${thrownText(err)}` } };
|
|
1182
1183
|
}
|
|
1183
1184
|
if (bytes === undefined)
|
|
1184
1185
|
return { ok: false, error: { code: "not_found", message: `source blob ${v.blobHash} is missing — the envelope's graph cannot be completed, so nothing is published` } };
|
|
@@ -1222,7 +1223,7 @@ export class FileFileHistoryStore {
|
|
|
1222
1223
|
}
|
|
1223
1224
|
catch (err) {
|
|
1224
1225
|
safeRm(staging);
|
|
1225
|
-
return { ok: false, error: { code: "adopt_failed", message: `importHistory could not publish the staged graph for "${scope}": ${err
|
|
1226
|
+
return { ok: false, error: { code: "adopt_failed", message: `importHistory could not publish the staged graph for "${scope}": ${thrownText(err)} — nothing was published (a local storage fault, not a malformed envelope)` } };
|
|
1226
1227
|
}
|
|
1227
1228
|
if (published !== "published") {
|
|
1228
1229
|
safeRm(staging);
|
|
@@ -1238,7 +1239,7 @@ export class FileFileHistoryStore {
|
|
|
1238
1239
|
return { ok: true };
|
|
1239
1240
|
}
|
|
1240
1241
|
catch (err) {
|
|
1241
|
-
return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${err
|
|
1242
|
+
return { ok: false, error: { code: "unsupported_format", message: `importHistory failed: ${thrownText(err)}` } };
|
|
1242
1243
|
}
|
|
1243
1244
|
finally {
|
|
1244
1245
|
safeRm(importJournal);
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_comment": "design/87 L3 — frozen public export surface of src/index.ts (name -> kind). DO NOT edit by hand to silence a red test. A removed/changed entry = a SemVer-BREAKING change; bump MAJOR and update this fixture in the SAME commit (design/87 §4.2 / §5.2). Regenerate via REGEN in test/export-surface.test.ts.",
|
|
3
3
|
"_tierComment": "#435 v1 — machine-readable layering of the public surface: stable = demonstrated by README.md / src/examples; internal = an `Internal`-marked name or a runner/engine deep-subtree declaration (the model seam src/engine/llm is excluded — it is the BYOM contract, not an engine internal); advanced = a supported export the front door does not walk you through. THIS IS AN INITIAL HEURISTIC, derived mechanically and expected to be refined ticket by ticket: no human reviewed these 1700+ entries one by one, and nothing here claims otherwise. Known bias: a short or English-word export name (ok, err, Result, Usage) can match ordinary prose in README.md and land `stable` on a coincidence. Every export MUST carry a tier — a new export with no row fails the gate in export-surface.test.ts.",
|
|
4
|
-
"count":
|
|
4
|
+
"count": 2397,
|
|
5
5
|
"exports": {
|
|
6
6
|
"A2ATaskState": "type",
|
|
7
7
|
"A2ATaskStateReversal": "type",
|
|
@@ -1867,6 +1867,7 @@
|
|
|
1867
1867
|
"devWorkflowScriptRunner": "variable",
|
|
1868
1868
|
"diffToolRoster": "function",
|
|
1869
1869
|
"directoryRuleAdmits": "function",
|
|
1870
|
+
"displayUrlOf": "function",
|
|
1870
1871
|
"distilledEquals": "function",
|
|
1871
1872
|
"dotAtOrBelowFrontier": "function",
|
|
1872
1873
|
"drainMemoryAnnouncements": "function",
|
|
@@ -2076,7 +2077,6 @@
|
|
|
2076
2077
|
"namespacedRuleNameCovers": "function",
|
|
2077
2078
|
"nextSyncBaseline": "function",
|
|
2078
2079
|
"normalizeAgentName": "function",
|
|
2079
|
-
"normalizeBaseUrl": "function",
|
|
2080
2080
|
"normalizeForExactMatch": "function",
|
|
2081
2081
|
"normalizeMemorySpec": "function",
|
|
2082
2082
|
"normalizePeerName": "function",
|
|
@@ -2242,6 +2242,7 @@
|
|
|
2242
2242
|
"resolveReadDenyBuiltins": "function",
|
|
2243
2243
|
"resolveReasoning": "function",
|
|
2244
2244
|
"resolveReasoningProfile": "function",
|
|
2245
|
+
"resolveRequestRoot": "function",
|
|
2245
2246
|
"resolveRouteCredential": "function",
|
|
2246
2247
|
"resolveSubagentTranscriptTier": "function",
|
|
2247
2248
|
"resolveTaskLimits": "function",
|
|
@@ -2255,6 +2256,7 @@
|
|
|
2255
2256
|
"retryBackoffMs": "function",
|
|
2256
2257
|
"riskSeverity": "function",
|
|
2257
2258
|
"rosterMemberBoundProblem": "function",
|
|
2259
|
+
"routeKeyOf": "function",
|
|
2258
2260
|
"routePairingStatus": "function",
|
|
2259
2261
|
"routePeerDeliveryReceipt": "function",
|
|
2260
2262
|
"routePeerDroppedReceipt": "function",
|
|
@@ -4264,6 +4266,7 @@
|
|
|
4264
4266
|
"devWorkflowScriptRunner": "stable",
|
|
4265
4267
|
"diffToolRoster": "advanced",
|
|
4266
4268
|
"directoryRuleAdmits": "advanced",
|
|
4269
|
+
"displayUrlOf": "advanced",
|
|
4267
4270
|
"distilledEquals": "stable",
|
|
4268
4271
|
"dotAtOrBelowFrontier": "advanced",
|
|
4269
4272
|
"drainMemoryAnnouncements": "advanced",
|
|
@@ -4473,7 +4476,6 @@
|
|
|
4473
4476
|
"namespacedRuleNameCovers": "advanced",
|
|
4474
4477
|
"nextSyncBaseline": "advanced",
|
|
4475
4478
|
"normalizeAgentName": "advanced",
|
|
4476
|
-
"normalizeBaseUrl": "advanced",
|
|
4477
4479
|
"normalizeForExactMatch": "internal",
|
|
4478
4480
|
"normalizeMemorySpec": "advanced",
|
|
4479
4481
|
"normalizePeerName": "advanced",
|
|
@@ -4639,6 +4641,7 @@
|
|
|
4639
4641
|
"resolveReadDenyBuiltins": "advanced",
|
|
4640
4642
|
"resolveReasoning": "advanced",
|
|
4641
4643
|
"resolveReasoningProfile": "advanced",
|
|
4644
|
+
"resolveRequestRoot": "stable",
|
|
4642
4645
|
"resolveRouteCredential": "advanced",
|
|
4643
4646
|
"resolveSubagentTranscriptTier": "advanced",
|
|
4644
4647
|
"resolveTaskLimits": "internal",
|
|
@@ -4652,6 +4655,7 @@
|
|
|
4652
4655
|
"retryBackoffMs": "advanced",
|
|
4653
4656
|
"riskSeverity": "advanced",
|
|
4654
4657
|
"rosterMemberBoundProblem": "advanced",
|
|
4658
|
+
"routeKeyOf": "advanced",
|
|
4655
4659
|
"routePairingStatus": "advanced",
|
|
4656
4660
|
"routePeerDeliveryReceipt": "advanced",
|
|
4657
4661
|
"routePeerDroppedReceipt": "advanced",
|
|
@@ -0,0 +1,249 @@
|
|
|
1
|
+
{
|
|
2
|
+
"repo": "core",
|
|
3
|
+
"version": "7.24.0",
|
|
4
|
+
"from": "6b1dcaefbdd7abf1a39f17d67c3b926a94ddc75f",
|
|
5
|
+
"to": "v7.24.0",
|
|
6
|
+
"added": [
|
|
7
|
+
{
|
|
8
|
+
"name": "displayUrlOf",
|
|
9
|
+
"kind": "function",
|
|
10
|
+
"tier": "advanced",
|
|
11
|
+
"at": [
|
|
12
|
+
"src/brain/route-adjudicator.ts:136",
|
|
13
|
+
"src/index.ts:3207"
|
|
14
|
+
],
|
|
15
|
+
"criteriaCovered": false,
|
|
16
|
+
"breaking": false
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "resolveRequestRoot",
|
|
20
|
+
"kind": "function",
|
|
21
|
+
"tier": "stable",
|
|
22
|
+
"at": [
|
|
23
|
+
"src/brain/route-adjudicator.ts:230",
|
|
24
|
+
"src/index.ts:3209"
|
|
25
|
+
],
|
|
26
|
+
"criteriaCovered": false,
|
|
27
|
+
"breaking": false
|
|
28
|
+
},
|
|
29
|
+
{
|
|
30
|
+
"name": "routeKeyOf",
|
|
31
|
+
"kind": "function",
|
|
32
|
+
"tier": "advanced",
|
|
33
|
+
"at": [
|
|
34
|
+
"src/brain/route-adjudicator.ts:96",
|
|
35
|
+
"src/index.ts:3206"
|
|
36
|
+
],
|
|
37
|
+
"criteriaCovered": false,
|
|
38
|
+
"breaking": false
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
"removed": [
|
|
42
|
+
{
|
|
43
|
+
"name": "normalizeBaseUrl",
|
|
44
|
+
"kind": "function",
|
|
45
|
+
"tier": "advanced",
|
|
46
|
+
"at": [
|
|
47
|
+
"src/brain/route-adjudicator.ts:60",
|
|
48
|
+
"src/index.ts:3206"
|
|
49
|
+
],
|
|
50
|
+
"breaking": true
|
|
51
|
+
}
|
|
52
|
+
],
|
|
53
|
+
"changed": [],
|
|
54
|
+
"narrowed": [
|
|
55
|
+
{
|
|
56
|
+
"id": "F1",
|
|
57
|
+
"source": "behaviorFlips.summary",
|
|
58
|
+
"text": "BREAKING export removal, plus a NARROWING of what three already-shipped members carry (#950). `normalizeBaseUrl` is REMOVED; the same function ships as `routeKeyOf` (the pairing law's comparison value, query byte-preserved), and two new exports join it — `displayUrlOf` (the only spelling of a request root allowed into text) and `resolveRequestRoot` (the request-root law itself, exported because a custom brain is a seat that builds one). `RouteRefusalDetail.{entryBaseUrl, requestBaseUrl, configBaseUrl}`, `fixHint`, the exported `routeRefusalText` and the `route.base_url_changed_key_unchanged` notice now carry DISPLAY spellings: userinfo dropped, EVERY query value replaced with `«redacted»`, query NAMES kept (dropping the query whole would render two roots that differ only in their query as one string, so the refusal about that very pair would read `targets X … paired with X`), and a BARE query token (`?<token>`, no `=`) rendered as one placeholder with no name. An unparseable root is withheld by POSITION in all three credential positions — userinfo, query and fragment. The ARRIVAL-time refusal took the same rule: `assertServableRequestRoot` used to hand-compose its own spelling (`${protocol}//${host}${pathname}`), and for a NON-SPECIAL scheme `pathname` IS the opaque body, so `weird:u:<secret>@h/v1`, `blob:https://u:<secret>@h/x` and `mailto:u:<secret>@h` echoed the credential in the very sentence that refuses them (`ftp:`/`file:` are special schemes and did not — the leak was shape-dependent, which is why a spot fix at one call site would have missed it). It now names its root through `displayUrlOf`, the one renderer. Two predicates make the split explicit: `servableParse` (http/https only) answers the KEY's question, `composableParse` (has an authority, or a real path) answers the RENDERING's — an opaque body has neither and falls to the positional arm. Who needs it: any deployment whose gateway root carries a credential in the query (`?api_key=<secret>` rode `fixHint`, all three detail members, `routeRefusalText` and the catalog-swap notice into whatever a host logs). Who is hurt: a consumer importing `normalizeBaseUrl` (server, `src/hooks/hook-llm.ts` — a pure comparison, so a rename is the whole migration), and any consumer COMPARING those three members against a catalog. Compensation: `routeKeyOf` is the same function under the name that says what it is; identity is computed with it; the refusal codes, the two-leg disposition and every posture word are byte-unchanged, and a conformance vector (`deployment-mismatch-query-differs`) was added so an origin+path-only implementation is caught pairing a credential with someone else's tenant. One sibling seat took the same rule in the same pass: `primaryActivityArg` (`src/core/arg-summary.ts`) rendered a URL as `origin + pathname`, and for an OPAQUE-body scheme `origin` is the string `\"null\"` while `host` is empty — so `blob:https://u:<secret>@h/v1` came out as `nullu:<secret>@h/v1`, gluing a literal `null` onto a credential it had just failed to drop. The arm is now judged on `host !== \"\"` and falls to the same positional withholding."
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"id": "F2",
|
|
62
|
+
"source": "behaviorFlips.summary",
|
|
63
|
+
"text": "ADDITIVE wire key, plus one NARROWING of a TypeScript guarantee (#946). The `compacted` event gains `freedTokens?: number` — the engine's own structural delta (one structural sum over the pre-messages minus the same sum over the post-messages), clamped >= 0 at the mint, published from all three lanes (turn boundary, prompt-too-long recovery, end-of-task settle) through ONE `mintCompactedEvent`. `Hooks.postCompact`'s `PostCompactContext` gains the same member from the same source. `tokensAfter` and `triggerTokensBefore` stay, un-clamped and un-deleted, retyped as DIAGNOSTICS with `not subtractable` said at the type: the trigger gate reads a usage-ANCHORED figure whenever the provider's last usage is fresh while the post size is always structural + the fixed prompt overhead, so their difference mixes coordinates and goes negative on ordinary runs (measured: 3037 - 4591 = -1554 on the plain auto lane; 4237 - 4987 = -750 on a short-session `/compact`). Who needs it: any consumer rendering a context meter — the cli `/context` line drew its arrow from the two diagnostics. Who is hurt: a caller doing arithmetic on `RunnerDeps.onCompaction`'s `freedTokens`, which is now optional (it previously carried `preChars` when the post measurement failed — a fabricated `fully effective` that is never true of a landing which leaves a summary behind), and the two anti-thrash floor sites that used the `triggerTokens - freedTokens` fallback. Compensation: purely additive on the wire; absence is information (`freedTokens` missing = the post measurement failed, render `unknown`, never `0`); no measurement now means the floor does not move, the same non-suppressing direction the fabricated value was chosen for, without the claim."
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "F4",
|
|
67
|
+
"source": "behaviorFlips.summary",
|
|
68
|
+
"text": "NARROWING of the member re-dispatch ladder, no key and no text change (#941). `runTurn` retried every member turn that did not settle completed-with-text, once, with the identical objective, prompt, model and toolset — including terminals that cannot come out differently. The retry is now refused only for the two terminals the engine can POSITIVELY identify as deterministic: a `blocked` cause (a host `UserPromptSubmit` denial, taken at its word), and a `failed` whose code the governance table adjudicated TERMINAL, read off `classifySubagentError` — no second opinion about any code. Everything else keeps its second attempt, INCLUDING that classifier's `logic` bucket, which is an ELSE-ARM: `stream_torn` (a response lost before any content or finish reason, the textbook re-issuable failure) lives there and lost its retry under a first draft of this change. Who needs it: any deployment paying for team discussions — such a turn now costs one child run instead of two (measured on a scripted runner: 3 runs instead of 6 for a two-member, one-round discussion). Who is hurt: nobody observably — the `[unavailable: <status>/<code>]` marker, the discussion, the transcript and the budget accounting are unchanged in shape. Compensation: the deliberate divergence from the classifier's own `retryable` on two rows is stated at the seat, and the row-level fix belongs in that table (ticket #964), not at this seat."
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
"id": "F5",
|
|
72
|
+
"source": "behaviorFlips.summary",
|
|
73
|
+
"text": "FAILURE FACE, plus one NARROWING stated rather than announced (#942). ELEVEN sites still read a value the engine did not construct bare, and three were load-bearing: a third-party `execute`'s RETURN value was read by a `normalizeContent` running OUTSIDE `defineTool`'s own try, so a member behind a throwing getter, a revoked proxy handed back as `content`, or one hostile content block raised a raw `TypeError` past the tool wrapper; and `reduceToolEnd` (`src/core/runner/turn-attachments.ts:454`, the TENTH station, found on the real lane rather than in the diff) read a third-party `details` inside the harness's tool_end handler, outside that try and a SECOND time after the result store already walked the card — measured end to end with a Runner, a scripted brain and a third-party `ToolSpec`: a `type` getter that answered once and raised on the second read ended the whole run as `failed` / `provider.error` on turn one, and the model never reached turn two. The ELEVENTH is the ERROR-frame code lift (`src/core/runner/tool-end-body.ts:99-104`), which read `result.details` and then its `code` / `errorKind` / `delivered` bare — on a failure path, in the same handler, after the result store had already walked the same card once, so a member raising on that SECOND read ended the run. All of them now read through `readMember` / `isErrorLike`, with two structural changes rather than more guards: `defineTool`'s whole result-building path runs inside the one try it already had, and `errorCodeOf`'s coarse try is replaced by per-member reads so an unreadable link costs THAT link and the walk continues (`{ code: <throws>, cause: { code: \"x\" } }` now answers `x`, and used to answer nothing). The class-level rules have ONE home each beside the other readers (`thrownIs`, `thrownName`), four private copies folded in. Who needs it: any deployment mounting a BYOM or MCP tool whose result crosses a host seam or a realm boundary. Who is hurt: a consumer text-matching the failure words for a HOSTILE value (three text changes, each named in the changelog), and a BYOM tool returning a truthy non-`true` `terminate` — now read `=== true` rather than `?? false`, the one unannounced narrowing, stated here because every in-tree consumer already tested `=== true`. Compensation: no wire key, no code word and no text change for any readable value. A REGRESSION this batch introduced was caught by the merge-tree review and fixed in it: `readListLength` accepted any value carrying a numeric `length`, so a third-party card whose `newTodos` was the STRING `\"bad card\"` read as a 8-element list and CLEARED the todo snapshot. A list is an object with a length; a string is not one. Pinned with a Proxy-over-array positive control, so the guard cannot be tightened into refusing a real list."
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
"id": "F6",
|
|
77
|
+
"source": "behaviorFlips.summary",
|
|
78
|
+
"text": "NARROWING at construction, no wire key (#943). `openAiCompatChatSeat` screened its `baseUrl` for emptiness and nothing else, then built `${baseUrl}/chat/completions` by hand: a root carrying userinfo, a `file:`/`ftp:` scheme, or a spelling that is not a URL at all constructed cleanly and failed at `fetch` as a transport error indistinguishable from an outage, so the consolidation driver retried it for the whole backoff ladder. #933 closed the same three shapes at the three brain factories; this seat builds a request root too and was not asked. The root now goes through `assertServableRequestRoot`, the same law, judged at CONSTRUCTION, with the trailing-slash strip moved there too so the root is read once instead of once per call. The ENVELOPE stays this seat's (`config.memory_consolidation_driver`, like its sibling api-key and alias-model screens) because a host screens on that code and the driver routes config-class throws differently from transport ones; only the envelope is local, the question and its wording are the adjudicator's, and the original refusal is kept as `cause`. Who needs it: any deployment wiring `RunnerDeps.memoryConsolidationDriver.chat` as an endpoint triple. Who is hurt: a deployment whose distillation seat carried one of the three bad roots and relied on it failing late — it now refuses where it is configured. Compensation: a userinfo root is named as `[redacted-credentials]@host`, never echoed; servable roots are untouched."
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
"id": "F9",
|
|
82
|
+
"source": "behaviorFlips.summary",
|
|
83
|
+
"text": "TWO VALUE FLIPS on the credential egress/refusal vocabularies, one of them a NARROWING of what the memory write face accepts, no wire key (#954). The two vendor tables had diverged, measured on synthetic shapes: a `github_pat_`-shaped token rode `scrubSecrets` (`src/core/arg-summary.ts`) and `redactSecrets` (`src/core/untrusted-egress.ts`) VERBATIM — the prefixed-token row is structurally unable to match that spelling — while `detectSecret` (`src/core/memory.ts`) recognised it; in the reverse direction an `hf_`-shaped token was masked on the way out but ACCEPTED by the memory write face. The EGRESS face now strips `github_pat_`, an Azure `AccountKey=` and a PGP `PRIVATE KEY BLOCK` banner where they used to ride in clear, and the memory WRITE door now throws `MemoryGateError(\"memory.secret_detected\")` on an `hf_` token of twenty or more characters CARRYING A DIGIT, at all three write entrances (`remember`, and consolidation's ADD and UPDATE). A two-way reconciliation pin is added over the ROW SETS, their FLAGS and their TIERS — not just the rows: every vendor shape in the refusal table must be masked by the egress table, every vendor shape in the egress table must be refused by (or explicitly exempted from) the refusal table, a masking row must mask EVERY occurrence in one rendering rather than the first, and a row added to a composed tier outside the egress pass list is caught by the kind list. A vendor added in ONE place alone reds. Who needs it: any deployment whose MCP failure text, delegation step summaries, tool-argument summaries or memory writes can carry a vendor credential. Who is hurt: a deployment relying on an `hf_`-shaped value being writable into memory verbatim, and a consumer byte-comparing an egress rendering that now carries `[redacted]`. Compensation: the digit discriminator keeps an ordinary `hf_`-prefixed IDENTIFIER writable; shapes already recognised by both tables (`ghp_`, `AKIA`, `AIza`) are byte-unchanged; the point repair stops the divergence until a single `CREDENTIAL_VOCABULARY` closes it for good (design ticket #958). A qualifier alphabet mismatch was found in the same pass: the refuse-write banner accepted a DIGIT in the qualifier (`-----BEGIN RSA2 PRIVATE KEY-----`) while the egress banner did not, so that shape was refused at the write door and rode out in clear. Both faces now carry the same alphabet, and the parity nail's mirror was corrected with them."
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"closedSetMembers": [],
|
|
87
|
+
"closedSetsUnreadable": [],
|
|
88
|
+
"typeKeys": [
|
|
89
|
+
{
|
|
90
|
+
"type": "PostCompactContext",
|
|
91
|
+
"at": [
|
|
92
|
+
"src/core/hooks.ts:711"
|
|
93
|
+
],
|
|
94
|
+
"added": [
|
|
95
|
+
"freedTokens"
|
|
96
|
+
],
|
|
97
|
+
"removed": [],
|
|
98
|
+
"breaking": false,
|
|
99
|
+
"criteriaCovered": true
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"type": "TaskEvent",
|
|
103
|
+
"at": [
|
|
104
|
+
"src/core/task-event.ts:265"
|
|
105
|
+
],
|
|
106
|
+
"added": [
|
|
107
|
+
"compacted.freedTokens"
|
|
108
|
+
],
|
|
109
|
+
"removed": [],
|
|
110
|
+
"breaking": false,
|
|
111
|
+
"criteriaCovered": true
|
|
112
|
+
}
|
|
113
|
+
],
|
|
114
|
+
"declarationMoves": [
|
|
115
|
+
{
|
|
116
|
+
"name": "resolveRequestRoot",
|
|
117
|
+
"kind": "function",
|
|
118
|
+
"onSurface": true,
|
|
119
|
+
"from": [
|
|
120
|
+
"src/brain/route-adjudicator.ts"
|
|
121
|
+
],
|
|
122
|
+
"to": [
|
|
123
|
+
"src/brain/route-adjudicator.ts",
|
|
124
|
+
"src/index.ts"
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
"mintMoves": [],
|
|
129
|
+
"criteriaObserves": [
|
|
130
|
+
{
|
|
131
|
+
"kind": "engineNoticeCode",
|
|
132
|
+
"name": "route.base_url_changed_key_unchanged",
|
|
133
|
+
"assertions": [
|
|
134
|
+
"G1.b"
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"kind": "taskEventField",
|
|
139
|
+
"name": "compacted.freedTokens",
|
|
140
|
+
"assertions": [
|
|
141
|
+
"G2.a"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
{
|
|
145
|
+
"kind": "taskEventField",
|
|
146
|
+
"name": "task_progress.currentAction",
|
|
147
|
+
"assertions": [
|
|
148
|
+
"G6.a"
|
|
149
|
+
]
|
|
150
|
+
},
|
|
151
|
+
{
|
|
152
|
+
"kind": "taskEventField",
|
|
153
|
+
"name": "tool_end.errorCode",
|
|
154
|
+
"assertions": [
|
|
155
|
+
"G6.b"
|
|
156
|
+
]
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"kind": "taskEventField",
|
|
160
|
+
"name": "tool_end.isError",
|
|
161
|
+
"assertions": [
|
|
162
|
+
"G4.a",
|
|
163
|
+
"G6.b"
|
|
164
|
+
]
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
"kind": "taskEventField",
|
|
168
|
+
"name": "tool_end.output",
|
|
169
|
+
"assertions": [
|
|
170
|
+
"G3.b",
|
|
171
|
+
"G6.a"
|
|
172
|
+
]
|
|
173
|
+
},
|
|
174
|
+
{
|
|
175
|
+
"kind": "taskEventField",
|
|
176
|
+
"name": "tool_end.structured",
|
|
177
|
+
"assertions": [
|
|
178
|
+
"G3.b"
|
|
179
|
+
]
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
"kind": "typeMember",
|
|
183
|
+
"name": "ListAgentsRow.state",
|
|
184
|
+
"assertions": [
|
|
185
|
+
"G3.a"
|
|
186
|
+
]
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
"kind": "typeMember",
|
|
190
|
+
"name": "PostCompactContext.freedTokens",
|
|
191
|
+
"assertions": [
|
|
192
|
+
"G2.b"
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
"kind": "typeMember",
|
|
197
|
+
"name": "RouteRefusalDetail.entryBaseUrl",
|
|
198
|
+
"assertions": [
|
|
199
|
+
"G1.a"
|
|
200
|
+
]
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
"kind": "typeMember",
|
|
204
|
+
"name": "RouteRefusalDetail.fixHint",
|
|
205
|
+
"assertions": [
|
|
206
|
+
"G1.a"
|
|
207
|
+
]
|
|
208
|
+
},
|
|
209
|
+
{
|
|
210
|
+
"kind": "typeMember",
|
|
211
|
+
"name": "RouteRefusalDetail.requestBaseUrl",
|
|
212
|
+
"assertions": [
|
|
213
|
+
"G1.b"
|
|
214
|
+
]
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
"kind": "typeMember",
|
|
218
|
+
"name": "RunnerDeps.memoryConsolidationDriver",
|
|
219
|
+
"assertions": [
|
|
220
|
+
"G5.a"
|
|
221
|
+
]
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
"kind": "typeMember",
|
|
225
|
+
"name": "RunnerDeps.onError",
|
|
226
|
+
"assertions": [
|
|
227
|
+
"G5.b"
|
|
228
|
+
]
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
"kind": "typeMember",
|
|
232
|
+
"name": "TaskResult.terminal.code",
|
|
233
|
+
"assertions": [
|
|
234
|
+
"G4.b"
|
|
235
|
+
]
|
|
236
|
+
}
|
|
237
|
+
],
|
|
238
|
+
"consumersHint": {
|
|
239
|
+
"cli": [],
|
|
240
|
+
"server": [],
|
|
241
|
+
"sdk": [],
|
|
242
|
+
"note": "NOT SCANNED: sema-cli, sema-server, sema-sdk — an empty list for those repos means \"not checked out\", not \"no consumer\""
|
|
243
|
+
},
|
|
244
|
+
"breakingCount": 1,
|
|
245
|
+
"breakingItems": [
|
|
246
|
+
"export removed: normalizeBaseUrl (function)"
|
|
247
|
+
],
|
|
248
|
+
"toResolvedAt": "f1abe12bc6c9dfcc40b6c68dde97c4b7a201284f"
|
|
249
|
+
}
|