@theokit/sdk 2.25.0 → 2.26.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 (37) hide show
  1. package/CHANGELOG.md +29 -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 +234 -6
  22. package/dist/index.cjs.map +1 -1
  23. package/dist/index.d.cts +56 -7
  24. package/dist/index.d.ts +56 -7
  25. package/dist/index.js +232 -7
  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/{run-Cr0C6cOM.d.cts → run-CdWiihyU.d.cts} +109 -2
  31. package/dist/{run-Cr0C6cOM.d.ts → run-CdWiihyU.d.ts} +109 -2
  32. package/dist/types/agent.d.ts +10 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/dist/types/processors.d.ts +84 -0
  35. package/dist/types/run-events.d.ts +11 -1
  36. package/dist/types/run.d.ts +12 -0
  37. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # Changelog
2
2
 
3
+ ## 2.26.0
4
+
5
+ ### Minor Changes
6
+
7
+ - d31e2ca: **SE24 — guardrail processor pipeline (`inputProcessors` / `outputProcessors`).**
8
+
9
+ `AgentOptions.inputProcessors` run in order before the LLM (normalize / validate / block / rewrite the user message); `outputProcessors` run on the model's final text before it reaches the caller (redact / block). A `Processor` is `{ id; processInput?; processOutput?; onViolation? }`; each handler receives `ctx` with `abort(reason)` (block → the run stops with `RunResult.tripwire { reason, processorId }` + a `tripwire` run-event via `SendOptions.onRunEvent`) and `warn(message, detail?)` (non-blocking → fires `onViolation`, continues), and returns the (possibly rewritten) payload.
10
+
11
+ The core ships no `strategy` enum — block/rewrite/redact/warn reduce to `abort` / return-string / `warn` (the built-in SE25 processors expose a `strategy` option over these). An input block never reaches the model (a terminal tripwire run); an output block turns a finished run's result into a tripwire on `wait()`. Streaming output redaction is deferred (v1 processes the buffered `wait()` path). Cloud agents reject processors (function handlers don't serialize). Back-compat: no processors ⇒ unchanged. New public types `Processor` / `ProcessorViolation` / `InputProcessorContext` / `OutputProcessorContext` / `ProcessorControls` / `ProcessorTripwire` / `RunTripwireEvent` + `RunResult.tripwire`. ADR 0008. Mirrors Mastra Guardrails input/output processors. From the Mastra Guardrails comparison (SDK Evolution roadmap SE24).
12
+
13
+ - cc8efee: **SE25 — deterministic in-tree guardrail processors (`createUnicodeNormalizer`, `createTokenLimiter`).**
14
+
15
+ Two churn-free, no-LLM processors built on the SE24 seam:
16
+
17
+ - `createUnicodeNormalizer({ stripControlChars?, collapseWhitespace? })` — an input processor: Unicode NFC normalization (stdlib `String.prototype.normalize`) plus optional C0/DEL control-char stripping (keeps tab/newline/carriage-return) and whitespace collapsing.
18
+ - `createTokenLimiter({ limit, strategy? })` — caps text to a token budget using a char-based estimate (~chars/4, no tokenizer dep; `estimateTokens` is exported). `strategy: "truncate"` (default, cut to fit) or `"block"` (abort → tripwire). Fires on whichever array it is placed in (input caps the prompt, output caps the response).
19
+
20
+ Both are OPT-IN (add to `inputProcessors`/`outputProcessors`); nothing auto-injects them; back-compat preserved.
21
+
22
+ **`BatchPartsProcessor` is intentionally DEFERRED**, not shipped: TheoKit's `run.stream()` emits full `SDKAssistantMessage`s, not token-granular deltas, so there is no SSE chunk stream to coalesce in the in-process runtime (Mastra's BatchParts cuts HTTP network overhead). It becomes meaningful only alongside a future HTTP/SSE streaming transport (the same milestone as SE24's deferred streaming-output redaction). Mirrors Mastra's deterministic guardrail processors. From the Mastra Guardrails comparison (SDK Evolution roadmap SE25).
23
+
24
+ ### Patch Changes
25
+
26
+ - 0685363: **SE26 — delegate LLM-classifier guardrail processors (ADR + recommendation + example).**
27
+
28
+ Records the decision (ADR 0009) to DELEGATE the LLM-classifier guardrail processors — moderation, PII, prompt-injection, language, prompt-scrubber — to specialist libraries / consumer code built ON the SE24 seam, rather than shipping concrete classifiers in `@theokit/sdk` core (mirrors the AUTH-DELEGATION lock: constant churn — provider/model deltas, taxonomies, thresholds, jailbreak patterns — vs a stable seam a single-maintainer core can own). No classifier is added to core.
29
+
30
+ Ships the paved path: `docs/concepts/guardrails.md` (how to build moderation / PII / injection processors on the seam + recommended external classifiers) and `examples/guardrails/` (a runnable moderation + PII-redaction example over a pluggable classifier). No public API change. From the Mastra Guardrails comparison (SDK Evolution roadmap SE26).
31
+
3
32
  ## 2.25.0
4
33
 
5
34
  ### Minor Changes
@@ -3454,8 +3454,18 @@ function validateCloudToolParity(options) {
3454
3454
  if (options.cloud === void 0) return;
3455
3455
  rejectFunctionSystemPrompt(options);
3456
3456
  rejectFunctionSkills(options);
3457
+ rejectProcessors(options);
3457
3458
  rejectStdioMcpLocalPaths(options);
3458
3459
  }
3460
+ function rejectProcessors(options) {
3461
+ const hasProcessors = (options.inputProcessors?.length ?? 0) > 0 || (options.outputProcessors?.length ?? 0) > 0;
3462
+ if (hasProcessors) {
3463
+ throw new ConfigurationError(
3464
+ "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.",
3465
+ { code: "cloud_incompatible_function_resolver" }
3466
+ );
3467
+ }
3468
+ }
3459
3469
  function rejectFunctionSystemPrompt(options) {
3460
3470
  if (typeof options.systemPrompt === "function") {
3461
3471
  throw new ConfigurationError(
@@ -16356,6 +16366,162 @@ var init_abort_utils = __esm({
16356
16366
  }
16357
16367
  });
16358
16368
 
16369
+ // src/internal/runtime/processors/run-processors.ts
16370
+ function fireViolation(processor, violation) {
16371
+ try {
16372
+ processor.onViolation?.(violation);
16373
+ } catch {
16374
+ }
16375
+ }
16376
+ function controlsFor(processor) {
16377
+ return {
16378
+ abort(reason) {
16379
+ throw new ProcessorAbort(processor.id, reason);
16380
+ },
16381
+ warn(message, detail) {
16382
+ fireViolation(processor, {
16383
+ processorId: processor.id,
16384
+ message,
16385
+ ...detail !== void 0 ? { detail } : {}
16386
+ });
16387
+ }
16388
+ };
16389
+ }
16390
+ function selectHandler(processor, phase) {
16391
+ if (phase === "input") {
16392
+ return processor.processInput ? { kind: "input", fn: processor.processInput } : void 0;
16393
+ }
16394
+ return processor.processOutput ? { kind: "output", fn: processor.processOutput } : void 0;
16395
+ }
16396
+ function invokeHandler(handler, value, agentId, controls) {
16397
+ return handler.kind === "input" ? handler.fn({ message: value, agentId, ...controls }) : handler.fn({ text: value, agentId, ...controls });
16398
+ }
16399
+ async function runOneProcessor(processor, value, agentId, phase) {
16400
+ const handler = selectHandler(processor, phase);
16401
+ if (handler === void 0) return { value };
16402
+ try {
16403
+ const out = await invokeHandler(handler, value, agentId, controlsFor(processor));
16404
+ return { value: typeof out === "string" ? out : value };
16405
+ } catch (err) {
16406
+ if (!(err instanceof ProcessorAbort)) throw err;
16407
+ fireViolation(processor, { processorId: err.processorId, message: err.reason });
16408
+ return { tripwire: { reason: err.reason, processorId: err.processorId } };
16409
+ }
16410
+ }
16411
+ async function runPipeline(processors, initial, agentId, phase) {
16412
+ let value = initial;
16413
+ for (const processor of processors) {
16414
+ const step = await runOneProcessor(processor, value, agentId, phase);
16415
+ if ("tripwire" in step) return { kind: "tripwire", tripwire: step.tripwire };
16416
+ value = step.value;
16417
+ }
16418
+ return { kind: "ok", value };
16419
+ }
16420
+ function runInputProcessors(processors, message, agentId) {
16421
+ return runPipeline(processors, message, agentId, "input");
16422
+ }
16423
+ function runOutputProcessors(processors, text, agentId) {
16424
+ return runPipeline(processors, text, agentId, "output");
16425
+ }
16426
+ var ProcessorAbort;
16427
+ var init_run_processors = __esm({
16428
+ "src/internal/runtime/processors/run-processors.ts"() {
16429
+ ProcessorAbort = class {
16430
+ constructor(processorId, reason) {
16431
+ this.processorId = processorId;
16432
+ this.reason = reason;
16433
+ }
16434
+ processorId;
16435
+ reason;
16436
+ };
16437
+ }
16438
+ });
16439
+
16440
+ // src/internal/runtime/processors/tripwire-run.ts
16441
+ function emptyStream() {
16442
+ return {
16443
+ next: () => Promise.resolve({ done: true, value: void 0 }),
16444
+ return: () => Promise.resolve({ done: true, value: void 0 }),
16445
+ throw: (err) => Promise.reject(err),
16446
+ [Symbol.asyncIterator]() {
16447
+ return this;
16448
+ }
16449
+ };
16450
+ }
16451
+ function createTripwireRun(args) {
16452
+ const id = globalThis.crypto.randomUUID();
16453
+ const result = {
16454
+ id,
16455
+ status: "cancelled",
16456
+ tripwire: args.tripwire,
16457
+ ...args.model !== void 0 ? { model: args.model } : {}
16458
+ };
16459
+ const run = {
16460
+ id,
16461
+ agentId: args.agentId,
16462
+ status: "cancelled",
16463
+ ...args.model !== void 0 ? { model: args.model } : {},
16464
+ stream: () => emptyStream(),
16465
+ wait: () => Promise.resolve(result),
16466
+ cancel: () => Promise.resolve(),
16467
+ conversation: () => Promise.resolve([]),
16468
+ supports: (op) => SUPPORTED.has(op),
16469
+ unsupportedReason: (op) => SUPPORTED.has(op) ? void 0 : `operation "${op}" is not available on a tripwire run`,
16470
+ onDidChangeStatus: () => () => {
16471
+ }
16472
+ // already terminal — status never changes
16473
+ };
16474
+ registerRun(run);
16475
+ return run;
16476
+ }
16477
+ var SUPPORTED;
16478
+ var init_tripwire_run = __esm({
16479
+ "src/internal/runtime/processors/tripwire-run.ts"() {
16480
+ init_run_registry();
16481
+ SUPPORTED = /* @__PURE__ */ new Set([
16482
+ "stream",
16483
+ "wait",
16484
+ "cancel",
16485
+ "conversation"
16486
+ ]);
16487
+ }
16488
+ });
16489
+
16490
+ // src/internal/runtime/processors/wrap-output-run.ts
16491
+ function wrapRunWithOutputProcessors(args) {
16492
+ if (args.processors.length === 0) return args.run;
16493
+ const compute = async () => {
16494
+ const result = await args.run.wait();
16495
+ if (result.status !== "finished" || result.result === void 0) return result;
16496
+ const res = await runOutputProcessors(args.processors, result.result, args.agentId);
16497
+ if (res.kind === "ok") return { ...result, result: res.value };
16498
+ emitRunEvent(args.onRunEvent, {
16499
+ type: "tripwire",
16500
+ reason: res.tripwire.reason,
16501
+ processorId: res.tripwire.processorId
16502
+ });
16503
+ const { result: _suppressed, ...metadata } = result;
16504
+ return { ...metadata, status: "cancelled", tripwire: res.tripwire };
16505
+ };
16506
+ let processed;
16507
+ const wrappedWait = () => {
16508
+ processed ??= compute();
16509
+ return processed;
16510
+ };
16511
+ return new Proxy(args.run, {
16512
+ get(target, prop, receiver) {
16513
+ if (prop === "wait") return wrappedWait;
16514
+ return Reflect.get(target, prop, receiver);
16515
+ }
16516
+ });
16517
+ }
16518
+ var init_wrap_output_run = __esm({
16519
+ "src/internal/runtime/processors/wrap-output-run.ts"() {
16520
+ init_run_events();
16521
+ init_run_processors();
16522
+ }
16523
+ });
16524
+
16359
16525
  // src/internal/runtime/local-agent/local-agent-memory-hooks.ts
16360
16526
  async function applyPreUserSendHook(args) {
16361
16527
  const handlers = args.pluginManager.hooksFor("pre_user_send");
@@ -16408,11 +16574,38 @@ var init_local_agent_memory_hooks = __esm({
16408
16574
  });
16409
16575
 
16410
16576
  // src/internal/runtime/local-agent/local-agent-send.ts
16577
+ async function applyInputProcessors(inputs, message, rawUserText, options, sendModel) {
16578
+ const processors = inputs.options.inputProcessors;
16579
+ if (processors === void 0 || processors.length === 0) {
16580
+ return { userText: rawUserText, effectiveMessage: message };
16581
+ }
16582
+ const res = await runInputProcessors(processors, rawUserText, inputs.agentId);
16583
+ if (res.kind === "tripwire") {
16584
+ emitRunEvent(options.onRunEvent, {
16585
+ type: "tripwire",
16586
+ reason: res.tripwire.reason,
16587
+ processorId: res.tripwire.processorId
16588
+ });
16589
+ return {
16590
+ tripwireRun: createTripwireRun({
16591
+ agentId: inputs.agentId,
16592
+ tripwire: res.tripwire,
16593
+ model: sendModel
16594
+ })
16595
+ };
16596
+ }
16597
+ const effectiveMessage = typeof message === "string" ? res.value : { ...message, text: res.value };
16598
+ return { userText: res.value, effectiveMessage };
16599
+ }
16411
16600
  async function executeSendLocked(inputs, message, options) {
16412
16601
  if (inputs.disposed) throw new AgentDisposedError(inputs.agentId);
16413
16602
  await consumePending(inputs.agentId, inputs.invalidationPending, inputs.clearInvalidation, inputs.reload);
16414
- inputs.applyModelOverride(normalizeModel(options.model));
16415
- const userText = typeof message === "string" ? message : message.text;
16603
+ const sendModel = normalizeModel(options.model);
16604
+ inputs.applyModelOverride(sendModel);
16605
+ const rawUserText = typeof message === "string" ? message : message.text;
16606
+ const gated = await applyInputProcessors(inputs, message, rawUserText, options, sendModel);
16607
+ if ("tripwireRun" in gated) return gated.tripwireRun;
16608
+ const { userText, effectiveMessage } = gated;
16416
16609
  if (inputs.options.onBeforeSend !== void 0) {
16417
16610
  await inputs.options.onBeforeSend({
16418
16611
  conversationId: inputs.agentId,
@@ -16424,7 +16617,7 @@ async function executeSendLocked(inputs, message, options) {
16424
16617
  pluginManager: inputs.pluginManagerCode,
16425
16618
  agentId: inputs.agentId,
16426
16619
  options: inputs.options,
16427
- original: message,
16620
+ original: effectiveMessage,
16428
16621
  userText,
16429
16622
  sendOptions: options
16430
16623
  });
@@ -16462,11 +16655,18 @@ async function executeSendLocked(inputs, message, options) {
16462
16655
  memoryTools,
16463
16656
  effectiveMemoryProvider
16464
16657
  );
16658
+ const outputProcessors = inputs.options.outputProcessors;
16659
+ const processedRun = outputProcessors !== void 0 && outputProcessors.length > 0 ? wrapRunWithOutputProcessors({
16660
+ run,
16661
+ processors: outputProcessors,
16662
+ agentId: inputs.agentId,
16663
+ onRunEvent: options.onRunEvent
16664
+ }) : run;
16465
16665
  return wrapRunWithPostReplyHook({
16466
16666
  pluginManager: inputs.pluginManagerCode,
16467
16667
  agentId: inputs.agentId,
16468
16668
  options: inputs.options,
16469
- run,
16669
+ run: processedRun,
16470
16670
  userText
16471
16671
  });
16472
16672
  }
@@ -16477,10 +16677,14 @@ function readMemoryForSend(workspaceCwd, memoryConfig) {
16477
16677
  var init_local_agent_send = __esm({
16478
16678
  "src/internal/runtime/local-agent/local-agent-send.ts"() {
16479
16679
  init_errors();
16680
+ init_run_events();
16480
16681
  init_abort_utils();
16481
16682
  init_memory_path_selector();
16482
16683
  init_memory_store();
16483
16684
  init_model_selection();
16685
+ init_run_processors();
16686
+ init_tripwire_run();
16687
+ init_wrap_output_run();
16484
16688
  init_agent_session();
16485
16689
  init_safe_call();
16486
16690
  init_local_agent_invalidate();