@runtypelabs/sdk 4.8.1 → 4.10.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/dist/index.cjs CHANGED
@@ -3,9 +3,6 @@ var __defProp = Object.defineProperty;
3
3
  var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
4
  var __getOwnPropNames = Object.getOwnPropertyNames;
5
5
  var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __esm = (fn, res) => function __init() {
7
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
- };
9
6
  var __export = (target, all) => {
10
7
  for (var name in all)
11
8
  __defProp(target, name, { get: all[name], enumerable: true });
@@ -20,17 +17,96 @@ var __copyProps = (to, from, except, desc) => {
20
17
  };
21
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
19
 
23
- // src/stream-utils.ts
24
- var stream_utils_exports = {};
25
- __export(stream_utils_exports, {
26
- flowErrorMessage: () => flowErrorMessage,
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ AgentDriftError: () => AgentDriftError,
24
+ AgentEnsureConflictError: () => AgentEnsureConflictError,
25
+ AgentVersionsEndpoint: () => AgentVersionsEndpoint,
26
+ AgentsEndpoint: () => AgentsEndpoint,
27
+ AgentsNamespace: () => AgentsNamespace,
28
+ AnalyticsEndpoint: () => AnalyticsEndpoint,
29
+ ApiKeysEndpoint: () => ApiKeysEndpoint,
30
+ AppsEndpoint: () => AppsEndpoint,
31
+ BatchBuilder: () => BatchBuilder,
32
+ BatchesNamespace: () => BatchesNamespace,
33
+ BillingEndpoint: () => BillingEndpoint,
34
+ ChatEndpoint: () => ChatEndpoint,
35
+ ClientBatchBuilder: () => ClientBatchBuilder,
36
+ ClientEvalBuilder: () => ClientEvalBuilder,
37
+ ClientFlowBuilder: () => ClientFlowBuilder,
38
+ ClientTokensEndpoint: () => ClientTokensEndpoint,
39
+ ContextTemplatesEndpoint: () => ContextTemplatesEndpoint,
40
+ ConversationsEndpoint: () => ConversationsEndpoint,
41
+ DispatchEndpoint: () => DispatchEndpoint,
42
+ EvalBuilder: () => EvalBuilder,
43
+ EvalEndpoint: () => EvalEndpoint,
44
+ EvalRunner: () => EvalRunner,
45
+ EvalsNamespace: () => EvalsNamespace,
46
+ FlowBuilder: () => FlowBuilder,
47
+ FlowDriftError: () => FlowDriftError,
48
+ FlowEnsureConflictError: () => FlowEnsureConflictError,
49
+ FlowResult: () => FlowResult,
50
+ FlowStepsEndpoint: () => FlowStepsEndpoint,
51
+ FlowVersionsEndpoint: () => FlowVersionsEndpoint,
52
+ FlowsEndpoint: () => FlowsEndpoint,
53
+ FlowsNamespace: () => FlowsNamespace,
54
+ IntegrationsEndpoint: () => IntegrationsEndpoint,
55
+ LEDGER_ARTIFACT_LINE_PREFIX: () => LEDGER_ARTIFACT_LINE_PREFIX,
56
+ LogsEndpoint: () => LogsEndpoint,
57
+ ModelConfigsEndpoint: () => ModelConfigsEndpoint,
58
+ PromptRunner: () => PromptRunner,
59
+ PromptsEndpoint: () => PromptsEndpoint,
60
+ PromptsNamespace: () => PromptsNamespace,
61
+ ProviderKeysEndpoint: () => ProviderKeysEndpoint,
62
+ RecordsEndpoint: () => RecordsEndpoint,
63
+ Runtype: () => Runtype,
64
+ RuntypeApiError: () => RuntypeApiError,
65
+ RuntypeClient: () => RuntypeClient2,
66
+ RuntypeFlowBuilder: () => RuntypeFlowBuilder,
67
+ STEP_FIELD_REGISTRY: () => STEP_FIELD_REGISTRY,
68
+ STEP_TYPE_TO_METHOD: () => STEP_TYPE_TO_METHOD,
69
+ SchedulesEndpoint: () => SchedulesEndpoint,
70
+ SecretsEndpoint: () => SecretsEndpoint,
71
+ SkillProposalsNamespace: () => SkillProposalsNamespace,
72
+ SkillsNamespace: () => SkillsNamespace,
73
+ SurfacesEndpoint: () => SurfacesEndpoint,
74
+ ToolsEndpoint: () => ToolsEndpoint,
75
+ UsersEndpoint: () => UsersEndpoint,
76
+ applyGeneratedRuntimeToolProposalToDispatchRequest: () => applyGeneratedRuntimeToolProposalToDispatchRequest,
77
+ attachRuntimeToolsToDispatchRequest: () => attachRuntimeToolsToDispatchRequest,
78
+ buildGeneratedRuntimeToolGateOutput: () => buildGeneratedRuntimeToolGateOutput,
79
+ buildLedgerOffloadReference: () => buildLedgerOffloadReference,
80
+ buildSendViewOffloadMarker: () => buildSendViewOffloadMarker,
81
+ computeAgentContentHash: () => computeAgentContentHash,
82
+ computeFlowContentHash: () => computeFlowContentHash,
83
+ createClient: () => createClient,
84
+ createExternalTool: () => createExternalTool,
85
+ defaultWorkflow: () => defaultWorkflow,
86
+ defineAgent: () => defineAgent,
87
+ defineFlow: () => defineFlow,
88
+ deployWorkflow: () => deployWorkflow,
89
+ evaluateGeneratedRuntimeToolProposal: () => evaluateGeneratedRuntimeToolProposal,
90
+ extractDeclaredToolResultChars: () => extractDeclaredToolResultChars,
91
+ gameWorkflow: () => gameWorkflow,
92
+ getDefaultPlanPath: () => getDefaultPlanPath,
93
+ getLikelySupportingCandidatePaths: () => getLikelySupportingCandidatePaths,
94
+ isDiscoveryToolName: () => isDiscoveryToolName,
95
+ isMarathonArtifactPath: () => isMarathonArtifactPath,
96
+ isPreservationSensitiveTask: () => isPreservationSensitiveTask,
97
+ normalizeAgentDefinition: () => normalizeAgentDefinition,
98
+ normalizeCandidatePath: () => normalizeCandidatePath,
27
99
  parseFinalBuffer: () => parseFinalBuffer,
100
+ parseLedgerArtifactRelativePath: () => parseLedgerArtifactRelativePath,
101
+ parseOffloadedOutputId: () => parseOffloadedOutputId,
28
102
  parseSSEChunk: () => parseSSEChunk,
29
103
  processStream: () => processStream,
30
- stepDeltaText: () => stepDeltaText,
31
- stepDisplayName: () => stepDisplayName,
104
+ sanitizeTaskSlug: () => sanitizeTaskSlug,
32
105
  streamEvents: () => streamEvents
33
106
  });
107
+ module.exports = __toCommonJS(index_exports);
108
+
109
+ // src/stream-utils.ts
34
110
  function parseSSEChunk(chunk, buffer) {
35
111
  buffer += chunk;
36
112
  const lines = buffer.split("\n");
@@ -280,86 +356,8 @@ async function* streamEvents(response) {
280
356
  reader.releaseLock();
281
357
  }
282
358
  }
283
- var init_stream_utils = __esm({
284
- "src/stream-utils.ts"() {
285
- "use strict";
286
- }
287
- });
288
-
289
- // src/index.ts
290
- var index_exports = {};
291
- __export(index_exports, {
292
- AgentVersionsEndpoint: () => AgentVersionsEndpoint,
293
- AgentsEndpoint: () => AgentsEndpoint,
294
- AnalyticsEndpoint: () => AnalyticsEndpoint,
295
- ApiKeysEndpoint: () => ApiKeysEndpoint,
296
- BatchBuilder: () => BatchBuilder,
297
- BatchesNamespace: () => BatchesNamespace,
298
- BillingEndpoint: () => BillingEndpoint,
299
- ChatEndpoint: () => ChatEndpoint,
300
- ClientBatchBuilder: () => ClientBatchBuilder,
301
- ClientEvalBuilder: () => ClientEvalBuilder,
302
- ClientFlowBuilder: () => ClientFlowBuilder,
303
- ClientTokensEndpoint: () => ClientTokensEndpoint,
304
- ContextTemplatesEndpoint: () => ContextTemplatesEndpoint,
305
- ConversationsEndpoint: () => ConversationsEndpoint,
306
- DispatchEndpoint: () => DispatchEndpoint,
307
- EvalBuilder: () => EvalBuilder,
308
- EvalEndpoint: () => EvalEndpoint,
309
- EvalRunner: () => EvalRunner,
310
- EvalsNamespace: () => EvalsNamespace,
311
- FlowBuilder: () => FlowBuilder,
312
- FlowResult: () => FlowResult,
313
- FlowStepsEndpoint: () => FlowStepsEndpoint,
314
- FlowVersionsEndpoint: () => FlowVersionsEndpoint,
315
- FlowsEndpoint: () => FlowsEndpoint,
316
- FlowsNamespace: () => FlowsNamespace,
317
- IntegrationsEndpoint: () => IntegrationsEndpoint,
318
- LogsEndpoint: () => LogsEndpoint,
319
- ModelConfigsEndpoint: () => ModelConfigsEndpoint,
320
- PromptRunner: () => PromptRunner,
321
- PromptsEndpoint: () => PromptsEndpoint,
322
- PromptsNamespace: () => PromptsNamespace,
323
- ProviderKeysEndpoint: () => ProviderKeysEndpoint,
324
- RecordsEndpoint: () => RecordsEndpoint,
325
- Runtype: () => Runtype,
326
- RuntypeApiError: () => RuntypeApiError,
327
- RuntypeClient: () => RuntypeClient2,
328
- RuntypeFlowBuilder: () => RuntypeFlowBuilder,
329
- STEP_FIELD_REGISTRY: () => STEP_FIELD_REGISTRY,
330
- STEP_TYPE_TO_METHOD: () => STEP_TYPE_TO_METHOD,
331
- SchedulesEndpoint: () => SchedulesEndpoint,
332
- SecretsEndpoint: () => SecretsEndpoint,
333
- SkillProposalsNamespace: () => SkillProposalsNamespace,
334
- SkillsNamespace: () => SkillsNamespace,
335
- SurfacesEndpoint: () => SurfacesEndpoint,
336
- ToolsEndpoint: () => ToolsEndpoint,
337
- UsersEndpoint: () => UsersEndpoint,
338
- applyGeneratedRuntimeToolProposalToDispatchRequest: () => applyGeneratedRuntimeToolProposalToDispatchRequest,
339
- attachRuntimeToolsToDispatchRequest: () => attachRuntimeToolsToDispatchRequest,
340
- buildGeneratedRuntimeToolGateOutput: () => buildGeneratedRuntimeToolGateOutput,
341
- createClient: () => createClient,
342
- createExternalTool: () => createExternalTool,
343
- defaultWorkflow: () => defaultWorkflow,
344
- deployWorkflow: () => deployWorkflow,
345
- evaluateGeneratedRuntimeToolProposal: () => evaluateGeneratedRuntimeToolProposal,
346
- gameWorkflow: () => gameWorkflow,
347
- getDefaultPlanPath: () => getDefaultPlanPath,
348
- getLikelySupportingCandidatePaths: () => getLikelySupportingCandidatePaths,
349
- isDiscoveryToolName: () => isDiscoveryToolName,
350
- isMarathonArtifactPath: () => isMarathonArtifactPath,
351
- isPreservationSensitiveTask: () => isPreservationSensitiveTask,
352
- normalizeCandidatePath: () => normalizeCandidatePath,
353
- parseFinalBuffer: () => parseFinalBuffer,
354
- parseSSEChunk: () => parseSSEChunk,
355
- processStream: () => processStream,
356
- sanitizeTaskSlug: () => sanitizeTaskSlug,
357
- streamEvents: () => streamEvents
358
- });
359
- module.exports = __toCommonJS(index_exports);
360
359
 
361
360
  // src/flow-result.ts
362
- init_stream_utils();
363
361
  var FlowResult = class {
364
362
  constructor(response, summary) {
365
363
  this.consumed = false;
@@ -495,7 +493,6 @@ var FlowResult = class {
495
493
  };
496
494
 
497
495
  // src/flow-builder.ts
498
- init_stream_utils();
499
496
  async function validateInlineFlow(client, args, savedFlowHint) {
500
497
  if (args.existingFlowId) {
501
498
  throw new Error(
@@ -1205,20 +1202,20 @@ var FlowBuilder = class {
1205
1202
  */
1206
1203
  build() {
1207
1204
  const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
1208
- const request = { flow };
1205
+ const request2 = { flow };
1209
1206
  if (this.recordConfig) {
1210
- request.record = this.recordConfig;
1207
+ request2.record = this.recordConfig;
1211
1208
  }
1212
1209
  if (this.messagesConfig) {
1213
- request.messages = this.messagesConfig;
1210
+ request2.messages = this.messagesConfig;
1214
1211
  }
1215
1212
  if (this.inputsConfig) {
1216
- request.inputs = this.inputsConfig;
1213
+ request2.inputs = this.inputsConfig;
1217
1214
  }
1218
1215
  if (Object.keys(this.optionsConfig).length > 0) {
1219
- request.options = this.optionsConfig;
1216
+ request2.options = this.optionsConfig;
1220
1217
  }
1221
- return request;
1218
+ return request2;
1222
1219
  }
1223
1220
  /**
1224
1221
  * Validate this prospective flow against the public validation endpoint
@@ -1455,22 +1452,22 @@ function resolveBatchExecutionId(pausedTools) {
1455
1452
  return "";
1456
1453
  }
1457
1454
 
1458
- // src/flows-namespace.ts
1459
- function isRecord(value) {
1455
+ // src/flows-ensure.ts
1456
+ function isPlainObject(value) {
1460
1457
  return value !== null && typeof value === "object" && !Array.isArray(value);
1461
1458
  }
1462
- function normalizeConfig(config) {
1463
- if (!isRecord(config)) return {};
1459
+ function normalizeConfigForHash(config) {
1460
+ if (!isPlainObject(config)) return {};
1464
1461
  const normalized = {};
1465
1462
  for (const key of Object.keys(config).sort()) {
1466
1463
  const value = config[key];
1467
1464
  if (value === void 0) continue;
1468
1465
  if (value !== null && typeof value === "object" && !Array.isArray(value)) {
1469
- normalized[key] = normalizeConfig(value);
1466
+ normalized[key] = normalizeConfigForHash(value);
1470
1467
  } else if (Array.isArray(value)) {
1471
1468
  normalized[key] = value.map((item) => {
1472
1469
  if (item !== null && typeof item === "object" && !Array.isArray(item)) {
1473
- return normalizeConfig(item);
1470
+ return normalizeConfigForHash(item);
1474
1471
  }
1475
1472
  return item;
1476
1473
  });
@@ -1481,28 +1478,249 @@ function normalizeConfig(config) {
1481
1478
  return normalized;
1482
1479
  }
1483
1480
  function normalizeStepForHash(step) {
1484
- const stepObj = isRecord(step) ? step : {};
1481
+ const stepObj = isPlainObject(step) ? step : {};
1485
1482
  return {
1486
1483
  type: typeof stepObj.type === "string" ? stepObj.type : "",
1487
1484
  name: typeof stepObj.name === "string" ? stepObj.name : "",
1488
1485
  enabled: stepObj.enabled !== false,
1489
1486
  ...typeof stepObj.when === "string" ? { when: stepObj.when } : {},
1490
- config: normalizeConfig(stepObj.config),
1487
+ config: normalizeConfigForHash(stepObj.config),
1491
1488
  order: typeof stepObj.order === "number" ? stepObj.order : 0
1492
1489
  };
1493
1490
  }
1494
1491
  async function computeFlowContentHash(steps) {
1495
1492
  const normalized = [...steps].sort((a, b) => {
1496
- const orderA = isRecord(a) && typeof a.order === "number" ? a.order : 0;
1497
- const orderB = isRecord(b) && typeof b.order === "number" ? b.order : 0;
1493
+ const orderA = isPlainObject(a) && typeof a.order === "number" ? a.order : 0;
1494
+ const orderB = isPlainObject(b) && typeof b.order === "number" ? b.order : 0;
1498
1495
  return orderA - orderB;
1499
1496
  }).map(normalizeStepForHash);
1500
1497
  const serialized = JSON.stringify(normalized);
1501
1498
  const encoded = new TextEncoder().encode(serialized);
1502
1499
  const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
1503
- const hashArray = new Uint8Array(hashBuffer);
1504
- return Array.from(hashArray).map((b) => b.toString(16).padStart(2, "0")).join("");
1500
+ return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
1501
+ }
1502
+ var DEFINE_FLOW_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "steps"]);
1503
+ var DEFINE_FLOW_STEP_KEYS = /* @__PURE__ */ new Set([
1504
+ "type",
1505
+ "name",
1506
+ "order",
1507
+ "enabled",
1508
+ "when",
1509
+ "config"
1510
+ ]);
1511
+ function collectStepNonPortableToolRefs(config, path) {
1512
+ const found = [];
1513
+ const tools = config.tools;
1514
+ const isAccountScoped = (ref) => typeof ref === "string" && ref.startsWith("tool_");
1515
+ const scanArray = (value, subPath) => {
1516
+ if (!Array.isArray(value)) return;
1517
+ value.forEach((ref, i) => {
1518
+ if (isAccountScoped(ref)) found.push(`${subPath}[${i}]`);
1519
+ });
1520
+ };
1521
+ const scanKeys = (value, subPath) => {
1522
+ if (!isPlainObject(value)) return;
1523
+ for (const key of Object.keys(value)) {
1524
+ if (isAccountScoped(key)) found.push(`${subPath}.${key}`);
1525
+ }
1526
+ };
1527
+ if (isPlainObject(tools)) {
1528
+ scanArray(tools.toolIds, `${path}.tools.toolIds`);
1529
+ scanKeys(tools.toolConfigs, `${path}.tools.toolConfigs`);
1530
+ scanKeys(tools.perToolLimits, `${path}.tools.perToolLimits`);
1531
+ if (isPlainObject(tools.approval)) {
1532
+ scanArray(tools.approval.require, `${path}.tools.approval.require`);
1533
+ }
1534
+ if (isPlainObject(tools.subagentConfig)) {
1535
+ scanArray(tools.subagentConfig.toolPool, `${path}.tools.subagentConfig.toolPool`);
1536
+ }
1537
+ if (isPlainObject(tools.codeModeConfig)) {
1538
+ scanArray(tools.codeModeConfig.toolPool, `${path}.tools.codeModeConfig.toolPool`);
1539
+ }
1540
+ }
1541
+ for (const branch of ["trueSteps", "falseSteps"]) {
1542
+ const nested = config[branch];
1543
+ if (!Array.isArray(nested)) continue;
1544
+ nested.forEach((nestedStep, i) => {
1545
+ if (isPlainObject(nestedStep) && isPlainObject(nestedStep.config)) {
1546
+ found.push(
1547
+ ...collectStepNonPortableToolRefs(
1548
+ nestedStep.config,
1549
+ `${path}.${branch}[${i}].config`
1550
+ )
1551
+ );
1552
+ }
1553
+ });
1554
+ }
1555
+ return found;
1556
+ }
1557
+ function defineFlow(input) {
1558
+ if (!input || typeof input !== "object") {
1559
+ throw new Error("defineFlow requires a definition object");
1560
+ }
1561
+ if (typeof input.name !== "string" || input.name.length === 0) {
1562
+ throw new Error('defineFlow requires a non-empty string "name"');
1563
+ }
1564
+ const unknownKeys = Object.keys(input).filter((key) => !DEFINE_FLOW_TOP_LEVEL_KEYS.has(key));
1565
+ if (unknownKeys.length > 0) {
1566
+ throw new Error(
1567
+ `defineFlow: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name and steps. (Description is not part of the v1 ensure surface.)`
1568
+ );
1569
+ }
1570
+ if (!Array.isArray(input.steps) || input.steps.length === 0) {
1571
+ throw new Error('defineFlow requires a non-empty "steps" array');
1572
+ }
1573
+ const steps = input.steps.map((step, index) => {
1574
+ if (!isPlainObject(step)) {
1575
+ throw new Error(`defineFlow: steps[${index}] must be an object`);
1576
+ }
1577
+ if (typeof step.type !== "string" || step.type.length === 0) {
1578
+ throw new Error(`defineFlow: steps[${index}] requires a non-empty string "type"`);
1579
+ }
1580
+ if (typeof step.name !== "string" || step.name.length === 0) {
1581
+ throw new Error(`defineFlow: steps[${index}] requires a non-empty string "name"`);
1582
+ }
1583
+ const unknownStepKeys = Object.keys(step).filter((key) => !DEFINE_FLOW_STEP_KEYS.has(key));
1584
+ if (unknownStepKeys.length > 0) {
1585
+ throw new Error(
1586
+ `defineFlow: steps[${index}] has unknown field(s): ${unknownStepKeys.join(", ")}. Allowed step fields are type, name, order, enabled, when, config. (Step ids are server artifacts and not part of a portable definition.)`
1587
+ );
1588
+ }
1589
+ const config = isPlainObject(step.config) ? step.config : void 0;
1590
+ if (config) {
1591
+ const nonPortable = collectStepNonPortableToolRefs(config, `steps[${index}].config`);
1592
+ if (nonPortable.length > 0) {
1593
+ throw new Error(
1594
+ `defineFlow: account-scoped tool reference(s) at ${nonPortable.join(", ")}. Definitions must be environment-portable \u2014 tool_\u2026 IDs belong to one account/environment. Use builtin:/platform:/mcp: references instead. Name-based resolution of saved tools is a planned follow-up.`
1595
+ );
1596
+ }
1597
+ }
1598
+ return {
1599
+ type: step.type,
1600
+ name: step.name,
1601
+ // Explicit 1-based order (the flow builder's convention) so the local
1602
+ // probe hash agrees with the server's persisted step order.
1603
+ order: typeof step.order === "number" ? step.order : index + 1,
1604
+ ...step.enabled !== void 0 ? { enabled: step.enabled } : {},
1605
+ ...typeof step.when === "string" ? { when: step.when } : {},
1606
+ ...config ? { config } : {}
1607
+ };
1608
+ });
1609
+ return { name: input.name, steps };
1610
+ }
1611
+ var FlowEnsureConflictError = class extends Error {
1612
+ constructor(body) {
1613
+ super(body.error ?? `Flow ensure conflict: ${body.code}`);
1614
+ this.name = "FlowEnsureConflictError";
1615
+ this.code = body.code;
1616
+ this.lastModifiedSource = body.lastModifiedSource;
1617
+ this.modifiedAt = body.modifiedAt;
1618
+ this.currentHash = body.currentHash;
1619
+ }
1620
+ };
1621
+ var FlowDriftError = class extends Error {
1622
+ constructor(plan) {
1623
+ super(
1624
+ `Flow "${plan.flowId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.flows.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
1625
+ );
1626
+ this.name = "FlowDriftError";
1627
+ this.plan = plan;
1628
+ }
1629
+ };
1630
+ function parseRequestError(err) {
1631
+ if (!(err instanceof Error)) return { status: null, body: null };
1632
+ const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
1633
+ if (!match) return { status: null, body: null };
1634
+ try {
1635
+ return { status: Number(match[1]), body: JSON.parse(match[2]) };
1636
+ } catch {
1637
+ return { status: Number(match[1]), body: null };
1638
+ }
1639
+ }
1640
+ function toConflictError(err) {
1641
+ const { status, body } = parseRequestError(err);
1642
+ if (status !== 409 || !isPlainObject(body)) return null;
1643
+ const code = body.code;
1644
+ if (code !== "external_modification" && code !== "remote_changed") return null;
1645
+ return new FlowEnsureConflictError(
1646
+ body
1647
+ );
1648
+ }
1649
+ var serverHashMemo = /* @__PURE__ */ new WeakMap();
1650
+ function memoFor(client) {
1651
+ let memo = serverHashMemo.get(client);
1652
+ if (!memo) {
1653
+ memo = /* @__PURE__ */ new Map();
1654
+ serverHashMemo.set(client, memo);
1655
+ }
1656
+ return memo;
1657
+ }
1658
+ function memoize(memo, memoKey, result) {
1659
+ if (result.result !== "plan") memo.set(memoKey, result.contentHash);
1660
+ }
1661
+ async function request(client, body) {
1662
+ try {
1663
+ return await client.post(
1664
+ "/flows/ensure",
1665
+ body
1666
+ );
1667
+ } catch (err) {
1668
+ const conflict = toConflictError(err);
1669
+ if (conflict) throw conflict;
1670
+ throw err;
1671
+ }
1672
+ }
1673
+ async function ensureFlow(client, definition, options = {}) {
1674
+ const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
1675
+ const passthrough = {
1676
+ ...onConflict ? { onConflict } : {},
1677
+ ...release ? { release } : {},
1678
+ ...expectedRemoteHash ? { expectedRemoteHash } : {}
1679
+ };
1680
+ if (dryRun || expectNoChanges) {
1681
+ const plan = await request(client, {
1682
+ name: definition.name,
1683
+ definition,
1684
+ dryRun: true,
1685
+ ...passthrough
1686
+ });
1687
+ if (plan.result !== "plan") {
1688
+ throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
1689
+ }
1690
+ if (expectNoChanges && plan.changes !== "none") {
1691
+ throw new FlowDriftError(plan);
1692
+ }
1693
+ return plan;
1694
+ }
1695
+ const memo = memoFor(client);
1696
+ const localHash = await computeFlowContentHash(definition.steps);
1697
+ const memoKey = `${definition.name} ${localHash}`;
1698
+ const contentHash = memo.get(memoKey) ?? localHash;
1699
+ const probe = await request(client, {
1700
+ name: definition.name,
1701
+ contentHash,
1702
+ ...passthrough
1703
+ });
1704
+ if (probe.result !== "definitionRequired") {
1705
+ memoize(memo, memoKey, probe);
1706
+ return probe;
1707
+ }
1708
+ const converged = await request(client, {
1709
+ name: definition.name,
1710
+ definition,
1711
+ ...passthrough
1712
+ });
1713
+ if (converged.result === "definitionRequired") {
1714
+ throw new Error("Server reported definitionRequired for a full-definition request");
1715
+ }
1716
+ memoize(memo, memoKey, converged);
1717
+ return converged;
1505
1718
  }
1719
+ async function pullFlow(client, name) {
1720
+ return client.get("/flows/pull", { name });
1721
+ }
1722
+
1723
+ // src/flows-namespace.ts
1506
1724
  var FlowsNamespace = class {
1507
1725
  constructor(getClient) {
1508
1726
  this.getClient = getClient;
@@ -1510,8 +1728,11 @@ var FlowsNamespace = class {
1510
1728
  /**
1511
1729
  * Create or update a flow by name (upsert mode)
1512
1730
  *
1513
- * The recommended pattern for code-first flow management.
1514
- * Creates the flow if it doesn't exist, updates if steps changed.
1731
+ * The recommended pattern for code-first flow management when you want to
1732
+ * save AND run in one dispatch. For a deploy-time, non-executing converge
1733
+ * (CI/CD config-as-code), use {@link ensure} instead — upsert and ensure
1734
+ * are siblings, not versions of each other: upsert is the runtime verb
1735
+ * (save-and-run), ensure is the deploy verb (converge only).
1515
1736
  *
1516
1737
  * @example
1517
1738
  * ```typescript
@@ -1526,6 +1747,33 @@ var FlowsNamespace = class {
1526
1747
  upsert(config) {
1527
1748
  return new RuntypeFlowBuilder(this.getClient, "upsert", config);
1528
1749
  }
1750
+ /**
1751
+ * Idempotently converge a `defineFlow` definition onto the platform —
1752
+ * the deploy-time, non-executing sibling of {@link upsert}. Hash-first:
1753
+ * the steady state is one tiny probe request. Creates an immutable version
1754
+ * snapshot on every change; never deletes; never executes the flow.
1755
+ *
1756
+ * @example
1757
+ * ```typescript
1758
+ * const def = defineFlow({ name: 'Onboarding Digest', steps: [...] })
1759
+ *
1760
+ * // Converge (CI/deploy).
1761
+ * const result = await Runtype.flows.ensure(def)
1762
+ *
1763
+ * // PR drift gate.
1764
+ * await Runtype.flows.ensure(def, { expectNoChanges: true })
1765
+ * ```
1766
+ */
1767
+ async ensure(definition, options = {}) {
1768
+ return ensureFlow(this.getClient(), definition, options);
1769
+ }
1770
+ /**
1771
+ * Pull the canonical definition + provenance for a flow by name — the
1772
+ * absorb-drift direction of the ensure protocol.
1773
+ */
1774
+ async pull(name) {
1775
+ return pullFlow(this.getClient(), name);
1776
+ }
1529
1777
  /**
1530
1778
  * Create a virtual flow (one-off, not saved)
1531
1779
  *
@@ -2211,9 +2459,8 @@ var RuntypeFlowBuilder = class {
2211
2459
  onFlowComplete: (event) => callbacks?.onFlowComplete?.(event),
2212
2460
  onError: (error) => callbacks?.onError?.(error)
2213
2461
  };
2214
- const { streamEvents: streamEvents2, stepDeltaText: stepDeltaText2, stepDisplayName: stepDisplayName2, flowErrorMessage: flowErrorMessage2 } = await Promise.resolve().then(() => (init_stream_utils(), stream_utils_exports));
2215
2462
  try {
2216
- for await (const event of streamEvents2(response)) {
2463
+ for await (const event of streamEvents(response)) {
2217
2464
  collectLocalToolAwait(pausedTools, event);
2218
2465
  switch (event.type) {
2219
2466
  case "flow_start":
@@ -2223,10 +2470,10 @@ var RuntypeFlowBuilder = class {
2223
2470
  wrappedCallbacks.onStepStart?.(event);
2224
2471
  break;
2225
2472
  case "step_delta":
2226
- wrappedCallbacks.onStepDelta?.(stepDeltaText2(event), event);
2473
+ wrappedCallbacks.onStepDelta?.(stepDeltaText(event), event);
2227
2474
  break;
2228
2475
  case "step_complete": {
2229
- accumulatedSummary.results?.set(stepDisplayName2(event), event.result);
2476
+ accumulatedSummary.results?.set(stepDisplayName(event), event.result);
2230
2477
  wrappedCallbacks.onStepComplete?.(event.result, event);
2231
2478
  break;
2232
2479
  }
@@ -2234,7 +2481,7 @@ var RuntypeFlowBuilder = class {
2234
2481
  wrappedCallbacks.onFlowComplete?.(event);
2235
2482
  break;
2236
2483
  case "flow_error":
2237
- wrappedCallbacks.onError?.(new Error(flowErrorMessage2(event)));
2484
+ wrappedCallbacks.onError?.(new Error(flowErrorMessage(event)));
2238
2485
  break;
2239
2486
  }
2240
2487
  }
@@ -2309,7 +2556,8 @@ var RuntypeFlowBuilder = class {
2309
2556
  return [toolName, await localTools[toolName](parameters)];
2310
2557
  } catch (error) {
2311
2558
  throw new Error(
2312
- `Error executing local tool "${toolName}": ${error instanceof Error ? error.message : String(error)}`
2559
+ `Error executing local tool "${toolName}": ${error instanceof Error ? error.message : String(error)}`,
2560
+ { cause: error }
2313
2561
  );
2314
2562
  }
2315
2563
  })
@@ -2342,15 +2590,15 @@ var RuntypeFlowBuilder = class {
2342
2590
  build() {
2343
2591
  const flowMode = this.mode === "existing" ? "existing" : this.mode;
2344
2592
  const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
2345
- const request = { flow };
2593
+ const request2 = { flow };
2346
2594
  if (this.recordConfig) {
2347
- request.record = this.recordConfig;
2595
+ request2.record = this.recordConfig;
2348
2596
  }
2349
2597
  if (this.messagesConfig) {
2350
- request.messages = this.messagesConfig;
2598
+ request2.messages = this.messagesConfig;
2351
2599
  }
2352
2600
  if (this.inputsConfig) {
2353
- request.inputs = this.inputsConfig;
2601
+ request2.inputs = this.inputsConfig;
2354
2602
  }
2355
2603
  const options = {
2356
2604
  flowMode,
@@ -2368,8 +2616,8 @@ var RuntypeFlowBuilder = class {
2368
2616
  if (this.mode === "upsert" && Object.keys(this.upsertOptions).length > 0) {
2369
2617
  options.upsertOptions = this.upsertOptions;
2370
2618
  }
2371
- request.options = options;
2372
- return request;
2619
+ request2.options = options;
2620
+ return request2;
2373
2621
  }
2374
2622
  /**
2375
2623
  * Validate this prospective flow against the public validation endpoint
@@ -3029,6 +3277,8 @@ var SkillsNamespace = class {
3029
3277
  }
3030
3278
  /**
3031
3279
  * List skills for the authenticated owner, optionally filtered by status.
3280
+ * Returns just the rows (one page); pass `cursor`/`limit` to page, or use
3281
+ * {@link listPage} when you need the pagination envelope.
3032
3282
  *
3033
3283
  * @example
3034
3284
  * ```typescript
@@ -3036,10 +3286,23 @@ var SkillsNamespace = class {
3036
3286
  * ```
3037
3287
  */
3038
3288
  async list(params) {
3039
- const client = this.getClient();
3040
- const res = await client.get("/skills", params);
3289
+ const res = await this.listPage(params);
3041
3290
  return res.data;
3042
3291
  }
3292
+ /**
3293
+ * List skills with the cursor-pagination envelope (mirrors the tools list
3294
+ * shape: `{ data, pagination }`).
3295
+ *
3296
+ * @example
3297
+ * ```typescript
3298
+ * const page1 = await Runtype.skills.listPage({ limit: 50, includeCount: true })
3299
+ * const page2 = await Runtype.skills.listPage({ limit: 50, cursor: page1.pagination?.nextCursor ?? undefined })
3300
+ * ```
3301
+ */
3302
+ async listPage(params) {
3303
+ const client = this.getClient();
3304
+ return client.get("/skills", params);
3305
+ }
3043
3306
  /**
3044
3307
  * Get a skill and its full version history.
3045
3308
  *
@@ -3132,6 +3395,260 @@ var SkillsNamespace = class {
3132
3395
  }
3133
3396
  };
3134
3397
 
3398
+ // src/agents-namespace.ts
3399
+ var AGENT_CONFIG_KEYS = [
3400
+ "model",
3401
+ "systemPrompt",
3402
+ "temperature",
3403
+ "topP",
3404
+ "topK",
3405
+ "frequencyPenalty",
3406
+ "presencePenalty",
3407
+ "seed",
3408
+ "tools",
3409
+ "reasoning",
3410
+ "advisor",
3411
+ "loopConfig",
3412
+ "voice",
3413
+ "errorHandling",
3414
+ "artifacts",
3415
+ "loggingPolicy",
3416
+ "temporal",
3417
+ "memory"
3418
+ ];
3419
+ var AGENT_CONFIG_KEY_LIST = [...AGENT_CONFIG_KEYS].sort();
3420
+ function isPlainObject2(value) {
3421
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3422
+ }
3423
+ function normalizeValue(value) {
3424
+ if (Array.isArray(value)) {
3425
+ return value.map((item) => normalizeValue(item));
3426
+ }
3427
+ if (isPlainObject2(value)) {
3428
+ const normalized = {};
3429
+ for (const key of Object.keys(value).sort()) {
3430
+ const entry = value[key];
3431
+ if (entry === void 0 || entry === null) continue;
3432
+ normalized[key] = normalizeValue(entry);
3433
+ }
3434
+ return normalized;
3435
+ }
3436
+ return value;
3437
+ }
3438
+ function normalizeAgentDefinition(definition) {
3439
+ const config = {};
3440
+ const rawConfig = isPlainObject2(definition.config) ? definition.config : {};
3441
+ for (const key of AGENT_CONFIG_KEY_LIST) {
3442
+ const value = rawConfig[key];
3443
+ if (value === void 0 || value === null) continue;
3444
+ config[key] = normalizeValue(value);
3445
+ }
3446
+ return {
3447
+ name: definition.name,
3448
+ ...definition.description ? { description: definition.description } : {},
3449
+ ...definition.icon ? { icon: definition.icon } : {},
3450
+ config
3451
+ };
3452
+ }
3453
+ async function computeAgentContentHash(definition) {
3454
+ const serialized = JSON.stringify(normalizeAgentDefinition(definition));
3455
+ const encoded = new TextEncoder().encode(serialized);
3456
+ const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
3457
+ return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
3458
+ }
3459
+ var DEFINE_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set(["name", "description", "icon", ...AGENT_CONFIG_KEYS]);
3460
+ function collectNonPortableToolRefs(config) {
3461
+ const tools = config.tools;
3462
+ if (!isPlainObject2(tools)) return [];
3463
+ const found = [];
3464
+ const isAccountScoped = (ref) => typeof ref === "string" && ref.startsWith("tool_");
3465
+ const scanArray = (value, path) => {
3466
+ if (!Array.isArray(value)) return;
3467
+ value.forEach((ref, i) => {
3468
+ if (isAccountScoped(ref)) found.push(`${path}[${i}]`);
3469
+ });
3470
+ };
3471
+ const scanKeys = (value, path) => {
3472
+ if (!isPlainObject2(value)) return;
3473
+ for (const key of Object.keys(value)) {
3474
+ if (isAccountScoped(key)) found.push(`${path}.${key}`);
3475
+ }
3476
+ };
3477
+ scanArray(tools.toolIds, "tools.toolIds");
3478
+ scanKeys(tools.toolConfigs, "tools.toolConfigs");
3479
+ scanKeys(tools.perToolLimits, "tools.perToolLimits");
3480
+ if (isPlainObject2(tools.approval)) scanArray(tools.approval.require, "tools.approval.require");
3481
+ if (isPlainObject2(tools.subagentConfig)) {
3482
+ scanArray(tools.subagentConfig.toolPool, "tools.subagentConfig.toolPool");
3483
+ }
3484
+ if (isPlainObject2(tools.codeModeConfig)) {
3485
+ scanArray(tools.codeModeConfig.toolPool, "tools.codeModeConfig.toolPool");
3486
+ }
3487
+ return found;
3488
+ }
3489
+ function defineAgent(input) {
3490
+ if (!input || typeof input !== "object") {
3491
+ throw new Error("defineAgent requires a definition object");
3492
+ }
3493
+ if (typeof input.name !== "string" || input.name.length === 0) {
3494
+ throw new Error('defineAgent requires a non-empty string "name"');
3495
+ }
3496
+ const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOP_LEVEL_KEYS.has(key));
3497
+ if (unknownKeys.length > 0) {
3498
+ throw new Error(
3499
+ `defineAgent: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, icon, and the agent runtime config surface (${AGENT_CONFIG_KEY_LIST.join(", ")}).`
3500
+ );
3501
+ }
3502
+ const config = {};
3503
+ for (const key of AGENT_CONFIG_KEYS) {
3504
+ const value = input[key];
3505
+ if (value !== void 0) config[key] = value;
3506
+ }
3507
+ const nonPortable = collectNonPortableToolRefs(config);
3508
+ if (nonPortable.length > 0) {
3509
+ throw new Error(
3510
+ `defineAgent: account-scoped tool reference(s) at ${nonPortable.join(", ")}. Definitions must be environment-portable \u2014 tool_\u2026 IDs belong to one account/environment. Use builtin:/platform:/mcp: references instead. Name-based resolution of saved tools is a planned follow-up.`
3511
+ );
3512
+ }
3513
+ return {
3514
+ name: input.name,
3515
+ ...input.description !== void 0 ? { description: input.description } : {},
3516
+ ...input.icon !== void 0 ? { icon: input.icon } : {},
3517
+ config
3518
+ };
3519
+ }
3520
+ var AgentEnsureConflictError = class extends Error {
3521
+ constructor(body) {
3522
+ super(body.error ?? `Agent ensure conflict: ${body.code}`);
3523
+ this.name = "AgentEnsureConflictError";
3524
+ this.code = body.code;
3525
+ this.lastModifiedSource = body.lastModifiedSource;
3526
+ this.modifiedAt = body.modifiedAt;
3527
+ this.currentHash = body.currentHash;
3528
+ }
3529
+ };
3530
+ var AgentDriftError = class extends Error {
3531
+ constructor(plan) {
3532
+ super(
3533
+ `Agent "${plan.agentId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.agents.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
3534
+ );
3535
+ this.name = "AgentDriftError";
3536
+ this.plan = plan;
3537
+ }
3538
+ };
3539
+ function parseRequestError2(err) {
3540
+ if (!(err instanceof Error)) return { status: null, body: null };
3541
+ const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
3542
+ if (!match) return { status: null, body: null };
3543
+ try {
3544
+ return { status: Number(match[1]), body: JSON.parse(match[2]) };
3545
+ } catch {
3546
+ return { status: Number(match[1]), body: null };
3547
+ }
3548
+ }
3549
+ function toConflictError2(err) {
3550
+ const { status, body } = parseRequestError2(err);
3551
+ if (status !== 409 || !isPlainObject2(body)) return null;
3552
+ const code = body.code;
3553
+ if (code !== "external_modification" && code !== "remote_changed") return null;
3554
+ return new AgentEnsureConflictError(
3555
+ body
3556
+ );
3557
+ }
3558
+ var serverHashMemo2 = /* @__PURE__ */ new WeakMap();
3559
+ function memoFor2(client) {
3560
+ let memo = serverHashMemo2.get(client);
3561
+ if (!memo) {
3562
+ memo = /* @__PURE__ */ new Map();
3563
+ serverHashMemo2.set(client, memo);
3564
+ }
3565
+ return memo;
3566
+ }
3567
+ var AgentsNamespace = class {
3568
+ constructor(getClient) {
3569
+ this.getClient = getClient;
3570
+ }
3571
+ /**
3572
+ * Idempotently converge a definition onto the platform. Hash-first: probes
3573
+ * with a content hash, and only ships the full definition when the server
3574
+ * reports a miss (`definitionRequired`). Creates an immutable version
3575
+ * snapshot on every change; never deletes.
3576
+ */
3577
+ async ensure(definition, options = {}) {
3578
+ const client = this.getClient();
3579
+ const { dryRun, onConflict, release, expectedRemoteHash, expectNoChanges } = options;
3580
+ const passthrough = {
3581
+ ...onConflict ? { onConflict } : {},
3582
+ ...release ? { release } : {},
3583
+ ...expectedRemoteHash ? { expectedRemoteHash } : {}
3584
+ };
3585
+ if (dryRun || expectNoChanges) {
3586
+ const plan = await this.request(client, {
3587
+ name: definition.name,
3588
+ definition,
3589
+ dryRun: true,
3590
+ ...passthrough
3591
+ });
3592
+ if (plan.result !== "plan") {
3593
+ throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
3594
+ }
3595
+ if (expectNoChanges && plan.changes !== "none") {
3596
+ throw new AgentDriftError(plan);
3597
+ }
3598
+ return plan;
3599
+ }
3600
+ const memo = memoFor2(client);
3601
+ const localHash = await computeAgentContentHash({
3602
+ ...definition,
3603
+ config: definition.config
3604
+ });
3605
+ const memoKey = `${definition.name}\0${localHash}`;
3606
+ const contentHash = memo.get(memoKey) ?? localHash;
3607
+ const probe = await this.request(client, {
3608
+ name: definition.name,
3609
+ contentHash,
3610
+ ...passthrough
3611
+ });
3612
+ if (probe.result !== "definitionRequired") {
3613
+ this.memoize(memo, memoKey, probe);
3614
+ return probe;
3615
+ }
3616
+ const converged = await this.request(client, {
3617
+ name: definition.name,
3618
+ definition,
3619
+ ...passthrough
3620
+ });
3621
+ if (converged.result === "definitionRequired") {
3622
+ throw new Error("Server reported definitionRequired for a full-definition request");
3623
+ }
3624
+ this.memoize(memo, memoKey, converged);
3625
+ return converged;
3626
+ }
3627
+ /**
3628
+ * Pull the canonical definition + provenance for an agent by name — the
3629
+ * absorb-drift direction. The contentHash reflects the live agent state.
3630
+ */
3631
+ async pull(name) {
3632
+ const client = this.getClient();
3633
+ return client.get("/agents/pull", { name });
3634
+ }
3635
+ memoize(memo, memoKey, result) {
3636
+ if (result.result !== "plan") memo.set(memoKey, result.contentHash);
3637
+ }
3638
+ async request(client, body) {
3639
+ try {
3640
+ return await client.post(
3641
+ "/agents/ensure",
3642
+ body
3643
+ );
3644
+ } catch (err) {
3645
+ const conflict = toConflictError2(err);
3646
+ if (conflict) throw conflict;
3647
+ throw err;
3648
+ }
3649
+ }
3650
+ };
3651
+
3135
3652
  // src/transform.ts
3136
3653
  function transformResponse(data) {
3137
3654
  return data;
@@ -3292,7 +3809,7 @@ var RuntypeClient = class {
3292
3809
  } catch (error) {
3293
3810
  clearTimeout(timeoutId);
3294
3811
  if (error instanceof Error && error.name === "AbortError") {
3295
- throw new Error(`Request timeout after ${this.timeout}ms`);
3812
+ throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
3296
3813
  }
3297
3814
  throw error;
3298
3815
  }
@@ -3319,7 +3836,7 @@ var RuntypeClient = class {
3319
3836
  } catch (error) {
3320
3837
  clearTimeout(timeoutId);
3321
3838
  if (error instanceof Error && error.name === "AbortError") {
3322
- throw new Error(`Request timeout after ${this.timeout}ms`);
3839
+ throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
3323
3840
  }
3324
3841
  throw error;
3325
3842
  }
@@ -3494,6 +4011,32 @@ var Runtype = class {
3494
4011
  static get skills() {
3495
4012
  return new SkillsNamespace(() => this.getClient());
3496
4013
  }
4014
+ /**
4015
+ * Agents namespace - Agent config-as-code (define / ensure / pull)
4016
+ *
4017
+ * @example
4018
+ * ```typescript
4019
+ * import { defineAgent, Runtype } from '@runtypelabs/sdk'
4020
+ *
4021
+ * const assistant = defineAgent({
4022
+ * name: 'Pricing Assistant',
4023
+ * model: 'claude-sonnet-4-6',
4024
+ * systemPrompt: renderPrompt(pricingData),
4025
+ * })
4026
+ *
4027
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
4028
+ * await Runtype.agents.ensure(assistant)
4029
+ *
4030
+ * // CI drift gate
4031
+ * await Runtype.agents.ensure(assistant, { expectNoChanges: true })
4032
+ *
4033
+ * // Absorb a dashboard edit back into the repo
4034
+ * const { definition } = await Runtype.agents.pull('Pricing Assistant')
4035
+ * ```
4036
+ */
4037
+ static get agents() {
4038
+ return new AgentsNamespace(() => this.getClient());
4039
+ }
3497
4040
  };
3498
4041
 
3499
4042
  // src/generated-tool-gate.ts
@@ -3716,8 +4259,8 @@ function buildGeneratedRuntimeToolGateOutput(proposal, options = {}) {
3716
4259
  ...decision.tool ? { tool: decision.tool } : {}
3717
4260
  };
3718
4261
  }
3719
- function attachRuntimeToolsToDispatchRequest(request, runtimeTools, options = {}) {
3720
- const stepList = request.flow.steps;
4262
+ function attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options = {}) {
4263
+ const stepList = request2.flow.steps;
3721
4264
  if (!stepList || !Array.isArray(stepList) || stepList.length === 0) {
3722
4265
  throw new Error("Cannot attach runtime tools: dispatch request must include flow.steps");
3723
4266
  }
@@ -3760,9 +4303,9 @@ function attachRuntimeToolsToDispatchRequest(request, runtimeTools, options = {}
3760
4303
  }
3761
4304
  };
3762
4305
  return {
3763
- ...request,
4306
+ ...request2,
3764
4307
  flow: {
3765
- ...request.flow,
4308
+ ...request2.flow,
3766
4309
  // `clonedSteps` is a structural clone of `request.flow.steps` (already
3767
4310
  // `FlowStepDefinition[]`); only the prompt step's `config.tools` was
3768
4311
  // merged, so every step's `type` discriminant is preserved. The clone is
@@ -3772,18 +4315,56 @@ function attachRuntimeToolsToDispatchRequest(request, runtimeTools, options = {}
3772
4315
  }
3773
4316
  };
3774
4317
  }
3775
- function applyGeneratedRuntimeToolProposalToDispatchRequest(request, proposal, options = {}) {
4318
+ function applyGeneratedRuntimeToolProposalToDispatchRequest(request2, proposal, options = {}) {
3776
4319
  const decision = evaluateGeneratedRuntimeToolProposal(proposal, options.gate);
3777
4320
  if (!decision.approved || !decision.tool) {
3778
- return { decision, request };
4321
+ return { decision, request: request2 };
3779
4322
  }
3780
- const nextRequest = attachRuntimeToolsToDispatchRequest(request, [decision.tool], options.attach);
4323
+ const nextRequest = attachRuntimeToolsToDispatchRequest(request2, [decision.tool], options.attach);
3781
4324
  return {
3782
4325
  decision,
3783
4326
  request: nextRequest
3784
4327
  };
3785
4328
  }
3786
4329
 
4330
+ // src/offload-markers.ts
4331
+ var LEDGER_ARTIFACT_LINE_PREFIX = "Ledger artifact: ";
4332
+ function formatChars(charLength) {
4333
+ return charLength.toLocaleString("en-US");
4334
+ }
4335
+ function buildSendViewOffloadMarker(details) {
4336
+ return `[${details.toolName} output (${formatChars(details.charLength)} chars) saved to ${details.filePath} \u2014 use read_file to retrieve if needed]`;
4337
+ }
4338
+ function buildLedgerOffloadReference(details) {
4339
+ return [
4340
+ `[Output offloaded as ${details.outputId} \u2014 ${formatChars(details.charLength)} chars stored in the marathon context ledger]`,
4341
+ `${LEDGER_ARTIFACT_LINE_PREFIX}${details.relativePath}`,
4342
+ `Preview: ${details.preview}${details.truncated ? "..." : ""}`,
4343
+ "",
4344
+ `Use read_offloaded_output with id "${details.outputId}" to retrieve the full output if needed.`
4345
+ ].join("\n");
4346
+ }
4347
+ var DECLARED_CHARS_PATTERNS = [
4348
+ /—\s*([\d,]+)\s+chars?\s+(?:stored|saved)/i,
4349
+ /\(([\d,]+)\s+chars?\)\s+saved/i
4350
+ ];
4351
+ function extractDeclaredToolResultChars(value) {
4352
+ if (typeof value !== "string") return void 0;
4353
+ for (const pattern of DECLARED_CHARS_PATTERNS) {
4354
+ const match = pattern.exec(value);
4355
+ if (!match?.[1]) continue;
4356
+ const parsed = Number.parseInt(match[1].replace(/,/g, ""), 10);
4357
+ if (Number.isFinite(parsed) && parsed > 0) return parsed;
4358
+ }
4359
+ return void 0;
4360
+ }
4361
+ function parseOffloadedOutputId(value) {
4362
+ return /\bread_offloaded_output\s+with\s+id\s+"([^"]+)"/i.exec(value)?.[1] || /\[Output offloaded as\s+([a-zA-Z0-9_-]+)/i.exec(value)?.[1] || void 0;
4363
+ }
4364
+ function parseLedgerArtifactRelativePath(value) {
4365
+ return value.split("\n").find((line) => line.startsWith(LEDGER_ARTIFACT_LINE_PREFIX))?.slice(LEDGER_ARTIFACT_LINE_PREFIX.length).trim();
4366
+ }
4367
+
3787
4368
  // src/workflow-utils.ts
3788
4369
  function normalizeCandidatePath(candidatePath) {
3789
4370
  return candidatePath.trim().replace(/\\/g, "/").replace(/^\.?\//, "").replace(/\/+/g, "/");
@@ -5515,15 +6096,15 @@ var DispatchEndpoint = class {
5515
6096
  * Attach approved runtime tools to a prompt step in a redispatch request.
5516
6097
  * Returns a new request object and does not mutate the original.
5517
6098
  */
5518
- attachApprovedRuntimeTools(request, runtimeTools, options) {
5519
- return attachRuntimeToolsToDispatchRequest(request, runtimeTools, options);
6099
+ attachApprovedRuntimeTools(request2, runtimeTools, options) {
6100
+ return attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options);
5520
6101
  }
5521
6102
  /**
5522
6103
  * Validate a generated runtime tool proposal and attach it to the redispatch
5523
6104
  * request if approved, in one call.
5524
6105
  */
5525
- applyGeneratedRuntimeToolProposal(request, proposal, options) {
5526
- return applyGeneratedRuntimeToolProposalToDispatchRequest(request, proposal, options);
6106
+ applyGeneratedRuntimeToolProposal(request2, proposal, options) {
6107
+ return applyGeneratedRuntimeToolProposalToDispatchRequest(request2, proposal, options);
5527
6108
  }
5528
6109
  };
5529
6110
  var ChatEndpoint = class {
@@ -6028,6 +6609,22 @@ async function processAgentStream(body, callbacks) {
6028
6609
  reader.releaseLock();
6029
6610
  }
6030
6611
  }
6612
+ function sleepWithAbort(delayMs, signal) {
6613
+ return new Promise((resolve) => {
6614
+ const onAbort = () => {
6615
+ clearTimeout(timer);
6616
+ resolve();
6617
+ };
6618
+ const timer = setTimeout(() => {
6619
+ signal?.removeEventListener("abort", onAbort);
6620
+ resolve();
6621
+ }, delayMs);
6622
+ if (signal) {
6623
+ if (signal.aborted) onAbort();
6624
+ else signal.addEventListener("abort", onAbort, { once: true });
6625
+ }
6626
+ });
6627
+ }
6031
6628
  var GENERATED_RUNTIME_TOOL_PROPOSAL_SCHEMA = {
6032
6629
  type: "object",
6033
6630
  properties: {
@@ -6059,8 +6656,8 @@ var GENERATED_RUNTIME_TOOL_PROPOSAL_SCHEMA = {
6059
6656
  },
6060
6657
  required: ["name", "description", "toolType", "parametersSchema", "config"]
6061
6658
  };
6062
- function appendRuntimeToolsToAgentRequest(request, runtimeTools) {
6063
- const existing = request.tools?.runtimeTools || [];
6659
+ function appendRuntimeToolsToAgentRequest(request2, runtimeTools) {
6660
+ const existing = request2.tools?.runtimeTools || [];
6064
6661
  const existingNames = new Set(existing.map((tool) => tool.name));
6065
6662
  const converted = runtimeTools.filter((tool) => !existingNames.has(tool.name)).map((tool) => ({
6066
6663
  name: tool.name,
@@ -6070,9 +6667,9 @@ function appendRuntimeToolsToAgentRequest(request, runtimeTools) {
6070
6667
  ...tool.config ? { config: tool.config } : {}
6071
6668
  }));
6072
6669
  return {
6073
- ...request,
6670
+ ...request2,
6074
6671
  tools: {
6075
- ...request.tools,
6672
+ ...request2.tools,
6076
6673
  runtimeTools: [...existing, ...converted]
6077
6674
  }
6078
6675
  };
@@ -6148,21 +6745,21 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6148
6745
  * Attach approved runtime tools to an agent execute request.
6149
6746
  * Returns a new request object and does not mutate the original.
6150
6747
  */
6151
- attachApprovedRuntimeTools(request, runtimeTools) {
6152
- return appendRuntimeToolsToAgentRequest(request, runtimeTools);
6748
+ attachApprovedRuntimeTools(request2, runtimeTools) {
6749
+ return appendRuntimeToolsToAgentRequest(request2, runtimeTools);
6153
6750
  }
6154
6751
  /**
6155
6752
  * Validate a generated runtime tool proposal and append it to an agent execute
6156
6753
  * request if approved, in one call.
6157
6754
  */
6158
- applyGeneratedRuntimeToolProposal(request, proposal, options) {
6755
+ applyGeneratedRuntimeToolProposal(request2, proposal, options) {
6159
6756
  const decision = evaluateGeneratedRuntimeToolProposal(proposal, options);
6160
6757
  if (!decision.approved || !decision.tool) {
6161
- return { decision, request };
6758
+ return { decision, request: request2 };
6162
6759
  }
6163
6760
  return {
6164
6761
  decision,
6165
- request: appendRuntimeToolsToAgentRequest(request, [decision.tool])
6762
+ request: appendRuntimeToolsToAgentRequest(request2, [decision.tool])
6166
6763
  };
6167
6764
  }
6168
6765
  /**
@@ -6192,13 +6789,14 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6192
6789
  * // ...
6193
6790
  * ```
6194
6791
  */
6195
- async executeStream(id, data) {
6792
+ async executeStream(id, data, init) {
6196
6793
  return this.client.requestStream(`/agents/${id}/execute`, {
6197
6794
  method: "POST",
6198
6795
  body: JSON.stringify({
6199
6796
  ...data,
6200
6797
  streamResponse: true
6201
- })
6798
+ }),
6799
+ ...init?.signal ? { signal: init.signal } : {}
6202
6800
  });
6203
6801
  }
6204
6802
  /**
@@ -6294,45 +6892,94 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6294
6892
  runtimeTools: [...data.tools?.runtimeTools || [], ...runtimeTools]
6295
6893
  }
6296
6894
  };
6297
- const response = await this.executeStream(id, requestData);
6298
- if (!response.ok) {
6299
- const error = await response.json().catch(() => ({ error: "Unknown error" }));
6300
- throw new Error(error.error || `HTTP ${response.status}`);
6301
- }
6302
- let currentBody = response.body;
6895
+ const abortSignal = options?.abortSignal;
6303
6896
  let accumulatedOutput = "";
6897
+ let lastKnownCost = 0;
6898
+ let lastKnownTokens;
6899
+ let lastSeenExecutionId = "";
6304
6900
  let pauseCount = 0;
6305
6901
  let discoveryPauseCount = 0;
6306
6902
  let consecutiveDiscoveryPauseCount = 0;
6307
6903
  const toolNameCounts = {};
6308
6904
  let recentActionKeys = [];
6309
6905
  const toolMessages = [];
6906
+ const finishAborted = (executionId) => {
6907
+ const abortCompleteEvent = {
6908
+ type: "agent_complete",
6909
+ executionId,
6910
+ seq: 0,
6911
+ agentId: id,
6912
+ success: true,
6913
+ iterations: 1,
6914
+ stopReason: "end_turn",
6915
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
6916
+ totalCost: lastKnownCost,
6917
+ ...lastKnownTokens ? { totalTokens: lastKnownTokens } : {},
6918
+ finalOutput: [accumulatedOutput.trim(), "Session aborted by user request."].filter(Boolean).join("\n\n"),
6919
+ duration: 0
6920
+ };
6921
+ callbacks?.onAgentComplete?.(abortCompleteEvent);
6922
+ return { completeEvent: abortCompleteEvent, toolMessages };
6923
+ };
6924
+ let response;
6925
+ try {
6926
+ response = await this.executeStream(id, requestData, {
6927
+ ...abortSignal ? { signal: abortSignal } : {}
6928
+ });
6929
+ } catch (error) {
6930
+ if (abortSignal?.aborted) return finishAborted(lastSeenExecutionId);
6931
+ throw error;
6932
+ }
6933
+ if (!response.ok) {
6934
+ const error = await response.json().catch(() => ({ error: "Unknown error" }));
6935
+ throw new Error(error.error || `HTTP ${response.status}`);
6936
+ }
6937
+ let currentBody = response.body;
6310
6938
  while (true) {
6311
6939
  let pausedEvent = null;
6312
6940
  let completeEvent = null;
6313
- await processAgentStream(currentBody, {
6314
- ...callbacks,
6315
- onTurnDelta: (event) => {
6316
- if (event.contentType === "text") {
6317
- accumulatedOutput += event.delta;
6318
- }
6319
- callbacks?.onTurnDelta?.(event);
6320
- },
6321
- onAgentPaused: (event) => {
6322
- pausedEvent = event;
6323
- callbacks?.onAgentPaused?.(event);
6324
- },
6325
- onAgentComplete: (event) => {
6326
- if (!event.finalOutput && accumulatedOutput) {
6327
- event.finalOutput = accumulatedOutput;
6941
+ try {
6942
+ await processAgentStream(currentBody, {
6943
+ ...callbacks,
6944
+ onAgentStart: (event) => {
6945
+ lastSeenExecutionId = event.executionId;
6946
+ callbacks?.onAgentStart?.(event);
6947
+ },
6948
+ onTurnDelta: (event) => {
6949
+ if (event.contentType === "text") {
6950
+ accumulatedOutput += event.delta;
6951
+ }
6952
+ callbacks?.onTurnDelta?.(event);
6953
+ },
6954
+ onTurnComplete: (event) => {
6955
+ if (typeof event.cost === "number") {
6956
+ lastKnownCost = event.cost;
6957
+ }
6958
+ if (event.tokens) {
6959
+ lastKnownTokens = event.tokens;
6960
+ }
6961
+ callbacks?.onTurnComplete?.(event);
6962
+ },
6963
+ onAgentPaused: (event) => {
6964
+ pausedEvent = event;
6965
+ callbacks?.onAgentPaused?.(event);
6966
+ },
6967
+ onAgentComplete: (event) => {
6968
+ if (!event.finalOutput && accumulatedOutput) {
6969
+ event.finalOutput = accumulatedOutput;
6970
+ }
6971
+ completeEvent = event;
6972
+ callbacks?.onAgentComplete?.(event);
6328
6973
  }
6329
- completeEvent = event;
6330
- callbacks?.onAgentComplete?.(event);
6331
- }
6332
- });
6974
+ });
6975
+ } catch (error) {
6976
+ if (abortSignal?.aborted) return finishAborted(lastSeenExecutionId);
6977
+ throw error;
6978
+ }
6333
6979
  if (completeEvent) return { completeEvent, toolMessages };
6334
6980
  if (pausedEvent) {
6335
6981
  const { toolName, toolId, parameters, executionId } = pausedEvent;
6982
+ lastSeenExecutionId = executionId;
6336
6983
  const toolDef = localTools[toolName];
6337
6984
  if (!toolDef) {
6338
6985
  throw new Error(`Local tool "${toolName}" required but not provided`);
@@ -6447,15 +7094,68 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6447
7094
  callbacks?.onAgentComplete?.(forcedCompleteEvent);
6448
7095
  return { completeEvent: forcedCompleteEvent, toolMessages };
6449
7096
  }
6450
- const resumeResponse = await this.client.requestStream(`/agents/${id}/resume`, {
6451
- method: "POST",
6452
- body: JSON.stringify({
7097
+ if (abortSignal?.aborted) {
7098
+ callbacks?.onLocalToolExecutionComplete?.({
6453
7099
  executionId,
6454
- toolOutputs: { [toolName]: toolResult },
6455
- streamResponse: true,
6456
- debugMode: data.debugMode
6457
- })
6458
- });
7100
+ toolCallId: toolId,
7101
+ toolName,
7102
+ parameters: parsedParams,
7103
+ result: toolResult,
7104
+ success: true,
7105
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
7106
+ durationMs: Date.now() - localExecutionStartedAtMs
7107
+ });
7108
+ return finishAborted(executionId);
7109
+ }
7110
+ if (options?.shouldInterrupt?.()) {
7111
+ callbacks?.onLocalToolExecutionComplete?.({
7112
+ executionId,
7113
+ toolCallId: toolId,
7114
+ toolName,
7115
+ parameters: parsedParams,
7116
+ result: toolResult,
7117
+ success: true,
7118
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
7119
+ durationMs: Date.now() - localExecutionStartedAtMs
7120
+ });
7121
+ const interruptCompleteEvent = {
7122
+ type: "agent_complete",
7123
+ executionId,
7124
+ seq: 0,
7125
+ agentId: id,
7126
+ success: true,
7127
+ iterations: 1,
7128
+ stopReason: "end_turn",
7129
+ completedAt: (/* @__PURE__ */ new Date()).toISOString(),
7130
+ // Carry the spend observed so far so the interrupted session's
7131
+ // cost still lands in marathon totals and budget accounting
7132
+ totalCost: lastKnownCost,
7133
+ ...lastKnownTokens ? { totalTokens: lastKnownTokens } : {},
7134
+ finalOutput: [
7135
+ accumulatedOutput.trim(),
7136
+ "Session ended early: user steering was queued and will be delivered at the start of the next session."
7137
+ ].filter(Boolean).join("\n\n"),
7138
+ duration: 0
7139
+ };
7140
+ callbacks?.onAgentComplete?.(interruptCompleteEvent);
7141
+ return { completeEvent: interruptCompleteEvent, toolMessages };
7142
+ }
7143
+ let resumeResponse;
7144
+ try {
7145
+ resumeResponse = await this.client.requestStream(`/agents/${id}/resume`, {
7146
+ method: "POST",
7147
+ body: JSON.stringify({
7148
+ executionId,
7149
+ toolOutputs: { [toolName]: toolResult },
7150
+ streamResponse: true,
7151
+ debugMode: data.debugMode
7152
+ }),
7153
+ ...abortSignal ? { signal: abortSignal } : {}
7154
+ });
7155
+ } catch (error) {
7156
+ if (abortSignal?.aborted) return finishAborted(executionId);
7157
+ throw error;
7158
+ }
6459
7159
  if (!resumeResponse.ok) {
6460
7160
  const error = await resumeResponse.json().catch(() => ({ error: "Unknown error" }));
6461
7161
  throw new Error(error.error || `HTTP ${resumeResponse.status}`);
@@ -6473,6 +7173,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6473
7173
  currentBody = resumeResponse.body;
6474
7174
  continue;
6475
7175
  }
7176
+ if (abortSignal?.aborted) return finishAborted(lastSeenExecutionId);
6476
7177
  return null;
6477
7178
  }
6478
7179
  }
@@ -6744,7 +7445,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6744
7445
  reasons.push("Best candidate file has not been verified (read back after writing)");
6745
7446
  }
6746
7447
  if (state.verificationRequired && !state.lastVerificationPassed && !trace.verificationPassed) {
6747
- reasons.push("Verification has not passed \u2014 run a verification command (run_check) before completing");
7448
+ reasons.push(
7449
+ "Verification has not passed \u2014 run a verification command (run_check) before completing"
7450
+ );
6748
7451
  }
6749
7452
  return reasons.length > 0 ? reasons.join("; ") : "Completion gates not satisfied for the current workflow phase";
6750
7453
  }
@@ -6787,32 +7490,71 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6787
7490
  );
6788
7491
  }
6789
7492
  /**
6790
- * Compact old tool results based on context mode and window setting.
6791
- * Modifies messages in-place.
7493
+ * Resolve the replay window: the base index sliced off the full history and
7494
+ * the durable summary message that stands in for everything before it.
7495
+ * The base is honored ONLY when the latest summary actually exists —
7496
+ * slicing history with no summary substitute would silently drop prior
7497
+ * context (defensive against states that carried a base but lost their
7498
+ * summaries). The base is also clamped so a stale pointer (fork truncation,
7499
+ * trimmed legacy state) never slices past the end of the array.
7500
+ */
7501
+ resolveWindowReplay(state, messageCount) {
7502
+ const base = state.contextWindowBaseIndex ?? 0;
7503
+ if (!Number.isFinite(base) || base <= 0) {
7504
+ return { windowBase: 0, windowSummaryMessages: [] };
7505
+ }
7506
+ const summaries = state.contextCompactionSummaries;
7507
+ const latest = summaries?.[summaries.length - 1];
7508
+ if (!latest) {
7509
+ return { windowBase: 0, windowSummaryMessages: [] };
7510
+ }
7511
+ return {
7512
+ windowBase: Math.min(Math.floor(base), messageCount),
7513
+ windowSummaryMessages: [{ role: "system", content: latest.content }]
7514
+ };
7515
+ }
7516
+ /**
7517
+ * Derive the message view sent to the model based on context mode and window
7518
+ * setting. This never mutates persisted marathon history; masking/offloading
7519
+ * is a send-time view over the full-fidelity ledger/history.
6792
7520
  */
6793
- compactToolResults(messages, newToolMessages, taskName, mode, window) {
6794
- if (mode === "full-inline") return;
7521
+ deriveToolContextMessages(messages, taskName, mode, window) {
7522
+ if (mode === "full-inline") return [...messages];
7523
+ const maskMessage = (msg) => ({
7524
+ ...msg,
7525
+ toolResults: (msg.toolResults ?? []).map((tr) => this.compactOneResult(tr, taskName, mode))
7526
+ });
7527
+ const view = [...messages];
6795
7528
  if (window === "session") {
6796
- for (const msg of messages) {
7529
+ const lastUserIndex = view.reduce(
7530
+ (lastIndex, message, index) => message.role === "user" ? index : lastIndex,
7531
+ -1
7532
+ );
7533
+ for (let index = 0; index < view.length; index++) {
7534
+ if (lastUserIndex >= 0 && index > lastUserIndex) continue;
7535
+ const msg = view[index];
7536
+ if (!msg) continue;
6797
7537
  if (msg.role === "tool" && msg.toolResults) {
6798
- msg.toolResults = msg.toolResults.map((tr) => this.compactOneResult(tr, taskName, mode));
7538
+ view[index] = maskMessage(msg);
6799
7539
  }
6800
7540
  }
6801
7541
  } else {
6802
- const newToolResultCount = newToolMessages.filter((m) => m.role === "tool").length;
6803
- const keepInlineFromExisting = Math.max(0, window - newToolResultCount);
6804
7542
  const toolResultIndices = [];
6805
- for (let i = 0; i < messages.length; i++) {
6806
- if (messages[i].role === "tool" && messages[i].toolResults) {
7543
+ for (let i = 0; i < view.length; i++) {
7544
+ const message = view[i];
7545
+ if (message?.role === "tool" && message.toolResults) {
6807
7546
  toolResultIndices.push(i);
6808
7547
  }
6809
7548
  }
6810
- const compactUpTo = toolResultIndices.length - keepInlineFromExisting;
7549
+ const compactUpTo = toolResultIndices.length - window;
6811
7550
  for (let j = 0; j < compactUpTo && j < toolResultIndices.length; j++) {
6812
- const msg = messages[toolResultIndices[j]];
6813
- msg.toolResults = msg.toolResults.map((tr) => this.compactOneResult(tr, taskName, mode));
7551
+ const index = toolResultIndices[j];
7552
+ const msg = index === void 0 ? void 0 : view[index];
7553
+ if (!msg) continue;
7554
+ view[index] = maskMessage(msg);
6814
7555
  }
6815
7556
  }
7557
+ return view;
6816
7558
  }
6817
7559
  compactOneResult(tr, taskName, mode) {
6818
7560
  if (typeof tr.result === "string" && tr.result.startsWith("[")) return tr;
@@ -6848,10 +7590,20 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6848
7590
  }
6849
7591
  const slug = this.sanitizeTaskSlug(taskName || "task");
6850
7592
  const dir = `.runtype/marathons/${slug}/tool-outputs`;
6851
- fs.mkdirSync(dir, { recursive: true });
6852
7593
  const filePath = `${dir}/${toolCallId}.txt`;
6853
- fs.writeFileSync(filePath, resultStr, "utf-8");
6854
- return `[${toolName} output (${resultStr.length} chars) saved to ${filePath} \u2014 use read_file to retrieve if needed]`;
7594
+ try {
7595
+ if (!fs.existsSync(filePath)) {
7596
+ fs.mkdirSync(dir, { recursive: true });
7597
+ fs.writeFileSync(filePath, resultStr, "utf-8");
7598
+ }
7599
+ } catch {
7600
+ return result;
7601
+ }
7602
+ return buildSendViewOffloadMarker({
7603
+ toolName,
7604
+ charLength: resultStr.length,
7605
+ filePath
7606
+ });
6855
7607
  }
6856
7608
  getDefaultPlanPath(taskName) {
6857
7609
  return getDefaultPlanPath(taskName);
@@ -6973,6 +7725,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6973
7725
  const migratedPlanPath = workflowVariant === "external" && planPath === this.getDefaultPlanPath(taskName) ? this.getDefaultExternalReportPath(taskName) : planPath;
6974
7726
  const candidatePaths = this.dedupeNormalizedCandidatePaths(resumeState.candidatePaths);
6975
7727
  const recentReadPaths = this.dedupeNormalizedCandidatePaths(resumeState.recentReadPaths);
7728
+ const contextCompactionSummaries = (resumeState.contextCompactionSummaries ?? []).slice(-20);
6976
7729
  const normalizedBestCandidatePath = typeof resumeState.bestCandidatePath === "string" && resumeState.bestCandidatePath.trim() ? this.normalizeCandidatePath(resumeState.bestCandidatePath) : void 0;
6977
7730
  const bestCandidatePath = normalizedBestCandidatePath && !this.isMarathonArtifactPath(normalizedBestCandidatePath) ? normalizedBestCandidatePath : [...candidatePaths, ...recentReadPaths].sort(
6978
7731
  (left, right) => this.scoreCandidatePath(right) - this.scoreCandidatePath(left)
@@ -6992,10 +7745,14 @@ var _AgentsEndpoint = class _AgentsEndpoint {
6992
7745
  bestCandidateVerified: Boolean(resumeState.bestCandidateVerified),
6993
7746
  ...resumeState.verificationRequired !== void 0 ? { verificationRequired: resumeState.verificationRequired } : {},
6994
7747
  lastVerificationPassed: Boolean(resumeState.lastVerificationPassed),
6995
- ...resumeState.consecutiveBlockedVerificationSessions !== void 0 ? { consecutiveBlockedVerificationSessions: resumeState.consecutiveBlockedVerificationSessions } : {},
7748
+ ...resumeState.consecutiveBlockedVerificationSessions !== void 0 ? {
7749
+ consecutiveBlockedVerificationSessions: resumeState.consecutiveBlockedVerificationSessions
7750
+ } : {},
6996
7751
  ...resumeState.isCreationTask !== void 0 ? { isCreationTask: resumeState.isCreationTask } : {},
6997
7752
  ...resumeState.workflowVariant !== void 0 ? { workflowVariant: resumeState.workflowVariant } : {},
6998
7753
  ...resumeState.workflowState !== void 0 ? { workflowState: resumeState.workflowState } : {},
7754
+ ...contextCompactionSummaries.length ? { contextCompactionSummaries } : {},
7755
+ ...typeof resumeState.contextWindowBaseIndex === "number" && Number.isFinite(resumeState.contextWindowBaseIndex) && resumeState.contextWindowBaseIndex > 0 ? { contextWindowBaseIndex: Math.floor(resumeState.contextWindowBaseIndex) } : {},
6999
7756
  ...typeof resumeState.outputRoot === "string" && resumeState.outputRoot.trim() ? { outputRoot: resumeState.outputRoot.trim().replace(/\\/g, "/").replace(/\/+/g, "/") } : {}
7000
7757
  };
7001
7758
  }
@@ -7461,8 +8218,13 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7461
8218
  } : {},
7462
8219
  ...seededResumeState?.candidatePaths ? { candidatePaths: seededResumeState.candidatePaths } : {},
7463
8220
  ...seededResumeState?.recentReadPaths ? { recentReadPaths: seededResumeState.recentReadPaths } : {},
7464
- ...seededResumeState?.recentActionKeys ? { recentActionKeys: seededResumeState.recentActionKeys } : {}
8221
+ ...seededResumeState?.recentActionKeys ? { recentActionKeys: seededResumeState.recentActionKeys } : {},
8222
+ ...seededResumeState?.contextCompactionSummaries?.length ? { contextCompactionSummaries: seededResumeState.contextCompactionSummaries } : {},
8223
+ ...typeof seededResumeState?.contextWindowBaseIndex === "number" ? { contextWindowBaseIndex: seededResumeState.contextWindowBaseIndex } : {}
7465
8224
  };
8225
+ if (options.previousMessages && options.previousMessages.length > 0) {
8226
+ state.messages = options.previousMessages.map((message) => structuredClone(message));
8227
+ }
7466
8228
  state.workflowVariant = classifiedVariant;
7467
8229
  state.isCreationTask = seededResumeState?.isCreationTask ?? state.workflowVariant === "create";
7468
8230
  state.outputRoot = seededResumeState?.outputRoot ?? (state.isCreationTask ? "public/" : void 0);
@@ -7495,6 +8257,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7495
8257
  }
7496
8258
  }
7497
8259
  for (let session = 0; session < maxSessions; session++) {
8260
+ if (options.abortSignal?.aborted) {
8261
+ state.status = "paused";
8262
+ break;
8263
+ }
7498
8264
  const phaseAtSessionStart = state.workflowPhase;
7499
8265
  const sessionTrace = this.createEmptyToolTrace();
7500
8266
  const sessionLocalTools = this.wrapLocalToolsForTrace(
@@ -7512,6 +8278,7 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7512
8278
  if (session === 0 && !options.previousMessages) {
7513
8279
  state.originalMessage = options.message;
7514
8280
  }
8281
+ const queuedSteeringMessages = options.getQueuedUserMessages?.() ?? [];
7515
8282
  const preparedSession = await this.prepareSessionContext(
7516
8283
  options.message,
7517
8284
  state,
@@ -7530,8 +8297,11 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7530
8297
  localTools: options.localTools,
7531
8298
  builtinToolSchemas,
7532
8299
  onContextCompaction: options.onContextCompaction,
7533
- onContextNotice: options.onContextNotice
7534
- }
8300
+ onContextNotice: options.onContextNotice,
8301
+ toolContextMode: options.toolContextMode || "hot-tail",
8302
+ toolWindow: options.toolWindow ?? "session"
8303
+ },
8304
+ queuedSteeringMessages
7535
8305
  );
7536
8306
  const { messages, requestContextManagement, pendingNativeCompactionEvent } = preparedSession;
7537
8307
  let sessionResult;
@@ -7558,7 +8328,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7558
8328
  sessionLocalTools || options.localTools,
7559
8329
  sessionCallbacks,
7560
8330
  {
7561
- onLocalToolResult: this.createLocalToolLoopGuard(state, sessionTrace, workflow)
8331
+ onLocalToolResult: this.createLocalToolLoopGuard(state, sessionTrace, workflow),
8332
+ shouldInterrupt: options.hasQueuedUserMessages,
8333
+ ...options.abortSignal ? { abortSignal: options.abortSignal } : {}
7562
8334
  },
7563
8335
  state.taskName
7564
8336
  );
@@ -7707,22 +8479,13 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7707
8479
  }
7708
8480
  }
7709
8481
  if (!state.messages) state.messages = [];
7710
- if (this.isCompactHistoryMessageSet(messages)) {
7711
- state.messages = [...messages];
7712
- } else if (state.messages.length > 0 && messages.length > state.messages.length) {
7713
- const newMessages = messages.slice(state.messages.length);
7714
- state.messages.push(...newMessages);
7715
- } else {
8482
+ const sentUserMessage = messages[messages.length - 1];
8483
+ if (sentUserMessage?.role === "user") {
8484
+ state.messages.push(sentUserMessage);
8485
+ } else if (state.messages.length === 0) {
7716
8486
  state.messages.push(...messages);
7717
8487
  }
7718
8488
  if (sessionToolMessages.length > 0) {
7719
- this.compactToolResults(
7720
- state.messages,
7721
- sessionToolMessages,
7722
- state.taskName,
7723
- options.toolContextMode || "hot-tail",
7724
- options.toolWindow ?? "session"
7725
- );
7726
8489
  state.messages.push(...sessionToolMessages);
7727
8490
  }
7728
8491
  const assistantContent = effectiveSessionOutput || `[Session ${session + 1} completed (${sessionResult.stopReason}). No text output captured.]`;
@@ -7742,7 +8505,10 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7742
8505
  workflow
7743
8506
  );
7744
8507
  if (detectedTaskCompletion && !acceptedTaskCompletion) {
7745
- state.lastCompletionRejectionReason = this.computeCompletionRejectionReason(state, sessionTrace);
8508
+ state.lastCompletionRejectionReason = this.computeCompletionRejectionReason(
8509
+ state,
8510
+ sessionTrace
8511
+ );
7746
8512
  if (state.verificationRequired && !state.lastVerificationPassed && !sessionTrace.verificationPassed && !sessionTrace.verificationAttempted) {
7747
8513
  state.consecutiveBlockedVerificationSessions = (state.consecutiveBlockedVerificationSessions || 0) + 1;
7748
8514
  if ((state.consecutiveBlockedVerificationSessions || 0) >= 2) {
@@ -7761,24 +8527,24 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7761
8527
  }
7762
8528
  if (sessionResult.stopReason === "complete" && !detectedTaskCompletion) {
7763
8529
  const currentPhase = workflow.phases.find((p) => p.name === state.workflowPhase);
7764
- const gatesSatisfied = currentPhase?.canAcceptCompletion ? currentPhase.canAcceptCompletion(state, sessionTrace) : true;
8530
+ const gatesSatisfied = currentPhase?.canAcceptCompletion ? currentPhase.canAcceptCompletion(
8531
+ state,
8532
+ sessionTrace
8533
+ ) : true;
7765
8534
  if (gatesSatisfied) {
7766
8535
  state.status = "complete";
7767
8536
  }
7768
8537
  } else if (sessionResult.stopReason === "error") {
7769
8538
  if (_AgentsEndpoint.isRetryableSessionError(sessionResult.error) && consecutiveServerNetworkErrors < maxServerNetworkRetries) {
7770
8539
  consecutiveServerNetworkErrors++;
7771
- const delayMs = Math.min(
7772
- 5e3 * Math.pow(2, consecutiveServerNetworkErrors - 1),
7773
- 3e4
7774
- );
8540
+ const delayMs = Math.min(5e3 * Math.pow(2, consecutiveServerNetworkErrors - 1), 3e4);
7775
8541
  const delaySec = Math.round(delayMs / 1e3);
7776
8542
  await this.emitContextNotice(options.onContextNotice, {
7777
8543
  kind: "server_network_retry",
7778
8544
  sessionIndex: session,
7779
8545
  message: `Server network error: ${sessionResult.error}. Retrying in ${delaySec}s (attempt ${consecutiveServerNetworkErrors}/${maxServerNetworkRetries})...`
7780
8546
  });
7781
- await new Promise((resolve) => setTimeout(resolve, delayMs));
8547
+ await sleepWithAbort(delayMs, options.abortSignal);
7782
8548
  } else {
7783
8549
  state.status = "error";
7784
8550
  }
@@ -7793,6 +8559,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7793
8559
  } else if (session + 1 >= maxSessions) {
7794
8560
  state.status = "max_sessions";
7795
8561
  }
8562
+ if (options.abortSignal?.aborted) {
8563
+ state.status = "paused";
8564
+ }
7796
8565
  if (options.trackProgress) {
7797
8566
  recordId = await this.syncProgressRecord(state, recordId);
7798
8567
  }
@@ -7869,6 +8638,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7869
8638
  return 0;
7870
8639
  }
7871
8640
  }
8641
+ extractDeclaredToolResultChars(value) {
8642
+ return extractDeclaredToolResultChars(value);
8643
+ }
7872
8644
  estimateMessageContentTokens(content) {
7873
8645
  if (typeof content === "string") return this.estimateTextTokens(content);
7874
8646
  return content.reduce((total, part) => {
@@ -7887,12 +8659,14 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7887
8659
  0
7888
8660
  );
7889
8661
  }
7890
- estimateToolResultTokens(toolResults) {
8662
+ estimateToolResultTokens(toolResults, options) {
7891
8663
  if (!toolResults || toolResults.length === 0) return 0;
7892
- return toolResults.reduce(
7893
- (sum, toolResult) => sum + 12 + this.estimateTextTokens(toolResult.toolName) + this.estimateUnknownTokens(toolResult.result),
7894
- 0
7895
- );
8664
+ return toolResults.reduce((sum, toolResult) => {
8665
+ const resultTokens = this.estimateUnknownTokens(toolResult.result);
8666
+ const declaredChars = options?.useDeclaredSize ? this.extractDeclaredToolResultChars(toolResult.result) : void 0;
8667
+ const declaredTokens = typeof declaredChars === "number" ? Math.ceil(declaredChars / 4) : 0;
8668
+ return sum + 12 + this.estimateTextTokens(toolResult.toolName) + Math.max(resultTokens, declaredTokens);
8669
+ }, 0);
7896
8670
  }
7897
8671
  estimateMessageTokens(message) {
7898
8672
  return 6 + this.estimateMessageContentTokens(message.content) + this.estimateToolCallTokens(message.toolCalls) + this.estimateToolResultTokens(message.toolResults);
@@ -7900,13 +8674,15 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7900
8674
  estimateConversationTokens(messages) {
7901
8675
  return messages.reduce((sum, message) => sum + this.estimateMessageTokens(message), 0);
7902
8676
  }
7903
- estimateConversationBreakdown(messages) {
8677
+ estimateConversationBreakdown(messages, options) {
7904
8678
  let historyTokens = 0;
7905
8679
  let toolOutputTokens = 0;
7906
8680
  for (const message of messages) {
7907
8681
  const contentTokens = this.estimateMessageContentTokens(message.content);
7908
8682
  const toolCallTokens = this.estimateToolCallTokens(message.toolCalls);
7909
- const toolResultTokens = this.estimateToolResultTokens(message.toolResults);
8683
+ const toolResultTokens = this.estimateToolResultTokens(message.toolResults, {
8684
+ useDeclaredSize: options?.useDeclaredToolResultSizes
8685
+ });
7910
8686
  const messageTotal = 6 + contentTokens + toolCallTokens + toolResultTokens;
7911
8687
  if (message.role === "tool") {
7912
8688
  toolOutputTokens += messageTotal;
@@ -7960,13 +8736,24 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7960
8736
  const compactInstructions = config.compactInstructions;
7961
8737
  return typeof compactInstructions === "string" && compactInstructions.trim() ? compactInstructions.trim() : void 0;
7962
8738
  }
7963
- extractArtifactReferences(state) {
8739
+ extractArtifactReferencesFromMessages(messages = []) {
7964
8740
  const references = /* @__PURE__ */ new Set();
7965
8741
  const offloadPrefix = "[Output saved to ";
7966
- for (const message of state.messages ?? []) {
8742
+ const ledgerArtifactPrefix = LEDGER_ARTIFACT_LINE_PREFIX;
8743
+ const savedToPattern = /saved to\s+([^—\]\n]+?)(?:\s+—|\]|\n|$)/gi;
8744
+ for (const message of messages) {
7967
8745
  if (!message.toolResults) continue;
7968
8746
  for (const toolResult of message.toolResults) {
7969
8747
  if (typeof toolResult.result !== "string") continue;
8748
+ for (const line of toolResult.result.split("\n")) {
8749
+ if (line.startsWith(ledgerArtifactPrefix)) {
8750
+ references.add(line.slice(ledgerArtifactPrefix.length).trim());
8751
+ }
8752
+ }
8753
+ for (const match of toolResult.result.matchAll(savedToPattern)) {
8754
+ const pathText = match[1]?.trim();
8755
+ if (pathText) references.add(pathText);
8756
+ }
7970
8757
  let startIndex = 0;
7971
8758
  while (startIndex < toolResult.result.length) {
7972
8759
  const prefixIndex = toolResult.result.indexOf(offloadPrefix, startIndex);
@@ -7984,6 +8771,13 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7984
8771
  }
7985
8772
  }
7986
8773
  }
8774
+ return Array.from(references);
8775
+ }
8776
+ extractArtifactReferences(state, additionalReferences = []) {
8777
+ const references = /* @__PURE__ */ new Set([
8778
+ ...this.extractArtifactReferencesFromMessages(state.messages ?? []),
8779
+ ...additionalReferences
8780
+ ]);
7987
8781
  if (state.planPath) {
7988
8782
  references.add(state.planPath);
7989
8783
  }
@@ -7991,6 +8785,9 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7991
8785
  }
7992
8786
  buildContextBudgetBreakdown(details) {
7993
8787
  const conversationBreakdown = this.estimateConversationBreakdown(details.historyMessages);
8788
+ const sourceConversationBreakdown = details.sourceHistoryMessages ? this.estimateConversationBreakdown(details.sourceHistoryMessages, {
8789
+ useDeclaredToolResultSizes: true
8790
+ }) : conversationBreakdown;
7994
8791
  const currentTurnTokens = this.estimateTextTokens(details.currentTurnContent);
7995
8792
  const toolDefinitionTokens = this.estimateToolDefinitionTokens(
7996
8793
  details.localTools,
@@ -8007,15 +8804,26 @@ ${details.summaryText}
8007
8804
 
8008
8805
  Do NOT redo any of the above work.`
8009
8806
  ) : void 0;
8807
+ const sendEstimatedInputTokens = conversationBreakdown.estimatedInputTokens + currentTurnTokens + toolDefinitionTokens;
8808
+ const estimatedInputTokens = sourceConversationBreakdown.estimatedInputTokens + currentTurnTokens + toolDefinitionTokens;
8809
+ const toolOutputReductionTokens = Math.max(
8810
+ 0,
8811
+ sourceConversationBreakdown.toolOutputTokens - conversationBreakdown.toolOutputTokens
8812
+ );
8010
8813
  return {
8011
- historyTokens: conversationBreakdown.historyTokens,
8012
- toolOutputTokens: conversationBreakdown.toolOutputTokens,
8814
+ historyTokens: sourceConversationBreakdown.historyTokens,
8815
+ toolOutputTokens: sourceConversationBreakdown.toolOutputTokens,
8013
8816
  currentTurnTokens,
8014
8817
  toolDefinitionTokens,
8015
8818
  ...summaryTokens ? { summaryTokens } : {},
8016
8819
  ...reservedOutputTokens ? { reservedOutputTokens } : {},
8017
8820
  ...effectiveInputBudgetTokens ? { effectiveInputBudgetTokens } : {},
8018
- estimatedInputTokens: conversationBreakdown.estimatedInputTokens + currentTurnTokens + toolDefinitionTokens
8821
+ ...toolOutputReductionTokens > 0 ? {
8822
+ sendEstimatedInputTokens,
8823
+ sendToolOutputTokens: conversationBreakdown.toolOutputTokens,
8824
+ toolOutputReductionTokens
8825
+ } : {},
8826
+ estimatedInputTokens
8019
8827
  };
8020
8828
  }
8021
8829
  async emitContextCompactionEvent(onContextCompaction, event) {
@@ -8055,16 +8863,33 @@ Do NOT redo any of the above work.`
8055
8863
  state,
8056
8864
  userContent,
8057
8865
  details.compactInstructions,
8058
- details.mode
8866
+ details.mode,
8867
+ details.artifactReferences
8059
8868
  );
8869
+ const summaryMessage = compactMessages[0];
8870
+ if (summaryMessage?.role === "system" && typeof summaryMessage.content === "string") {
8871
+ const existingSummaries = state.contextCompactionSummaries ?? [];
8872
+ state.contextCompactionSummaries = [
8873
+ ...existingSummaries,
8874
+ {
8875
+ id: `ctx_${sessionIndex + 1}_${existingSummaries.length + 1}`,
8876
+ sessionIndex: sessionIndex + 1,
8877
+ mode: details.mode,
8878
+ strategy: details.strategy,
8879
+ content: summaryMessage.content,
8880
+ createdAt: (/* @__PURE__ */ new Date()).toISOString()
8881
+ }
8882
+ ].slice(-20);
8883
+ }
8884
+ state.contextWindowBaseIndex = state.messages?.length ?? 0;
8060
8885
  await this.emitContextCompactionEvent(details.onContextCompaction, {
8061
8886
  phase: "complete",
8062
8887
  ...baseEvent
8063
8888
  });
8064
8889
  return compactMessages;
8065
8890
  }
8066
- buildCompactHistoryMessages(state, userContent, compactInstructions, mode = "auto") {
8067
- const summary = this.generateCompactSummary(state, compactInstructions);
8891
+ buildCompactHistoryMessages(state, userContent, compactInstructions, mode = "auto", artifactReferences) {
8892
+ const summary = this.generateCompactSummary(state, compactInstructions, artifactReferences);
8068
8893
  const prefix = mode === "forced" ? this.getForcedCompactionSummaryPrefix(state) : _AgentsEndpoint.AUTO_COMPACT_SUMMARY_PREFIX;
8069
8894
  return [
8070
8895
  {
@@ -8081,16 +8906,11 @@ Do NOT redo any of the above work.`
8081
8906
  }
8082
8907
  ];
8083
8908
  }
8084
- isCompactHistoryMessageSet(messages) {
8085
- if (messages.length === 0) return false;
8086
- const firstMessage = messages[0];
8087
- return firstMessage?.role === "system" && typeof firstMessage.content === "string" && (firstMessage.content.startsWith(_AgentsEndpoint.AUTO_COMPACT_SUMMARY_PREFIX) || firstMessage.content.startsWith(_AgentsEndpoint.RESUMED_COMPACT_SUMMARY_PREFIX) || firstMessage.content.startsWith(_AgentsEndpoint.COMPLETED_COMPACT_SUMMARY_PREFIX));
8088
- }
8089
8909
  /**
8090
8910
  * Generate a compact summary of prior work for continuation context.
8091
8911
  * Used when compact mode is enabled to keep token usage low.
8092
8912
  */
8093
- generateCompactSummary(state, compactInstructions) {
8913
+ generateCompactSummary(state, compactInstructions, additionalArtifactReferences = []) {
8094
8914
  const recentSessions = (state.sessions ?? []).slice(-5);
8095
8915
  const sessionSummaries = recentSessions.map(
8096
8916
  (session) => `- Session ${session.index}: ${session.stopReason} ($${session.cost.toFixed(4)}) ${session.outputPreview.slice(0, 160)}`
@@ -8104,7 +8924,7 @@ Do NOT redo any of the above work.`
8104
8924
  )
8105
8925
  ).slice(0, 8);
8106
8926
  const verificationSummary = state.bestCandidateVerified ? "Latest candidate verified." : state.bestCandidateNeedsVerification ? "Latest candidate still needs verification." : state.lastVerificationPassed ? "Latest verification passed." : state.verificationRequired ? "Verification is still required." : "No verification requirement recorded.";
8107
- const artifactReferences = this.extractArtifactReferences(state);
8927
+ const artifactReferences = this.extractArtifactReferences(state, additionalArtifactReferences);
8108
8928
  const pendingNextStep = state.lastStopReason === "complete" ? "Confirm nothing else remains before declaring the task complete." : `Continue the ${state.workflowPhase || "research"} phase without redoing prior work.`;
8109
8929
  const instructions = compactInstructions || this.buildDefaultCompactInstructions();
8110
8930
  return [
@@ -8234,7 +9054,7 @@ Do NOT redo any of the above work.`
8234
9054
  );
8235
9055
  return prepared.messages;
8236
9056
  }
8237
- async prepareSessionContext(originalMessage, state, sessionIndex, maxSessions, localToolNames, continuationContext, workflow, builtinToolIds, compactionOptions) {
9057
+ async prepareSessionContext(originalMessage, state, sessionIndex, maxSessions, localToolNames, continuationContext, workflow, builtinToolIds, compactionOptions, steeringMessages) {
8238
9058
  const wf = workflow ?? defaultWorkflow;
8239
9059
  const compactInstructions = compactionOptions?.compactInstructions;
8240
9060
  const resolvedStrategy = continuationContext?.compact ? "summary_fallback" : this.resolveCompactStrategy(compactionOptions?.compactStrategy, compactionOptions?.model);
@@ -8319,9 +9139,23 @@ Do NOT redo any of the above work.`
8319
9139
  const phaseBlock = ["", this.buildPhaseInstructions(state, wf)].join("\n");
8320
9140
  const candidateBlock = wf.buildCandidateBlock?.(state) ?? "";
8321
9141
  const multiSessionInstruction = `This is a multi-session task (session ${sessionIndex + 1}/${maxSessions}). When you have fully completed the task, end your response with TASK_COMPLETE on its own line.`;
9142
+ const steeringLines = steeringMessages && steeringMessages.length > 0 ? ["--- User steering (queued during the previous session) ---", ...steeringMessages, ""] : [];
8322
9143
  if (continuationContext && sessionIndex === 0) {
8323
- const replayHistoryMessages = this.sanitizeReplayHistoryMessages(
8324
- continuationContext.previousMessages
9144
+ const resumeWindow = this.resolveWindowReplay(
9145
+ state,
9146
+ continuationContext.previousMessages.length
9147
+ );
9148
+ const sourceReplayHistoryMessages = [
9149
+ ...resumeWindow.windowSummaryMessages,
9150
+ ...this.sanitizeReplayHistoryMessages(
9151
+ continuationContext.previousMessages.slice(resumeWindow.windowBase)
9152
+ )
9153
+ ];
9154
+ const replayHistoryMessages = this.deriveToolContextMessages(
9155
+ sourceReplayHistoryMessages,
9156
+ state.taskName,
9157
+ compactionOptions?.toolContextMode || "hot-tail",
9158
+ compactionOptions?.toolWindow ?? "session"
8325
9159
  );
8326
9160
  const continuationGuardrail = this.buildContinuationGuardrail(state);
8327
9161
  const defaultContinueMessage = "Continue the task. Review your prior work above and proceed with any remaining work. If everything is already complete, respond with TASK_COMPLETE.";
@@ -8329,6 +9163,7 @@ Do NOT redo any of the above work.`
8329
9163
  const userContent = [
8330
9164
  continuationGuardrail,
8331
9165
  "",
9166
+ ...steeringLines,
8332
9167
  userMessage,
8333
9168
  phaseBlock,
8334
9169
  toolsBlock,
@@ -8344,9 +9179,15 @@ Do NOT redo any of the above work.`
8344
9179
  content: userContent
8345
9180
  }
8346
9181
  ];
8347
- const summaryText = this.generateCompactSummary(state, compactInstructions);
9182
+ const replayArtifactReferences = this.extractArtifactReferencesFromMessages(replayHistoryMessages);
9183
+ const summaryText = this.generateCompactSummary(
9184
+ state,
9185
+ compactInstructions,
9186
+ replayArtifactReferences
9187
+ );
8348
9188
  const breakdown = this.buildContextBudgetBreakdown({
8349
9189
  historyMessages: replayHistoryMessages,
9190
+ sourceHistoryMessages: sourceReplayHistoryMessages,
8350
9191
  currentTurnContent: userContent,
8351
9192
  localTools: compactionOptions?.localTools,
8352
9193
  builtinToolSchemas: compactionOptions?.builtinToolSchemas || [],
@@ -8372,7 +9213,8 @@ Do NOT redo any of the above work.`
8372
9213
  reservedOutputTokens: breakdown.reservedOutputTokens,
8373
9214
  breakdown,
8374
9215
  onContextCompaction: compactionOptions?.onContextCompaction,
8375
- compactInstructions
9216
+ compactInstructions,
9217
+ artifactReferences: replayArtifactReferences
8376
9218
  }
8377
9219
  ),
8378
9220
  requestContextManagement
@@ -8396,7 +9238,8 @@ Do NOT redo any of the above work.`
8396
9238
  reservedOutputTokens: breakdown.reservedOutputTokens,
8397
9239
  breakdown,
8398
9240
  onContextCompaction: compactionOptions?.onContextCompaction,
8399
- compactInstructions
9241
+ compactInstructions,
9242
+ artifactReferences: replayArtifactReferences
8400
9243
  }
8401
9244
  ),
8402
9245
  requestContextManagement
@@ -8431,6 +9274,7 @@ Do NOT redo any of the above work.`
8431
9274
  const recoveryMessage2 = this.buildStuckTurnRecoveryMessage(state, wf);
8432
9275
  const rejectionNotice = state.lastCompletionRejectionReason ? `TASK_COMPLETE was rejected because: ${state.lastCompletionRejectionReason}. Address this before signaling completion again.` : void 0;
8433
9276
  const continuationContent = [
9277
+ ...steeringLines,
8434
9278
  "Continue the task.",
8435
9279
  phaseBlock,
8436
9280
  toolsBlock,
@@ -8446,23 +9290,45 @@ Do NOT redo any of the above work.`
8446
9290
  "Do not redo previous work. If the task is already complete, respond with TASK_COMPLETE."
8447
9291
  ].join("\n");
8448
9292
  const MAX_HISTORY_MESSAGES = 60;
8449
- let historyMessages = this.sanitizeReplayHistoryMessages(state.messages);
8450
- if (historyMessages.length > MAX_HISTORY_MESSAGES) {
8451
- const trimmedHistory = this.trimReplayHistoryMessages(historyMessages, MAX_HISTORY_MESSAGES);
8452
- historyMessages = trimmedHistory.historyMessages;
9293
+ const { windowBase, windowSummaryMessages } = this.resolveWindowReplay(
9294
+ state,
9295
+ state.messages.length
9296
+ );
9297
+ let sourceHistoryMessages = this.sanitizeReplayHistoryMessages(
9298
+ state.messages.slice(windowBase)
9299
+ );
9300
+ if (sourceHistoryMessages.length > MAX_HISTORY_MESSAGES) {
9301
+ const trimmedHistory = this.trimReplayHistoryMessages(
9302
+ sourceHistoryMessages,
9303
+ MAX_HISTORY_MESSAGES
9304
+ );
9305
+ sourceHistoryMessages = trimmedHistory.historyMessages;
8453
9306
  if (trimmedHistory.trimmedCount > 0) {
8454
- historyMessages = [
9307
+ sourceHistoryMessages = [
8455
9308
  {
8456
9309
  role: "system",
8457
9310
  content: `[${trimmedHistory.trimmedCount} earlier messages trimmed to stay within context limits. Original task: ${(state.originalMessage || originalMessage).slice(0, 500)}]`
8458
9311
  },
8459
- ...historyMessages
9312
+ ...sourceHistoryMessages
8460
9313
  ];
8461
9314
  }
8462
9315
  }
8463
- const summaryText = this.generateCompactSummary(state, compactInstructions);
9316
+ sourceHistoryMessages = [...windowSummaryMessages, ...sourceHistoryMessages];
9317
+ const historyMessages = this.deriveToolContextMessages(
9318
+ sourceHistoryMessages,
9319
+ state.taskName,
9320
+ compactionOptions?.toolContextMode || "hot-tail",
9321
+ compactionOptions?.toolWindow ?? "session"
9322
+ );
9323
+ const historyArtifactReferences = this.extractArtifactReferencesFromMessages(historyMessages);
9324
+ const summaryText = this.generateCompactSummary(
9325
+ state,
9326
+ compactInstructions,
9327
+ historyArtifactReferences
9328
+ );
8464
9329
  const breakdown = this.buildContextBudgetBreakdown({
8465
9330
  historyMessages,
9331
+ sourceHistoryMessages,
8466
9332
  currentTurnContent: continuationContent,
8467
9333
  localTools: compactionOptions?.localTools,
8468
9334
  builtinToolSchemas: compactionOptions?.builtinToolSchemas || [],
@@ -8489,7 +9355,8 @@ Do NOT redo any of the above work.`
8489
9355
  reservedOutputTokens: breakdown.reservedOutputTokens,
8490
9356
  breakdown,
8491
9357
  onContextCompaction: compactionOptions?.onContextCompaction,
8492
- compactInstructions
9358
+ compactInstructions,
9359
+ artifactReferences: historyArtifactReferences
8493
9360
  }
8494
9361
  ),
8495
9362
  requestContextManagement
@@ -8504,6 +9371,7 @@ Do NOT redo any of the above work.`
8504
9371
  const recoveryMessage = this.buildStuckTurnRecoveryMessage(state, wf);
8505
9372
  const fallbackRejectionNotice = state.lastCompletionRejectionReason ? `TASK_COMPLETE was rejected because: ${state.lastCompletionRejectionReason}. Address this before signaling completion again.` : void 0;
8506
9373
  const content = [
9374
+ ...steeringLines,
8507
9375
  originalMessage,
8508
9376
  phaseBlock,
8509
9377
  toolsBlock,
@@ -8962,6 +9830,52 @@ var BillingEndpoint = class {
8962
9830
  return this.client.get("/billing/spend-analytics", params);
8963
9831
  }
8964
9832
  };
9833
+ var AppsEndpoint = class {
9834
+ constructor(client) {
9835
+ this.client = client;
9836
+ }
9837
+ /** List apps for the authenticated owner, newest first. */
9838
+ async list() {
9839
+ return this.client.get("/apps");
9840
+ }
9841
+ /** Get an app by id, including its URL and active version pointer. */
9842
+ async get(id) {
9843
+ return this.client.get(`/apps/${id}`);
9844
+ }
9845
+ /** Create an app. A client token scoped to the app origin is auto-provisioned. */
9846
+ async create(data) {
9847
+ return this.client.post("/apps", data);
9848
+ }
9849
+ /** Update name, description, visibility, or status (suspended serves 410). */
9850
+ async update(id, data) {
9851
+ return this.client.patch(`/apps/${id}`, data);
9852
+ }
9853
+ /** Delete an app, its versions, and its hosting. Irreversible. */
9854
+ async delete(id) {
9855
+ return this.client.delete(`/apps/${id}`);
9856
+ }
9857
+ /** List an app's versions, newest first. */
9858
+ async listVersions(id) {
9859
+ return this.client.get(`/apps/${id}/versions`);
9860
+ }
9861
+ /** Upload a zipped bundle (raw application/zip body) as a new version. */
9862
+ async uploadVersion(id, zipBytes) {
9863
+ return this.client.postBinary(`/apps/${id}/versions`, zipBytes, "application/zip");
9864
+ }
9865
+ /**
9866
+ * Upload a bundle from in-memory file maps (the API zips server-side).
9867
+ * Text files in `files`, binary files base64-encoded in `filesBase64`.
9868
+ */
9869
+ async uploadVersionFiles(id, data) {
9870
+ return this.client.post(`/apps/${id}/versions`, data);
9871
+ }
9872
+ /** Activate an uploaded version (deploy or rollback). */
9873
+ async activate(id, versionId) {
9874
+ return this.client.post(`/apps/${id}/activate`, {
9875
+ versionId
9876
+ });
9877
+ }
9878
+ };
8965
9879
 
8966
9880
  // src/client.ts
8967
9881
  function isObjectRecord(value) {
@@ -9004,6 +9918,7 @@ var RuntypeClient2 = class {
9004
9918
  this.clientTokens = new ClientTokensEndpoint(this);
9005
9919
  this.agents = new AgentsEndpoint(this);
9006
9920
  this.secrets = new SecretsEndpoint(this);
9921
+ this.apps = new AppsEndpoint(this);
9007
9922
  this.schedules = new SchedulesEndpoint(this);
9008
9923
  this.surfaces = new SurfacesEndpoint(this);
9009
9924
  this.conversations = new ConversationsEndpoint(this);
@@ -9050,7 +9965,7 @@ var RuntypeClient2 = class {
9050
9965
  clearApiKey() {
9051
9966
  delete this.headers.Authorization;
9052
9967
  }
9053
- async runWithLocalTools(request, localTools, arg3, arg4) {
9968
+ async runWithLocalTools(request2, localTools, arg3, arg4) {
9054
9969
  const isOptionsObject = (val) => typeof val === "object" && val !== null && "scope" in val;
9055
9970
  const callbacks = isOptionsObject(arg3) ? void 0 : arg3;
9056
9971
  const options = (isOptionsObject(arg3) ? arg3 : arg4) ?? {};
@@ -9064,12 +9979,12 @@ var RuntypeClient2 = class {
9064
9979
  ...entry.pageOrigin ? { pageOrigin: entry.pageOrigin } : {}
9065
9980
  })) : [];
9066
9981
  const modifiedRequest = {
9067
- ...request,
9982
+ ...request2,
9068
9983
  ...derivedClientTools.length > 0 ? {
9069
- clientTools: [...request.clientTools ?? [], ...derivedClientTools]
9984
+ clientTools: [...request2.clientTools ?? [], ...derivedClientTools]
9070
9985
  } : {},
9071
9986
  options: {
9072
- ...request.options || {},
9987
+ ...request2.options || {},
9073
9988
  streamResponse: isStreaming
9074
9989
  }
9075
9990
  };
@@ -9085,13 +10000,12 @@ var RuntypeClient2 = class {
9085
10000
  onFlowComplete: (event) => callbacks?.onFlowComplete?.(event),
9086
10001
  onError: (error) => callbacks?.onError?.(error)
9087
10002
  };
9088
- const { streamEvents: streamEvents2, stepDeltaText: stepDeltaText2, stepDisplayName: stepDisplayName2, flowErrorMessage: flowErrorMessage2 } = await Promise.resolve().then(() => (init_stream_utils(), stream_utils_exports));
9089
10003
  const summary = {
9090
10004
  results: /* @__PURE__ */ new Map(),
9091
10005
  success: true
9092
10006
  };
9093
10007
  try {
9094
- for await (const event of streamEvents2(response)) {
10008
+ for await (const event of streamEvents(response)) {
9095
10009
  collectLocalToolAwait(pausedTools, event);
9096
10010
  switch (event.type) {
9097
10011
  case "flow_start":
@@ -9101,10 +10015,10 @@ var RuntypeClient2 = class {
9101
10015
  wrappedCallbacks.onStepStart?.(event);
9102
10016
  break;
9103
10017
  case "step_delta":
9104
- wrappedCallbacks.onStepDelta?.(stepDeltaText2(event), event);
10018
+ wrappedCallbacks.onStepDelta?.(stepDeltaText(event), event);
9105
10019
  break;
9106
10020
  case "step_complete": {
9107
- summary.results?.set(stepDisplayName2(event), event.result);
10021
+ summary.results?.set(stepDisplayName(event), event.result);
9108
10022
  wrappedCallbacks.onStepComplete?.(event.result, event);
9109
10023
  break;
9110
10024
  }
@@ -9112,7 +10026,7 @@ var RuntypeClient2 = class {
9112
10026
  wrappedCallbacks.onFlowComplete?.(event);
9113
10027
  break;
9114
10028
  case "flow_error":
9115
- wrappedCallbacks.onError?.(new Error(flowErrorMessage2(event)));
10029
+ wrappedCallbacks.onError?.(new Error(flowErrorMessage(event)));
9116
10030
  break;
9117
10031
  }
9118
10032
  }
@@ -9191,7 +10105,8 @@ var RuntypeClient2 = class {
9191
10105
  return [toolName, await handler(parameters)];
9192
10106
  } catch (error) {
9193
10107
  throw new Error(
9194
- `Error executing local tool "${toolName}": ${error instanceof Error ? error.message : String(error)}`
10108
+ `Error executing local tool "${toolName}": ${error instanceof Error ? error.message : String(error)}`,
10109
+ { cause: error }
9195
10110
  );
9196
10111
  }
9197
10112
  })
@@ -9255,6 +10170,21 @@ var RuntypeClient2 = class {
9255
10170
  });
9256
10171
  return transformResponse(response);
9257
10172
  }
10173
+ /**
10174
+ * POST request with a raw binary body (e.g. application/zip bundle uploads).
10175
+ */
10176
+ async postBinary(path, body, contentType) {
10177
+ const url = this.buildUrl(path);
10178
+ const headers = { ...this.headers, "Content-Type": contentType };
10179
+ const response = await this.makeRequest(url, {
10180
+ method: "POST",
10181
+ headers,
10182
+ // TS 5.7 types Uint8Array over ArrayBufferLike, which no longer
10183
+ // overlaps DOM BodyInit; the runtime value is a valid fetch body.
10184
+ body
10185
+ });
10186
+ return transformResponse(response);
10187
+ }
9258
10188
  /**
9259
10189
  * Generic request that returns raw Response for streaming
9260
10190
  */
@@ -9355,7 +10285,7 @@ var RuntypeClient2 = class {
9355
10285
  } catch (error) {
9356
10286
  if (timeoutId) clearTimeout(timeoutId);
9357
10287
  if (timeoutId && error instanceof Error && error.name === "AbortError") {
9358
- throw new Error(`Request timeout after ${this.timeout}ms`);
10288
+ throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
9359
10289
  }
9360
10290
  throw error;
9361
10291
  }
@@ -9364,8 +10294,18 @@ var RuntypeClient2 = class {
9364
10294
  * Make HTTP request that returns raw Response (for streaming)
9365
10295
  */
9366
10296
  async makeRawRequest(url, options) {
9367
- const controller = this.timeout === null ? null : new AbortController();
10297
+ const callerSignal = options.signal ?? null;
10298
+ const controller = this.timeout === null && !callerSignal ? null : new AbortController();
9368
10299
  const timeoutId = controller && this.timeout !== null ? setTimeout(() => controller.abort(), this.timeout) : null;
10300
+ if (callerSignal && controller) {
10301
+ if (callerSignal.aborted) {
10302
+ controller.abort(callerSignal.reason);
10303
+ } else {
10304
+ callerSignal.addEventListener("abort", () => controller.abort(callerSignal.reason), {
10305
+ once: true
10306
+ });
10307
+ }
10308
+ }
9369
10309
  try {
9370
10310
  const response = await fetch(url, {
9371
10311
  ...options,
@@ -9378,8 +10318,8 @@ var RuntypeClient2 = class {
9378
10318
  return response;
9379
10319
  } catch (error) {
9380
10320
  if (timeoutId) clearTimeout(timeoutId);
9381
- if (timeoutId && error instanceof Error && error.name === "AbortError") {
9382
- throw new Error(`Request timeout after ${this.timeout}ms`);
10321
+ if (timeoutId && error instanceof Error && error.name === "AbortError" && !callerSignal?.aborted) {
10322
+ throw new Error(`Request timeout after ${this.timeout}ms`, { cause: error });
9383
10323
  }
9384
10324
  throw error;
9385
10325
  }
@@ -9425,9 +10365,6 @@ function createClient(config) {
9425
10365
  return new RuntypeClient2(config);
9426
10366
  }
9427
10367
 
9428
- // src/index.ts
9429
- init_stream_utils();
9430
-
9431
10368
  // src/batch-builder.ts
9432
10369
  var BatchBuilder = class {
9433
10370
  constructor() {
@@ -9485,20 +10422,20 @@ var BatchBuilder = class {
9485
10422
  if (!this.recordType) {
9486
10423
  throw new Error("BatchBuilder: recordType is required. Call .forRecordType(type) first.");
9487
10424
  }
9488
- const request = {
10425
+ const request2 = {
9489
10426
  flowId: this.flowId,
9490
10427
  recordType: this.recordType
9491
10428
  };
9492
10429
  if (Object.keys(this.batchOptions).length > 0) {
9493
- request.options = this.batchOptions;
10430
+ request2.options = this.batchOptions;
9494
10431
  }
9495
10432
  if (this.filterConfig) {
9496
- request.filter = this.filterConfig;
10433
+ request2.filter = this.filterConfig;
9497
10434
  }
9498
10435
  if (this.limitConfig !== void 0) {
9499
- request.limit = this.limitConfig;
10436
+ request2.limit = this.limitConfig;
9500
10437
  }
9501
- return request;
10438
+ return request2;
9502
10439
  }
9503
10440
  /**
9504
10441
  * Execute the batch operation
@@ -9655,32 +10592,32 @@ var EvalBuilder = class {
9655
10592
  "EvalBuilder: records are required. Call .forRecordType(type) or .withRecords([...]) first."
9656
10593
  );
9657
10594
  }
9658
- const request = {};
10595
+ const request2 = {};
9659
10596
  if (this.flowId) {
9660
- request.flowId = this.flowId;
10597
+ request2.flowId = this.flowId;
9661
10598
  } else if (this.virtualFlow) {
9662
- request.flow = this.virtualFlow;
10599
+ request2.flow = this.virtualFlow;
9663
10600
  }
9664
10601
  if (this.recordType) {
9665
- request.recordType = this.recordType;
10602
+ request2.recordType = this.recordType;
9666
10603
  } else if (this.inlineRecords) {
9667
- request.records = this.inlineRecords;
10604
+ request2.records = this.inlineRecords;
9668
10605
  }
9669
10606
  if (this.modelOverrides) {
9670
- request.modelOverrides = this.modelOverrides;
10607
+ request2.modelOverrides = this.modelOverrides;
9671
10608
  } else if (this.modelConfigs) {
9672
- request.modelConfigs = this.modelConfigs;
10609
+ request2.modelConfigs = this.modelConfigs;
9673
10610
  }
9674
10611
  if (Object.keys(this.evalOptions).length > 0) {
9675
- request.options = this.evalOptions;
10612
+ request2.options = this.evalOptions;
9676
10613
  }
9677
10614
  if (this.filterConfig) {
9678
- request.filter = this.filterConfig;
10615
+ request2.filter = this.filterConfig;
9679
10616
  }
9680
10617
  if (this.limitConfig !== void 0) {
9681
- request.limit = this.limitConfig;
10618
+ request2.limit = this.limitConfig;
9682
10619
  }
9683
- return request;
10620
+ return request2;
9684
10621
  }
9685
10622
  /**
9686
10623
  * Execute the evaluation
@@ -10147,10 +11084,14 @@ var STEP_TYPE_TO_METHOD = {
10147
11084
  };
10148
11085
  // Annotate the CommonJS export names for ESM import in node:
10149
11086
  0 && (module.exports = {
11087
+ AgentDriftError,
11088
+ AgentEnsureConflictError,
10150
11089
  AgentVersionsEndpoint,
10151
11090
  AgentsEndpoint,
11091
+ AgentsNamespace,
10152
11092
  AnalyticsEndpoint,
10153
11093
  ApiKeysEndpoint,
11094
+ AppsEndpoint,
10154
11095
  BatchBuilder,
10155
11096
  BatchesNamespace,
10156
11097
  BillingEndpoint,
@@ -10167,12 +11108,15 @@ var STEP_TYPE_TO_METHOD = {
10167
11108
  EvalRunner,
10168
11109
  EvalsNamespace,
10169
11110
  FlowBuilder,
11111
+ FlowDriftError,
11112
+ FlowEnsureConflictError,
10170
11113
  FlowResult,
10171
11114
  FlowStepsEndpoint,
10172
11115
  FlowVersionsEndpoint,
10173
11116
  FlowsEndpoint,
10174
11117
  FlowsNamespace,
10175
11118
  IntegrationsEndpoint,
11119
+ LEDGER_ARTIFACT_LINE_PREFIX,
10176
11120
  LogsEndpoint,
10177
11121
  ModelConfigsEndpoint,
10178
11122
  PromptRunner,
@@ -10196,19 +11140,29 @@ var STEP_TYPE_TO_METHOD = {
10196
11140
  applyGeneratedRuntimeToolProposalToDispatchRequest,
10197
11141
  attachRuntimeToolsToDispatchRequest,
10198
11142
  buildGeneratedRuntimeToolGateOutput,
11143
+ buildLedgerOffloadReference,
11144
+ buildSendViewOffloadMarker,
11145
+ computeAgentContentHash,
11146
+ computeFlowContentHash,
10199
11147
  createClient,
10200
11148
  createExternalTool,
10201
11149
  defaultWorkflow,
11150
+ defineAgent,
11151
+ defineFlow,
10202
11152
  deployWorkflow,
10203
11153
  evaluateGeneratedRuntimeToolProposal,
11154
+ extractDeclaredToolResultChars,
10204
11155
  gameWorkflow,
10205
11156
  getDefaultPlanPath,
10206
11157
  getLikelySupportingCandidatePaths,
10207
11158
  isDiscoveryToolName,
10208
11159
  isMarathonArtifactPath,
10209
11160
  isPreservationSensitiveTask,
11161
+ normalizeAgentDefinition,
10210
11162
  normalizeCandidatePath,
10211
11163
  parseFinalBuffer,
11164
+ parseLedgerArtifactRelativePath,
11165
+ parseOffloadedOutputId,
10212
11166
  parseSSEChunk,
10213
11167
  processStream,
10214
11168
  sanitizeTaskSlug,