@theokit/sdk 2.21.0 → 2.22.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.
@@ -5,9 +5,53 @@
5
5
  * invoked by the LLM, creates a child agent and sends the input as a
6
6
  * message. EC-2: delegation depth tracked to prevent infinite recursion.
7
7
  *
8
+ * SE10 — the handler forwards the parent run's `AbortSignal` to the child.
9
+ * SE11 — optional `onDelegationStart` / `onDelegationComplete` lifecycle hooks
10
+ * let the caller reject, rewrite, observe, or annotate a delegation.
11
+ *
8
12
  * @public
9
13
  */
10
- import type { CustomTool } from "../types/agent.js";
14
+ import type { CustomTool, ToolContextMessage } from "../types/agent.js";
15
+ /** Arguments passed to {@link SubAgentSpec.messageFilter} (SE12). */
16
+ export interface MessageFilterArgs {
17
+ /** The supervisor transcript (read-only text projection) available to this delegation. */
18
+ messages: readonly ToolContextMessage[];
19
+ /** The prompt about to be delegated (after any `onDelegationStart` rewrite). */
20
+ input: string;
21
+ /** The subagent's name. */
22
+ name: string;
23
+ }
24
+ /** Context passed to {@link SubAgentSpec.onDelegationStart} before the child runs. */
25
+ export interface DelegationStartContext {
26
+ input: string;
27
+ name: string;
28
+ }
29
+ /**
30
+ * Decision returned from {@link SubAgentSpec.onDelegationStart}. Discriminated on
31
+ * `proceed` so a rejection (`proceed: false` + `rejectionReason`) and an approval
32
+ * (`modifiedInput`) cannot be mixed into one nonsensical object.
33
+ */
34
+ export type DelegationStartDecision = {
35
+ proceed: false;
36
+ rejectionReason?: string;
37
+ } | {
38
+ proceed?: true;
39
+ modifiedInput?: string;
40
+ };
41
+ /** Context passed to {@link SubAgentSpec.onDelegationComplete} after the child settles. */
42
+ export interface DelegationCompleteContext {
43
+ input: string;
44
+ name: string;
45
+ /** The child's text result (present on success). */
46
+ result?: string;
47
+ /** The error the child threw (present on failure); the error is still re-thrown. */
48
+ error?: unknown;
49
+ }
50
+ /** Decision returned from {@link SubAgentSpec.onDelegationComplete}. */
51
+ export interface DelegationCompleteDecision {
52
+ /** Appended to the child's result string. */
53
+ feedback?: string;
54
+ }
11
55
  export interface SubAgentSpec {
12
56
  name: string;
13
57
  description: string;
@@ -15,6 +59,31 @@ export interface SubAgentSpec {
15
59
  model?: string;
16
60
  tools?: CustomTool[];
17
61
  maxDelegationDepth?: number;
62
+ /**
63
+ * SE11 — called before the supervisor delegates. Return `{ proceed: false }`
64
+ * to reject (the child never runs and `rejectionReason` becomes the tool
65
+ * result), or `{ modifiedInput }` to rewrite the delegated prompt. A throwing
66
+ * hook surfaces (never silently swallowed).
67
+ */
68
+ onDelegationStart?: (ctx: DelegationStartContext) => DelegationStartDecision | undefined | Promise<DelegationStartDecision | undefined>;
69
+ /**
70
+ * SE11 — called after the delegation settles. On success `ctx.result` is set
71
+ * and an optional `{ feedback }` is appended to it. On failure `ctx.error` is
72
+ * set and the original error is ALWAYS re-thrown after this hook runs — a throw
73
+ * from this hook on the error path is suppressed so it cannot mask the
74
+ * delegation's real failure (on the success path a throw does propagate).
75
+ */
76
+ onDelegationComplete?: (ctx: DelegationCompleteContext) => DelegationCompleteDecision | undefined | Promise<DelegationCompleteDecision | undefined>;
77
+ /**
78
+ * SE12 — opt-in parent-context forwarding. When set, the supervisor transcript
79
+ * (`ctx.messages`, a read-only text projection) is passed to this filter and the
80
+ * returned subset is forwarded to the child as a role-tagged context preamble
81
+ * prepended to the delegated input. When ABSENT the child runs input-only —
82
+ * memory isolation stays the default. A filter returning `[]` forwards nothing.
83
+ * A throwing filter propagates (fail-fast, never swallowed — same contract as
84
+ * `onDelegationStart`); the delegation surfaces as a tool error.
85
+ */
86
+ messageFilter?: (args: MessageFilterArgs) => readonly ToolContextMessage[];
18
87
  }
19
88
  export declare class MaxDelegationDepthError extends Error {
20
89
  readonly currentDepth: number;
@@ -5,9 +5,53 @@
5
5
  * invoked by the LLM, creates a child agent and sends the input as a
6
6
  * message. EC-2: delegation depth tracked to prevent infinite recursion.
7
7
  *
8
+ * SE10 — the handler forwards the parent run's `AbortSignal` to the child.
9
+ * SE11 — optional `onDelegationStart` / `onDelegationComplete` lifecycle hooks
10
+ * let the caller reject, rewrite, observe, or annotate a delegation.
11
+ *
8
12
  * @public
9
13
  */
10
- import type { CustomTool } from "../types/agent.js";
14
+ import type { CustomTool, ToolContextMessage } from "../types/agent.js";
15
+ /** Arguments passed to {@link SubAgentSpec.messageFilter} (SE12). */
16
+ export interface MessageFilterArgs {
17
+ /** The supervisor transcript (read-only text projection) available to this delegation. */
18
+ messages: readonly ToolContextMessage[];
19
+ /** The prompt about to be delegated (after any `onDelegationStart` rewrite). */
20
+ input: string;
21
+ /** The subagent's name. */
22
+ name: string;
23
+ }
24
+ /** Context passed to {@link SubAgentSpec.onDelegationStart} before the child runs. */
25
+ export interface DelegationStartContext {
26
+ input: string;
27
+ name: string;
28
+ }
29
+ /**
30
+ * Decision returned from {@link SubAgentSpec.onDelegationStart}. Discriminated on
31
+ * `proceed` so a rejection (`proceed: false` + `rejectionReason`) and an approval
32
+ * (`modifiedInput`) cannot be mixed into one nonsensical object.
33
+ */
34
+ export type DelegationStartDecision = {
35
+ proceed: false;
36
+ rejectionReason?: string;
37
+ } | {
38
+ proceed?: true;
39
+ modifiedInput?: string;
40
+ };
41
+ /** Context passed to {@link SubAgentSpec.onDelegationComplete} after the child settles. */
42
+ export interface DelegationCompleteContext {
43
+ input: string;
44
+ name: string;
45
+ /** The child's text result (present on success). */
46
+ result?: string;
47
+ /** The error the child threw (present on failure); the error is still re-thrown. */
48
+ error?: unknown;
49
+ }
50
+ /** Decision returned from {@link SubAgentSpec.onDelegationComplete}. */
51
+ export interface DelegationCompleteDecision {
52
+ /** Appended to the child's result string. */
53
+ feedback?: string;
54
+ }
11
55
  export interface SubAgentSpec {
12
56
  name: string;
13
57
  description: string;
@@ -15,6 +59,31 @@ export interface SubAgentSpec {
15
59
  model?: string;
16
60
  tools?: CustomTool[];
17
61
  maxDelegationDepth?: number;
62
+ /**
63
+ * SE11 — called before the supervisor delegates. Return `{ proceed: false }`
64
+ * to reject (the child never runs and `rejectionReason` becomes the tool
65
+ * result), or `{ modifiedInput }` to rewrite the delegated prompt. A throwing
66
+ * hook surfaces (never silently swallowed).
67
+ */
68
+ onDelegationStart?: (ctx: DelegationStartContext) => DelegationStartDecision | undefined | Promise<DelegationStartDecision | undefined>;
69
+ /**
70
+ * SE11 — called after the delegation settles. On success `ctx.result` is set
71
+ * and an optional `{ feedback }` is appended to it. On failure `ctx.error` is
72
+ * set and the original error is ALWAYS re-thrown after this hook runs — a throw
73
+ * from this hook on the error path is suppressed so it cannot mask the
74
+ * delegation's real failure (on the success path a throw does propagate).
75
+ */
76
+ onDelegationComplete?: (ctx: DelegationCompleteContext) => DelegationCompleteDecision | undefined | Promise<DelegationCompleteDecision | undefined>;
77
+ /**
78
+ * SE12 — opt-in parent-context forwarding. When set, the supervisor transcript
79
+ * (`ctx.messages`, a read-only text projection) is passed to this filter and the
80
+ * returned subset is forwarded to the child as a role-tagged context preamble
81
+ * prepended to the delegated input. When ABSENT the child runs input-only —
82
+ * memory isolation stays the default. A filter returning `[]` forwards nothing.
83
+ * A throwing filter propagates (fail-fast, never swallowed — same contract as
84
+ * `onDelegationStart`); the delegation surfaces as a tool error.
85
+ */
86
+ messageFilter?: (args: MessageFilterArgs) => readonly ToolContextMessage[];
18
87
  }
19
88
  export declare class MaxDelegationDepthError extends Error {
20
89
  readonly currentDepth: number;
@@ -1,4 +1,4 @@
1
- import { C as CustomTool, M as ModelSelection, Z as SDKUserMessage, $ as SendOptions, b as Run, G as GenerateOptions, j as GenerateRunResult, F as RunToCompletionOptions, H as RunToCompletionResult, S as SDKMessage, a6 as StreamToCompletionResult, a as McpServerConfig } from './run-BMo8yRwK.js';
1
+ import { C as CustomTool, M as ModelSelection, Z as SDKUserMessage, $ as SendOptions, b as Run, G as GenerateOptions, j as GenerateRunResult, F as RunToCompletionOptions, H as RunToCompletionResult, S as SDKMessage, a6 as StreamToCompletionResult, a as McpServerConfig } from './run-CrIulPF7.js';
2
2
  import * as zod from 'zod';
3
3
 
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { C as CustomTool, M as ModelSelection, Z as SDKUserMessage, $ as SendOptions, b as Run, G as GenerateOptions, j as GenerateRunResult, F as RunToCompletionOptions, H as RunToCompletionResult, S as SDKMessage, a6 as StreamToCompletionResult, a as McpServerConfig } from './run-BMo8yRwK.cjs';
1
+ import { C as CustomTool, M as ModelSelection, Z as SDKUserMessage, $ as SendOptions, b as Run, G as GenerateOptions, j as GenerateRunResult, F as RunToCompletionOptions, H as RunToCompletionResult, S as SDKMessage, a6 as StreamToCompletionResult, a as McpServerConfig } from './run-CrIulPF7.cjs';
2
2
  import * as zod from 'zod';
3
3
 
4
4
  /**
package/dist/cron.cjs CHANGED
@@ -9454,21 +9454,21 @@ async function executeTool(inputs, resolved, call) {
9454
9454
  if (resolved.origin === "shell") return runShellTool(inputs, call);
9455
9455
  if (resolved.origin === "memory") return runMemoryTool(resolved, call, inputs.context);
9456
9456
  if (resolved.origin === "custom")
9457
- return runCustomTool(resolved, call, inputs.signal, inputs.context);
9457
+ return runCustomTool(resolved, call, inputs.signal, inputs.context, inputs.messages);
9458
9458
  return runMcpTool(inputs, resolved, call);
9459
9459
  }
9460
9460
  async function runMemoryTool(resolved, call, context) {
9461
9461
  return runHandlerTool("memory", resolved.memoryHandler, call, void 0, context);
9462
9462
  }
9463
- async function runCustomTool(resolved, call, signal, context) {
9464
- return runHandlerTool("custom", resolved.customHandler, call, signal, context);
9463
+ async function runCustomTool(resolved, call, signal, context, messages) {
9464
+ return runHandlerTool("custom", resolved.customHandler, call, signal, context, messages);
9465
9465
  }
9466
- async function runHandlerTool(kind, handler, call, signal, context) {
9466
+ async function runHandlerTool(kind, handler, call, signal, context, messages) {
9467
9467
  if (handler === void 0) {
9468
9468
  return { stdout: "", stderr: `${kind} tool ${call.name} has no handler`, exitCode: 127 };
9469
9469
  }
9470
9470
  try {
9471
- const out = await handler(call.input, { signal, context });
9471
+ const out = await handler(call.input, { signal, context, messages });
9472
9472
  if (typeof out !== "string") return { stdout: "", stderr: "", exitCode: 0, content: out };
9473
9473
  return { stdout: out, stderr: "", exitCode: 0 };
9474
9474
  } catch (cause) {
@@ -10228,6 +10228,14 @@ function computeUsageCost(inputs, usage) {
10228
10228
  }
10229
10229
 
10230
10230
  // src/internal/agent-loop/loop.ts
10231
+ function projectToolContextMessages(messages) {
10232
+ const projected = [];
10233
+ for (const m of messages) {
10234
+ const content = m.content.flatMap((p) => p.type === "text" ? [p.text] : []).join("");
10235
+ if (content !== "") projected.push({ role: m.role, content });
10236
+ }
10237
+ return projected;
10238
+ }
10231
10239
  var MAX_NUDGE_ATTEMPTS = 2;
10232
10240
  var MAX_STOP_FEEDBACK_ATTEMPTS = 2;
10233
10241
  async function runAgentLoop(inputs) {
@@ -10470,7 +10478,9 @@ async function continueOrTerminate(inputs, ctx, llmOutput) {
10470
10478
  const outText = await transformLlmOutputText(inputs, llmOutput.text, tCtx);
10471
10479
  ctx.messages.push(buildAssistantTurn(outText, llmOutput.toolCalls));
10472
10480
  const rawResults = await dispatchTools(
10473
- inputs,
10481
+ // SE12 — forward a read-only text projection of the transcript-so-far to tool
10482
+ // handlers via `ctx.messages` (consumed by defineSubAgent's messageFilter).
10483
+ { ...inputs, messages: projectToolContextMessages(ctx.messages) },
10474
10484
  ctx.tools,
10475
10485
  llmOutput.toolCalls,
10476
10486
  ctx.events,