@theokit/sdk 2.25.0 → 2.27.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.
Files changed (47) hide show
  1. package/CHANGELOG.md +57 -0
  2. package/dist/a2a/index.cjs +208 -4
  3. package/dist/a2a/index.cjs.map +1 -1
  4. package/dist/a2a/index.js +208 -4
  5. package/dist/a2a/index.js.map +1 -1
  6. package/dist/{cron-B44D-678.d.ts → cron-BR1NCSk1.d.cts} +11 -1
  7. package/dist/{cron-qI-dbG7c.d.cts → cron-DgEQCJ2i.d.ts} +11 -1
  8. package/dist/cron.cjs +187 -4
  9. package/dist/cron.cjs.map +1 -1
  10. package/dist/cron.d.cts +2 -2
  11. package/dist/cron.d.ts +2 -2
  12. package/dist/cron.js +187 -4
  13. package/dist/cron.js.map +1 -1
  14. package/dist/{errors-DRS-kqOK.d.ts → errors-CbY3pxY7.d.ts} +1 -1
  15. package/dist/{errors-DIKBXffg.d.cts → errors-DLMNb4Ka.d.cts} +1 -1
  16. package/dist/errors.d.cts +2 -2
  17. package/dist/eval.cjs +187 -4
  18. package/dist/eval.cjs.map +1 -1
  19. package/dist/eval.js +187 -4
  20. package/dist/eval.js.map +1 -1
  21. package/dist/index.cjs +483 -51
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +69 -7
  24. package/dist/index.d.ts +69 -7
  25. package/dist/index.js +481 -52
  26. package/dist/index.js.map +1 -1
  27. package/dist/internal/runtime/processors/run-processors.d.ts +10 -0
  28. package/dist/internal/runtime/processors/tripwire-run.d.ts +16 -0
  29. package/dist/internal/runtime/processors/wrap-output-run.d.ts +18 -0
  30. package/dist/internal/workflow/ctx.d.ts +6 -1
  31. package/dist/internal/workflow/event-stream.d.ts +13 -0
  32. package/dist/internal/workflow/executor-helpers.d.ts +30 -0
  33. package/dist/{run-Cr0C6cOM.d.cts → run-CdWiihyU.d.cts} +109 -2
  34. package/dist/{run-Cr0C6cOM.d.ts → run-CdWiihyU.d.ts} +109 -2
  35. package/dist/types/agent.d.ts +10 -0
  36. package/dist/types/index.d.ts +1 -0
  37. package/dist/types/processors.d.ts +84 -0
  38. package/dist/types/run-events.d.ts +11 -1
  39. package/dist/types/run.d.ts +12 -0
  40. package/dist/types/workflow.d.ts +134 -1
  41. package/dist/workflow.cjs +289 -45
  42. package/dist/workflow.cjs.map +1 -1
  43. package/dist/workflow.d.cts +42 -2
  44. package/dist/workflow.d.ts +42 -2
  45. package/dist/workflow.js +288 -46
  46. package/dist/workflow.js.map +1 -1
  47. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -4336,7 +4336,7 @@ var init_batch = __esm({
4336
4336
  });
4337
4337
 
4338
4338
  // src/types/workflow.ts
4339
- var WorkflowDuplicateStepIdError, WorkflowAlreadyRunningError, WorkflowSnapshotNotFoundError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowResumeStepNotFoundError, WorkflowParallelError, WorkflowCompensateNotImplementedError;
4339
+ var WorkflowDuplicateStepIdError, WorkflowInputError, WorkflowOutputError, WorkflowStateError, WorkflowAlreadyRunningError, WorkflowSnapshotNotFoundError, WorkflowMaxIterationsExceededError, WorkflowNotSerializableError, WorkflowResumeStepNotFoundError, WorkflowParallelError, WorkflowCompensateNotImplementedError;
4340
4340
  var init_workflow = __esm({
4341
4341
  "src/types/workflow.ts"() {
4342
4342
  WorkflowDuplicateStepIdError = class extends Error {
@@ -4347,6 +4347,36 @@ var init_workflow = __esm({
4347
4347
  stepId;
4348
4348
  name = "WorkflowDuplicateStepIdError";
4349
4349
  };
4350
+ WorkflowInputError = class extends Error {
4351
+ constructor(workflowName, detail) {
4352
+ super(`Workflow "${workflowName}" input failed schema validation: ${detail}`);
4353
+ this.workflowName = workflowName;
4354
+ this.detail = detail;
4355
+ }
4356
+ workflowName;
4357
+ detail;
4358
+ name = "WorkflowInputError";
4359
+ };
4360
+ WorkflowOutputError = class extends Error {
4361
+ constructor(workflowName, detail) {
4362
+ super(`Workflow "${workflowName}" output failed schema validation: ${detail}`);
4363
+ this.workflowName = workflowName;
4364
+ this.detail = detail;
4365
+ }
4366
+ workflowName;
4367
+ detail;
4368
+ name = "WorkflowOutputError";
4369
+ };
4370
+ WorkflowStateError = class extends Error {
4371
+ constructor(workflowName, detail) {
4372
+ super(`Workflow "${workflowName}" state failed schema validation: ${detail}`);
4373
+ this.workflowName = workflowName;
4374
+ this.detail = detail;
4375
+ }
4376
+ workflowName;
4377
+ detail;
4378
+ name = "WorkflowStateError";
4379
+ };
4350
4380
  WorkflowAlreadyRunningError = class extends Error {
4351
4381
  constructor(workflowName, runId) {
4352
4382
  super(`Workflow "${workflowName}" run "${runId}" already in-flight.`);
@@ -4539,7 +4569,7 @@ var init_snapshot_store = __esm({
4539
4569
  });
4540
4570
 
4541
4571
  // src/internal/workflow/ctx.ts
4542
- function makeStepContext(runId, signal) {
4572
+ function makeStepContext(runId, signal, state4) {
4543
4573
  return {
4544
4574
  runId,
4545
4575
  signal,
@@ -4550,7 +4580,13 @@ function makeStepContext(runId, signal) {
4550
4580
  },
4551
4581
  suspend: async (payload) => {
4552
4582
  throw new WorkflowSuspendedSentinel(payload);
4553
- }
4583
+ },
4584
+ // SE29 — read reflects the current shared state; write goes through the
4585
+ // controller (which validates against `stateSchema`).
4586
+ get state() {
4587
+ return state4.getState();
4588
+ },
4589
+ setState: (next) => state4.setState(next)
4554
4590
  };
4555
4591
  }
4556
4592
  function emit(level, runId, msg, attrs) {
@@ -4603,6 +4639,57 @@ var init_error_shape = __esm({
4603
4639
  }
4604
4640
  });
4605
4641
 
4642
+ // src/internal/workflow/executor-helpers.ts
4643
+ function assembleRun(params) {
4644
+ return {
4645
+ id: params.runId,
4646
+ name: params.name,
4647
+ status: params.status,
4648
+ startedAt: params.startedAt,
4649
+ endedAt: Date.now(),
4650
+ stepResults: params.stepResults,
4651
+ ...params.output !== void 0 ? { output: params.output } : {},
4652
+ ...params.error !== void 0 ? { error: params.error } : {}
4653
+ };
4654
+ }
4655
+ function abortRun(name, runId, startedAt, stepResults, signal) {
4656
+ return assembleRun({
4657
+ runId,
4658
+ name,
4659
+ status: "cancelled",
4660
+ stepResults,
4661
+ startedAt,
4662
+ error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
4663
+ });
4664
+ }
4665
+ function validateWorkflowSchema(schema, value) {
4666
+ if (schema === void 0) return void 0;
4667
+ let parsed;
4668
+ try {
4669
+ parsed = schema.safeParse(value);
4670
+ } catch {
4671
+ return "schema uses async refinements, which whole-workflow validation does not support (use a synchronous Zod schema)";
4672
+ }
4673
+ if (parsed.success) return void 0;
4674
+ return parsed.error.issues.map((issue) => `${issue.path.join(".") || "(root)"}: ${issue.message}`).join("; ");
4675
+ }
4676
+ function makeStateController(options, initial) {
4677
+ let current = initial;
4678
+ return {
4679
+ getState: () => current,
4680
+ setState: (next) => {
4681
+ const issues = validateWorkflowSchema(options.stateSchema, next);
4682
+ if (issues !== void 0) throw new WorkflowStateError(options.name, issues);
4683
+ current = next;
4684
+ }
4685
+ };
4686
+ }
4687
+ var init_executor_helpers = __esm({
4688
+ "src/internal/workflow/executor-helpers.ts"() {
4689
+ init_workflow();
4690
+ }
4691
+ });
4692
+
4606
4693
  // src/internal/workflow/run-id.ts
4607
4694
  function mintRunId() {
4608
4695
  return `wfr-${globalThis.crypto.randomUUID().replace(/-/g, "").slice(0, 8)}`;
@@ -5269,6 +5356,8 @@ async function handleSuspend(err, ctx) {
5269
5356
  suspendedPayload: err.payload,
5270
5357
  stepResults: ctx.stepResults,
5271
5358
  accumulatedInput: ctx.acc,
5359
+ state: ctx.stepCtx.state,
5360
+ // SE29 — capture the shared state at suspend
5272
5361
  options: ctx.options
5273
5362
  });
5274
5363
  } catch (snapErr) {
@@ -5320,7 +5409,7 @@ async function runOneStep(args) {
5320
5409
  result = await dispatchStep(args.step, args.acc, args.ctx, args.options, args.stepResults);
5321
5410
  } catch (err) {
5322
5411
  if (err instanceof WorkflowSuspendedSentinel) {
5323
- const outcome = await handleSuspend(err, { ...args, stepSpan });
5412
+ const outcome = await handleSuspend(err, { ...args, stepSpan, stepCtx: args.ctx });
5324
5413
  return { kind: "terminal", run: outcome.run };
5325
5414
  }
5326
5415
  result = {
@@ -5337,22 +5426,42 @@ async function runOneStep(args) {
5337
5426
  stepSpan.end();
5338
5427
  return { kind: "ok", result };
5339
5428
  }
5340
- function abortRun(name, runId, startedAt, stepResults, signal) {
5341
- return assembleRun({
5342
- runId,
5343
- name,
5344
- status: "cancelled",
5345
- stepResults,
5346
- startedAt,
5347
- error: { name: "AbortError", message: String(signal.reason ?? "Aborted") }
5348
- });
5429
+ function handleStepOutcome(outcome, step, loop, onStepEvent) {
5430
+ if (outcome.kind === "terminal") {
5431
+ if (outcome.run.status === "suspended") {
5432
+ onStepEvent?.({ type: "workflow_suspended", stepId: step.id });
5433
+ }
5434
+ return { terminal: outcome.run };
5435
+ }
5436
+ loop.stepResults.push(outcome.result);
5437
+ if (outcome.result.status === "failed") {
5438
+ onStepEvent?.({
5439
+ type: "step_failed",
5440
+ stepId: step.id,
5441
+ error: outcome.result.error ?? { name: "WorkflowStepError", message: "step failed" }
5442
+ });
5443
+ return {
5444
+ terminal: assembleRun({
5445
+ runId: loop.runId,
5446
+ name: loop.name,
5447
+ status: "failed",
5448
+ stepResults: loop.stepResults,
5449
+ startedAt: loop.startedAt,
5450
+ error: outcome.result.error
5451
+ })
5452
+ };
5453
+ }
5454
+ onStepEvent?.({ type: "step_completed", stepId: step.id, output: outcome.result.output });
5455
+ return { acc: outcome.result.output };
5349
5456
  }
5350
5457
  async function runStepsLoop(params) {
5351
- const { options, steps, ctx, runId, startedAt, signal } = params;
5458
+ const { options, steps, ctx, runId, startedAt, signal, onStepEvent } = params;
5352
5459
  const stepResults = [...params.initialStepResults ?? []];
5460
+ const loop = { stepResults, runId, name: options.name, startedAt };
5353
5461
  let acc = params.input;
5354
5462
  for (const step of steps) {
5355
5463
  if (signal.aborted) return abortRun(options.name, runId, startedAt, stepResults, signal);
5464
+ onStepEvent?.({ type: "step_started", stepId: step.id });
5356
5465
  const outcome = await runOneStep({
5357
5466
  step,
5358
5467
  acc,
@@ -5363,20 +5472,22 @@ async function runStepsLoop(params) {
5363
5472
  name: options.name,
5364
5473
  startedAt
5365
5474
  });
5366
- if (outcome.kind === "terminal") return outcome.run;
5367
- stepResults.push(outcome.result);
5368
- if (outcome.result.status === "failed") {
5369
- return assembleRun({
5370
- runId,
5371
- name: options.name,
5372
- status: "failed",
5373
- stepResults,
5374
- startedAt,
5375
- error: outcome.result.error
5376
- });
5377
- }
5378
- acc = outcome.result.output;
5475
+ const handled = handleStepOutcome(outcome, step, loop, onStepEvent);
5476
+ if ("terminal" in handled) return handled.terminal;
5477
+ acc = handled.acc;
5478
+ }
5479
+ const outputIssues = validateWorkflowSchema(options.outputSchema, acc);
5480
+ if (outputIssues !== void 0) {
5481
+ return assembleRun({
5482
+ runId,
5483
+ name: options.name,
5484
+ status: "failed",
5485
+ stepResults,
5486
+ startedAt,
5487
+ error: errToShape(new WorkflowOutputError(options.name, outputIssues))
5488
+ });
5379
5489
  }
5490
+ onStepEvent?.({ type: "workflow_completed" });
5380
5491
  return assembleRun({
5381
5492
  runId,
5382
5493
  name: options.name,
@@ -5399,8 +5510,33 @@ async function executeWorkflow(options, steps, input, runOpts) {
5399
5510
  runSpan.end();
5400
5511
  return abortRun(options.name, runId, startedAt, [], signal);
5401
5512
  }
5402
- const ctx = makeStepContext(runId, signal);
5513
+ const internal = runOpts;
5514
+ const seededState = internal?.restoredState !== void 0 ? internal.restoredState : options.initialState;
5515
+ const stateController = makeStateController(options, seededState);
5516
+ const ctx = makeStepContext(runId, signal, stateController);
5403
5517
  try {
5518
+ const inputIssues = validateWorkflowSchema(options.inputSchema, input);
5519
+ if (inputIssues !== void 0) {
5520
+ return assembleRun({
5521
+ runId,
5522
+ name: options.name,
5523
+ status: "failed",
5524
+ stepResults: [],
5525
+ startedAt,
5526
+ error: errToShape(new WorkflowInputError(options.name, inputIssues))
5527
+ });
5528
+ }
5529
+ const stateIssues = seededState !== void 0 ? validateWorkflowSchema(options.stateSchema, seededState) : void 0;
5530
+ if (stateIssues !== void 0) {
5531
+ return assembleRun({
5532
+ runId,
5533
+ name: options.name,
5534
+ status: "failed",
5535
+ stepResults: [],
5536
+ startedAt,
5537
+ error: errToShape(new WorkflowStateError(options.name, stateIssues))
5538
+ });
5539
+ }
5404
5540
  return await runStepsLoop({
5405
5541
  options,
5406
5542
  steps,
@@ -5409,7 +5545,8 @@ async function executeWorkflow(options, steps, input, runOpts) {
5409
5545
  runId,
5410
5546
  startedAt,
5411
5547
  signal,
5412
- ...runOpts?.initialStepResults !== void 0 ? { initialStepResults: runOpts.initialStepResults } : {}
5548
+ ...internal?.initialStepResults !== void 0 ? { initialStepResults: internal.initialStepResults } : {},
5549
+ ...internal?.onStepEvent !== void 0 ? { onStepEvent: internal.onStepEvent } : {}
5413
5550
  });
5414
5551
  } finally {
5415
5552
  runSpan.end();
@@ -5440,28 +5577,17 @@ async function dispatchStep(step, input, ctx, options, prevStepResults) {
5440
5577
  }
5441
5578
  }
5442
5579
  }
5443
- function assembleRun(params) {
5444
- const endedAt = Date.now();
5445
- return {
5446
- id: params.runId,
5447
- name: params.name,
5448
- status: params.status,
5449
- startedAt: params.startedAt,
5450
- endedAt,
5451
- stepResults: params.stepResults,
5452
- ...params.output !== void 0 ? { output: params.output } : {},
5453
- ...params.error !== void 0 ? { error: params.error } : {}
5454
- };
5455
- }
5456
5580
  async function saveSnapshot(p) {
5457
5581
  const snapshot = {
5458
- _schemaVersion: 1,
5582
+ _schemaVersion: 2,
5583
+ // SE29 — carries `state`
5459
5584
  runId: p.runId,
5460
5585
  workflowName: p.workflowName,
5461
5586
  currentStepId: p.currentStepId,
5462
5587
  suspendedPayload: p.suspendedPayload,
5463
5588
  stepResults: p.stepResults,
5464
5589
  accumulatedInput: p.accumulatedInput,
5590
+ ...p.state !== void 0 ? { state: p.state } : {},
5465
5591
  suspendedAt: Date.now()
5466
5592
  };
5467
5593
  const store = getSnapshotStoreFor(p.options);
@@ -5494,7 +5620,10 @@ async function resumeWorkflow(opts) {
5494
5620
  signal: opts.signal,
5495
5621
  runId: opts.runId,
5496
5622
  // M3 #62 — restore prior step outputs so the resumed run is not lossy (internal seam).
5497
- initialStepResults: snapshot.stepResults
5623
+ initialStepResults: snapshot.stepResults,
5624
+ // SE29 — restore shared state (v2 snapshot). A v1 snapshot has no `state` →
5625
+ // executeWorkflow falls back to `options.initialState`.
5626
+ ...snapshot.state !== void 0 ? { restoredState: snapshot.state } : {}
5498
5627
  });
5499
5628
  }
5500
5629
  var init_executor = __esm({
@@ -5502,6 +5631,7 @@ var init_executor = __esm({
5502
5631
  init_workflow();
5503
5632
  init_ctx();
5504
5633
  init_error_shape();
5634
+ init_executor_helpers();
5505
5635
  init_run_id();
5506
5636
  init_single_flight();
5507
5637
  init_snapshot_store();
@@ -7737,8 +7867,18 @@ function validateCloudToolParity(options) {
7737
7867
  if (options.cloud === void 0) return;
7738
7868
  rejectFunctionSystemPrompt(options);
7739
7869
  rejectFunctionSkills(options);
7870
+ rejectProcessors(options);
7740
7871
  rejectStdioMcpLocalPaths(options);
7741
7872
  }
7873
+ function rejectProcessors(options) {
7874
+ const hasProcessors = (options.inputProcessors?.length ?? 0) > 0 || (options.outputProcessors?.length ?? 0) > 0;
7875
+ if (hasProcessors) {
7876
+ throw new exports.ConfigurationError(
7877
+ "Cloud agents can't run guardrail processors \u2014 a Processor carries function handlers that don't survive serialization to PaaS. Run processors on a local agent, or move the guardrail into a server-side gateway in front of TheoCloud.",
7878
+ { code: "cloud_incompatible_function_resolver" }
7879
+ );
7880
+ }
7881
+ }
7742
7882
  function rejectFunctionSystemPrompt(options) {
7743
7883
  if (typeof options.systemPrompt === "function") {
7744
7884
  throw new exports.ConfigurationError(
@@ -17677,6 +17817,145 @@ function ponyfillAny(signals) {
17677
17817
  return ctrl.signal;
17678
17818
  }
17679
17819
 
17820
+ // src/internal/runtime/processors/run-processors.ts
17821
+ var ProcessorAbort = class {
17822
+ constructor(processorId, reason) {
17823
+ this.processorId = processorId;
17824
+ this.reason = reason;
17825
+ }
17826
+ processorId;
17827
+ reason;
17828
+ };
17829
+ function fireViolation(processor, violation) {
17830
+ try {
17831
+ processor.onViolation?.(violation);
17832
+ } catch {
17833
+ }
17834
+ }
17835
+ function controlsFor(processor) {
17836
+ return {
17837
+ abort(reason) {
17838
+ throw new ProcessorAbort(processor.id, reason);
17839
+ },
17840
+ warn(message, detail) {
17841
+ fireViolation(processor, {
17842
+ processorId: processor.id,
17843
+ message,
17844
+ ...detail !== void 0 ? { detail } : {}
17845
+ });
17846
+ }
17847
+ };
17848
+ }
17849
+ function selectHandler(processor, phase) {
17850
+ if (phase === "input") {
17851
+ return processor.processInput ? { kind: "input", fn: processor.processInput } : void 0;
17852
+ }
17853
+ return processor.processOutput ? { kind: "output", fn: processor.processOutput } : void 0;
17854
+ }
17855
+ function invokeHandler(handler, value, agentId, controls) {
17856
+ return handler.kind === "input" ? handler.fn({ message: value, agentId, ...controls }) : handler.fn({ text: value, agentId, ...controls });
17857
+ }
17858
+ async function runOneProcessor(processor, value, agentId, phase) {
17859
+ const handler = selectHandler(processor, phase);
17860
+ if (handler === void 0) return { value };
17861
+ try {
17862
+ const out = await invokeHandler(handler, value, agentId, controlsFor(processor));
17863
+ return { value: typeof out === "string" ? out : value };
17864
+ } catch (err) {
17865
+ if (!(err instanceof ProcessorAbort)) throw err;
17866
+ fireViolation(processor, { processorId: err.processorId, message: err.reason });
17867
+ return { tripwire: { reason: err.reason, processorId: err.processorId } };
17868
+ }
17869
+ }
17870
+ async function runPipeline(processors, initial, agentId, phase) {
17871
+ let value = initial;
17872
+ for (const processor of processors) {
17873
+ const step = await runOneProcessor(processor, value, agentId, phase);
17874
+ if ("tripwire" in step) return { kind: "tripwire", tripwire: step.tripwire };
17875
+ value = step.value;
17876
+ }
17877
+ return { kind: "ok", value };
17878
+ }
17879
+ function runInputProcessors(processors, message, agentId) {
17880
+ return runPipeline(processors, message, agentId, "input");
17881
+ }
17882
+ function runOutputProcessors(processors, text, agentId) {
17883
+ return runPipeline(processors, text, agentId, "output");
17884
+ }
17885
+
17886
+ // src/internal/runtime/processors/tripwire-run.ts
17887
+ var SUPPORTED = /* @__PURE__ */ new Set([
17888
+ "stream",
17889
+ "wait",
17890
+ "cancel",
17891
+ "conversation"
17892
+ ]);
17893
+ function emptyStream() {
17894
+ return {
17895
+ next: () => Promise.resolve({ done: true, value: void 0 }),
17896
+ return: () => Promise.resolve({ done: true, value: void 0 }),
17897
+ throw: (err) => Promise.reject(err),
17898
+ [Symbol.asyncIterator]() {
17899
+ return this;
17900
+ }
17901
+ };
17902
+ }
17903
+ function createTripwireRun(args) {
17904
+ const id = globalThis.crypto.randomUUID();
17905
+ const result = {
17906
+ id,
17907
+ status: "cancelled",
17908
+ tripwire: args.tripwire,
17909
+ ...args.model !== void 0 ? { model: args.model } : {}
17910
+ };
17911
+ const run = {
17912
+ id,
17913
+ agentId: args.agentId,
17914
+ status: "cancelled",
17915
+ ...args.model !== void 0 ? { model: args.model } : {},
17916
+ stream: () => emptyStream(),
17917
+ wait: () => Promise.resolve(result),
17918
+ cancel: () => Promise.resolve(),
17919
+ conversation: () => Promise.resolve([]),
17920
+ supports: (op) => SUPPORTED.has(op),
17921
+ unsupportedReason: (op) => SUPPORTED.has(op) ? void 0 : `operation "${op}" is not available on a tripwire run`,
17922
+ onDidChangeStatus: () => () => {
17923
+ }
17924
+ // already terminal — status never changes
17925
+ };
17926
+ registerRun(run);
17927
+ return run;
17928
+ }
17929
+
17930
+ // src/internal/runtime/processors/wrap-output-run.ts
17931
+ function wrapRunWithOutputProcessors(args) {
17932
+ if (args.processors.length === 0) return args.run;
17933
+ const compute = async () => {
17934
+ const result = await args.run.wait();
17935
+ if (result.status !== "finished" || result.result === void 0) return result;
17936
+ const res = await runOutputProcessors(args.processors, result.result, args.agentId);
17937
+ if (res.kind === "ok") return { ...result, result: res.value };
17938
+ emitRunEvent(args.onRunEvent, {
17939
+ type: "tripwire",
17940
+ reason: res.tripwire.reason,
17941
+ processorId: res.tripwire.processorId
17942
+ });
17943
+ const { result: _suppressed, ...metadata } = result;
17944
+ return { ...metadata, status: "cancelled", tripwire: res.tripwire };
17945
+ };
17946
+ let processed;
17947
+ const wrappedWait = () => {
17948
+ processed ??= compute();
17949
+ return processed;
17950
+ };
17951
+ return new Proxy(args.run, {
17952
+ get(target, prop, receiver) {
17953
+ if (prop === "wait") return wrappedWait;
17954
+ return Reflect.get(target, prop, receiver);
17955
+ }
17956
+ });
17957
+ }
17958
+
17680
17959
  // src/internal/runtime/local-agent/local-agent-memory-hooks.ts
17681
17960
  var DEFAULT_MAX_RECALL_BYTES = 16e3;
17682
17961
  async function applyPreUserSendHook(args) {
@@ -17724,11 +18003,38 @@ function wrapRunWithPostReplyHook(args) {
17724
18003
  }
17725
18004
 
17726
18005
  // src/internal/runtime/local-agent/local-agent-send.ts
18006
+ async function applyInputProcessors(inputs, message, rawUserText, options, sendModel) {
18007
+ const processors = inputs.options.inputProcessors;
18008
+ if (processors === void 0 || processors.length === 0) {
18009
+ return { userText: rawUserText, effectiveMessage: message };
18010
+ }
18011
+ const res = await runInputProcessors(processors, rawUserText, inputs.agentId);
18012
+ if (res.kind === "tripwire") {
18013
+ emitRunEvent(options.onRunEvent, {
18014
+ type: "tripwire",
18015
+ reason: res.tripwire.reason,
18016
+ processorId: res.tripwire.processorId
18017
+ });
18018
+ return {
18019
+ tripwireRun: createTripwireRun({
18020
+ agentId: inputs.agentId,
18021
+ tripwire: res.tripwire,
18022
+ model: sendModel
18023
+ })
18024
+ };
18025
+ }
18026
+ const effectiveMessage = typeof message === "string" ? res.value : { ...message, text: res.value };
18027
+ return { userText: res.value, effectiveMessage };
18028
+ }
17727
18029
  async function executeSendLocked(inputs, message, options) {
17728
18030
  if (inputs.disposed) throw new exports.AgentDisposedError(inputs.agentId);
17729
18031
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
17730
- inputs.applyModelOverride(normalizeModel(options.model));
17731
- const userText = typeof message === "string" ? message : message.text;
18032
+ const sendModel = normalizeModel(options.model);
18033
+ inputs.applyModelOverride(sendModel);
18034
+ const rawUserText = typeof message === "string" ? message : message.text;
18035
+ const gated = await applyInputProcessors(inputs, message, rawUserText, options, sendModel);
18036
+ if ("tripwireRun" in gated) return gated.tripwireRun;
18037
+ const { userText, effectiveMessage } = gated;
17732
18038
  if (inputs.options.onBeforeSend !== void 0) {
17733
18039
  await inputs.options.onBeforeSend({
17734
18040
  conversationId: inputs.agentId,
@@ -17740,7 +18046,7 @@ async function executeSendLocked(inputs, message, options) {
17740
18046
  pluginManager: inputs.pluginManagerCode,
17741
18047
  agentId: inputs.agentId,
17742
18048
  options: inputs.options,
17743
- original: message,
18049
+ original: effectiveMessage,
17744
18050
  userText,
17745
18051
  sendOptions: options
17746
18052
  });
@@ -17778,11 +18084,18 @@ async function executeSendLocked(inputs, message, options) {
17778
18084
  memoryTools,
17779
18085
  effectiveMemoryProvider
17780
18086
  );
18087
+ const outputProcessors = inputs.options.outputProcessors;
18088
+ const processedRun = outputProcessors !== void 0 && outputProcessors.length > 0 ? wrapRunWithOutputProcessors({
18089
+ run,
18090
+ processors: outputProcessors,
18091
+ agentId: inputs.agentId,
18092
+ onRunEvent: options.onRunEvent
18093
+ }) : run;
17781
18094
  return wrapRunWithPostReplyHook({
17782
18095
  pluginManager: inputs.pluginManagerCode,
17783
18096
  agentId: inputs.agentId,
17784
18097
  options: inputs.options,
17785
- run,
18098
+ run: processedRun,
17786
18099
  userText
17787
18100
  });
17788
18101
  }
@@ -19141,6 +19454,48 @@ var Budget = class {
19141
19454
  }
19142
19455
  };
19143
19456
 
19457
+ // src/built-in-processors.ts
19458
+ var CHARS_PER_TOKEN = 4;
19459
+ function estimateTokens(text) {
19460
+ return Math.ceil(text.length / CHARS_PER_TOKEN);
19461
+ }
19462
+ var CONTROL_CHARS = /[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g;
19463
+ function createUnicodeNormalizer(opts = {}) {
19464
+ const stripControlChars = opts.stripControlChars ?? false;
19465
+ const collapseWhitespace = opts.collapseWhitespace ?? false;
19466
+ return {
19467
+ id: "unicode-normalizer",
19468
+ processInput(ctx) {
19469
+ let s = ctx.message.normalize("NFC");
19470
+ if (stripControlChars) s = s.replace(CONTROL_CHARS, "");
19471
+ if (collapseWhitespace) {
19472
+ s = s.replace(/[^\S\n]+/g, " ").replace(/ *\n */g, "\n").replace(/\n{3,}/g, "\n\n").trim();
19473
+ }
19474
+ return s;
19475
+ }
19476
+ };
19477
+ }
19478
+ function createTokenLimiter(opts) {
19479
+ if (!Number.isInteger(opts.limit) || opts.limit <= 0) {
19480
+ throw new Error("createTokenLimiter: `limit` must be a positive integer.");
19481
+ }
19482
+ const limit = opts.limit;
19483
+ const strategy = opts.strategy ?? "truncate";
19484
+ const cap2 = (text, controls) => {
19485
+ const estimated = estimateTokens(text);
19486
+ if (estimated <= limit) return text;
19487
+ if (strategy === "block") {
19488
+ controls.abort(`exceeds token limit ${limit} (~${estimated} estimated)`);
19489
+ }
19490
+ return [...text].slice(0, limit * CHARS_PER_TOKEN).join("");
19491
+ };
19492
+ return {
19493
+ id: "token-limiter",
19494
+ processInput: (ctx) => cap2(ctx.message, ctx),
19495
+ processOutput: (ctx) => cap2(ctx.text, ctx)
19496
+ };
19497
+ }
19498
+
19144
19499
  // src/create-skill.ts
19145
19500
  function createSkill(spec) {
19146
19501
  if (!spec.name) throw new Error("createSkill: `name` is required.");
@@ -19822,7 +20177,7 @@ function createCounterBudgetTracker(options = {}) {
19822
20177
  }
19823
20178
 
19824
20179
  // src/internal/runtime/context/replay-history.ts
19825
- var CHARS_PER_TOKEN = 4;
20180
+ var CHARS_PER_TOKEN2 = 4;
19826
20181
  var DEFAULT_RESERVE_TOKENS = 8e3;
19827
20182
  function finiteOr(value, fallback) {
19828
20183
  return Number.isFinite(value) ? value : fallback;
@@ -19830,7 +20185,7 @@ function finiteOr(value, fallback) {
19830
20185
  function charBudget(options) {
19831
20186
  const window = finiteOr(options.contextWindowTokens, 0);
19832
20187
  const reserve = finiteOr(options.reserveTokens ?? DEFAULT_RESERVE_TOKENS, DEFAULT_RESERVE_TOKENS);
19833
- return Math.max(0, window - reserve) * CHARS_PER_TOKEN;
20188
+ return Math.max(0, window - reserve) * CHARS_PER_TOKEN2;
19834
20189
  }
19835
20190
  function assistantText2(event) {
19836
20191
  return event.message.content.filter((block) => block.type === "text").map((block) => block.text).join("");
@@ -20806,6 +21161,45 @@ var PersistenceSchema = zod.z.object({
20806
21161
 
20807
21162
  // src/workflow.ts
20808
21163
  init_path_guard();
21164
+
21165
+ // src/internal/workflow/event-stream.ts
21166
+ function createEventStream() {
21167
+ const buffer = [];
21168
+ const waiters = [];
21169
+ let ended = false;
21170
+ const stream = {
21171
+ push(event) {
21172
+ if (ended) return;
21173
+ const waiter = waiters.shift();
21174
+ if (waiter !== void 0) waiter({ value: event, done: false });
21175
+ else buffer.push(event);
21176
+ },
21177
+ end() {
21178
+ if (ended) return;
21179
+ ended = true;
21180
+ for (const waiter of waiters.splice(0)) waiter({ value: void 0, done: true });
21181
+ },
21182
+ next() {
21183
+ const buffered = buffer.shift();
21184
+ if (buffered !== void 0) return Promise.resolve({ value: buffered, done: false });
21185
+ if (ended) return Promise.resolve({ value: void 0, done: true });
21186
+ return new Promise((resolve3) => waiters.push(resolve3));
21187
+ },
21188
+ // `for await` calls return() on break/throw — close early so events stop
21189
+ // buffering in memory for a consumer that stopped iterating.
21190
+ return() {
21191
+ stream.end();
21192
+ buffer.length = 0;
21193
+ return Promise.resolve({ value: void 0, done: true });
21194
+ },
21195
+ [Symbol.asyncIterator]() {
21196
+ return stream;
21197
+ }
21198
+ };
21199
+ return stream;
21200
+ }
21201
+
21202
+ // src/workflow.ts
20809
21203
  init_workflow();
20810
21204
  var RetryPolicySchema = zod.z.object({
20811
21205
  // EC-3 absorbed: maxAttempts MUST be a finite int in [1, 20].
@@ -20817,7 +21211,12 @@ var RetryPolicySchema = zod.z.object({
20817
21211
  });
20818
21212
  var WorkflowOptionsSchema = zod.z.object({
20819
21213
  name: zod.z.string().min(1).max(128),
20820
- persistence: PersistenceSchema
21214
+ persistence: PersistenceSchema,
21215
+ // SE27 — declared so a future `new WorkflowBuilder(parsed)` refactor cannot
21216
+ // silently drop them (create() passes the ORIGINAL options today, but the
21217
+ // schema is also the documentation of the shape).
21218
+ inputSchema: zod.z.custom().optional(),
21219
+ outputSchema: zod.z.custom().optional()
20821
21220
  });
20822
21221
  var WorkflowBuilder = class {
20823
21222
  /** @internal */
@@ -20994,6 +21393,36 @@ var Workflow = class {
20994
21393
  }
20995
21394
  return result;
20996
21395
  }
21396
+ /**
21397
+ * SE28 — run the workflow and STREAM step-level events as they happen. Returns
21398
+ * an async iterator of {@link WorkflowEvent}s (`step_started` / `step_completed`
21399
+ * / `step_failed` / `workflow_suspended` / `workflow_completed`, top-level
21400
+ * steps) plus a `result` promise resolving to the same terminal
21401
+ * {@link WorkflowRun} `run()` returns. Iterate for progress; await `result` for
21402
+ * the outcome. The stream ends when the run terminates.
21403
+ *
21404
+ * `result` is the AUTHORITATIVE terminal status. Not every terminal state has a
21405
+ * closing event: a step failure emits `step_failed`, but an `outputSchema`
21406
+ * rejection (SE27) or an abort ends the stream WITHOUT `workflow_completed` —
21407
+ * always `await result` to read the final `status`. Consuming order is free:
21408
+ * awaiting `result` without draining, or draining without awaiting `result`,
21409
+ * both work (breaking out of `for await` stops the buffering early).
21410
+ */
21411
+ stream(input, opts) {
21412
+ const queue = createEventStream();
21413
+ const result = (async () => {
21414
+ const { executeWorkflow: executeWorkflow2 } = await Promise.resolve().then(() => (init_executor(), executor_exports));
21415
+ try {
21416
+ return await executeWorkflow2(this._options, this._steps, input, {
21417
+ ...opts,
21418
+ onStepEvent: (event) => queue.push(event)
21419
+ });
21420
+ } finally {
21421
+ queue.end();
21422
+ }
21423
+ })();
21424
+ return Object.assign(queue, { result });
21425
+ }
20997
21426
  /**
20998
21427
  * Resume a suspended workflow from its snapshot. Throws
20999
21428
  * `WorkflowSnapshotNotFoundError` if `runId` is unknown.
@@ -21542,11 +21971,14 @@ exports.createPermissionPlugin = createPermissionPlugin;
21542
21971
  exports.createSessionManager = createSessionManager;
21543
21972
  exports.createSkill = createSkill;
21544
21973
  exports.createSquad = createSquad;
21974
+ exports.createTokenLimiter = createTokenLimiter;
21975
+ exports.createUnicodeNormalizer = createUnicodeNormalizer;
21545
21976
  exports.definePlugin = definePlugin;
21546
21977
  exports.defineProvider = defineProvider;
21547
21978
  exports.defineSkillReadTool = defineSkillReadTool;
21548
21979
  exports.defineTool = defineTool;
21549
21980
  exports.emitRunEvent = emitRunEvent;
21981
+ exports.estimateTokens = estimateTokens;
21550
21982
  exports.extractRawId = extractRawId;
21551
21983
  exports.getPricingEntry = getPricingEntry;
21552
21984
  exports.inferApiMode = inferApiMode;