@wrongstack/core 0.1.10 → 0.3.1

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 (54) hide show
  1. package/dist/{agent-bridge-6KPqsFx6.d.ts → agent-bridge-C3DUGjSb.d.ts} +1 -1
  2. package/dist/{compactor-B4mQZXf2.d.ts → compactor-BUU6Zm_3.d.ts} +1 -1
  3. package/dist/{config-BU9f_5yH.d.ts → config-CKLYPkCi.d.ts} +1 -1
  4. package/dist/{context-BmM2xGUZ.d.ts → context-IovtuTf8.d.ts} +10 -0
  5. package/dist/coordination/index.d.ts +211 -13
  6. package/dist/coordination/index.js +964 -67
  7. package/dist/coordination/index.js.map +1 -1
  8. package/dist/defaults/index.d.ts +33 -18
  9. package/dist/defaults/index.js +1273 -42
  10. package/dist/defaults/index.js.map +1 -1
  11. package/dist/{events-BMNaEFZl.d.ts → events-CNB9PALO.d.ts} +99 -1
  12. package/dist/execution/index.d.ts +12 -12
  13. package/dist/extension/index.d.ts +9 -0
  14. package/dist/extension/index.js +234 -0
  15. package/dist/extension/index.js.map +1 -0
  16. package/dist/index-BDb0cAMP.d.ts +806 -0
  17. package/dist/index.d.ts +112 -29
  18. package/dist/index.js +2036 -490
  19. package/dist/index.js.map +1 -1
  20. package/dist/infrastructure/index.d.ts +6 -6
  21. package/dist/kernel/index.d.ts +12 -9
  22. package/dist/kernel/index.js +73 -7
  23. package/dist/kernel/index.js.map +1 -1
  24. package/dist/{mcp-servers-Dzgg4x1w.d.ts → mcp-servers-DR35ojJZ.d.ts} +3 -3
  25. package/dist/models/index.d.ts +2 -2
  26. package/dist/models/index.js +24 -1
  27. package/dist/models/index.js.map +1 -1
  28. package/dist/{multi-agent-fmkRHtof.d.ts → multi-agent-B9a6sflH.d.ts} +71 -3
  29. package/dist/observability/index.d.ts +2 -2
  30. package/dist/{path-resolver-DBjaoXFq.d.ts → path-resolver-Cl_q0u-R.d.ts} +2 -2
  31. package/dist/provider-runner-BXuADQqQ.d.ts +36 -0
  32. package/dist/sdd/index.d.ts +3 -3
  33. package/dist/{secret-scrubber-CicHLN4G.d.ts → secret-scrubber-CgG2tV2B.d.ts} +1 -1
  34. package/dist/{secret-scrubber-DF88luOe.d.ts → secret-scrubber-Cuy5afaQ.d.ts} +1 -1
  35. package/dist/security/index.d.ts +20 -4
  36. package/dist/security/index.js +37 -2
  37. package/dist/security/index.js.map +1 -1
  38. package/dist/{selector-BbJqiEP4.d.ts → selector-wT2fv9Fg.d.ts} +1 -1
  39. package/dist/{session-reader-Drq8RvJu.d.ts → session-reader-CcPi4BQ8.d.ts} +1 -1
  40. package/dist/{skill-DhfSizKv.d.ts → skill-C_7znCIC.d.ts} +2 -2
  41. package/dist/storage/index.d.ts +164 -6
  42. package/dist/storage/index.js +297 -2
  43. package/dist/storage/index.js.map +1 -1
  44. package/dist/{renderer-rk_1Swwc.d.ts → system-prompt-Dk1qm8ey.d.ts} +30 -2
  45. package/dist/{tool-executor-CpuJPYm9.d.ts → tool-executor-DKu4A6nB.d.ts} +5 -5
  46. package/dist/types/index.d.ts +16 -16
  47. package/dist/types/index.js +24 -1
  48. package/dist/types/index.js.map +1 -1
  49. package/dist/utils/index.d.ts +1 -1
  50. package/dist/utils/index.js +24 -1
  51. package/dist/utils/index.js.map +1 -1
  52. package/package.json +5 -1
  53. package/dist/plugin-DJk6LL8B.d.ts +0 -434
  54. package/dist/system-prompt-BC_8ypCG.d.ts +0 -23
@@ -0,0 +1,806 @@
1
+ import { u as Tool, z as ToolResultBlock, T as TextBlock, a0 as Context, R as Request, j as Response, D as ToolUseBlock, g as Provider, W as WrongStackError, b as ContentBlock, a7 as RunOptions, J as JSONSchema } from './context-IovtuTf8.js';
2
+ import { L as Logger } from './logger-BMQgxvdy.js';
3
+ import { R as Renderer, B as BuildContext, C as Container, P as Pipeline, e as ReadonlyPipeline } from './system-prompt-Dk1qm8ey.js';
4
+ import { T as Tracer } from './observability-BhnVLBLS.js';
5
+ import { E as EventBus, a as EventName, L as Listener } from './events-CNB9PALO.js';
6
+ import { a as PermissionPolicy, S as SecretScrubber } from './secret-scrubber-CgG2tV2B.js';
7
+ import { e as ProviderConfig, C as Config } from './config-CKLYPkCi.js';
8
+ import { W as WireFamily } from './models-registry-Y2xbog0E.js';
9
+
10
+ /**
11
+ * A function that wraps (decorates) an existing tool. Receives the
12
+ * original tool and returns a modified version — typically the same
13
+ * tool with a wrapped `execute` / `executeStream`, or with modified
14
+ * metadata (description, permission).
15
+ *
16
+ * Use `ToolRegistry.wrap()` to apply; the wrapper is called immediately
17
+ * and the result replaces the registered tool. Multiple wraps stack —
18
+ * each wrapper receives the output of the previous.
19
+ *
20
+ * @example
21
+ * ```ts
22
+ * registry.wrap('read', (original) => ({
23
+ * ...original,
24
+ * async execute(input, ctx, opts) {
25
+ * console.log('read called');
26
+ * return original.execute(input, ctx, opts);
27
+ * }
28
+ * }));
29
+ * ```
30
+ */
31
+ type ToolWrapper = (tool: Tool) => Tool;
32
+ declare class ToolRegistry {
33
+ private readonly tools;
34
+ register(tool: Tool, owner?: string): void;
35
+ /**
36
+ * Attempt to register a tool. Returns true if successful, false if a tool
37
+ * with the same name is already registered. Useful in multi-agent or plugin
38
+ * scenarios where duplicate registration may be intentional.
39
+ */
40
+ tryRegister(tool: Tool, owner?: string): boolean;
41
+ /**
42
+ * Bulk-register multiple tools at once. Each tool that conflicts with an
43
+ * existing registration is silently skipped — use `registerAllOrThrow`
44
+ * if you want it to throw on conflicts.
45
+ */
46
+ registerAll(tools: Tool[], owner?: string): void;
47
+ /**
48
+ * Bulk-register and throw on the first conflict. Use when you need
49
+ * strict registration (e.g. at boot time).
50
+ */
51
+ registerAllOrThrow(tools: Tool[], owner?: string): void;
52
+ /**
53
+ * Register a tool as a default. If the tool name is already registered,
54
+ * this is a no-op — the existing registration (from core or another
55
+ * plugin) takes precedence. Use `override` to intentionally replace.
56
+ */
57
+ registerDefault(tool: Tool, owner?: string): void;
58
+ unregister(name: string): boolean;
59
+ /**
60
+ * Override an existing tool. Throws if the tool is not already registered.
61
+ * Plugins use this to replace built-in tools with custom implementations.
62
+ */
63
+ override(name: string, tool: Tool, owner?: string): void;
64
+ /**
65
+ * Wrap (decorate) an existing tool. The wrapper receives the current
66
+ * tool and must return a new tool — typically the same tool with a
67
+ * wrapped `execute` or `executeStream`. Throws if the tool is not
68
+ * registered.
69
+ *
70
+ * Multiple wraps stack: each wrapper gets the output of the previous.
71
+ *
72
+ * @example
73
+ * registry.wrap('bash', (t) => ({ ...t, permission: 'confirm' }));
74
+ */
75
+ wrap(name: string, wrapper: ToolWrapper, owner?: string): void;
76
+ get(name: string): Tool | undefined;
77
+ ownerOf(name: string): string | undefined;
78
+ list(): Tool[];
79
+ /**
80
+ * Group tools by their `category` field. Tools without a category
81
+ * are placed under the key `""` (empty string). Returns a Map of
82
+ * category → tools, sorted by registration order within each category.
83
+ */
84
+ listByCategory(): Map<string, Tool[]>;
85
+ listWithOwner(): {
86
+ tool: Tool;
87
+ owner: string;
88
+ }[];
89
+ clear(): void;
90
+ }
91
+
92
+ /**
93
+ * Output from a single tool execution.
94
+ */
95
+ interface ToolExecutionOutput {
96
+ result: ToolResultBlock | ToolConfirmPendingResult;
97
+ tool?: Tool;
98
+ durationMs: number;
99
+ }
100
+ /**
101
+ * Result of running a batch of tools for a single agent iteration.
102
+ */
103
+ interface ToolBatchResult {
104
+ outputs: ToolExecutionOutput[];
105
+ remainingBudget: number;
106
+ }
107
+ type ConfirmAwaiter = (tool: Tool, input: unknown, toolUseId: string, suggestedPattern: string) => Promise<'yes' | 'no' | 'always' | 'deny'>;
108
+ interface ToolExecutorOptions {
109
+ permissionPolicy: PermissionPolicy;
110
+ secretScrubber: SecretScrubber;
111
+ renderer?: Renderer | undefined;
112
+ /**
113
+ * Optional event bus. When provided, the executor emits `tool.started`
114
+ * before invoking each tool's `execute()`. Closes the observability gap
115
+ * between "model decided to call tool" and "tool finished".
116
+ */
117
+ events?: EventBus | undefined;
118
+ /**
119
+ * Optional tracer. When provided, every tool execution opens a
120
+ * `tool.<name>` span with attributes for tool name, permission decision,
121
+ * input size, output size, and outcome. Spans are no-op by default.
122
+ */
123
+ tracer?: Tracer | undefined;
124
+ /**
125
+ * Async callback invoked when a tool needs user confirmation.
126
+ * When omitted and confirmation is required, the executor returns a
127
+ * failure result immediately (TUI path). When provided (CLI path),
128
+ * the callback handles the interactive prompt and returns a decision.
129
+ */
130
+ confirmAwaiter?: ConfirmAwaiter | undefined;
131
+ iterationTimeoutMs?: number;
132
+ perIterationOutputCapBytes?: number;
133
+ }
134
+ /**
135
+ * Result returned by executeBatch when a tool needs confirmation and
136
+ * no confirmAwaiter is available. The TUI catches this and surfaces a
137
+ * confirmation dialog; once resolved the tool is re-executed.
138
+ * The string tag identifies it as a "pending confirm" result so callers
139
+ * can distinguish it from an error without inspecting content strings.
140
+ */
141
+ interface ToolConfirmPendingResult {
142
+ type: 'tool_confirm_pending';
143
+ toolUseId: string;
144
+ toolName: string;
145
+ input: unknown;
146
+ suggestedPattern: string;
147
+ }
148
+ type ToolExecutorStrategy = 'parallel' | 'sequential' | 'smart';
149
+
150
+ /**
151
+ * A contributor that injects additional TextBlocks into the system prompt.
152
+ *
153
+ * Contributors are called on every `build()` in registration order.
154
+ * Their output is inserted after the core blocks (identity, tool usage,
155
+ * environment) but before the mode and plan blocks. This lets plugins
156
+ * inject ephemeral context — current state, recent events, plugin-specific
157
+ * instructions — without replacing the entire system prompt builder.
158
+ *
159
+ * @example
160
+ * ```ts
161
+ * api.extensions.registerSystemPromptContributor(async (ctx) => {
162
+ * return [{ type: 'text', text: '## My Plugin Context\n...' }];
163
+ * });
164
+ * ```
165
+ */
166
+ interface SystemPromptContributor {
167
+ (ctx: BuildContext): Promise<TextBlock[]>;
168
+ }
169
+
170
+ /**
171
+ * Extension points for the Agent lifecycle.
172
+ *
173
+ * Each extension point is a hook that gets called at a specific phase.
174
+ * Extensions are always optional and failures are isolated — a failing
175
+ * extension never aborts the agent run.
176
+ *
177
+ * Plugins register extensions via `PluginAPI.extensions`, not by
178
+ * directly importing this module. The Agent calls the registry in
179
+ * order at each phase.
180
+ */
181
+
182
+ /**
183
+ * Called before Agent.run() begins the main iteration loop.
184
+ * Returns `false` or throws to prevent the run from starting.
185
+ */
186
+ type BeforeRunHook = (ctx: Context, input: UserInputPayload) => void | Promise<void>;
187
+ /**
188
+ * Called after Agent.run() completes (or fails/aborts).
189
+ * Receives the final RunResult, always called regardless of outcome.
190
+ */
191
+ type AfterRunHook = (ctx: Context, result: RunResult) => void | Promise<void>;
192
+ /**
193
+ * Called right before each iteration of the agent loop.
194
+ * The context is live (messages, signal, etc.) and can be inspected.
195
+ * Modifications to ctx (e.g. ctx.messages, ctx.model) take effect
196
+ * for the upcoming iteration.
197
+ */
198
+ type BeforeIterationHook = (ctx: Context, iterationIndex: number) => void | Promise<void>;
199
+ /**
200
+ * Called after each iteration completes (tool results appended,
201
+ * compaction done, but before the next loop iteration check).
202
+ */
203
+ type AfterIterationHook = (ctx: Context, iterationIndex: number) => void | Promise<void>;
204
+ /**
205
+ * Called when the agent encounters an error during the provider call
206
+ * or tool execution phase. The hook can return a modified context
207
+ * or signal that recovery should be attempted.
208
+ *
209
+ * Return `{ action: 'retry', model?: string }` to retry the turn
210
+ * (possibly with a different model).
211
+ * Return `{ action: 'fail' }` to propagate the error.
212
+ * Return `{ action: 'continue' }` to skip and continue the loop.
213
+ */
214
+ type OnErrorHook = (ctx: Context, err: unknown, phase: 'provider' | 'tool' | 'agent', iterationIndex: number) => {
215
+ action: 'retry';
216
+ model?: string;
217
+ } | {
218
+ action: 'fail';
219
+ } | {
220
+ action: 'continue';
221
+ } | void | Promise<{
222
+ action: 'retry';
223
+ model?: string;
224
+ } | {
225
+ action: 'fail';
226
+ } | {
227
+ action: 'continue';
228
+ } | void>;
229
+ /**
230
+ * The default provider runner function signature — what the Agent's
231
+ * built-in provider runner looks like. Extensions that wrap the provider
232
+ * runner receive this as the `inner` parameter they can delegate to.
233
+ */
234
+ type ProviderRunnerFn = (ctx: Context, request: Request) => Promise<Response>;
235
+ /**
236
+ * Wrap or replace the provider call in the agent loop.
237
+ *
238
+ * The `inner` function is the default provider runner (with retries).
239
+ * The extension can call it, modify the request/response, add caching,
240
+ * or bypass it entirely.
241
+ */
242
+ type ProviderRunnerWrapper = (ctx: Context, request: Request, inner: ProviderRunnerFn) => Promise<Response>;
243
+ /**
244
+ * Called before a batch of tools is executed. Can modify or reject
245
+ * the tool list. Return the (possibly filtered/modified) tool uses.
246
+ */
247
+ type BeforeToolExecutionHook = (ctx: Context, toolUses: ToolUseBlock[]) => ToolUseBlock[] | Promise<ToolUseBlock[]>;
248
+ /**
249
+ * Called after a batch of tools has been executed and results
250
+ * are available. The extension can inspect or transform results
251
+ * before they're appended to context.
252
+ */
253
+ type AfterToolExecutionHook = (ctx: Context, outputs: ToolExecutionOutput[]) => void | Promise<void>;
254
+ /**
255
+ * An extension registered by a plugin or the host application.
256
+ *
257
+ * Every hook is optional — implement only the phases you need.
258
+ * Hooks are called in registration order. A hook failure is
259
+ * caught, logged, and does not prevent subsequent hooks from running.
260
+ *
261
+ * @example
262
+ * ```ts
263
+ * const myExt: AgentExtension = {
264
+ * name: 'my-plugin-ext',
265
+ * beforeIteration: async (ctx, idx) => {
266
+ * console.log('Starting iteration', idx);
267
+ * },
268
+ * };
269
+ * api.extensions.register(myExt);
270
+ * ```
271
+ */
272
+ interface AgentExtension {
273
+ /** Unique name for this extension. Used in diagnostics and logging. */
274
+ name: string;
275
+ /** Optional owner tag (plugin name or host identifier). */
276
+ owner?: string;
277
+ beforeRun?: BeforeRunHook;
278
+ afterRun?: AfterRunHook;
279
+ beforeIteration?: BeforeIterationHook;
280
+ afterIteration?: AfterIterationHook;
281
+ onError?: OnErrorHook;
282
+ wrapProviderRunner?: ProviderRunnerWrapper;
283
+ beforeToolExecution?: BeforeToolExecutionHook;
284
+ afterToolExecution?: AfterToolExecutionHook;
285
+ }
286
+
287
+ /**
288
+ * ExtensionRegistry — manages AgentExtension registrations.
289
+ *
290
+ * Extensions are called in registration order at each lifecycle phase.
291
+ * Each extension hook failure is caught and logged independently so
292
+ * one bad extension can't take down the agent.
293
+ */
294
+
295
+ declare class ExtensionRegistry {
296
+ private readonly extensions;
297
+ private readonly promptContributors;
298
+ private log;
299
+ setLogger(log: Logger): void;
300
+ /**
301
+ * Register a system prompt contributor. Returns an unregister function.
302
+ * Contributors are called on every system prompt build in registration
303
+ * order. Their output blocks are inserted after the core environment
304
+ * block, before the mode and plan blocks.
305
+ */
306
+ registerSystemPromptContributor(c: SystemPromptContributor): () => void;
307
+ /**
308
+ * Build all registered system prompt contributions.
309
+ * Failures are caught and logged — one bad contributor doesn't
310
+ * break the prompt assembly.
311
+ */
312
+ buildSystemPromptContributions(ctx: Parameters<SystemPromptContributor>[0]): Promise<TextBlock[]>;
313
+ /**
314
+ * Returns the live array of contributors (readonly snapshot for
315
+ * passing to DefaultSystemPromptBuilder at build time).
316
+ */
317
+ listSystemPromptContributors(): readonly SystemPromptContributor[];
318
+ /**
319
+ * Register an extension. Duplicate names are rejected.
320
+ * Returns an unregister function.
321
+ */
322
+ register(ext: AgentExtension): () => void;
323
+ /**
324
+ * Register an extension, silently replacing any previous registration
325
+ * with the same name. Use this when overriding a default extension.
326
+ */
327
+ registerOrReplace(ext: AgentExtension): () => void;
328
+ /**
329
+ * Unregister an extension by name. Returns true if found.
330
+ */
331
+ unregister(name: string): boolean;
332
+ /**
333
+ * List registered extension names in order.
334
+ */
335
+ list(): readonly string[];
336
+ /**
337
+ * Check if an extension with the given name is registered.
338
+ */
339
+ has(name: string): boolean;
340
+ /**
341
+ * Remove all registered extensions and contributors.
342
+ */
343
+ clear(): void;
344
+ runBeforeRun(...args: Parameters<BeforeRunHook>): Promise<void>;
345
+ runAfterRun(...args: Parameters<AfterRunHook>): Promise<void>;
346
+ runBeforeIteration(...args: Parameters<BeforeIterationHook>): Promise<void>;
347
+ runAfterIteration(...args: Parameters<AfterIterationHook>): Promise<void>;
348
+ /**
349
+ * Run onError hooks in order. The first hook that returns a non-void
350
+ * result wins; subsequent hooks are skipped.
351
+ */
352
+ runOnError(...args: Parameters<OnErrorHook>): Promise<{
353
+ action: 'retry';
354
+ model?: string;
355
+ } | {
356
+ action: 'fail';
357
+ } | {
358
+ action: 'continue';
359
+ } | void>;
360
+ /**
361
+ * Build a composed provider runner. Extensions with `wrapProviderRunner`
362
+ * form a middleware-style chain: the innermost extension wraps the
363
+ * default runner, each subsequent wrapper wraps the previous.
364
+ */
365
+ wrapProviderRunner(inner: ProviderRunnerFn): ProviderRunnerFn;
366
+ runBeforeToolExecution(...args: Parameters<BeforeToolExecutionHook>): Promise<Parameters<BeforeToolExecutionHook>[1]>;
367
+ runAfterToolExecution(...args: Parameters<AfterToolExecutionHook>): Promise<void>;
368
+ }
369
+
370
+ /**
371
+ * Factory for constructing a Provider instance. The `family` field
372
+ * declares the wire protocol so callers can route without inspecting
373
+ * the returned instance. The `type` is the registry key (e.g. a
374
+ * provider's models.dev id or a user-chosen alias).
375
+ */
376
+ interface ProviderFactory$1 {
377
+ /**
378
+ * Unique identifier used as the registry key. When registered via
379
+ * a plugin, this becomes `cfg.type` in `ProviderRegistry.create(cfg)`.
380
+ */
381
+ type: string;
382
+ /**
383
+ * Declares the wire protocol family so consumers can route based on
384
+ * capability (e.g. which tool-format converter to use) without
385
+ * instantiating the provider.
386
+ */
387
+ family: WireFamily;
388
+ create(cfg: ProviderConfig): Provider;
389
+ }
390
+ declare class ProviderRegistry {
391
+ private readonly factories;
392
+ /**
393
+ * Register a provider factory. If a factory with the same type already
394
+ * exists, it is replaced. Use this for both initial registration and
395
+ * runtime overrides (e.g. from plugins or CLI flags).
396
+ */
397
+ register(f: ProviderFactory$1): void;
398
+ /**
399
+ * Bulk-register multiple provider factories at once.
400
+ */
401
+ registerAll(factories: ProviderFactory$1[]): void;
402
+ /**
403
+ * Override an existing factory. Throws if no factory is registered
404
+ * for the given type. Use this to safely replace a provider at runtime
405
+ * (e.g. in tests or when a plugin provides a custom implementation).
406
+ */
407
+ override(type: string, f: ProviderFactory$1): void;
408
+ has(type: string): boolean;
409
+ create(cfg: ProviderConfig): Provider;
410
+ list(): string[];
411
+ }
412
+
413
+ /** Default iteration cap. Use 0 or Infinity via config to disable. */
414
+ declare const DEFAULT_MAX_ITERATIONS = 100;
415
+ interface RunResult {
416
+ status: 'done' | 'failed' | 'max_iterations' | 'aborted';
417
+ /**
418
+ * Set when `status === 'failed'` (always) or `'aborted'` (when the abort
419
+ * carried an error context). Always a `WrongStackError` so callers can
420
+ * branch on `code`, `severity`, and `recoverable` without parsing strings.
421
+ * Raw throws are wrapped into an `AgentError` with code `AGENT_RUN_FAILED`
422
+ * by `Agent.run` before they reach this field.
423
+ */
424
+ error?: WrongStackError;
425
+ finalText?: string;
426
+ iterations: number;
427
+ }
428
+ interface AgentInit {
429
+ container: Container;
430
+ tools: ToolRegistry;
431
+ providers: ProviderRegistry;
432
+ events: EventBus;
433
+ pipelines: AgentPipelines;
434
+ context: Context;
435
+ maxIterations?: number;
436
+ iterationTimeoutMs?: number;
437
+ executionStrategy?: 'parallel' | 'sequential' | 'smart';
438
+ perIterationOutputCapBytes?: number;
439
+ /**
440
+ * When true (default), the agent automatically extends its iteration
441
+ * limit by 100 when hit, without asking the user. Set to false to
442
+ * emit `iteration.limit_reached` and wait for a listener to grant/deny.
443
+ */
444
+ autoExtendLimit?: boolean;
445
+ /**
446
+ * Optional confirm handler. When set, the executor calls it synchronously
447
+ * when a tool needs user confirmation (CLI path). When omitted, the
448
+ * executor returns a `ToolConfirmPendingResult` and the agent emits
449
+ * `tool.confirm_needed` for the TUI to resolve.
450
+ */
451
+ confirmAwaiter?: ConfirmAwaiter | undefined;
452
+ /**
453
+ * Override the PermissionPolicy resolved from the container. Subagents
454
+ * use this to force auto-approval — they cannot respond to interactive
455
+ * permission prompts, so inheriting the leader's non-YOLO policy would
456
+ * silently hang the entire delegated run on the first tool call.
457
+ */
458
+ permissionPolicy?: PermissionPolicy;
459
+ /**
460
+ * Optional tracer. When provided, `Agent.run` opens an `agent.run` span,
461
+ * per-iteration `agent.iteration` spans, and `provider.complete` spans
462
+ * inside the retry loop. Tool spans are opened by the ToolExecutor.
463
+ * Default is `NoopTracer` (zero overhead).
464
+ */
465
+ tracer?: Tracer | undefined;
466
+ /**
467
+ * Optional extension registry. Plugins and host applications register
468
+ * extensions here to hook into the agent lifecycle (beforeRun, afterRun,
469
+ * beforeIteration, onError, wrapProviderRunner, etc.).
470
+ * When not provided, the agent creates an empty registry internally —
471
+ * no overhead, zero breakage.
472
+ */
473
+ extensions?: ExtensionRegistry | undefined;
474
+ }
475
+ interface AgentPipelines {
476
+ request: Pipeline<Request>;
477
+ response: Pipeline<Response>;
478
+ toolCall: Pipeline<ToolCallPipelinePayload>;
479
+ userInput: Pipeline<UserInputPayload>;
480
+ assistantOutput: Pipeline<TextBlock>;
481
+ contextWindow: Pipeline<Context>;
482
+ }
483
+ interface UserInputPayload {
484
+ content: ContentBlock[];
485
+ /** Concatenation of text blocks — convenience for middleware that only cares about text. */
486
+ text: string;
487
+ ctx: Context;
488
+ }
489
+ type AgentInput = string | ContentBlock[];
490
+ interface ToolCallPipelinePayload {
491
+ toolUse: ToolUseBlock;
492
+ result: ToolResultBlock;
493
+ ctx: Context;
494
+ /** Undefined when the model invoked a tool name we don't know. */
495
+ tool?: Tool;
496
+ }
497
+ declare function createDefaultPipelines(): AgentPipelines;
498
+ declare class Agent {
499
+ readonly container: Container;
500
+ readonly tools: ToolRegistry;
501
+ readonly providers: ProviderRegistry;
502
+ readonly events: EventBus;
503
+ readonly pipelines: AgentPipelines;
504
+ readonly ctx: Context;
505
+ private readonly maxIterations;
506
+ private readonly iterationTimeoutMs;
507
+ private readonly executionStrategy;
508
+ private readonly perIterationOutputCapBytes;
509
+ private readonly plugins;
510
+ private readonly toolExecutor;
511
+ private readonly autoExtendLimit;
512
+ private readonly tracer;
513
+ readonly extensions: ExtensionRegistry;
514
+ constructor(init: AgentInit);
515
+ private get logger();
516
+ private get retry();
517
+ private get errorHandler();
518
+ private get permission();
519
+ private get scrubber();
520
+ private get renderer();
521
+ register(tool: Tool): void;
522
+ use(plugin: Plugin, api: PluginAPI): Promise<void>;
523
+ run(userInput: AgentInput, opts?: RunOptions): Promise<RunResult>;
524
+ private runInner;
525
+ /**
526
+ * Check if iteration limit has been reached and request extension if needed.
527
+ * Returns the new effective limit (possibly extended) and a RunResult if
528
+ * the loop should exit. Returns `{ limit }` with no result when the
529
+ * iteration may proceed.
530
+ */
531
+ private checkIterationLimit;
532
+ /**
533
+ * Build request and run through request pipeline.
534
+ */
535
+ private buildAndRunRequestPipeline;
536
+ /**
537
+ * Process the provider response: run response pipeline, emit events,
538
+ * update session, render text, handle abort.
539
+ */
540
+ private processResponse;
541
+ /**
542
+ * Execute tools and append tool results to context.
543
+ * When a tool returns `tool_confirm_pending` (no confirmAwaiter set),
544
+ * we pause and emit `tool.confirm_needed`. The run is blocked until
545
+ * the event listener resolves the confirmation, then we re-run the
546
+ * single tool.
547
+ */
548
+ private executeTools;
549
+ private waitForConfirm;
550
+ private executeSingleWithDecision;
551
+ /**
552
+ * Run context window pipeline. The pipeline may be empty, or it may contain
553
+ * middleware with its own injected dependencies.
554
+ */
555
+ private compactContextIfNeeded;
556
+ }
557
+
558
+ /**
559
+ * A slash command registered with the CLI or available to plugins.
560
+ * Plugins receive a view of the registry via PluginAPI.slashCommands.
561
+ *
562
+ * Commands registered by plugins use a namespaced name: `pluginName:commandName`.
563
+ * This prevents collisions with built-in commands and other plugins.
564
+ */
565
+ interface SlashCommand {
566
+ /** Unique command name. For plugins: `pluginName:commandName`. */
567
+ name: string;
568
+ /** Short aliases — also prefixed automatically: `pluginName:alias`. */
569
+ aliases?: string[];
570
+ description: string;
571
+ /**
572
+ * Optional detailed help shown by `/help <name>`. Use this for usage,
573
+ * arguments, examples, side-effects — anything that doesn't fit in
574
+ * `description`. Renders verbatim, so format with line breaks.
575
+ * If absent, `/help <name>` falls back to `description`.
576
+ */
577
+ help?: string;
578
+ /**
579
+ * Execute the command.
580
+ * @param args Everything after the command name (trimmed by dispatch).
581
+ * @param ctx The current agent context.
582
+ * @returns `{ exit: true }` to quit the REPL. `{ message }` to print and
583
+ * continue. `{ runText }` to send a follow-up user-role message to the
584
+ * model immediately (e.g. `/steer <text>` builds a STEERING preamble
585
+ * here and asks the TUI to run it as the next turn). The TUI prints
586
+ * `message` first (if any) so the user sees the slash result before
587
+ * the model's response starts streaming.
588
+ */
589
+ run(args: string, ctx: Context): Promise<{
590
+ exit?: boolean;
591
+ message?: string;
592
+ runText?: string;
593
+ } | void>;
594
+ }
595
+
596
+ interface ToolRegistryView {
597
+ register(t: Tool): void;
598
+ unregister(name: string): void;
599
+ /** Wrap (decorate) an existing tool. The wrapper gets the current tool and returns the decorated version. */
600
+ wrap(name: string, wrapper: ToolWrapper): void;
601
+ get(name: string): Tool | undefined;
602
+ list(): Tool[];
603
+ }
604
+ interface ProviderFactory {
605
+ type: string;
606
+ family: WireFamily;
607
+ create(cfg: unknown): Provider;
608
+ }
609
+ interface ProviderRegistryView {
610
+ register(f: ProviderFactory): void;
611
+ create(cfg: {
612
+ type: string;
613
+ } & Record<string, unknown>): Provider;
614
+ list(): string[];
615
+ }
616
+ interface MCPRegistryView {
617
+ start(cfg: unknown): Promise<void>;
618
+ stop(name: string): Promise<void>;
619
+ restart(name: string): Promise<void>;
620
+ list(): {
621
+ name: string;
622
+ state: string;
623
+ toolCount: number;
624
+ }[];
625
+ }
626
+ interface SlashCommandRegistryView {
627
+ register(cmd: SlashCommand): void;
628
+ unregister(name: string): boolean;
629
+ get(name: string): SlashCommand | undefined;
630
+ list(): SlashCommand[];
631
+ }
632
+ /**
633
+ * Read-only view of the session writer. Plugins can append custom events
634
+ * to the JSONL session log and read the transcript path.
635
+ *
636
+ * The `append` method accepts any JSON-serializable payload — custom
637
+ * event types are persisted verbatim next to the built-in events.
638
+ */
639
+ interface SessionWriterView {
640
+ readonly transcriptPath?: string;
641
+ append(event: Record<string, unknown> & {
642
+ type: string;
643
+ ts: string;
644
+ }): Promise<void>;
645
+ }
646
+ /**
647
+ * Metrics sink scoped to a plugin. The host auto-prefixes metric names
648
+ * with `plugin.<pluginName>.` so plugins don't need to namespace
649
+ * manually. Plugins call counter/histogram/gauge directly; the values
650
+ * flow to the host's MetricsSink (Prometheus, OTLP, or noop).
651
+ */
652
+ interface MetricsSinkView {
653
+ counter(name: string, value?: number, labels?: Record<string, string>): void;
654
+ histogram(name: string, value: number, labels?: Record<string, string>): void;
655
+ gauge(name: string, value: number, labels?: Record<string, string>): void;
656
+ }
657
+ interface PluginPipelines {
658
+ request: ReadonlyPipeline<Request>;
659
+ response: ReadonlyPipeline<Response>;
660
+ toolCall: ReadonlyPipeline<ToolCallPipelinePayload>;
661
+ userInput: ReadonlyPipeline<{
662
+ content: ContentBlock[];
663
+ text: string;
664
+ ctx: Context;
665
+ }>;
666
+ assistantOutput: ReadonlyPipeline<TextBlock>;
667
+ contextWindow: ReadonlyPipeline<Context>;
668
+ [k: string]: ReadonlyPipeline<any>;
669
+ }
670
+ interface PluginAPI {
671
+ container: Container;
672
+ pipelines: PluginPipelines;
673
+ events: EventBus;
674
+ tools: ToolRegistryView;
675
+ providers: ProviderRegistryView;
676
+ mcp: MCPRegistryView;
677
+ slashCommands: SlashCommandRegistryView;
678
+ /** Live session writer — plugins can append custom events here. */
679
+ session: SessionWriterView;
680
+ /** Scoped metrics sink — counters/histograms/gauges auto-namespaced under `plugin.<name>.` */
681
+ metrics: MetricsSinkView;
682
+ /** Registry for agent lifecycle extensions — hooks like beforeRun, beforeIteration, onError, etc. */
683
+ extensions: ExtensionRegistry;
684
+ /**
685
+ * Register a system prompt contributor. Plugins call this to inject
686
+ * ephemeral TextBlocks into the system prompt on every build.
687
+ * Returns an unregister function.
688
+ */
689
+ registerSystemPromptContributor(c: SystemPromptContributor): () => void;
690
+ config: Config;
691
+ log: Logger;
692
+ /**
693
+ * Register a one-time event listener. The handler is automatically removed
694
+ * after the first emission, or when the plugin is uninstalled — whichever
695
+ * comes first.
696
+ */
697
+ onEvent<K extends EventName>(event: K, handler: Listener<K>): () => void;
698
+ /**
699
+ * Subscribe to all events matching a glob-style pattern.
700
+ * `'tool.*'` matches all tool events. `'*'` matches everything.
701
+ * Returns an unsubscribe function.
702
+ */
703
+ onPattern(pattern: string, handler: (event: string, payload: unknown) => void): () => void;
704
+ /**
705
+ * Emit a custom event on the agent's EventBus. Use for inter-plugin
706
+ * communication or to surface plugin-specific state to the host.
707
+ *
708
+ * Custom events use a `pluginName:eventName` convention to avoid
709
+ * collisions with built-in events (e.g. `my-plugin:cache_hit`).
710
+ * The payload is passed through to all subscribers.
711
+ */
712
+ emitCustom(event: string, payload: unknown): void;
713
+ /**
714
+ * Register a callback that fires when the configuration changes at
715
+ * runtime (e.g. via `/config` slash command or programmatic update).
716
+ * The handler receives the new and previous config snapshots.
717
+ * Returns an unsubscribe function.
718
+ */
719
+ onConfigChange(handler: (next: Readonly<Config>, prev: Readonly<Config>) => void): () => void;
720
+ }
721
+ /**
722
+ * Capability declaration — informs the host which subsystems a plugin
723
+ * intends to touch. Used for diagnostics and per-plugin enable/disable UX
724
+ * (e.g. "this plugin registers tools — disable to remove them"). Not
725
+ * enforced at runtime: a plugin that declares `tools: false` can still
726
+ * call `api.tools.register()`, but the host can flag the discrepancy.
727
+ */
728
+ interface PluginCapabilities {
729
+ /** Will register tools via `api.tools.register()`. */
730
+ tools?: boolean;
731
+ /** Will register provider factories via `api.providers.register()`. */
732
+ providers?: boolean;
733
+ /**
734
+ * Pipelines the plugin hooks into. Use the standard names
735
+ * (`request | response | toolCall | userInput | assistantOutput | contextWindow`)
736
+ * or custom pipeline names exposed by other plugins.
737
+ */
738
+ pipelines?: string[];
739
+ /** Will register slash commands via `api.slashCommands.register()`. */
740
+ slashCommands?: boolean;
741
+ /** Will start MCP servers via `api.mcp.start()`. */
742
+ mcp?: boolean;
743
+ }
744
+ /**
745
+ * Structured dependency declaration. The string form (`dependsOn: ['foo']`)
746
+ * is shorthand for `[{ name: 'foo' }]` — both work. Use the structured form
747
+ * when you need a version constraint:
748
+ *
749
+ * dependsOn: [{ name: 'wstack-auth', version: '^1.2.0' }]
750
+ */
751
+ interface PluginDependency {
752
+ name: string;
753
+ /** npm-style semver range. Supports `^`, `~`, exact, and unprefixed. */
754
+ version?: string;
755
+ }
756
+ interface Plugin {
757
+ name: string;
758
+ version?: string;
759
+ /** One-line summary for `wstack plugins list` and error messages. */
760
+ description?: string;
761
+ /** Semver range against the kernel API version (KERNEL_API_VERSION). */
762
+ apiVersion: string;
763
+ /**
764
+ * Capability hints — what subsystems the plugin will register against.
765
+ * Optional; provided for diagnostics and UX. The loader does not enforce
766
+ * these, but mismatch is surfaced via logger at warn level.
767
+ */
768
+ capabilities?: PluginCapabilities;
769
+ /**
770
+ * JSON Schema for the options under `Config.plugins[<name>].options`.
771
+ * When present, the loader validates that section before calling `setup`
772
+ * and rejects the plugin with a clear error path on failure.
773
+ */
774
+ configSchema?: JSONSchema;
775
+ /**
776
+ * Mandatory plugin dependencies — loading fails if any are absent or
777
+ * version-incompatible. Accepts both the legacy string-array form and
778
+ * the structured form with version constraints.
779
+ */
780
+ dependsOn?: (string | PluginDependency)[];
781
+ /** Optional plugin dependencies — silently skipped if absent. */
782
+ optionalDeps?: (string | PluginDependency)[];
783
+ conflictsWith?: string[];
784
+ /**
785
+ * Default configuration values, deep-merged under the plugin's options
786
+ * key before `configSchema` validation. User-provided values take
787
+ * precedence over defaults — this is a fallback, not an override.
788
+ *
789
+ * @example
790
+ * defaultConfig: { ttl: 3600, maxSize: 100 }
791
+ */
792
+ defaultConfig?: Record<string, unknown>;
793
+ setup(api: PluginAPI): void | Promise<void>;
794
+ teardown?(api: PluginAPI): void | Promise<void>;
795
+ /**
796
+ * Optional health check. Called by the host (e.g. `/diag plugins` slash
797
+ * command or health endpoint) to surface plugin status. Return
798
+ * `{ ok: false, message: '...' }` when the plugin is degraded.
799
+ */
800
+ health?(): Promise<{
801
+ ok: boolean;
802
+ message?: string;
803
+ }>;
804
+ }
805
+
806
+ export { type AfterIterationHook as A, type BeforeIterationHook as B, type ToolWrapper as C, DEFAULT_MAX_ITERATIONS as D, ExtensionRegistry as E, createDefaultPipelines as F, type ProviderRunnerFn as G, type MCPRegistryView as M, type OnErrorHook as O, type Plugin as P, type RunResult as R, type SessionWriterView as S, type ToolRegistryView as T, type UserInputPayload as U, type MetricsSinkView as a, type PluginAPI as b, type PluginCapabilities as c, type PluginDependency as d, type PluginPipelines as e, type ProviderFactory as f, type ProviderRegistryView as g, type SlashCommand as h, type SlashCommandRegistryView as i, type SystemPromptContributor as j, type ToolExecutorOptions as k, type ToolExecutorStrategy as l, type ToolBatchResult as m, ToolRegistry as n, ProviderRegistry as o, type AfterRunHook as p, type AfterToolExecutionHook as q, Agent as r, type AgentExtension as s, type AgentInit as t, type AgentInput as u, type AgentPipelines as v, type BeforeRunHook as w, type BeforeToolExecutionHook as x, type ProviderFactory$1 as y, type ProviderRunnerWrapper as z };