@runtypelabs/sdk 4.11.0 → 4.12.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.mjs CHANGED
@@ -1094,20 +1094,20 @@ var FlowBuilder = class {
1094
1094
  */
1095
1095
  build() {
1096
1096
  const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
1097
- const request2 = { flow };
1097
+ const request3 = { flow };
1098
1098
  if (this.recordConfig) {
1099
- request2.record = this.recordConfig;
1099
+ request3.record = this.recordConfig;
1100
1100
  }
1101
1101
  if (this.messagesConfig) {
1102
- request2.messages = this.messagesConfig;
1102
+ request3.messages = this.messagesConfig;
1103
1103
  }
1104
1104
  if (this.inputsConfig) {
1105
- request2.inputs = this.inputsConfig;
1105
+ request3.inputs = this.inputsConfig;
1106
1106
  }
1107
1107
  if (Object.keys(this.optionsConfig).length > 0) {
1108
- request2.options = this.optionsConfig;
1108
+ request3.options = this.optionsConfig;
1109
1109
  }
1110
- return request2;
1110
+ return request3;
1111
1111
  }
1112
1112
  /**
1113
1113
  * Validate this prospective flow against the public validation endpoint
@@ -1430,6 +1430,9 @@ function collectStepNonPortableToolRefs(config, path) {
1430
1430
  scanArray(tools.codeModeConfig.toolPool, `${path}.tools.codeModeConfig.toolPool`);
1431
1431
  }
1432
1432
  }
1433
+ if (isAccountScoped(config.toolId)) {
1434
+ found.push(`${path}.toolId`);
1435
+ }
1433
1436
  for (const branch of ["trueSteps", "falseSteps"]) {
1434
1437
  const nested = config[branch];
1435
1438
  if (!Array.isArray(nested)) continue;
@@ -1483,7 +1486,7 @@ function defineFlow(input) {
1483
1486
  const nonPortable = collectStepNonPortableToolRefs(config, `steps[${index}].config`);
1484
1487
  if (nonPortable.length > 0) {
1485
1488
  throw new Error(
1486
- `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.`
1489
+ `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, or reference a saved tool by name with tool:<name> instead.`
1487
1490
  );
1488
1491
  }
1489
1492
  }
@@ -2482,15 +2485,15 @@ var RuntypeFlowBuilder = class {
2482
2485
  build() {
2483
2486
  const flowMode = this.mode === "existing" ? "existing" : this.mode;
2484
2487
  const flow = this.existingFlowId ? { id: this.existingFlowId } : { name: this.flowConfig.name, steps: this.steps };
2485
- const request2 = { flow };
2488
+ const request3 = { flow };
2486
2489
  if (this.recordConfig) {
2487
- request2.record = this.recordConfig;
2490
+ request3.record = this.recordConfig;
2488
2491
  }
2489
2492
  if (this.messagesConfig) {
2490
- request2.messages = this.messagesConfig;
2493
+ request3.messages = this.messagesConfig;
2491
2494
  }
2492
2495
  if (this.inputsConfig) {
2493
- request2.inputs = this.inputsConfig;
2496
+ request3.inputs = this.inputsConfig;
2494
2497
  }
2495
2498
  const options = {
2496
2499
  flowMode,
@@ -2508,8 +2511,8 @@ var RuntypeFlowBuilder = class {
2508
2511
  if (this.mode === "upsert" && Object.keys(this.upsertOptions).length > 0) {
2509
2512
  options.upsertOptions = this.upsertOptions;
2510
2513
  }
2511
- request2.options = options;
2512
- return request2;
2514
+ request3.options = options;
2515
+ return request3;
2513
2516
  }
2514
2517
  /**
2515
2518
  * Validate this prospective flow against the public validation endpoint
@@ -3399,7 +3402,7 @@ function defineAgent(input) {
3399
3402
  const nonPortable = collectNonPortableToolRefs(config);
3400
3403
  if (nonPortable.length > 0) {
3401
3404
  throw new Error(
3402
- `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.`
3405
+ `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, or reference a saved tool by name with tool:<name> instead.`
3403
3406
  );
3404
3407
  }
3405
3408
  return {
@@ -3541,6 +3544,242 @@ var AgentsNamespace = class {
3541
3544
  }
3542
3545
  };
3543
3546
 
3547
+ // src/tools-ensure.ts
3548
+ function isPlainObject3(value) {
3549
+ return value !== null && typeof value === "object" && !Array.isArray(value);
3550
+ }
3551
+ function normalizeValue2(value) {
3552
+ if (Array.isArray(value)) {
3553
+ return value.map((item) => normalizeValue2(item));
3554
+ }
3555
+ if (isPlainObject3(value)) {
3556
+ const normalized = {};
3557
+ for (const key of Object.keys(value).sort()) {
3558
+ const entry = value[key];
3559
+ if (entry === void 0 || entry === null) continue;
3560
+ normalized[key] = normalizeValue2(entry);
3561
+ }
3562
+ return normalized;
3563
+ }
3564
+ return value;
3565
+ }
3566
+ function normalizeToolDefinition(definition) {
3567
+ const parametersSchema = isPlainObject3(definition.parametersSchema) ? normalizeValue2(definition.parametersSchema) : {};
3568
+ const config = isPlainObject3(definition.config) ? normalizeValue2(definition.config) : {};
3569
+ return {
3570
+ toolType: definition.toolType,
3571
+ ...definition.description ? { description: definition.description } : {},
3572
+ parametersSchema,
3573
+ config
3574
+ };
3575
+ }
3576
+ async function computeToolContentHash(definition) {
3577
+ const serialized = JSON.stringify(normalizeToolDefinition(definition));
3578
+ const encoded = new TextEncoder().encode(serialized);
3579
+ const hashBuffer = await crypto.subtle.digest("SHA-256", encoded);
3580
+ return Array.from(new Uint8Array(hashBuffer)).map((b) => b.toString(16).padStart(2, "0")).join("");
3581
+ }
3582
+ var DEFINE_TOOL_TOP_LEVEL_KEYS = /* @__PURE__ */ new Set([
3583
+ "name",
3584
+ "description",
3585
+ "toolType",
3586
+ "parametersSchema",
3587
+ "config"
3588
+ ]);
3589
+ var TOOL_DEFINITION_TYPES = /* @__PURE__ */ new Set([
3590
+ "flow",
3591
+ "custom",
3592
+ "external",
3593
+ "graphql",
3594
+ "mcp",
3595
+ "local",
3596
+ "subagent"
3597
+ ]);
3598
+ function defineTool(input) {
3599
+ if (!input || typeof input !== "object") {
3600
+ throw new Error("defineTool requires a definition object");
3601
+ }
3602
+ if (typeof input.name !== "string" || input.name.length === 0) {
3603
+ throw new Error('defineTool requires a non-empty string "name"');
3604
+ }
3605
+ if (typeof input.description !== "string" || input.description.length === 0) {
3606
+ throw new Error('defineTool requires a non-empty string "description"');
3607
+ }
3608
+ if (typeof input.toolType !== "string" || !TOOL_DEFINITION_TYPES.has(input.toolType)) {
3609
+ throw new Error(
3610
+ `defineTool requires "toolType" to be one of: ${[...TOOL_DEFINITION_TYPES].join(", ")}`
3611
+ );
3612
+ }
3613
+ if (!isPlainObject3(input.parametersSchema)) {
3614
+ throw new Error('defineTool requires a "parametersSchema" object (a JSON Schema)');
3615
+ }
3616
+ if (!isPlainObject3(input.config)) {
3617
+ throw new Error('defineTool requires a "config" object');
3618
+ }
3619
+ const unknownKeys = Object.keys(input).filter((key) => !DEFINE_TOOL_TOP_LEVEL_KEYS.has(key));
3620
+ if (unknownKeys.length > 0) {
3621
+ throw new Error(
3622
+ `defineTool: unknown field(s): ${unknownKeys.join(", ")}. Allowed fields are name, description, toolType, parametersSchema, config.`
3623
+ );
3624
+ }
3625
+ return {
3626
+ name: input.name,
3627
+ description: input.description,
3628
+ toolType: input.toolType,
3629
+ parametersSchema: input.parametersSchema,
3630
+ config: input.config
3631
+ };
3632
+ }
3633
+ var ToolEnsureConflictError = class extends Error {
3634
+ constructor(body) {
3635
+ super(body.error ?? `Tool ensure conflict: ${body.code}`);
3636
+ this.name = "ToolEnsureConflictError";
3637
+ this.code = body.code;
3638
+ this.lastModifiedSource = body.lastModifiedSource;
3639
+ this.modifiedAt = body.modifiedAt;
3640
+ this.currentHash = body.currentHash;
3641
+ }
3642
+ };
3643
+ var ToolDriftError = class extends Error {
3644
+ constructor(plan) {
3645
+ super(
3646
+ `Tool "${plan.toolId ?? "definition"}" drifted: plan is '${plan.changes}' (changed: ${plan.changedKeys.join(", ") || "n/a"}). Run client.tools.pull(name) to absorb the remote edit into your repo, or re-run ensure to converge.`
3647
+ );
3648
+ this.name = "ToolDriftError";
3649
+ this.plan = plan;
3650
+ }
3651
+ };
3652
+ function parseRequestError3(err) {
3653
+ if (!(err instanceof Error)) return { status: null, body: null };
3654
+ const match = err.message.match(/^API request failed: (\d{3}) .*? - ([\s\S]*)$/);
3655
+ if (!match) return { status: null, body: null };
3656
+ try {
3657
+ return { status: Number(match[1]), body: JSON.parse(match[2]) };
3658
+ } catch {
3659
+ return { status: Number(match[1]), body: null };
3660
+ }
3661
+ }
3662
+ function toConflictError3(err) {
3663
+ const { status, body } = parseRequestError3(err);
3664
+ if (status !== 409 || !isPlainObject3(body)) return null;
3665
+ const code = body.code;
3666
+ if (code !== "external_modification" && code !== "remote_changed") return null;
3667
+ return new ToolEnsureConflictError(
3668
+ body
3669
+ );
3670
+ }
3671
+ var serverHashMemo3 = /* @__PURE__ */ new WeakMap();
3672
+ function memoFor3(client) {
3673
+ let memo = serverHashMemo3.get(client);
3674
+ if (!memo) {
3675
+ memo = /* @__PURE__ */ new Map();
3676
+ serverHashMemo3.set(client, memo);
3677
+ }
3678
+ return memo;
3679
+ }
3680
+ function memoize2(memo, memoKey, result) {
3681
+ if (result.result !== "plan") memo.set(memoKey, result.contentHash);
3682
+ }
3683
+ async function request2(client, body) {
3684
+ try {
3685
+ return await client.post(
3686
+ "/tools/ensure",
3687
+ body
3688
+ );
3689
+ } catch (err) {
3690
+ const conflict = toConflictError3(err);
3691
+ if (conflict) throw conflict;
3692
+ throw err;
3693
+ }
3694
+ }
3695
+ async function ensureTool(client, definition, options = {}) {
3696
+ const { dryRun, onConflict, expectedRemoteHash, expectNoChanges } = options;
3697
+ const passthrough = {
3698
+ ...onConflict ? { onConflict } : {},
3699
+ ...expectedRemoteHash ? { expectedRemoteHash } : {}
3700
+ };
3701
+ if (dryRun || expectNoChanges) {
3702
+ const plan = await request2(client, {
3703
+ name: definition.name,
3704
+ definition,
3705
+ dryRun: true,
3706
+ ...passthrough
3707
+ });
3708
+ if (plan.result !== "plan") {
3709
+ throw new Error(`Expected a plan result from dryRun, got '${plan.result}'`);
3710
+ }
3711
+ if (expectNoChanges && plan.changes !== "none") {
3712
+ throw new ToolDriftError(plan);
3713
+ }
3714
+ return plan;
3715
+ }
3716
+ const memo = memoFor3(client);
3717
+ const localHash = await computeToolContentHash(definition);
3718
+ const memoKey = `${definition.name} ${localHash}`;
3719
+ const contentHash = memo.get(memoKey) ?? localHash;
3720
+ const probe = await request2(client, {
3721
+ name: definition.name,
3722
+ contentHash,
3723
+ ...passthrough
3724
+ });
3725
+ if (probe.result !== "definitionRequired") {
3726
+ memoize2(memo, memoKey, probe);
3727
+ return probe;
3728
+ }
3729
+ const converged = await request2(client, {
3730
+ name: definition.name,
3731
+ definition,
3732
+ ...passthrough
3733
+ });
3734
+ if (converged.result === "definitionRequired") {
3735
+ throw new Error("Server reported definitionRequired for a full-definition request");
3736
+ }
3737
+ memoize2(memo, memoKey, converged);
3738
+ return converged;
3739
+ }
3740
+ async function pullTool(client, name) {
3741
+ return client.get("/tools/pull", { name });
3742
+ }
3743
+
3744
+ // src/tools-namespace.ts
3745
+ var ToolsNamespace = class {
3746
+ constructor(getClient) {
3747
+ this.getClient = getClient;
3748
+ }
3749
+ /**
3750
+ * Idempotently converge a `defineTool` definition onto the platform.
3751
+ * Hash-first: the steady state is one tiny probe request. Creates or updates
3752
+ * the saved tool; never deletes. Identity is name + account scope.
3753
+ *
3754
+ * @example
3755
+ * ```typescript
3756
+ * const weather = defineTool({
3757
+ * name: 'Weather Lookup',
3758
+ * description: 'Fetch the current weather for a city',
3759
+ * toolType: 'external',
3760
+ * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
3761
+ * config: { url: 'https://api.example.com/weather', method: 'GET' },
3762
+ * })
3763
+ *
3764
+ * // Converge (CI/deploy).
3765
+ * const result = await Runtype.tools.ensure(weather)
3766
+ *
3767
+ * // PR drift gate.
3768
+ * await Runtype.tools.ensure(weather, { expectNoChanges: true })
3769
+ * ```
3770
+ */
3771
+ async ensure(definition, options = {}) {
3772
+ return ensureTool(this.getClient(), definition, options);
3773
+ }
3774
+ /**
3775
+ * Pull the canonical definition + provenance for a tool by name — the
3776
+ * absorb-drift direction of the ensure protocol.
3777
+ */
3778
+ async pull(name) {
3779
+ return pullTool(this.getClient(), name);
3780
+ }
3781
+ };
3782
+
3544
3783
  // src/transform.ts
3545
3784
  function transformResponse(data) {
3546
3785
  return data;
@@ -3929,6 +4168,34 @@ var Runtype = class {
3929
4168
  static get agents() {
3930
4169
  return new AgentsNamespace(() => this.getClient());
3931
4170
  }
4171
+ /**
4172
+ * Tools namespace - Tool config-as-code (define / ensure / pull)
4173
+ *
4174
+ * @example
4175
+ * ```typescript
4176
+ * import { defineTool, Runtype } from '@runtypelabs/sdk'
4177
+ *
4178
+ * const weather = defineTool({
4179
+ * name: 'Weather Lookup',
4180
+ * description: 'Fetch the current weather for a city',
4181
+ * toolType: 'external',
4182
+ * parametersSchema: { type: 'object', properties: { city: { type: 'string' } } },
4183
+ * config: { url: 'https://api.example.com/weather', method: 'GET' },
4184
+ * })
4185
+ *
4186
+ * // Converge at deploy time (idempotent; one tiny probe in steady state)
4187
+ * await Runtype.tools.ensure(weather)
4188
+ *
4189
+ * // CI drift gate
4190
+ * await Runtype.tools.ensure(weather, { expectNoChanges: true })
4191
+ *
4192
+ * // Absorb a dashboard edit back into the repo
4193
+ * const { definition } = await Runtype.tools.pull('Weather Lookup')
4194
+ * ```
4195
+ */
4196
+ static get tools() {
4197
+ return new ToolsNamespace(() => this.getClient());
4198
+ }
3932
4199
  };
3933
4200
 
3934
4201
  // src/generated-tool-gate.ts
@@ -4151,8 +4418,8 @@ function buildGeneratedRuntimeToolGateOutput(proposal, options = {}) {
4151
4418
  ...decision.tool ? { tool: decision.tool } : {}
4152
4419
  };
4153
4420
  }
4154
- function attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options = {}) {
4155
- const stepList = request2.flow.steps;
4421
+ function attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options = {}) {
4422
+ const stepList = request3.flow.steps;
4156
4423
  if (!stepList || !Array.isArray(stepList) || stepList.length === 0) {
4157
4424
  throw new Error("Cannot attach runtime tools: dispatch request must include flow.steps");
4158
4425
  }
@@ -4195,9 +4462,9 @@ function attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options = {
4195
4462
  }
4196
4463
  };
4197
4464
  return {
4198
- ...request2,
4465
+ ...request3,
4199
4466
  flow: {
4200
- ...request2.flow,
4467
+ ...request3.flow,
4201
4468
  // `clonedSteps` is a structural clone of `request.flow.steps` (already
4202
4469
  // `FlowStepDefinition[]`); only the prompt step's `config.tools` was
4203
4470
  // merged, so every step's `type` discriminant is preserved. The clone is
@@ -4207,12 +4474,12 @@ function attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options = {
4207
4474
  }
4208
4475
  };
4209
4476
  }
4210
- function applyGeneratedRuntimeToolProposalToDispatchRequest(request2, proposal, options = {}) {
4477
+ function applyGeneratedRuntimeToolProposalToDispatchRequest(request3, proposal, options = {}) {
4211
4478
  const decision = evaluateGeneratedRuntimeToolProposal(proposal, options.gate);
4212
4479
  if (!decision.approved || !decision.tool) {
4213
- return { decision, request: request2 };
4480
+ return { decision, request: request3 };
4214
4481
  }
4215
- const nextRequest = attachRuntimeToolsToDispatchRequest(request2, [decision.tool], options.attach);
4482
+ const nextRequest = attachRuntimeToolsToDispatchRequest(request3, [decision.tool], options.attach);
4216
4483
  return {
4217
4484
  decision,
4218
4485
  request: nextRequest
@@ -6121,6 +6388,19 @@ var RecordsEndpoint = class {
6121
6388
  async getResults(id, params) {
6122
6389
  return this.client.get(`/records/${id}/results`, params);
6123
6390
  }
6391
+ /**
6392
+ * Get unified step-level execution results for a record, with filtering and
6393
+ * pagination.
6394
+ */
6395
+ async getStepResults(id, params) {
6396
+ return this.client.get(`/records/${id}/step-results`, params);
6397
+ }
6398
+ /**
6399
+ * Get the aggregated cost breakdown (by model) for a record's executions.
6400
+ */
6401
+ async getCosts(id) {
6402
+ return this.client.get(`/records/${id}/costs`);
6403
+ }
6124
6404
  /**
6125
6405
  * Delete a specific result for a record
6126
6406
  */
@@ -6449,15 +6729,15 @@ var DispatchEndpoint = class {
6449
6729
  * Attach approved runtime tools to a prompt step in a redispatch request.
6450
6730
  * Returns a new request object and does not mutate the original.
6451
6731
  */
6452
- attachApprovedRuntimeTools(request2, runtimeTools, options) {
6453
- return attachRuntimeToolsToDispatchRequest(request2, runtimeTools, options);
6732
+ attachApprovedRuntimeTools(request3, runtimeTools, options) {
6733
+ return attachRuntimeToolsToDispatchRequest(request3, runtimeTools, options);
6454
6734
  }
6455
6735
  /**
6456
6736
  * Validate a generated runtime tool proposal and attach it to the redispatch
6457
6737
  * request if approved, in one call.
6458
6738
  */
6459
- applyGeneratedRuntimeToolProposal(request2, proposal, options) {
6460
- return applyGeneratedRuntimeToolProposalToDispatchRequest(request2, proposal, options);
6739
+ applyGeneratedRuntimeToolProposal(request3, proposal, options) {
6740
+ return applyGeneratedRuntimeToolProposalToDispatchRequest(request3, proposal, options);
6461
6741
  }
6462
6742
  };
6463
6743
  var ChatEndpoint = class {
@@ -7009,8 +7289,8 @@ var GENERATED_RUNTIME_TOOL_PROPOSAL_SCHEMA = {
7009
7289
  },
7010
7290
  required: ["name", "description", "toolType", "parametersSchema", "config"]
7011
7291
  };
7012
- function appendRuntimeToolsToAgentRequest(request2, runtimeTools) {
7013
- const existing = request2.tools?.runtimeTools || [];
7292
+ function appendRuntimeToolsToAgentRequest(request3, runtimeTools) {
7293
+ const existing = request3.tools?.runtimeTools || [];
7014
7294
  const existingNames = new Set(existing.map((tool) => tool.name));
7015
7295
  const converted = runtimeTools.filter((tool) => !existingNames.has(tool.name)).map((tool) => ({
7016
7296
  name: tool.name,
@@ -7020,9 +7300,9 @@ function appendRuntimeToolsToAgentRequest(request2, runtimeTools) {
7020
7300
  ...tool.config ? { config: tool.config } : {}
7021
7301
  }));
7022
7302
  return {
7023
- ...request2,
7303
+ ...request3,
7024
7304
  tools: {
7025
- ...request2.tools,
7305
+ ...request3.tools,
7026
7306
  runtimeTools: [...existing, ...converted]
7027
7307
  }
7028
7308
  };
@@ -7098,21 +7378,21 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7098
7378
  * Attach approved runtime tools to an agent execute request.
7099
7379
  * Returns a new request object and does not mutate the original.
7100
7380
  */
7101
- attachApprovedRuntimeTools(request2, runtimeTools) {
7102
- return appendRuntimeToolsToAgentRequest(request2, runtimeTools);
7381
+ attachApprovedRuntimeTools(request3, runtimeTools) {
7382
+ return appendRuntimeToolsToAgentRequest(request3, runtimeTools);
7103
7383
  }
7104
7384
  /**
7105
7385
  * Validate a generated runtime tool proposal and append it to an agent execute
7106
7386
  * request if approved, in one call.
7107
7387
  */
7108
- applyGeneratedRuntimeToolProposal(request2, proposal, options) {
7388
+ applyGeneratedRuntimeToolProposal(request3, proposal, options) {
7109
7389
  const decision = evaluateGeneratedRuntimeToolProposal(proposal, options);
7110
7390
  if (!decision.approved || !decision.tool) {
7111
- return { decision, request: request2 };
7391
+ return { decision, request: request3 };
7112
7392
  }
7113
7393
  return {
7114
7394
  decision,
7115
- request: appendRuntimeToolsToAgentRequest(request2, [decision.tool])
7395
+ request: appendRuntimeToolsToAgentRequest(request3, [decision.tool])
7116
7396
  };
7117
7397
  }
7118
7398
  /**
@@ -7871,11 +8151,13 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7871
8151
  * setting. This never mutates persisted marathon history; masking/offloading
7872
8152
  * is a send-time view over the full-fidelity ledger/history.
7873
8153
  */
7874
- deriveToolContextMessages(messages, taskName, mode, window) {
8154
+ deriveToolContextMessages(messages, taskName, mode, window, offloadRecorder) {
7875
8155
  if (mode === "full-inline") return [...messages];
7876
8156
  const maskMessage = (msg) => ({
7877
8157
  ...msg,
7878
- toolResults: (msg.toolResults ?? []).map((tr) => this.compactOneResult(tr, taskName, mode))
8158
+ toolResults: (msg.toolResults ?? []).map(
8159
+ (tr) => this.compactOneResult(tr, taskName, mode, offloadRecorder)
8160
+ )
7879
8161
  });
7880
8162
  const view = [...messages];
7881
8163
  if (window === "session") {
@@ -7909,12 +8191,18 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7909
8191
  }
7910
8192
  return view;
7911
8193
  }
7912
- compactOneResult(tr, taskName, mode) {
8194
+ compactOneResult(tr, taskName, mode, offloadRecorder) {
7913
8195
  if (typeof tr.result === "string" && tr.result.startsWith("[")) return tr;
7914
8196
  if (mode === "hot-tail") {
7915
8197
  return {
7916
8198
  ...tr,
7917
- result: this.offloadToolResult(taskName, tr.toolCallId, tr.toolName, tr.result)
8199
+ result: this.offloadToolResult(
8200
+ taskName,
8201
+ tr.toolCallId,
8202
+ tr.toolName,
8203
+ tr.result,
8204
+ offloadRecorder
8205
+ )
7918
8206
  };
7919
8207
  }
7920
8208
  return { ...tr, result: `[Output from ${tr.toolName} masked \u2014 re-run the tool if needed]` };
@@ -7930,9 +8218,16 @@ var _AgentsEndpoint = class _AgentsEndpoint {
7930
8218
  return taskName.toLowerCase().replace(/[^a-z0-9_-]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
7931
8219
  }
7932
8220
  // chars
7933
- offloadToolResult(taskName, toolCallId, toolName, result) {
8221
+ offloadToolResult(taskName, toolCallId, toolName, result, offloadRecorder) {
7934
8222
  const resultStr = typeof result === "string" ? result : JSON.stringify(result, null, 2);
7935
8223
  if (resultStr.length <= this.TOOL_OUTPUT_INLINE_THRESHOLD) return result;
8224
+ if (offloadRecorder) {
8225
+ try {
8226
+ const recorded = offloadRecorder({ toolCallId, toolName, content: resultStr });
8227
+ if (recorded?.reference) return recorded.reference;
8228
+ } catch {
8229
+ }
8230
+ }
7936
8231
  let fs;
7937
8232
  try {
7938
8233
  const dynamicRequire = (0, eval)('typeof require !== "undefined" ? require : undefined');
@@ -8659,7 +8954,8 @@ var _AgentsEndpoint = class _AgentsEndpoint {
8659
8954
  onContextCompaction: options.onContextCompaction,
8660
8955
  onContextNotice: options.onContextNotice,
8661
8956
  toolContextMode: options.toolContextMode || "hot-tail",
8662
- toolWindow: options.toolWindow ?? "session"
8957
+ toolWindow: options.toolWindow ?? "session",
8958
+ offloadRecorder: options.offloadRecorder
8663
8959
  },
8664
8960
  queuedSteeringMessages
8665
8961
  );
@@ -9519,7 +9815,8 @@ Do NOT redo any of the above work.`
9519
9815
  sourceReplayHistoryMessages,
9520
9816
  state.taskName,
9521
9817
  compactionOptions?.toolContextMode || "hot-tail",
9522
- compactionOptions?.toolWindow ?? "session"
9818
+ compactionOptions?.toolWindow ?? "session",
9819
+ compactionOptions?.offloadRecorder
9523
9820
  );
9524
9821
  const continuationGuardrail = this.buildContinuationGuardrail(state);
9525
9822
  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.";
@@ -9682,7 +9979,8 @@ Do NOT redo any of the above work.`
9682
9979
  sourceHistoryMessages,
9683
9980
  state.taskName,
9684
9981
  compactionOptions?.toolContextMode || "hot-tail",
9685
- compactionOptions?.toolWindow ?? "session"
9982
+ compactionOptions?.toolWindow ?? "session",
9983
+ compactionOptions?.offloadRecorder
9686
9984
  );
9687
9985
  const historyArtifactReferences = this.extractArtifactReferencesFromMessages(historyMessages);
9688
9986
  const summaryText = this.generateCompactSummary(
@@ -10329,7 +10627,7 @@ var RuntypeClient2 = class {
10329
10627
  clearApiKey() {
10330
10628
  delete this.headers.Authorization;
10331
10629
  }
10332
- async runWithLocalTools(request2, localTools, arg3, arg4) {
10630
+ async runWithLocalTools(request3, localTools, arg3, arg4) {
10333
10631
  const isOptionsObject = (val) => typeof val === "object" && val !== null && "scope" in val;
10334
10632
  const callbacks = isOptionsObject(arg3) ? void 0 : arg3;
10335
10633
  const options = (isOptionsObject(arg3) ? arg3 : arg4) ?? {};
@@ -10343,12 +10641,12 @@ var RuntypeClient2 = class {
10343
10641
  ...entry.pageOrigin ? { pageOrigin: entry.pageOrigin } : {}
10344
10642
  })) : [];
10345
10643
  const modifiedRequest = {
10346
- ...request2,
10644
+ ...request3,
10347
10645
  ...derivedClientTools.length > 0 ? {
10348
- clientTools: [...request2.clientTools ?? [], ...derivedClientTools]
10646
+ clientTools: [...request3.clientTools ?? [], ...derivedClientTools]
10349
10647
  } : {},
10350
10648
  options: {
10351
- ...request2.options || {},
10649
+ ...request3.options || {},
10352
10650
  streamResponse: isStreaming
10353
10651
  }
10354
10652
  };
@@ -10786,20 +11084,20 @@ var BatchBuilder = class {
10786
11084
  if (!this.recordType) {
10787
11085
  throw new Error("BatchBuilder: recordType is required. Call .forRecordType(type) first.");
10788
11086
  }
10789
- const request2 = {
11087
+ const request3 = {
10790
11088
  flowId: this.flowId,
10791
11089
  recordType: this.recordType
10792
11090
  };
10793
11091
  if (Object.keys(this.batchOptions).length > 0) {
10794
- request2.options = this.batchOptions;
11092
+ request3.options = this.batchOptions;
10795
11093
  }
10796
11094
  if (this.filterConfig) {
10797
- request2.filter = this.filterConfig;
11095
+ request3.filter = this.filterConfig;
10798
11096
  }
10799
11097
  if (this.limitConfig !== void 0) {
10800
- request2.limit = this.limitConfig;
11098
+ request3.limit = this.limitConfig;
10801
11099
  }
10802
- return request2;
11100
+ return request3;
10803
11101
  }
10804
11102
  /**
10805
11103
  * Execute the batch operation
@@ -10956,32 +11254,32 @@ var EvalBuilder = class {
10956
11254
  "EvalBuilder: records are required. Call .forRecordType(type) or .withRecords([...]) first."
10957
11255
  );
10958
11256
  }
10959
- const request2 = {};
11257
+ const request3 = {};
10960
11258
  if (this.flowId) {
10961
- request2.flowId = this.flowId;
11259
+ request3.flowId = this.flowId;
10962
11260
  } else if (this.virtualFlow) {
10963
- request2.flow = this.virtualFlow;
11261
+ request3.flow = this.virtualFlow;
10964
11262
  }
10965
11263
  if (this.recordType) {
10966
- request2.recordType = this.recordType;
11264
+ request3.recordType = this.recordType;
10967
11265
  } else if (this.inlineRecords) {
10968
- request2.records = this.inlineRecords;
11266
+ request3.records = this.inlineRecords;
10969
11267
  }
10970
11268
  if (this.modelOverrides) {
10971
- request2.modelOverrides = this.modelOverrides;
11269
+ request3.modelOverrides = this.modelOverrides;
10972
11270
  } else if (this.modelConfigs) {
10973
- request2.modelConfigs = this.modelConfigs;
11271
+ request3.modelConfigs = this.modelConfigs;
10974
11272
  }
10975
11273
  if (Object.keys(this.evalOptions).length > 0) {
10976
- request2.options = this.evalOptions;
11274
+ request3.options = this.evalOptions;
10977
11275
  }
10978
11276
  if (this.filterConfig) {
10979
- request2.filter = this.filterConfig;
11277
+ request3.filter = this.filterConfig;
10980
11278
  }
10981
11279
  if (this.limitConfig !== void 0) {
10982
- request2.limit = this.limitConfig;
11280
+ request3.limit = this.limitConfig;
10983
11281
  }
10984
- return request2;
11282
+ return request3;
10985
11283
  }
10986
11284
  /**
10987
11285
  * Execute the evaluation
@@ -11500,7 +11798,10 @@ export {
11500
11798
  SkillProposalsNamespace,
11501
11799
  SkillsNamespace,
11502
11800
  SurfacesEndpoint,
11801
+ ToolDriftError,
11802
+ ToolEnsureConflictError,
11503
11803
  ToolsEndpoint,
11804
+ ToolsNamespace,
11504
11805
  UsersEndpoint,
11505
11806
  applyGeneratedRuntimeToolProposalToDispatchRequest,
11506
11807
  attachRuntimeToolsToDispatchRequest,
@@ -11512,6 +11813,7 @@ export {
11512
11813
  compileWorkflowConfig,
11513
11814
  computeAgentContentHash,
11514
11815
  computeFlowContentHash,
11816
+ computeToolContentHash,
11515
11817
  createClient,
11516
11818
  createExternalTool,
11517
11819
  defaultWorkflow,
@@ -11519,6 +11821,7 @@ export {
11519
11821
  defineAgent,
11520
11822
  defineFlow,
11521
11823
  definePlaybook,
11824
+ defineTool,
11522
11825
  deployWorkflow,
11523
11826
  ensureDefaultWorkflowHooks,
11524
11827
  evaluateGeneratedRuntimeToolProposal,
@@ -11534,6 +11837,7 @@ export {
11534
11837
  listWorkflowHooks,
11535
11838
  normalizeAgentDefinition,
11536
11839
  normalizeCandidatePath,
11840
+ normalizeToolDefinition,
11537
11841
  parseFinalBuffer,
11538
11842
  parseLedgerArtifactRelativePath,
11539
11843
  parseOffloadedOutputId,