@prestyj/agent 5.28.1 → 5.29.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.d.cts CHANGED
@@ -1,6 +1,82 @@
1
- import { StreamOptions, Message, Tool, ToolResultContent, ServerToolDefinition, Usage, StopReason, AssistantMessage } from '@prestyj/ai';
1
+ import { Message, StreamOptions, Tool, ToolResultContent, ServerToolDefinition, Usage, StopReason, AssistantMessage } from '@prestyj/ai';
2
2
  import { z } from 'zod';
3
3
 
4
+ /**
5
+ * Stream rules: regex guards matched against a response WHILE it streams.
6
+ *
7
+ * A rule costs zero prompt tokens until the model actually breaks it. On a
8
+ * match the agent loop aborts the in-flight response, discards the partial
9
+ * assistant message (nothing is persisted, no partial tool call runs), appends
10
+ * the rule's reminder as a hidden runtime note, and retries the same step.
11
+ *
12
+ * Matching is incremental: each stream (assistant text, or one tool call's
13
+ * argument JSON) keeps a bounded rolling window, so a delta is scanned together
14
+ * with only the last `windowChars` characters before it — never the whole
15
+ * output. A pattern whose match spans more than the window is not detected.
16
+ *
17
+ * Tool-call arguments arrive as JSON text; they are unescaped incrementally so
18
+ * rules see `\n`, `"`, etc. as the model meant them, not as JSON escapes.
19
+ */
20
+
21
+ /** Which streamed output a rule watches. Thinking is never matched. */
22
+ type StreamRuleScope = "text" | "tool" | "both";
23
+ interface StreamRule {
24
+ /** Stable identifier; also the once-per-run dedupe key. */
25
+ name: string;
26
+ /** Pattern tested against the rolling window. `g`/`y` flags are tolerated. */
27
+ pattern: RegExp;
28
+ scope: StreamRuleScope;
29
+ /** Reminder appended to the context when the rule fires. */
30
+ reminder: string;
31
+ /** Restrict tool-scope matching to these tool names. Unset = every tool. */
32
+ tools?: readonly string[];
33
+ }
34
+ interface StreamRulesConfig {
35
+ rules: readonly StreamRule[];
36
+ /** Rule-triggered retries allowed per agent run (one user turn). Default 3. */
37
+ maxRetries?: number;
38
+ /** Characters of prior output kept per stream for cross-delta matches. Default 1024. */
39
+ windowChars?: number;
40
+ }
41
+ type StreamRuleSource = "text" | "tool";
42
+ interface StreamRuleMatch {
43
+ rules: StreamRule[];
44
+ source: StreamRuleSource;
45
+ toolName?: string;
46
+ }
47
+ declare const DEFAULT_STREAM_RULE_MAX_RETRIES = 3;
48
+ declare const DEFAULT_STREAM_RULE_WINDOW_CHARS = 1024;
49
+ /** Incremental JSON string-escape decoder that tolerates escapes split across chunks. */
50
+ declare class JsonEscapeDecoder {
51
+ private pending;
52
+ push(chunk: string): string;
53
+ }
54
+ /**
55
+ * Per-run rule state. Create one per `agentLoop` run; call `beginAttempt()`
56
+ * before every provider attempt so windows never leak across attempts.
57
+ */
58
+ declare class StreamRuleMonitor {
59
+ readonly maxRetries: number;
60
+ private readonly rules;
61
+ private readonly windowChars;
62
+ private readonly fired;
63
+ private retries;
64
+ private textWindow;
65
+ private readonly toolStreams;
66
+ constructor(config: StreamRulesConfig);
67
+ /** False once the retry cap is spent or every rule has fired — skip all matching. */
68
+ get active(): boolean;
69
+ get retriesUsed(): number;
70
+ beginAttempt(): void;
71
+ checkText(delta: string): StreamRuleMatch | null;
72
+ checkToolArgs(id: string, toolName: string, argsDelta: string): StreamRuleMatch | null;
73
+ /** Consume one retry and mark the rules fired. Returns the retry ordinal (1-based). */
74
+ recordTrigger(rules: readonly StreamRule[]): number;
75
+ private match;
76
+ }
77
+ /** The hidden runtime note appended before the retry. */
78
+ declare function buildStreamRuleReminder(rules: readonly StreamRule[]): Message;
79
+
4
80
  interface StructuredToolResult {
5
81
  content: ToolResultContent;
6
82
  details?: unknown;
@@ -27,6 +103,12 @@ interface AgentTool<T extends z.ZodType = z.ZodType> extends Tool {
27
103
  * message — becomes unreachable.
28
104
  */
29
105
  timeoutMs?: number;
106
+ /**
107
+ * Whether a mid-run steering message may preempt this tool. Defaults to
108
+ * true, except for atomic file mutators (`edit`, `write`, …) which always
109
+ * run to completion so they are never left half-applied.
110
+ */
111
+ interruptible?: boolean;
30
112
  execute: (args: z.infer<T>, context: ToolContext) => ToolExecuteResult | Promise<ToolExecuteResult>;
31
113
  }
32
114
  interface AgentTextDeltaEvent {
@@ -146,7 +228,7 @@ interface AgentTruncatedEvent {
146
228
  }
147
229
  interface AgentRetryEvent {
148
230
  type: "retry";
149
- reason: "overloaded" | "rate_limit" | "provider_error" | "empty_response" | "stream_stall" | "overflow_compact" | "tool_argument_glitch" | "runaway_toolcall";
231
+ reason: "overloaded" | "rate_limit" | "provider_error" | "empty_response" | "stream_stall" | "overflow_compact" | "tool_argument_glitch" | "runaway_toolcall" | "stream_rule";
150
232
  attempt: number;
151
233
  maxAttempts: number;
152
234
  delayMs: number;
@@ -164,6 +246,29 @@ interface AgentRetryEvent {
164
246
  */
165
247
  preservedChars?: number;
166
248
  }
249
+ /**
250
+ * A stream rule matched mid-response. The attempt was aborted and discarded
251
+ * (no partial message persisted, no partial tool call executed), the rule's
252
+ * reminder was appended to the context, and the step is retried. Always
253
+ * followed by a silent `retry` (reason `stream_rule`) so UIs roll back the
254
+ * streamed partial exactly as for any other replayed attempt.
255
+ */
256
+ interface AgentStreamRuleTriggeredEvent {
257
+ type: "stream_rule_triggered";
258
+ /** Names of the rules that matched (usually one). */
259
+ rules: string[];
260
+ source: "text" | "tool";
261
+ /** Tool whose streamed arguments matched, for `source: "tool"`. */
262
+ toolName?: string;
263
+ attempt: number;
264
+ maxAttempts: number;
265
+ /**
266
+ * ESTIMATED usage of the aborted attempt (providers report none for an
267
+ * aborted stream): prompt chars/4 in, streamed chars/4 out. Already added to
268
+ * the run's `totalUsage`.
269
+ */
270
+ usage: Usage;
271
+ }
167
272
  interface AgentToolCallDeltaEvent {
168
273
  type: "toolcall_delta";
169
274
  chars: number;
@@ -192,7 +297,7 @@ interface AgentFollowUpMessageEvent {
192
297
  type: "follow_up_message";
193
298
  content: Message["content"];
194
299
  }
195
- type AgentEvent = AgentTextDeltaEvent | AgentThinkingDeltaEvent | AgentToolCallStartEvent | AgentToolCallUpdateEvent | AgentToolCallEndEvent | AgentToolCallDeltaEvent | AgentServerToolCallEvent | AgentServerToolResultEvent | AgentSteeringMessageEvent | AgentFollowUpMessageEvent | AgentRetryEvent | AgentTurnEndEvent | AgentCheckpointEvent | AgentDoneEvent | AgentMaxTurnsEvent | AgentTurnBudgetExtendedEvent | AgentTruncatedEvent | AgentErrorEvent;
300
+ type AgentEvent = AgentTextDeltaEvent | AgentThinkingDeltaEvent | AgentToolCallStartEvent | AgentToolCallUpdateEvent | AgentToolCallEndEvent | AgentToolCallDeltaEvent | AgentServerToolCallEvent | AgentServerToolResultEvent | AgentSteeringMessageEvent | AgentFollowUpMessageEvent | AgentRetryEvent | AgentStreamRuleTriggeredEvent | AgentTurnEndEvent | AgentCheckpointEvent | AgentDoneEvent | AgentMaxTurnsEvent | AgentTurnBudgetExtendedEvent | AgentTruncatedEvent | AgentErrorEvent;
196
301
  interface TransformContextOptions {
197
302
  /** Force a transform after the provider reports context overflow. */
198
303
  force?: boolean;
@@ -244,6 +349,7 @@ interface AgentOptions {
244
349
  transportSessionId?: StreamOptions["transportSessionId"];
245
350
  projectId?: StreamOptions["projectId"];
246
351
  cacheRetention?: StreamOptions["cacheRetention"];
352
+ onContextPrepared?: StreamOptions["onContextPrepared"];
247
353
  /** Stable per-session cache routing key for providers that support it. */
248
354
  promptCacheKey?: StreamOptions["promptCacheKey"];
249
355
  /** Override the User-Agent sent with OAuth-authenticated Anthropic requests. */
@@ -271,6 +377,14 @@ interface AgentOptions {
271
377
  * against parallel fan-outs injecting huge uncached context in one turn;
272
378
  * the largest results are trimmed (water-filling) with a re-run notice. */
273
379
  maxTurnToolResultChars?: number;
380
+ /** Optional post-processing of a SUCCESSFUL tool result (after redaction,
381
+ * before the tool_call_end event and the provider context). Return the
382
+ * content unchanged to leave it alone. A throw is ignored (original kept).
383
+ * Used e.g. to append a warning to untrusted-content results. */
384
+ transformToolResult?: (call: {
385
+ name: string;
386
+ args: Record<string, unknown>;
387
+ }, content: ToolResultContent) => ToolResultContent;
274
388
  /** Max consecutive pause_turn continuations before stopping (default: 5).
275
389
  * Prevents infinite loops when server-side tools keep pausing. */
276
390
  maxContinuations?: number;
@@ -292,6 +406,15 @@ interface AgentOptions {
292
406
  * on read.
293
407
  */
294
408
  getSteeringMessages?: () => Promise<Message[] | null> | Message[] | null;
409
+ /**
410
+ * Instant interrupt (codex `instant_interrupt`): subscribe to "a steering
411
+ * message just arrived". While tools are running, the listener preempts
412
+ * interruptible tools (their AbortSignal fires; unfinished calls get an
413
+ * "Interrupted" error result) and the loop drains steering and continues.
414
+ * Distinct from `signal` (the Stop button), which ends the run. Returns an
415
+ * unsubscribe function.
416
+ */
417
+ onSteeringAvailable?: (listener: () => void) => () => void;
295
418
  /**
296
419
  * Polled when the agent would otherwise stop (no tool calls, no steering).
297
420
  * Returns messages to inject and continue the loop. Lower priority than
@@ -312,6 +435,13 @@ interface AgentOptions {
312
435
  maxTurns: number;
313
436
  extension: number;
314
437
  }) => Promise<boolean> | boolean;
438
+ /**
439
+ * Regex rules matched against streamed assistant text and tool-call
440
+ * arguments. A match aborts the attempt, discards it, appends the rule's
441
+ * reminder and retries the step. Each rule fires at most once per run;
442
+ * `maxRetries` (default 3) caps rule retries per run. Unset = no matching.
443
+ */
444
+ streamRules?: StreamRulesConfig;
315
445
  }
316
446
  interface AgentResult {
317
447
  message: AssistantMessage;
@@ -349,6 +479,7 @@ declare class Agent {
349
479
  private options;
350
480
  private steeringQueue;
351
481
  private followUpQueue;
482
+ private steeringListeners;
352
483
  constructor(options: AgentOptions);
353
484
  /** Snapshot of the current message history. Used for session persistence. */
354
485
  getMessages(): Message[];
@@ -359,7 +490,11 @@ declare class Agent {
359
490
  */
360
491
  setSignal(signal: AbortSignal | undefined): void;
361
492
  get running(): boolean;
362
- /** Queue a steering message for injection after current tool execution completes. */
493
+ /**
494
+ * Queue a steering message. Instant interrupt: if tools are running, the
495
+ * interruptible ones are preempted right away and the message is injected
496
+ * before the next model call (the turn continues — unlike abort/Stop).
497
+ */
363
498
  steer(msg: Message): void;
364
499
  /** Queue a follow-up message for injection when the agent would otherwise stop. */
365
500
  followUp(msg: Message): void;
@@ -415,6 +550,7 @@ declare function cancelledBeforeStartText(name: string): string;
415
550
  * something never ran when it did.
416
551
  */
417
552
  declare function indeterminateOutcomeText(name: string): string;
553
+ declare function repairToolPairingAdjacent(messages: Message[]): void;
418
554
 
419
555
  /**
420
556
  * A local inference server (llama.cpp, vLLM, Ollama, LM Studio) can spend
@@ -425,4 +561,4 @@ declare function indeterminateOutcomeText(name: string): string;
425
561
  */
426
562
  declare function isLocalBackendUrl(baseUrl?: string): boolean;
427
563
 
428
- export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentFollowUpMessageEvent, type AgentOptions, type AgentResult, type AgentRetryEvent, type AgentServerToolCallEvent, type AgentServerToolResultEvent, type AgentSteeringMessageEvent, AgentStream, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallDeltaEvent, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type AgentTurnTiming, type StreamDiagnosticFn, type StructuredToolResult, type ToolContext, type ToolExecuteResult, type ToolExecutionMode, type TransformContextOptions, agentLoop, cancelledBeforeStartText, indeterminateOutcomeText, isAbortError, isBillingError, isContextOverflow, isLocalBackendUrl, isUsageLimitError, setStreamDiagnostic };
564
+ export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentFollowUpMessageEvent, type AgentOptions, type AgentResult, type AgentRetryEvent, type AgentServerToolCallEvent, type AgentServerToolResultEvent, type AgentSteeringMessageEvent, AgentStream, type AgentStreamRuleTriggeredEvent, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallDeltaEvent, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type AgentTurnTiming, DEFAULT_STREAM_RULE_MAX_RETRIES, DEFAULT_STREAM_RULE_WINDOW_CHARS, JsonEscapeDecoder, type StreamDiagnosticFn, type StreamRule, type StreamRuleMatch, StreamRuleMonitor, type StreamRuleScope, type StreamRuleSource, type StreamRulesConfig, type StructuredToolResult, type ToolContext, type ToolExecuteResult, type ToolExecutionMode, type TransformContextOptions, agentLoop, buildStreamRuleReminder, cancelledBeforeStartText, indeterminateOutcomeText, isAbortError, isBillingError, isContextOverflow, isLocalBackendUrl, isUsageLimitError, repairToolPairingAdjacent, setStreamDiagnostic };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,82 @@
1
- import { StreamOptions, Message, Tool, ToolResultContent, ServerToolDefinition, Usage, StopReason, AssistantMessage } from '@prestyj/ai';
1
+ import { Message, StreamOptions, Tool, ToolResultContent, ServerToolDefinition, Usage, StopReason, AssistantMessage } from '@prestyj/ai';
2
2
  import { z } from 'zod';
3
3
 
4
+ /**
5
+ * Stream rules: regex guards matched against a response WHILE it streams.
6
+ *
7
+ * A rule costs zero prompt tokens until the model actually breaks it. On a
8
+ * match the agent loop aborts the in-flight response, discards the partial
9
+ * assistant message (nothing is persisted, no partial tool call runs), appends
10
+ * the rule's reminder as a hidden runtime note, and retries the same step.
11
+ *
12
+ * Matching is incremental: each stream (assistant text, or one tool call's
13
+ * argument JSON) keeps a bounded rolling window, so a delta is scanned together
14
+ * with only the last `windowChars` characters before it — never the whole
15
+ * output. A pattern whose match spans more than the window is not detected.
16
+ *
17
+ * Tool-call arguments arrive as JSON text; they are unescaped incrementally so
18
+ * rules see `\n`, `"`, etc. as the model meant them, not as JSON escapes.
19
+ */
20
+
21
+ /** Which streamed output a rule watches. Thinking is never matched. */
22
+ type StreamRuleScope = "text" | "tool" | "both";
23
+ interface StreamRule {
24
+ /** Stable identifier; also the once-per-run dedupe key. */
25
+ name: string;
26
+ /** Pattern tested against the rolling window. `g`/`y` flags are tolerated. */
27
+ pattern: RegExp;
28
+ scope: StreamRuleScope;
29
+ /** Reminder appended to the context when the rule fires. */
30
+ reminder: string;
31
+ /** Restrict tool-scope matching to these tool names. Unset = every tool. */
32
+ tools?: readonly string[];
33
+ }
34
+ interface StreamRulesConfig {
35
+ rules: readonly StreamRule[];
36
+ /** Rule-triggered retries allowed per agent run (one user turn). Default 3. */
37
+ maxRetries?: number;
38
+ /** Characters of prior output kept per stream for cross-delta matches. Default 1024. */
39
+ windowChars?: number;
40
+ }
41
+ type StreamRuleSource = "text" | "tool";
42
+ interface StreamRuleMatch {
43
+ rules: StreamRule[];
44
+ source: StreamRuleSource;
45
+ toolName?: string;
46
+ }
47
+ declare const DEFAULT_STREAM_RULE_MAX_RETRIES = 3;
48
+ declare const DEFAULT_STREAM_RULE_WINDOW_CHARS = 1024;
49
+ /** Incremental JSON string-escape decoder that tolerates escapes split across chunks. */
50
+ declare class JsonEscapeDecoder {
51
+ private pending;
52
+ push(chunk: string): string;
53
+ }
54
+ /**
55
+ * Per-run rule state. Create one per `agentLoop` run; call `beginAttempt()`
56
+ * before every provider attempt so windows never leak across attempts.
57
+ */
58
+ declare class StreamRuleMonitor {
59
+ readonly maxRetries: number;
60
+ private readonly rules;
61
+ private readonly windowChars;
62
+ private readonly fired;
63
+ private retries;
64
+ private textWindow;
65
+ private readonly toolStreams;
66
+ constructor(config: StreamRulesConfig);
67
+ /** False once the retry cap is spent or every rule has fired — skip all matching. */
68
+ get active(): boolean;
69
+ get retriesUsed(): number;
70
+ beginAttempt(): void;
71
+ checkText(delta: string): StreamRuleMatch | null;
72
+ checkToolArgs(id: string, toolName: string, argsDelta: string): StreamRuleMatch | null;
73
+ /** Consume one retry and mark the rules fired. Returns the retry ordinal (1-based). */
74
+ recordTrigger(rules: readonly StreamRule[]): number;
75
+ private match;
76
+ }
77
+ /** The hidden runtime note appended before the retry. */
78
+ declare function buildStreamRuleReminder(rules: readonly StreamRule[]): Message;
79
+
4
80
  interface StructuredToolResult {
5
81
  content: ToolResultContent;
6
82
  details?: unknown;
@@ -27,6 +103,12 @@ interface AgentTool<T extends z.ZodType = z.ZodType> extends Tool {
27
103
  * message — becomes unreachable.
28
104
  */
29
105
  timeoutMs?: number;
106
+ /**
107
+ * Whether a mid-run steering message may preempt this tool. Defaults to
108
+ * true, except for atomic file mutators (`edit`, `write`, …) which always
109
+ * run to completion so they are never left half-applied.
110
+ */
111
+ interruptible?: boolean;
30
112
  execute: (args: z.infer<T>, context: ToolContext) => ToolExecuteResult | Promise<ToolExecuteResult>;
31
113
  }
32
114
  interface AgentTextDeltaEvent {
@@ -146,7 +228,7 @@ interface AgentTruncatedEvent {
146
228
  }
147
229
  interface AgentRetryEvent {
148
230
  type: "retry";
149
- reason: "overloaded" | "rate_limit" | "provider_error" | "empty_response" | "stream_stall" | "overflow_compact" | "tool_argument_glitch" | "runaway_toolcall";
231
+ reason: "overloaded" | "rate_limit" | "provider_error" | "empty_response" | "stream_stall" | "overflow_compact" | "tool_argument_glitch" | "runaway_toolcall" | "stream_rule";
150
232
  attempt: number;
151
233
  maxAttempts: number;
152
234
  delayMs: number;
@@ -164,6 +246,29 @@ interface AgentRetryEvent {
164
246
  */
165
247
  preservedChars?: number;
166
248
  }
249
+ /**
250
+ * A stream rule matched mid-response. The attempt was aborted and discarded
251
+ * (no partial message persisted, no partial tool call executed), the rule's
252
+ * reminder was appended to the context, and the step is retried. Always
253
+ * followed by a silent `retry` (reason `stream_rule`) so UIs roll back the
254
+ * streamed partial exactly as for any other replayed attempt.
255
+ */
256
+ interface AgentStreamRuleTriggeredEvent {
257
+ type: "stream_rule_triggered";
258
+ /** Names of the rules that matched (usually one). */
259
+ rules: string[];
260
+ source: "text" | "tool";
261
+ /** Tool whose streamed arguments matched, for `source: "tool"`. */
262
+ toolName?: string;
263
+ attempt: number;
264
+ maxAttempts: number;
265
+ /**
266
+ * ESTIMATED usage of the aborted attempt (providers report none for an
267
+ * aborted stream): prompt chars/4 in, streamed chars/4 out. Already added to
268
+ * the run's `totalUsage`.
269
+ */
270
+ usage: Usage;
271
+ }
167
272
  interface AgentToolCallDeltaEvent {
168
273
  type: "toolcall_delta";
169
274
  chars: number;
@@ -192,7 +297,7 @@ interface AgentFollowUpMessageEvent {
192
297
  type: "follow_up_message";
193
298
  content: Message["content"];
194
299
  }
195
- type AgentEvent = AgentTextDeltaEvent | AgentThinkingDeltaEvent | AgentToolCallStartEvent | AgentToolCallUpdateEvent | AgentToolCallEndEvent | AgentToolCallDeltaEvent | AgentServerToolCallEvent | AgentServerToolResultEvent | AgentSteeringMessageEvent | AgentFollowUpMessageEvent | AgentRetryEvent | AgentTurnEndEvent | AgentCheckpointEvent | AgentDoneEvent | AgentMaxTurnsEvent | AgentTurnBudgetExtendedEvent | AgentTruncatedEvent | AgentErrorEvent;
300
+ type AgentEvent = AgentTextDeltaEvent | AgentThinkingDeltaEvent | AgentToolCallStartEvent | AgentToolCallUpdateEvent | AgentToolCallEndEvent | AgentToolCallDeltaEvent | AgentServerToolCallEvent | AgentServerToolResultEvent | AgentSteeringMessageEvent | AgentFollowUpMessageEvent | AgentRetryEvent | AgentStreamRuleTriggeredEvent | AgentTurnEndEvent | AgentCheckpointEvent | AgentDoneEvent | AgentMaxTurnsEvent | AgentTurnBudgetExtendedEvent | AgentTruncatedEvent | AgentErrorEvent;
196
301
  interface TransformContextOptions {
197
302
  /** Force a transform after the provider reports context overflow. */
198
303
  force?: boolean;
@@ -244,6 +349,7 @@ interface AgentOptions {
244
349
  transportSessionId?: StreamOptions["transportSessionId"];
245
350
  projectId?: StreamOptions["projectId"];
246
351
  cacheRetention?: StreamOptions["cacheRetention"];
352
+ onContextPrepared?: StreamOptions["onContextPrepared"];
247
353
  /** Stable per-session cache routing key for providers that support it. */
248
354
  promptCacheKey?: StreamOptions["promptCacheKey"];
249
355
  /** Override the User-Agent sent with OAuth-authenticated Anthropic requests. */
@@ -271,6 +377,14 @@ interface AgentOptions {
271
377
  * against parallel fan-outs injecting huge uncached context in one turn;
272
378
  * the largest results are trimmed (water-filling) with a re-run notice. */
273
379
  maxTurnToolResultChars?: number;
380
+ /** Optional post-processing of a SUCCESSFUL tool result (after redaction,
381
+ * before the tool_call_end event and the provider context). Return the
382
+ * content unchanged to leave it alone. A throw is ignored (original kept).
383
+ * Used e.g. to append a warning to untrusted-content results. */
384
+ transformToolResult?: (call: {
385
+ name: string;
386
+ args: Record<string, unknown>;
387
+ }, content: ToolResultContent) => ToolResultContent;
274
388
  /** Max consecutive pause_turn continuations before stopping (default: 5).
275
389
  * Prevents infinite loops when server-side tools keep pausing. */
276
390
  maxContinuations?: number;
@@ -292,6 +406,15 @@ interface AgentOptions {
292
406
  * on read.
293
407
  */
294
408
  getSteeringMessages?: () => Promise<Message[] | null> | Message[] | null;
409
+ /**
410
+ * Instant interrupt (codex `instant_interrupt`): subscribe to "a steering
411
+ * message just arrived". While tools are running, the listener preempts
412
+ * interruptible tools (their AbortSignal fires; unfinished calls get an
413
+ * "Interrupted" error result) and the loop drains steering and continues.
414
+ * Distinct from `signal` (the Stop button), which ends the run. Returns an
415
+ * unsubscribe function.
416
+ */
417
+ onSteeringAvailable?: (listener: () => void) => () => void;
295
418
  /**
296
419
  * Polled when the agent would otherwise stop (no tool calls, no steering).
297
420
  * Returns messages to inject and continue the loop. Lower priority than
@@ -312,6 +435,13 @@ interface AgentOptions {
312
435
  maxTurns: number;
313
436
  extension: number;
314
437
  }) => Promise<boolean> | boolean;
438
+ /**
439
+ * Regex rules matched against streamed assistant text and tool-call
440
+ * arguments. A match aborts the attempt, discards it, appends the rule's
441
+ * reminder and retries the step. Each rule fires at most once per run;
442
+ * `maxRetries` (default 3) caps rule retries per run. Unset = no matching.
443
+ */
444
+ streamRules?: StreamRulesConfig;
315
445
  }
316
446
  interface AgentResult {
317
447
  message: AssistantMessage;
@@ -349,6 +479,7 @@ declare class Agent {
349
479
  private options;
350
480
  private steeringQueue;
351
481
  private followUpQueue;
482
+ private steeringListeners;
352
483
  constructor(options: AgentOptions);
353
484
  /** Snapshot of the current message history. Used for session persistence. */
354
485
  getMessages(): Message[];
@@ -359,7 +490,11 @@ declare class Agent {
359
490
  */
360
491
  setSignal(signal: AbortSignal | undefined): void;
361
492
  get running(): boolean;
362
- /** Queue a steering message for injection after current tool execution completes. */
493
+ /**
494
+ * Queue a steering message. Instant interrupt: if tools are running, the
495
+ * interruptible ones are preempted right away and the message is injected
496
+ * before the next model call (the turn continues — unlike abort/Stop).
497
+ */
363
498
  steer(msg: Message): void;
364
499
  /** Queue a follow-up message for injection when the agent would otherwise stop. */
365
500
  followUp(msg: Message): void;
@@ -415,6 +550,7 @@ declare function cancelledBeforeStartText(name: string): string;
415
550
  * something never ran when it did.
416
551
  */
417
552
  declare function indeterminateOutcomeText(name: string): string;
553
+ declare function repairToolPairingAdjacent(messages: Message[]): void;
418
554
 
419
555
  /**
420
556
  * A local inference server (llama.cpp, vLLM, Ollama, LM Studio) can spend
@@ -425,4 +561,4 @@ declare function indeterminateOutcomeText(name: string): string;
425
561
  */
426
562
  declare function isLocalBackendUrl(baseUrl?: string): boolean;
427
563
 
428
- export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentFollowUpMessageEvent, type AgentOptions, type AgentResult, type AgentRetryEvent, type AgentServerToolCallEvent, type AgentServerToolResultEvent, type AgentSteeringMessageEvent, AgentStream, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallDeltaEvent, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type AgentTurnTiming, type StreamDiagnosticFn, type StructuredToolResult, type ToolContext, type ToolExecuteResult, type ToolExecutionMode, type TransformContextOptions, agentLoop, cancelledBeforeStartText, indeterminateOutcomeText, isAbortError, isBillingError, isContextOverflow, isLocalBackendUrl, isUsageLimitError, setStreamDiagnostic };
564
+ export { Agent, type AgentDoneEvent, type AgentErrorEvent, type AgentEvent, type AgentFollowUpMessageEvent, type AgentOptions, type AgentResult, type AgentRetryEvent, type AgentServerToolCallEvent, type AgentServerToolResultEvent, type AgentSteeringMessageEvent, AgentStream, type AgentStreamRuleTriggeredEvent, type AgentTextDeltaEvent, type AgentThinkingDeltaEvent, type AgentTool, type AgentToolCallDeltaEvent, type AgentToolCallEndEvent, type AgentToolCallStartEvent, type AgentToolCallUpdateEvent, type AgentTurnEndEvent, type AgentTurnTiming, DEFAULT_STREAM_RULE_MAX_RETRIES, DEFAULT_STREAM_RULE_WINDOW_CHARS, JsonEscapeDecoder, type StreamDiagnosticFn, type StreamRule, type StreamRuleMatch, StreamRuleMonitor, type StreamRuleScope, type StreamRuleSource, type StreamRulesConfig, type StructuredToolResult, type ToolContext, type ToolExecuteResult, type ToolExecutionMode, type TransformContextOptions, agentLoop, buildStreamRuleReminder, cancelledBeforeStartText, indeterminateOutcomeText, isAbortError, isBillingError, isContextOverflow, isLocalBackendUrl, isUsageLimitError, repairToolPairingAdjacent, setStreamDiagnostic };