@kb-labs/agent-sdk 0.6.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.
@@ -0,0 +1,841 @@
1
+ import { A as AgentMiddleware, R as RunContext, L as LLMCallResult, T as ToolExecCtx, a as LLMCtx, E as ExecutionLoop } from './loop-BeFjNV2F.js';
2
+ export { j as AgentEventBus, i as AgentEvents, B as BaseMiddleware, C as ContextMeta, e as ControlAction, b as LLMCallPatch, f as LoopContext, g as LoopOutput, h as LoopResult, c as ToolCallInput, d as ToolOutput, U as Unsubscribe } from './loop-BeFjNV2F.js';
3
+ import { LLMTier, TaskResult, KernelState, AgentMode as AgentMode$1, EvidenceRequirements, PromptContextSelection, RepositoryModel, ToolCapability, RepositoryTopology, RepositoryStack, RepositoryFingerprints, RepositoryWorkspaceLayout, RepositoryConventions, ToolCallRecord, IterationSnapshot, RunEvaluation, CorrectionRecord, TurnInterpretation, ToolPack, AgentConfig } from '@kb-labs/agent-contracts';
4
+ import { LLMTool, LLMMessage } from '@kb-labs/sdk';
5
+
6
+ /**
7
+ * Tracing interface for the Agent SDK.
8
+ *
9
+ * All tracing goes through a single TracingMiddleware [order=0] in agent-core.
10
+ * Business logic never calls tracer.trace() directly — zero tracing lапша.
11
+ *
12
+ * Levels:
13
+ * minimal — run:start/end only
14
+ * normal — + iteration, llm:start/end, tool:start/end
15
+ * full — + full prompts, raw LLM responses, tool outputs without truncation
16
+ */
17
+
18
+ type TraceLevel = 'minimal' | 'normal' | 'full';
19
+ interface TraceEvent {
20
+ type: string;
21
+ timestamp: string;
22
+ /** = RunContext.requestId */
23
+ runId: string;
24
+ iteration?: number;
25
+ /** For span nesting (LLM call, tool call, sub-agent) */
26
+ spanId?: string;
27
+ parentSpanId?: string;
28
+ data: Record<string, unknown>;
29
+ }
30
+ type RunStartEvent = TraceEvent & {
31
+ type: 'run:start';
32
+ data: {
33
+ task: string;
34
+ tier: LLMTier;
35
+ };
36
+ };
37
+ type RunEndEvent = TraceEvent & {
38
+ type: 'run:end';
39
+ data: {
40
+ success: boolean;
41
+ totalTokens: number;
42
+ durationMs: number;
43
+ };
44
+ };
45
+ type IterStartEvent = TraceEvent & {
46
+ type: 'iteration:start';
47
+ data: {
48
+ iteration: number;
49
+ maxIterations: number;
50
+ };
51
+ };
52
+ type IterEndEvent = TraceEvent & {
53
+ type: 'iteration:end';
54
+ data: {
55
+ iteration: number;
56
+ };
57
+ };
58
+ type LLMStartEvent = TraceEvent & {
59
+ type: 'llm:start';
60
+ data: {
61
+ messageCount: number;
62
+ tools: string[];
63
+ };
64
+ };
65
+ type LLMEndEvent = TraceEvent & {
66
+ type: 'llm:end';
67
+ data: {
68
+ promptTokens: number;
69
+ completionTokens: number;
70
+ durationMs: number;
71
+ };
72
+ };
73
+ type ToolStartEvent = TraceEvent & {
74
+ type: 'tool:start';
75
+ data: {
76
+ toolName: string;
77
+ input: unknown;
78
+ };
79
+ };
80
+ type ToolEndEvent = TraceEvent & {
81
+ type: 'tool:end';
82
+ data: {
83
+ toolName: string;
84
+ success: boolean;
85
+ durationMs: number;
86
+ };
87
+ };
88
+ type EscalateEvent = TraceEvent & {
89
+ type: 'escalate';
90
+ data: {
91
+ fromTier: LLMTier;
92
+ toTier: LLMTier;
93
+ reason: string;
94
+ };
95
+ };
96
+ type AbortEvent = TraceEvent & {
97
+ type: 'abort';
98
+ data: {
99
+ reason: string;
100
+ };
101
+ };
102
+ type SpawnEvent = TraceEvent & {
103
+ type: 'spawn';
104
+ data: {
105
+ profileId: string;
106
+ childRunId: string;
107
+ };
108
+ };
109
+ interface AgentTracer {
110
+ trace(event: TraceEvent): void;
111
+ /** For async tracers (batching, network writes). Called at run end. */
112
+ flush?(): Promise<void>;
113
+ }
114
+
115
+ /**
116
+ * AgentMode — defines a mode of execution (execute, plan, spec, debug, etc.).
117
+ *
118
+ * A mode can:
119
+ * - Add system prompt instructions
120
+ * - Filter available tools (e.g. plan mode = read-only)
121
+ * - Register mode-specific middlewares
122
+ * - Take full control via execute() and call next() for the standard loop
123
+ *
124
+ * Modes are registered via sdk.withMode(mode) and selected at runtime
125
+ * based on AgentConfig.mode. Multiple modes can be registered;
126
+ * only the matching one is activated.
127
+ */
128
+
129
+ interface ToolFilter {
130
+ /** If set, only tools matching these names are included */
131
+ allowNames?: string[];
132
+ /** If set, tools matching these names are excluded */
133
+ denyNames?: string[];
134
+ /** If true, only read-only tools (no filesystem writes, no shell) */
135
+ readOnly?: boolean;
136
+ /** Filter by tool capability tags */
137
+ capabilities?: string[];
138
+ }
139
+ type ToolFilterFn = (tool: LLMTool) => boolean;
140
+ interface AgentMode {
141
+ /** Mode name — matched against AgentConfig.mode */
142
+ name: string;
143
+ /** Extra instructions appended to the system prompt in this mode */
144
+ getSystemPromptAdditions?(): string;
145
+ /** Restricts which tools are visible to the LLM in this mode */
146
+ getToolFilter?(): ToolFilter | ToolFilterFn;
147
+ /** Additional middlewares activated only in this mode */
148
+ getMiddlewares?(): AgentMiddleware[];
149
+ /**
150
+ * Full mode override — mode takes control of execution.
151
+ * Call next() to delegate to the standard LinearExecutionLoop.
152
+ *
153
+ * Use this for modes that wrap the loop (e.g. plan mode: validate → loop → validate).
154
+ */
155
+ execute?(task: string, ctx: RunContext, next: () => Promise<TaskResult>): Promise<TaskResult>;
156
+ }
157
+
158
+ /**
159
+ * AgentMemory — interface for what the agent remembers across iterations.
160
+ *
161
+ * Implementations live in agent-core:
162
+ * - InMemoryAgentMemory — simple in-process store
163
+ * - ArchiveAgentMemory — persistent file-backed store
164
+ * - RAGAgentMemory — vector-search backed (mind-engine)
165
+ */
166
+ interface MemoryEntry {
167
+ content: string;
168
+ type: 'fact' | 'task' | 'observation' | 'error';
169
+ metadata?: Record<string, unknown>;
170
+ }
171
+ interface AgentMemory {
172
+ add(entry: MemoryEntry): Promise<void>;
173
+ /** Returns entries relevant to the query (semantic or keyword search) */
174
+ get(query: string): Promise<MemoryEntry[]>;
175
+ clear(): Promise<void>;
176
+ }
177
+
178
+ /**
179
+ * StopCondition — defines when the execution loop should stop.
180
+ *
181
+ * All registered conditions are evaluated after each LLM response.
182
+ * When multiple conditions fire simultaneously, the one with the
183
+ * lowest priority number wins (priority = 0 is highest).
184
+ *
185
+ * Built-in conditions in agent-core (priorities 0–9 reserved):
186
+ * AbortCondition 0 — abortSignal.aborted
187
+ * ReportCondition 1 — agent called the report tool
188
+ * HardBudgetCondition 2 — token hard limit reached
189
+ * MaxIterations 3 — iteration limit reached
190
+ * LoopDetected 4 — same tools called 3x in a row
191
+ * NoToolCalls 5 — agent returned no tool calls
192
+ *
193
+ * Custom conditions: use priority >= 10.
194
+ */
195
+
196
+ interface StopConditionResult {
197
+ /** Human-readable reason label */
198
+ reason: string;
199
+ /** Machine-readable code (e.g. 'report_complete', 'max_iterations') */
200
+ reasonCode: string;
201
+ /** Priority of this condition (lower = more important) */
202
+ priority: number;
203
+ }
204
+ interface StopCondition {
205
+ name: string;
206
+ /**
207
+ * Evaluated after each LLM response.
208
+ * Return a StopConditionResult if this condition fires, null otherwise.
209
+ */
210
+ evaluate(ctx: RunContext, response: LLMCallResult): StopConditionResult | null;
211
+ }
212
+
213
+ /**
214
+ * OutputProcessor — transforms tool output before it enters the message context.
215
+ *
216
+ * Processors run in registration order after tool execution, before
217
+ * the output is appended to the conversation history.
218
+ *
219
+ * Built-in processors in agent-core:
220
+ * TruncationProcessor — truncates output > N chars (fixes 55k token problem)
221
+ * DeduplicationProcessor — removes repeated content across iterations
222
+ * CompressionProcessor — compresses large structured outputs (JSON, logs)
223
+ */
224
+
225
+ interface OutputProcessor {
226
+ name: string;
227
+ /**
228
+ * Transforms the raw tool output string.
229
+ * Return the transformed string — or the original if no change needed.
230
+ */
231
+ process(output: string, ctx: ToolExecCtx): string | Promise<string>;
232
+ }
233
+
234
+ /**
235
+ * ToolGuard — security layer around tool execution.
236
+ *
237
+ * Guards run inside ToolManager, forming a GuardPipeline:
238
+ * LLM → validateInput() → [reject = error result] → ToolManager.execute()
239
+ * → validateOutput() → [sanitize or reject] → OutputProcessors → context
240
+ *
241
+ * Guards are the single enforcement point for permissions.
242
+ * Tool implementations do NOT check permissions themselves.
243
+ *
244
+ * Built-in guards in agent-core:
245
+ * PromptInjectionGuard — detects injection attempts in tool input
246
+ * SecretRedactionGuard — scrubs api keys / tokens from output
247
+ * PathSandboxGuard — enforces allowed filesystem paths
248
+ * NetworkGuard — controls outbound requests (MCP tools)
249
+ */
250
+
251
+ type ValidationResult = {
252
+ ok: true;
253
+ } | {
254
+ ok: false;
255
+ reason: string;
256
+ action: 'reject';
257
+ } | {
258
+ ok: false;
259
+ reason: string;
260
+ action: 'sanitize';
261
+ sanitized: string;
262
+ };
263
+ interface ToolGuard {
264
+ name: string;
265
+ /**
266
+ * Called BEFORE tool execution.
267
+ * Return { ok: false, action: 'reject' } to block the call entirely —
268
+ * the tool output will be an error message.
269
+ */
270
+ validateInput?(toolName: string, input: Record<string, unknown>, ctx: ToolExecCtx): ValidationResult | Promise<ValidationResult>;
271
+ /**
272
+ * Called AFTER tool execution.
273
+ * Return { ok: false, action: 'sanitize', sanitized } to replace the output.
274
+ * Return { ok: false, action: 'reject' } to replace output with an error message.
275
+ */
276
+ validateOutput?(toolName: string, output: string, ctx: ToolExecCtx): ValidationResult | Promise<ValidationResult>;
277
+ }
278
+
279
+ /**
280
+ * InputNormalizer — transforms tool inputs before guards and execution.
281
+ *
282
+ * Normalizers run inside ToolExecutor in registration order, BEFORE guards:
283
+ * LLM → InputNormalizer.normalize() → ToolGuard.validateInput() → execute() → OutputProcessor
284
+ *
285
+ * Use cases:
286
+ * - Path resolution (.bak → source, .js → .ts)
287
+ * - Glob pattern expansion (bare filename → `**\/*name*`)
288
+ * - Adaptive read limits per tier
289
+ * - Directory field normalization
290
+ * - Shell cwd defaulting
291
+ *
292
+ * Contract:
293
+ * - Return a new (or same) input object — never throw.
294
+ * - If normalization doesn't apply to this tool, return input unchanged.
295
+ * - Normalizers are composable — each receives the output of the previous one.
296
+ */
297
+
298
+ interface InputNormalizer {
299
+ name: string;
300
+ /**
301
+ * Transforms tool input before guards and execution.
302
+ * Return the (possibly modified) input object.
303
+ *
304
+ * @param toolName - Name of the tool being called
305
+ * @param input - Current input (may have been modified by a prior normalizer)
306
+ * @param ctx - Execution context (run, iteration, tier, etc.)
307
+ * @returns Normalized input — same reference or a new object
308
+ */
309
+ normalize(toolName: string, input: Record<string, unknown>, ctx: ToolExecCtx): Record<string, unknown> | Promise<Record<string, unknown>>;
310
+ }
311
+
312
+ /**
313
+ * ContextStrategy — controls how the conversation history is built and trimmed.
314
+ *
315
+ * Called before each LLM call to produce the message list that will be sent.
316
+ * Responsible for context window management.
317
+ *
318
+ * Built-in: LinearContextStrategy (agent-core) — keeps full history
319
+ * Custom examples:
320
+ * SummaryContextStrategy — summarizes old messages to save tokens
321
+ * RAGContextStrategy — retrieves relevant history via vector search
322
+ */
323
+
324
+ interface ContextStrategy {
325
+ /**
326
+ * Builds the message list to send to the LLM for this iteration.
327
+ * May summarize, truncate, or retrieve from memory.
328
+ */
329
+ build(history: ReadonlyArray<LLMMessage>, task: string, iteration: number): Promise<LLMMessage[]>;
330
+ /**
331
+ * Called after each iteration to append new messages to history.
332
+ * May apply deduplication or compression before returning the new history.
333
+ */
334
+ append(history: ReadonlyArray<LLMMessage>, newMessages: LLMMessage[]): LLMMessage[];
335
+ }
336
+
337
+ /**
338
+ * IBudgetManager — token and iteration budget tracking.
339
+ *
340
+ * BudgetSnapshot is the read-only view of current state.
341
+ * BudgetDecision is what the manager recommends doing next.
342
+ *
343
+ * The BudgetMiddleware in agent-core calls snapshot() + decide() in
344
+ * beforeIteration() and returns the appropriate ControlAction.
345
+ */
346
+
347
+ interface BudgetSnapshot {
348
+ totalTokens: number;
349
+ iterationsUsed: number;
350
+ /** 0 = unlimited */
351
+ tokenBudget: number;
352
+ iterationBudget: number;
353
+ /** ~80% of token budget consumed */
354
+ softLimitReached: boolean;
355
+ /** ~95% of token budget consumed */
356
+ hardLimitReached: boolean;
357
+ }
358
+ interface BudgetDecision {
359
+ action: 'continue' | 'escalate' | 'stop';
360
+ reason?: string;
361
+ /** If true: stop iterating and synthesize a partial answer from history */
362
+ forceSynthesis?: boolean;
363
+ /** Target tier for escalation */
364
+ escalateTo?: LLMTier;
365
+ }
366
+ interface IBudgetManager {
367
+ /** Current budget state */
368
+ snapshot(): BudgetSnapshot;
369
+ /** Recommend an action based on current state */
370
+ decide(snapshot: BudgetSnapshot): BudgetDecision;
371
+ /** Record tokens consumed in one LLM call */
372
+ record(promptTokens: number, completionTokens: number): void;
373
+ /** Total tokens consumed so far */
374
+ readonly totalTokens: number;
375
+ }
376
+
377
+ /**
378
+ * AgentProfile — defines the role and capabilities of an agent.
379
+ *
380
+ * Three roles:
381
+ * orchestrator — full rights, all modes (plan, spec), human-in-loop support
382
+ * sub-agent — same rights as orchestrator but scoped context, limited iterations
383
+ * atomic — minimal rights: one tool pack, no spawn, isolated execution
384
+ *
385
+ * Profiles are registered via sdk.withProfile() and applied at createRunner() time.
386
+ */
387
+
388
+ type AgentRole = 'orchestrator' | 'sub-agent' | 'atomic';
389
+ interface AgentProfile {
390
+ id: string;
391
+ role: AgentRole;
392
+ /** Base system prompt for this profile (appended to global system prompt) */
393
+ systemPrompt?: string;
394
+ /** Additional instruction bullets (appended after systemPrompt) */
395
+ instructions?: string[];
396
+ budget?: {
397
+ maxIterations?: number;
398
+ tier?: LLMTier;
399
+ enableEscalation?: boolean;
400
+ /** 0 = unlimited */
401
+ tokenBudget?: number;
402
+ };
403
+ /**
404
+ * Spawn configuration — only applicable for orchestrator and sub-agent roles.
405
+ * Atomic agents cannot spawn sub-agents.
406
+ */
407
+ spawn?: {
408
+ /** Maximum sub-agent depth (default: 3). Prevents infinite recursion. */
409
+ maxDepth?: number;
410
+ /** If set, only profiles in this list can be spawned by this agent */
411
+ allowedProfiles?: string[];
412
+ };
413
+ }
414
+
415
+ interface ResponseRequirements {
416
+ requirements: EvidenceRequirements;
417
+ rationale: string;
418
+ }
419
+ interface ToolPolicy {
420
+ access: 'restricted' | 'read-only' | 'controlled' | 'balanced' | 'aggressive';
421
+ allowedToolNames?: string[];
422
+ allowedCapabilities?: ToolCapability[];
423
+ blockedCapabilities?: ToolCapability[];
424
+ }
425
+ interface DirectAnswerResolution {
426
+ answer: string;
427
+ confidence: number;
428
+ filesRead?: string[];
429
+ }
430
+ interface ModePolicy {
431
+ id: string;
432
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
433
+ describe(): {
434
+ responseStyle: 'dialogue-first' | 'execution-first' | 'planning-first';
435
+ toolUse: 'controlled' | 'balanced' | 'aggressive';
436
+ };
437
+ }
438
+ interface RepositoryDiagnosticsProvider {
439
+ id: string;
440
+ describe(input: {
441
+ workingDir: string;
442
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
443
+ profile: RuntimeProfile | null;
444
+ kernel: KernelState | null;
445
+ }): Promise<RepositoryModel | null> | RepositoryModel | null;
446
+ }
447
+ interface RepositoryProbeObservation {
448
+ topology?: RepositoryTopology;
449
+ stack?: Partial<RepositoryStack>;
450
+ fingerprints?: Partial<RepositoryFingerprints>;
451
+ workspace?: Partial<RepositoryWorkspaceLayout>;
452
+ conventions?: Partial<RepositoryConventions>;
453
+ riskSignals?: string[];
454
+ sources?: string[];
455
+ }
456
+ interface RepositoryProbe {
457
+ id: string;
458
+ probe(input: {
459
+ workingDir: string;
460
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
461
+ profile: RuntimeProfile | null;
462
+ kernel: KernelState | null;
463
+ fileNames: string[];
464
+ }): Promise<RepositoryProbeObservation | null> | RepositoryProbeObservation | null;
465
+ }
466
+ interface ToolCapabilityResolver {
467
+ id: string;
468
+ resolve(input: {
469
+ workingDir: string;
470
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
471
+ profile: RuntimeProfile | null;
472
+ repositoryModel: RepositoryModel | null;
473
+ kernel: KernelState | null;
474
+ }): Promise<ToolCapability[] | null> | ToolCapability[] | null;
475
+ }
476
+ interface MemoryCapability {
477
+ id: string;
478
+ apply(state: KernelState): KernelState | Promise<KernelState>;
479
+ }
480
+ interface PromptProjector {
481
+ id: string;
482
+ project(input: {
483
+ state: KernelState;
484
+ messages: LLMMessage[];
485
+ repositoryModel?: RepositoryModel | null;
486
+ toolCapabilities?: ToolCapability[];
487
+ }): string | Promise<string>;
488
+ }
489
+ interface PromptContextSelector {
490
+ id: string;
491
+ select(input: {
492
+ state: KernelState;
493
+ messages: LLMMessage[];
494
+ responseRequirements?: ResponseRequirements;
495
+ }): PromptContextSelection | Promise<PromptContextSelection>;
496
+ }
497
+ interface ResponseRequirementsSelector {
498
+ id: string;
499
+ select(input: {
500
+ state: KernelState | null;
501
+ messages: LLMMessage[];
502
+ task: string;
503
+ }): ResponseRequirements | Promise<ResponseRequirements>;
504
+ }
505
+ interface SessionRecallResolver {
506
+ id: string;
507
+ resolve(input: {
508
+ state: KernelState;
509
+ messages: LLMMessage[];
510
+ task: string;
511
+ toolRecords: ToolCallRecord[];
512
+ responseRequirements?: ResponseRequirements;
513
+ }): Promise<DirectAnswerResolution | null> | DirectAnswerResolution | null;
514
+ }
515
+ interface OutputValidationResult {
516
+ verdict: 'allow' | 'warn' | 'block';
517
+ rationale: string;
518
+ }
519
+ interface OutputValidator {
520
+ id: string;
521
+ validate(input: {
522
+ state: KernelState;
523
+ answer: string;
524
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
525
+ metadata?: Record<string, unknown>;
526
+ }): Promise<OutputValidationResult | null> | OutputValidationResult | null;
527
+ }
528
+ interface ArtifactWriter {
529
+ id: string;
530
+ write(input: {
531
+ state: KernelState;
532
+ sessionId: string;
533
+ summary: string;
534
+ runId?: string;
535
+ metadata?: Record<string, unknown>;
536
+ }): Promise<void> | void;
537
+ }
538
+ interface ResultMapperResult {
539
+ taskResult?: Partial<TaskResult>;
540
+ runtimeMetadata?: Record<string, unknown>;
541
+ summary?: string;
542
+ }
543
+ interface ResultMapper {
544
+ id: string;
545
+ map(input: {
546
+ state: KernelState | null;
547
+ answer: string;
548
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
549
+ task: string;
550
+ sessionId?: string;
551
+ workingDir: string;
552
+ metadata?: Record<string, unknown>;
553
+ }): Promise<ResultMapperResult | null> | ResultMapperResult | null;
554
+ }
555
+ interface CompletionPolicy {
556
+ requireReportTool?: boolean;
557
+ requireValidatorsToPass?: boolean;
558
+ }
559
+ interface RuntimeProfile {
560
+ id: string;
561
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
562
+ description?: string;
563
+ toolPolicy?: ToolPolicy;
564
+ repositoryDiagnosticsProviders?: RepositoryDiagnosticsProvider[];
565
+ repositoryProbes?: RepositoryProbe[];
566
+ toolCapabilityResolvers?: ToolCapabilityResolver[];
567
+ promptContextSelectors?: PromptContextSelector[];
568
+ responseRequirementsSelectors?: ResponseRequirementsSelector[];
569
+ promptProjectors?: PromptProjector[];
570
+ sessionRecallResolvers?: SessionRecallResolver[];
571
+ runEvaluators?: RunEvaluator[];
572
+ resultMappers?: ResultMapper[];
573
+ outputValidators?: OutputValidator[];
574
+ artifactWriters?: ArtifactWriter[];
575
+ completionPolicy?: CompletionPolicy;
576
+ }
577
+ interface RuntimeObserver {
578
+ id: string;
579
+ onKernelUpdated?(state: KernelState): void | Promise<void>;
580
+ onToolCall?(record: ToolCallRecord): void | Promise<void>;
581
+ onCorrection?(record: CorrectionRecord): void | Promise<void>;
582
+ }
583
+ interface TurnInterpreter {
584
+ id: string;
585
+ supports(mode: AgentMode$1 | 'assistant' | 'autonomous'): boolean;
586
+ interpret(input: {
587
+ sessionId?: string;
588
+ mode: AgentMode$1 | 'assistant' | 'autonomous';
589
+ message: string;
590
+ kernel: KernelState | null;
591
+ }): Promise<TurnInterpretation | null> | TurnInterpretation | null;
592
+ }
593
+ interface RunEvaluator {
594
+ id: string;
595
+ evaluate(input: {
596
+ run: RunContext;
597
+ snapshot: IterationSnapshot;
598
+ }): Promise<RunEvaluation | null> | RunEvaluation | null;
599
+ }
600
+
601
+ /**
602
+ * IAgentSpawner — contract for spawning sub-agents.
603
+ *
604
+ * The spawner is registered in RunContext.meta by AgentRunner at startup:
605
+ * ctx.meta.get<IAgentSpawner>('core', 'spawner')
606
+ *
607
+ * This makes it accessible to any middleware or tool without direct coupling
608
+ * to AgentRunner.
609
+ *
610
+ * Implementation lives in agent-core (AgentSpawner).
611
+ * Enforcement:
612
+ * - canSpawn() checks depth, allowed profiles, and remaining budget
613
+ * - budgetPartition is deducted from parent's remaining token budget
614
+ * - parent's AbortSignal is wired to all child AbortControllers
615
+ */
616
+
617
+ interface SpawnOptions {
618
+ /** Profile ID to use — must be registered in the parent SDK */
619
+ profileId: string;
620
+ /** Task string for the sub-agent */
621
+ task: string;
622
+ /** Parent context — used to inherit requestId, abortSignal, deadlineMs */
623
+ parentContext: RunContext;
624
+ /**
625
+ * Fraction of parent's remaining token budget to allocate (0.0–1.0).
626
+ * Default: 0.3 (30%).
627
+ */
628
+ budgetPartition?: number;
629
+ /** Additional tool packs available only to this sub-agent */
630
+ additionalPacks?: ToolPack[];
631
+ }
632
+ interface SpawnResult {
633
+ result: TaskResult;
634
+ /** Actual tokens consumed — parent should deduct this from its budget */
635
+ tokensConsumed: number;
636
+ }
637
+ interface IAgentSpawner {
638
+ /** Spawn a single sub-agent and await its result */
639
+ spawn(options: SpawnOptions): Promise<SpawnResult>;
640
+ /**
641
+ * Spawn multiple sub-agents in parallel.
642
+ * The budgetPartition is divided equally among all spawned agents.
643
+ */
644
+ spawnParallel(options: SpawnOptions[]): Promise<SpawnResult[]>;
645
+ /**
646
+ * Check whether spawning is allowed in the current context.
647
+ * Returns false if depth limit is reached, profile is not allowed,
648
+ * or remaining budget is insufficient.
649
+ */
650
+ canSpawn(profileId: string, ctx: RunContext): boolean;
651
+ }
652
+
653
+ /**
654
+ * AgentErrorHandler — defines what to do when a tool or LLM call fails.
655
+ *
656
+ * Registered via sdk.withErrorHandler(handler).
657
+ *
658
+ * Default behaviour in agent-core:
659
+ * tool error → retry once → skip (return empty output, continue)
660
+ * LLM error → retry with exponential backoff (3x) → stop
661
+ *
662
+ * The `attempt` parameter is 1-based — first failure = attempt 1.
663
+ */
664
+
665
+ type ToolErrorAction = {
666
+ action: 'retry';
667
+ delayMs?: number;
668
+ } | {
669
+ action: 'skip';
670
+ } | {
671
+ action: 'stop';
672
+ reason: string;
673
+ };
674
+ type LLMErrorAction = {
675
+ action: 'retry';
676
+ delayMs?: number;
677
+ } | {
678
+ action: 'stop';
679
+ reason: string;
680
+ };
681
+ interface AgentErrorHandler {
682
+ /**
683
+ * Called when a tool execution throws.
684
+ * @param attempt 1-based attempt count
685
+ */
686
+ onToolError(error: unknown, ctx: ToolExecCtx, attempt: number): ToolErrorAction;
687
+ /**
688
+ * Called when an LLM API call throws (rate limit, timeout, network error, etc.).
689
+ * @param attempt 1-based attempt count
690
+ */
691
+ onLLMError(error: unknown, ctx: LLMCtx, attempt: number): LLMErrorAction;
692
+ }
693
+
694
+ /**
695
+ * AgentSDK — composable builder + IAgentSDK interface for mocking in tests.
696
+ *
697
+ * Usage:
698
+ * import { AgentSDK } from '@kb-labs/agent-sdk';
699
+ * import { CoreToolPack, PromptInjectionGuard } from '@kb-labs/agent-core';
700
+ *
701
+ * const agent = new AgentSDK()
702
+ * .withProfile({ id: 'default', role: 'orchestrator' })
703
+ * .register(new CoreToolPack())
704
+ * .addGuard(new PromptInjectionGuard())
705
+ * .use(new AuditMiddleware());
706
+ *
707
+ * extend() returns a deep clone — changes never affect the original:
708
+ * const subAgent = agent.extend().withProfile(atomicProfile);
709
+ *
710
+ * createRunner() is implemented by agent-core (injected via AgentSDK.setRunnerFactory()).
711
+ * agent-sdk itself has no runtime dependency on agent-core.
712
+ */
713
+
714
+ interface IAgentRunner {
715
+ readonly agentId: string;
716
+ execute(task: string): Promise<TaskResult>;
717
+ requestStop(): void;
718
+ injectUserContext(message: string): void;
719
+ }
720
+ type RunnerFactory = (config: AgentConfig, sdk: AgentSDK) => IAgentRunner;
721
+ interface IAgentSDK {
722
+ use(middleware: AgentMiddleware): IAgentSDK;
723
+ register(pack: ToolPack): IAgentSDK;
724
+ withTracer(tracer: AgentTracer, level?: TraceLevel): IAgentSDK;
725
+ withMode(mode: AgentMode): IAgentSDK;
726
+ withMemory(memory: AgentMemory): IAgentSDK;
727
+ withProfile(profile: AgentProfile): IAgentSDK;
728
+ withLoop(loop: ExecutionLoop): IAgentSDK;
729
+ withContextStrategy(strategy: ContextStrategy): IAgentSDK;
730
+ withErrorHandler(handler: AgentErrorHandler): IAgentSDK;
731
+ addStopCondition(condition: StopCondition): IAgentSDK;
732
+ addOutputProcessor(processor: OutputProcessor): IAgentSDK;
733
+ addGuard(guard: ToolGuard): IAgentSDK;
734
+ addInputNormalizer(normalizer: InputNormalizer): IAgentSDK;
735
+ registerModePolicy(policy: ModePolicy): IAgentSDK;
736
+ registerMemoryCapability(capability: MemoryCapability): IAgentSDK;
737
+ registerPromptContextSelector(selector: PromptContextSelector): IAgentSDK;
738
+ registerResponseRequirementsSelector(selector: ResponseRequirementsSelector): IAgentSDK;
739
+ registerSessionRecallResolver(resolver: SessionRecallResolver): IAgentSDK;
740
+ registerRepositoryDiagnosticsProvider(provider: RepositoryDiagnosticsProvider): IAgentSDK;
741
+ registerRepositoryProbe(probe: RepositoryProbe): IAgentSDK;
742
+ registerToolCapabilityResolver(resolver: ToolCapabilityResolver): IAgentSDK;
743
+ registerRuntimeProfile(profile: RuntimeProfile): IAgentSDK;
744
+ registerPromptProjector(projector: PromptProjector): IAgentSDK;
745
+ registerRunEvaluator(evaluator: RunEvaluator): IAgentSDK;
746
+ registerObserver(observer: RuntimeObserver): IAgentSDK;
747
+ registerTurnInterpreter(interpreter: TurnInterpreter): IAgentSDK;
748
+ extend(): IAgentSDK;
749
+ createRunner(config: AgentConfig): IAgentRunner;
750
+ }
751
+ interface SdkState {
752
+ middlewares: AgentMiddleware[];
753
+ packs: ToolPack[];
754
+ tracer: AgentTracer | null;
755
+ traceLevel: TraceLevel;
756
+ modes: AgentMode[];
757
+ memory: AgentMemory | null;
758
+ profile: AgentProfile | null;
759
+ loop: ExecutionLoop | null;
760
+ contextStrategy: ContextStrategy | null;
761
+ errorHandler: AgentErrorHandler | null;
762
+ stopConditions: StopCondition[];
763
+ outputProcessors: OutputProcessor[];
764
+ guards: ToolGuard[];
765
+ inputNormalizers: InputNormalizer[];
766
+ modePolicies: ModePolicy[];
767
+ memoryCapabilities: MemoryCapability[];
768
+ promptContextSelectors: PromptContextSelector[];
769
+ responseRequirementsSelectors: ResponseRequirementsSelector[];
770
+ sessionRecallResolvers: SessionRecallResolver[];
771
+ repositoryDiagnosticsProviders: RepositoryDiagnosticsProvider[];
772
+ repositoryProbes: RepositoryProbe[];
773
+ toolCapabilityResolvers: ToolCapabilityResolver[];
774
+ runtimeProfiles: RuntimeProfile[];
775
+ promptProjectors: PromptProjector[];
776
+ runEvaluators: RunEvaluator[];
777
+ observers: RuntimeObserver[];
778
+ turnInterpreters: TurnInterpreter[];
779
+ }
780
+ declare class AgentSDK implements IAgentSDK {
781
+ private readonly _state;
782
+ constructor(state?: SdkState);
783
+ static setRunnerFactory(factory: RunnerFactory): void;
784
+ use(middleware: AgentMiddleware): this;
785
+ register(pack: ToolPack): this;
786
+ withTracer(tracer: AgentTracer, level?: TraceLevel): this;
787
+ withMode(mode: AgentMode): this;
788
+ withMemory(memory: AgentMemory): this;
789
+ withProfile(profile: AgentProfile): this;
790
+ withLoop(loop: ExecutionLoop): this;
791
+ withContextStrategy(strategy: ContextStrategy): this;
792
+ withErrorHandler(handler: AgentErrorHandler): this;
793
+ addStopCondition(condition: StopCondition): this;
794
+ addOutputProcessor(processor: OutputProcessor): this;
795
+ addGuard(guard: ToolGuard): this;
796
+ addInputNormalizer(normalizer: InputNormalizer): this;
797
+ registerModePolicy(policy: ModePolicy): this;
798
+ registerMemoryCapability(capability: MemoryCapability): this;
799
+ registerPromptContextSelector(selector: PromptContextSelector): this;
800
+ registerResponseRequirementsSelector(selector: ResponseRequirementsSelector): this;
801
+ registerSessionRecallResolver(resolver: SessionRecallResolver): this;
802
+ registerRepositoryDiagnosticsProvider(provider: RepositoryDiagnosticsProvider): this;
803
+ registerRepositoryProbe(probe: RepositoryProbe): this;
804
+ registerToolCapabilityResolver(resolver: ToolCapabilityResolver): this;
805
+ registerRuntimeProfile(profile: RuntimeProfile): this;
806
+ registerPromptProjector(projector: PromptProjector): this;
807
+ registerRunEvaluator(evaluator: RunEvaluator): this;
808
+ registerObserver(observer: RuntimeObserver): this;
809
+ registerTurnInterpreter(interpreter: TurnInterpreter): this;
810
+ extend(): AgentSDK;
811
+ get middlewares(): ReadonlyArray<AgentMiddleware>;
812
+ get packs(): ReadonlyArray<ToolPack>;
813
+ get tracer(): AgentTracer | null;
814
+ get traceLevel(): TraceLevel;
815
+ get modes(): ReadonlyArray<AgentMode>;
816
+ get memory(): AgentMemory | null;
817
+ get profile(): AgentProfile | null;
818
+ get loop(): ExecutionLoop | null;
819
+ get contextStrategy(): ContextStrategy | null;
820
+ get errorHandler(): AgentErrorHandler | null;
821
+ get stopConditions(): ReadonlyArray<StopCondition>;
822
+ get outputProcessors(): ReadonlyArray<OutputProcessor>;
823
+ get guards(): ReadonlyArray<ToolGuard>;
824
+ get inputNormalizers(): ReadonlyArray<InputNormalizer>;
825
+ get modePolicies(): ReadonlyArray<ModePolicy>;
826
+ get memoryCapabilities(): ReadonlyArray<MemoryCapability>;
827
+ get promptContextSelectors(): ReadonlyArray<PromptContextSelector>;
828
+ get responseRequirementsSelectors(): ReadonlyArray<ResponseRequirementsSelector>;
829
+ get sessionRecallResolvers(): ReadonlyArray<SessionRecallResolver>;
830
+ get repositoryDiagnosticsProviders(): ReadonlyArray<RepositoryDiagnosticsProvider>;
831
+ get repositoryProbes(): ReadonlyArray<RepositoryProbe>;
832
+ get toolCapabilityResolvers(): ReadonlyArray<ToolCapabilityResolver>;
833
+ get runtimeProfiles(): ReadonlyArray<RuntimeProfile>;
834
+ get promptProjectors(): ReadonlyArray<PromptProjector>;
835
+ get runEvaluators(): ReadonlyArray<RunEvaluator>;
836
+ get observers(): ReadonlyArray<RuntimeObserver>;
837
+ get turnInterpreters(): ReadonlyArray<TurnInterpreter>;
838
+ createRunner(config: AgentConfig): IAgentRunner;
839
+ }
840
+
841
+ export { type AbortEvent, type AgentErrorHandler, type AgentMemory, AgentMiddleware, type AgentMode, type AgentProfile, type AgentRole, AgentSDK, type AgentTracer, type ArtifactWriter, type BudgetDecision, type BudgetSnapshot, type CompletionPolicy, type ContextStrategy, type DirectAnswerResolution, type EscalateEvent, ExecutionLoop, type IAgentRunner, type IAgentSDK, type IAgentSpawner, type IBudgetManager, type InputNormalizer, type IterEndEvent, type IterStartEvent, LLMCallResult, LLMCtx, type LLMEndEvent, type LLMErrorAction, type LLMStartEvent, type MemoryCapability, type MemoryEntry, type ModePolicy, type OutputProcessor, type OutputValidationResult, type OutputValidator, type PromptContextSelector, type PromptProjector, type RepositoryDiagnosticsProvider, type RepositoryProbe, type RepositoryProbeObservation, type ResponseRequirements, type ResponseRequirementsSelector, type ResultMapper, type ResultMapperResult, RunContext, type RunEndEvent, type RunEvaluator, type RunStartEvent, type RunnerFactory, type RuntimeObserver, type RuntimeProfile, type SessionRecallResolver, type SpawnEvent, type SpawnOptions, type SpawnResult, type StopCondition, type StopConditionResult, type ToolCapabilityResolver, type ToolEndEvent, type ToolErrorAction, ToolExecCtx, type ToolFilter, type ToolFilterFn, type ToolGuard, type ToolPolicy, type ToolStartEvent, type TraceEvent, type TraceLevel, type TurnInterpreter, type ValidationResult };