@juspay/neurolink 10.5.2 → 10.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.
Files changed (94) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/agent/agent.js +39 -8
  3. package/dist/agent/agentNetwork.js +62 -20
  4. package/dist/agent/agentToolRegistrar.d.ts +48 -0
  5. package/dist/agent/agentToolRegistrar.js +336 -0
  6. package/dist/agent/index.d.ts +3 -0
  7. package/dist/agent/index.js +4 -0
  8. package/dist/agent/isolatedAgentRunner.d.ts +73 -0
  9. package/dist/agent/isolatedAgentRunner.js +946 -0
  10. package/dist/agent/structuredRecovery.d.ts +30 -0
  11. package/dist/agent/structuredRecovery.js +104 -0
  12. package/dist/browser/neurolink.min.js +414 -398
  13. package/dist/cli/loop/optionsSchema.d.ts +1 -1
  14. package/dist/core/baseProvider.d.ts +8 -0
  15. package/dist/core/baseProvider.js +40 -19
  16. package/dist/core/modules/GenerationHandler.d.ts +2 -6
  17. package/dist/core/modules/GenerationHandler.js +10 -1
  18. package/dist/core/toolExecutionRecorder.d.ts +76 -0
  19. package/dist/core/toolExecutionRecorder.js +261 -0
  20. package/dist/evaluation/contextBuilder.js +6 -6
  21. package/dist/lib/agent/agent.js +39 -8
  22. package/dist/lib/agent/agentNetwork.js +62 -20
  23. package/dist/lib/agent/agentToolRegistrar.d.ts +48 -0
  24. package/dist/lib/agent/agentToolRegistrar.js +337 -0
  25. package/dist/lib/agent/index.d.ts +3 -0
  26. package/dist/lib/agent/index.js +4 -0
  27. package/dist/lib/agent/isolatedAgentRunner.d.ts +73 -0
  28. package/dist/lib/agent/isolatedAgentRunner.js +947 -0
  29. package/dist/lib/agent/structuredRecovery.d.ts +30 -0
  30. package/dist/lib/agent/structuredRecovery.js +105 -0
  31. package/dist/lib/core/baseProvider.d.ts +8 -0
  32. package/dist/lib/core/baseProvider.js +40 -19
  33. package/dist/lib/core/modules/GenerationHandler.d.ts +2 -6
  34. package/dist/lib/core/modules/GenerationHandler.js +10 -1
  35. package/dist/lib/core/toolExecutionRecorder.d.ts +76 -0
  36. package/dist/lib/core/toolExecutionRecorder.js +262 -0
  37. package/dist/lib/evaluation/contextBuilder.js +6 -6
  38. package/dist/lib/models/modelRegistry.d.ts +23 -0
  39. package/dist/lib/models/modelRegistry.js +62 -1
  40. package/dist/lib/models/modelResolver.js +1 -0
  41. package/dist/lib/neurolink.d.ts +80 -1
  42. package/dist/lib/neurolink.js +199 -37
  43. package/dist/lib/providers/amazonBedrock.js +15 -2
  44. package/dist/lib/providers/anthropic.js +23 -11
  45. package/dist/lib/providers/googleAiStudio.js +8 -1
  46. package/dist/lib/providers/googleNativeGemini3.d.ts +2 -0
  47. package/dist/lib/providers/googleNativeGemini3.js +8 -1
  48. package/dist/lib/providers/googleVertex.js +56 -16
  49. package/dist/lib/providers/openaiChatCompletionsClient.js +18 -5
  50. package/dist/lib/tasks/autoresearchTaskExecutor.js +7 -6
  51. package/dist/lib/tasks/taskExecutor.js +2 -5
  52. package/dist/lib/types/agentNetwork.d.ts +23 -8
  53. package/dist/lib/types/generate.d.ts +62 -5
  54. package/dist/lib/types/index.d.ts +1 -0
  55. package/dist/lib/types/index.js +1 -0
  56. package/dist/lib/types/isolatedAgent.d.ts +365 -0
  57. package/dist/lib/types/isolatedAgent.js +12 -0
  58. package/dist/lib/types/model.d.ts +8 -0
  59. package/dist/lib/types/stream.d.ts +3 -1
  60. package/dist/lib/types/task.d.ts +3 -3
  61. package/dist/lib/utils/logger.d.ts +12 -3
  62. package/dist/lib/utils/logger.js +11 -3
  63. package/dist/lib/utils/transformationUtils.d.ts +14 -0
  64. package/dist/lib/utils/transformationUtils.js +33 -10
  65. package/dist/lib/voice/livekit/realtimeVoiceAgent.js +6 -3
  66. package/dist/models/modelRegistry.d.ts +23 -0
  67. package/dist/models/modelRegistry.js +62 -1
  68. package/dist/models/modelResolver.js +1 -0
  69. package/dist/neurolink.d.ts +80 -1
  70. package/dist/neurolink.js +199 -37
  71. package/dist/providers/amazonBedrock.js +15 -2
  72. package/dist/providers/anthropic.js +23 -11
  73. package/dist/providers/googleAiStudio.js +8 -1
  74. package/dist/providers/googleNativeGemini3.d.ts +2 -0
  75. package/dist/providers/googleNativeGemini3.js +8 -1
  76. package/dist/providers/googleVertex.js +56 -16
  77. package/dist/providers/openaiChatCompletionsClient.js +18 -5
  78. package/dist/tasks/autoresearchTaskExecutor.js +7 -6
  79. package/dist/tasks/taskExecutor.js +2 -5
  80. package/dist/types/agentNetwork.d.ts +23 -8
  81. package/dist/types/generate.d.ts +62 -5
  82. package/dist/types/index.d.ts +1 -0
  83. package/dist/types/index.js +1 -0
  84. package/dist/types/isolatedAgent.d.ts +365 -0
  85. package/dist/types/isolatedAgent.js +11 -0
  86. package/dist/types/model.d.ts +8 -0
  87. package/dist/types/stream.d.ts +3 -1
  88. package/dist/types/task.d.ts +3 -3
  89. package/dist/utils/logger.d.ts +12 -3
  90. package/dist/utils/logger.js +11 -3
  91. package/dist/utils/transformationUtils.d.ts +14 -0
  92. package/dist/utils/transformationUtils.js +33 -10
  93. package/dist/voice/livekit/realtimeVoiceAgent.js +6 -3
  94. package/package.json +3 -2
@@ -0,0 +1,365 @@
1
+ /**
2
+ * Isolated sub-agent runtime types: worker-mode instances, the
3
+ * runIsolatedAgent() two-pass runner, leashed legs/handles, waste detection,
4
+ * and host-loop delegation (registerAgentTool).
5
+ *
6
+ * Design contract: no product policy lives here — every tunable is an option
7
+ * with a sane default, and all shapes were validated against the three
8
+ * production consumers (Curator's research + log-analysis workers, Yama's
9
+ * ContextExplorerService). See docs/plans/2026-07-27-isolated-agent-runner-rfc.md.
10
+ */
11
+ import type { z } from "zod";
12
+ import type { TokenUsage } from "./analytics.js";
13
+ import type { AgentDefinition } from "./agentNetwork.js";
14
+ import type { GenerateStopReason, ToolExecutionRecord } from "./generate.js";
15
+ /**
16
+ * A log event forwarded by a worker instance's log bridge.
17
+ */
18
+ export type WorkerLogEvent = {
19
+ /** Caller-supplied tag identifying which worker produced the event. */
20
+ tag: string;
21
+ /** Log level ("debug" | "info" | "warn" | "error"). */
22
+ level: string;
23
+ /** Log message. */
24
+ message: string;
25
+ /** Epoch milliseconds. */
26
+ timestamp: number;
27
+ /** Structured payload attached to the log call, if any. */
28
+ data?: unknown;
29
+ };
30
+ /**
31
+ * Options for `NeuroLink.createWorkerInstance()`.
32
+ *
33
+ * A worker instance is a sub-agent-grade NeuroLink: conversation memory off,
34
+ * orchestration off, observability inherited from the creating instance with
35
+ * `autoDetectExternalProvider: true` + `skipLangfuseSpanProcessor: true`
36
+ * (so worker spans join the host's tracer without duplicate Langfuse
37
+ * exports), and an internal log bridge attached with a caller-supplied tag.
38
+ */
39
+ export type WorkerInstanceOptions = {
40
+ /** Tag stamped on every forwarded log event (default "worker"). */
41
+ logTag?: string;
42
+ /**
43
+ * Log bridge sink. Fire-and-forget: listener errors never disrupt the
44
+ * worker.
45
+ *
46
+ * KNOWN LIMITATION: the underlying NeuroLink logger is process-global with
47
+ * a single active emitter, so this bridge receives ALL NeuroLink log
48
+ * events emitted in the process (host, other workers, MCP) for the
49
+ * worker's lifetime, each stamped with this worker's `tag`. The tag
50
+ * identifies which bridge forwarded the event, not which instance emitted
51
+ * it. Per-instance log attribution requires per-instance logger routing —
52
+ * tracked as follow-up work in the RFC.
53
+ */
54
+ onLog?: (event: WorkerLogEvent) => void;
55
+ /**
56
+ * Share the creating instance's tool registry (custom tools + in-memory
57
+ * MCP servers) so the worker calls tools through the host's existing
58
+ * connections. Default: true.
59
+ */
60
+ shareToolRegistry?: boolean;
61
+ /**
62
+ * Extra constructor config merged into the worker (e.g. `credentials`,
63
+ * `tools`, `modelPool`). Worker-mode fields (memory off, orchestration
64
+ * off, observability flags) always win over this merge.
65
+ */
66
+ config?: Record<string, unknown>;
67
+ };
68
+ /**
69
+ * Structured-extraction configuration for an isolated agent run.
70
+ *
71
+ * The extraction pass always runs tools-off on its own timeout, fed from the
72
+ * run's tool-execution records — so a research generate that died on a
73
+ * provider error still extracts from the records instead of losing the run.
74
+ */
75
+ export type IsolatedAgentExtraction = {
76
+ /** Local validator (lenient — may carry defaults/catch). Required. */
77
+ schema: z.ZodSchema;
78
+ /**
79
+ * Provider-attached wire schema (strict: no defaults/catch, which many
80
+ * providers reject in constrained decoding). Falls back to `schema`.
81
+ */
82
+ wireSchema?: z.ZodSchema;
83
+ /**
84
+ * Human/model-readable JSON shape description used in the extraction
85
+ * prompt and in corrective retries alongside validation errors.
86
+ */
87
+ shapeDoc?: string;
88
+ /**
89
+ * Normalizer applied to every recovery candidate before validation
90
+ * (e.g. wrap a bare top-level array into the expected envelope).
91
+ */
92
+ coerce?: (candidate: unknown) => unknown;
93
+ /** Corrective re-ask attempts after ladder failure (default 2). */
94
+ maxRetries?: number;
95
+ /**
96
+ * Per-attempt extraction timeout in ms (default 60_000). Never carved out
97
+ * of the research budget.
98
+ */
99
+ timeoutMs?: number;
100
+ /**
101
+ * Phase-level deadline bounding ALL extraction attempts (ms). Defaults to
102
+ * `(maxRetries + 1) × timeoutMs` — i.e. 180s at the defaults. Callers that
103
+ * derive an outer tool-execution ceiling from the leg budget must add this
104
+ * bound (plus the ~20s next-plan ask in leashed mode) on top of the
105
+ * research budget.
106
+ */
107
+ totalTimeoutMs?: number;
108
+ };
109
+ /**
110
+ * Definition of an isolated sub-agent: a standard AgentDefinition plus
111
+ * optional structured extraction.
112
+ */
113
+ export type IsolatedAgentDefinition = AgentDefinition & {
114
+ extraction?: IsolatedAgentExtraction;
115
+ };
116
+ /** Per-run overrides for an isolated agent run (internal-caller knobs). */
117
+ export type AgentRunOverrides = {
118
+ /** Wall-clock cap for the research pass (ms). */
119
+ turnTimeoutMs?: number;
120
+ /** Stall watchdog for the research pass (ms). */
121
+ stallTimeoutMs?: number;
122
+ /** Wrap-up lead for the research pass (ms). */
123
+ wrapupTimeLeadMs?: number;
124
+ /** Max agentic steps for the research pass. */
125
+ maxSteps?: number;
126
+ /** Max output tokens per model call. */
127
+ maxTokens?: number;
128
+ /** Model override (wins over the definition). */
129
+ model?: string;
130
+ /** Provider override (wins over the definition). */
131
+ provider?: string;
132
+ };
133
+ /** Leg budget for leashed mode. Setting either enables leashed mode. */
134
+ export type AgentLegOptions = {
135
+ /** Wall-clock budget for one leg (ms). */
136
+ budgetMs?: number;
137
+ /** Tool-call budget for one leg. */
138
+ budgetToolCalls?: number;
139
+ };
140
+ /**
141
+ * Mechanical waste-signature thresholds, checked per tool call. A tripped
142
+ * signature ends the leg early with `wasteSignals` populated.
143
+ */
144
+ export type AgentWasteThresholds = {
145
+ /**
146
+ * Max times the same call hash (tool + normalized params) may be seen in
147
+ * one run before tripping (default 2 — the third identical call trips).
148
+ */
149
+ duplicateCallLimit?: number;
150
+ /** Consecutive empty/zero-result calls before tripping (default 3). */
151
+ emptyResultStreakLimit?: number;
152
+ /** Consecutive error results before tripping (default 3). */
153
+ errorStreakLimit?: number;
154
+ /**
155
+ * Calls without a new distinct result payload before tripping
156
+ * (default 8).
157
+ */
158
+ noNewResultsLimit?: number;
159
+ };
160
+ /** Lifecycle event types emitted by an isolated agent run. */
161
+ export type AgentRunEventType = "start" | "tool_call" | "tool_result" | "phase" | "wrapup" | "leg_end" | "waste" | "complete" | "error";
162
+ /**
163
+ * Lifecycle event for `AgentRunOptions.onEvent`. Fire-and-forget — listener
164
+ * errors never break the run.
165
+ *
166
+ * Note: `tool_call` and `tool_result` both fire AFTER the execution
167
+ * completes (they are driven by the capture record) — a long-running tool
168
+ * emits nothing until it returns. Treat them as accounting events, not
169
+ * live started/finished signals.
170
+ */
171
+ export type AgentRunEvent = {
172
+ type: AgentRunEventType;
173
+ /** Run id (also the default tool-context sessionId). */
174
+ runId: string;
175
+ /** Agent definition id. */
176
+ agentId: string;
177
+ /** Epoch milliseconds. */
178
+ timestamp: number;
179
+ /** Current phase, on `phase` events. */
180
+ phase?: "research" | "extraction";
181
+ /** Tool name, on tool_call/tool_result events. */
182
+ toolName?: string;
183
+ /** Tool params, on tool_call events. */
184
+ params?: unknown;
185
+ /** Bounded result summary, on tool_result events. */
186
+ resultSummary?: string;
187
+ /** Whether the tool result was an error, on tool_result events. */
188
+ isError?: boolean;
189
+ /** Leg index, on leg_end events (leashed mode). */
190
+ legIndex?: number;
191
+ /** Tripped waste signatures, on waste events. */
192
+ wasteSignals?: string[];
193
+ /** Error message, on error events. */
194
+ error?: string;
195
+ /** Final status, on complete events. */
196
+ status?: AgentRunStatus;
197
+ };
198
+ /**
199
+ * Options for one isolated agent run (`NeuroLink.runIsolatedAgent`).
200
+ */
201
+ export type AgentRunOptions = {
202
+ /**
203
+ * Parent cancellation. When provided it MUST be honored: an aborted parent
204
+ * stops research AND extraction cleanly, the outcome reports the run was
205
+ * cancelled, and no ghost workers survive.
206
+ */
207
+ abortSignal?: AbortSignal;
208
+ /** Per-run overrides (internal-caller knobs). */
209
+ overrides?: AgentRunOverrides;
210
+ /**
211
+ * Set on the worker for EVERY tool call (merged into the worker's tool
212
+ * context), including a caller-supplied `sessionId`; the run id is used
213
+ * when no sessionId is supplied.
214
+ */
215
+ toolContext?: Record<string, unknown>;
216
+ /** Lifecycle event stream. Fire-and-forget. */
217
+ onEvent?: (event: AgentRunEvent) => void;
218
+ /** Leg budget — enables leashed mode. */
219
+ leg?: AgentLegOptions;
220
+ /** TTL for a leashed handle in ms (default 600_000 = 10 min). */
221
+ handleTtlMs?: number;
222
+ /** Waste-signature thresholds (defaults apply when omitted). */
223
+ waste?: AgentWasteThresholds;
224
+ /**
225
+ * Bounds for the run's tool execution records. Raise `maxResultChars`
226
+ * when the CALLER verifies evidence from `toolExecutions` (raw result
227
+ * texts must be available up to the cap).
228
+ */
229
+ capture?: {
230
+ maxResultChars?: number;
231
+ maxRecords?: number;
232
+ };
233
+ };
234
+ /** Terminal (or leg-boundary) status of an isolated agent run. */
235
+ export type AgentRunStatus = "completed" | "partial" | "in_progress" | "insufficient_data" | "error";
236
+ /** Per-leg accounting for leashed runs. */
237
+ export type AgentRunLegInfo = {
238
+ /** 0-based leg index. */
239
+ index: number;
240
+ /** Tool calls made this leg. */
241
+ toolCalls: number;
242
+ /** Wall-clock duration of this leg (ms). */
243
+ durationMs: number;
244
+ };
245
+ /** Cumulative budget accounting for leashed runs. */
246
+ export type AgentRunBudget = {
247
+ /** Total wall-clock spent across legs (ms). */
248
+ spentMs: number;
249
+ /** Remaining wall-clock vs the leg budget (ms; 0 when exhausted). */
250
+ remainingMs: number;
251
+ /** Total tool calls across legs. */
252
+ spentToolCalls: number;
253
+ };
254
+ /**
255
+ * Outcome of an isolated agent run.
256
+ *
257
+ * Delivery guarantee: a run with a non-empty execution record never returns
258
+ * an empty result — when extraction is unrecoverable, `data` carries a
259
+ * mechanical digest (which tools ran, ok/failed counts, bounded excerpts of
260
+ * successful payloads).
261
+ */
262
+ export type AgentRunOutcome = {
263
+ status: AgentRunStatus;
264
+ /** Schema-valid extraction output when `extraction.schema` was given. */
265
+ data?: unknown;
266
+ /** Final research-pass text (the worker's own narrative). */
267
+ content?: string;
268
+ /** Why the research turn ended (honest — see GenerateStopReason). */
269
+ stopReason?: GenerateStopReason | string;
270
+ /**
271
+ * Real tool execution records (params/results/timing). Terminal outcomes
272
+ * carry the WHOLE run's records (all legs — what `data` was built from);
273
+ * `in_progress` legs carry this leg's records only.
274
+ */
275
+ toolExecutions: ToolExecutionRecord[];
276
+ /** Aggregated token usage for the run (research + extraction). */
277
+ usage?: TokenUsage;
278
+ /** Wall-clock duration of this call (ms). */
279
+ durationMs: number;
280
+ /** Present when extraction fell back through the recovery ladder. */
281
+ extractionSource?: string;
282
+ /** Extraction/validation error summary when data is a mechanical digest. */
283
+ extractionError?: string;
284
+ /** Resume handle (status "in_progress" only). */
285
+ handle?: string;
286
+ /** This leg's accounting. */
287
+ leg?: AgentRunLegInfo;
288
+ /** One-line query→outcome summaries for this leg. */
289
+ delta?: string[];
290
+ /** The worker's own stated intent for the next leg. */
291
+ nextPlan?: string;
292
+ /** Tripped waste signatures, if any. */
293
+ wasteSignals?: string[];
294
+ /** Cumulative budget accounting. */
295
+ budget?: AgentRunBudget;
296
+ };
297
+ /** Where a recovered value came from, for observability and outcome fields. */
298
+ export type StructuredRecoverySource = "structured-data" | "raw-json" | "json-fence" | "brace-span" | "top-level-array";
299
+ /** One recovery candidate: source label + parsed (uncoerced) value. */
300
+ export type StructuredRecoveryCandidate = {
301
+ source: StructuredRecoverySource;
302
+ value: unknown;
303
+ };
304
+ /** Result of a structured recovery attempt. */
305
+ export type StructuredRecoveryResult = {
306
+ /** Schema-valid data, when any candidate survived validation. */
307
+ data?: unknown;
308
+ /** Which ladder rung produced the winning candidate. */
309
+ source?: StructuredRecoverySource;
310
+ /** Validation error summaries per failed candidate (for re-ask prompts). */
311
+ errors: string[];
312
+ };
313
+ /** Mechanical digest shape (delivery-guarantee fallback payload). */
314
+ export type AgentMechanicalDigest = {
315
+ kind: "mechanical-digest";
316
+ toolsRun: Record<string, {
317
+ calls: number;
318
+ ok: number;
319
+ failed: number;
320
+ }>;
321
+ excerpts: Array<{
322
+ toolName: string;
323
+ params: string;
324
+ resultText: string;
325
+ }>;
326
+ };
327
+ /**
328
+ * Options for `NeuroLink.registerAgentTool()` — wraps an isolated agent as a
329
+ * tool on the HOST instance so its existing generate() loop delegates
330
+ * without a second router generate.
331
+ */
332
+ export type AgentToolRegistrationOptions = {
333
+ /** Tool name (default: the agent definition id). */
334
+ name?: string;
335
+ /**
336
+ * Max delegations to this tool per top-level generate() turn, counted in
337
+ * the loop itself. A refused call returns a recovery instruction, never a
338
+ * silent failure.
339
+ */
340
+ maxDelegationsPerTurn?: number;
341
+ /**
342
+ * Max delegation depth (via tool context `agentDepth`). At the limit the
343
+ * tool is withheld from the request entirely.
344
+ */
345
+ maxDepth?: number;
346
+ /**
347
+ * Process-wide concurrent delegation pool size. The pool is shared across
348
+ * all registered agent tools; the largest registered value wins (default
349
+ * 4) — registering raises the pool and can never lower it, so this is NOT
350
+ * a per-agent throttle. Nested delegations (agentDepth > 0) bypass the
351
+ * pool: the outer delegation already holds a slot, and queueing nested
352
+ * work behind a full pool would deadlock it.
353
+ */
354
+ maxConcurrent?: number;
355
+ /** Queue timeout when the pool is saturated (ms, default 30_000). */
356
+ poolQueueTimeoutMs?: number;
357
+ /** Leashed-by-default leg budget for this tool. */
358
+ leg?: AgentLegOptions;
359
+ /** Handle TTL for leashed delegations (ms, default 600_000). */
360
+ handleTtlMs?: number;
361
+ /** Waste thresholds forwarded to each delegated run. */
362
+ waste?: AgentWasteThresholds;
363
+ /** Per-run overrides forwarded to each delegated run. */
364
+ overrides?: AgentRunOverrides;
365
+ };
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Isolated sub-agent runtime types: worker-mode instances, the
3
+ * runIsolatedAgent() two-pass runner, leashed legs/handles, waste detection,
4
+ * and host-loop delegation (registerAgentTool).
5
+ *
6
+ * Design contract: no product policy lives here — every tunable is an option
7
+ * with a sane default, and all shapes were validated against the three
8
+ * production consumers (Curator's research + log-analysis workers, Yama's
9
+ * ContextExplorerService). See docs/plans/2026-07-27-isolated-agent-runner-rfc.md.
10
+ */
11
+ export {};
12
+ //# sourceMappingURL=isolatedAgent.js.map
@@ -122,6 +122,14 @@ export type ModelCapabilities = {
122
122
  multimodal: boolean;
123
123
  streaming: boolean;
124
124
  jsonMode: boolean;
125
+ /**
126
+ * Whether the model accepts classic sampling parameters
127
+ * (`temperature` / `topP`). Reasoning-effort models (Claude Sonnet 5,
128
+ * Opus 4.7+, Fable 5 families) reject them. Optional: unset means
129
+ * supported, and `modelSupportsSamplingParams` falls back to the known
130
+ * family patterns.
131
+ */
132
+ samplingParams?: boolean;
125
133
  };
126
134
  /**
127
135
  * Model pricing information
@@ -10,7 +10,7 @@ import type { JsonValue, UnknownRecord } from "./common.js";
10
10
  import type { Content, ImageWithAltText } from "./content.js";
11
11
  import type { ChatMessage } from "./conversation.js";
12
12
  import type { StreamNoOutputSentinel } from "./noOutputSentinel.js";
13
- import type { AdditionalMemoryUser, GenerateStopReason } from "./generate.js";
13
+ import type { AdditionalMemoryUser, GenerateStopReason, ToolExecutionCaptureOptions } from "./generate.js";
14
14
  import type { AIModelProviderConfig, NeurolinkCredentials } from "./providers.js";
15
15
  import type { TTSChunk, TTSOptions, TTSResult } from "./tts.js";
16
16
  import type { STTOptions, STTResult } from "./stt.js";
@@ -354,6 +354,8 @@ export type StreamOptions = {
354
354
  toolTimeoutMs?: number;
355
355
  /** AbortSignal for external cancellation of the AI call */
356
356
  abortSignal?: AbortSignal;
357
+ /** Bounds for tool execution capture. See GenerateOptions.toolExecutionCapture. */
358
+ toolExecutionCapture?: ToolExecutionCaptureOptions;
357
359
  disableTools?: boolean;
358
360
  /** Disable the schema-driven tool call repair mechanism (BZ-665). Default: false (repair enabled). */
359
361
  disableToolCallRepair?: boolean;
@@ -220,9 +220,9 @@ export type NeuroLinkExecutable = {
220
220
  generate(optionsOrPrompt: unknown): Promise<{
221
221
  content: string;
222
222
  toolExecutions?: Array<{
223
- name: string;
224
- input: unknown;
225
- output: unknown;
223
+ toolName: string;
224
+ params: unknown;
225
+ resultText: string;
226
226
  }>;
227
227
  usage?: {
228
228
  input?: number;
@@ -32,9 +32,16 @@ declare class NeuroLinkLogger {
32
32
  }): void;
33
33
  /**
34
34
  * Clears the event emitter reference.
35
- * Should be called when a NeuroLink instance is disposed to prevent memory leaks.
35
+ * Should be called when a NeuroLink instance is disposed to prevent memory
36
+ * leaks. Pass the disposing instance's emitter so a short-lived instance
37
+ * (e.g. a worker sub-agent) only clears the bridge when it actually owns
38
+ * it — never yanking a host instance's live log bridge.
39
+ *
40
+ * @param ifEmitter - When provided, clear only if it is the current emitter
36
41
  */
37
- clearEventEmitter(): void;
42
+ clearEventEmitter(ifEmitter?: {
43
+ emit: (event: string, ...args: unknown[]) => boolean;
44
+ }): void;
38
45
  /**
39
46
  * Sets the minimum log level that will be processed and output.
40
47
  * Log messages with a level lower than this will be ignored.
@@ -220,7 +227,9 @@ export declare const logger: {
220
227
  setEventEmitter: (emitter: {
221
228
  emit: (event: string, ...args: unknown[]) => boolean;
222
229
  }) => void;
223
- clearEventEmitter: () => void;
230
+ clearEventEmitter: (ifEmitter?: {
231
+ emit: (event: string, ...args: unknown[]) => boolean;
232
+ }) => void;
224
233
  };
225
234
  /**
226
235
  * MCP compatibility exports - all use the same unified logger instance.
@@ -64,9 +64,17 @@ class NeuroLinkLogger {
64
64
  }
65
65
  /**
66
66
  * Clears the event emitter reference.
67
- * Should be called when a NeuroLink instance is disposed to prevent memory leaks.
67
+ * Should be called when a NeuroLink instance is disposed to prevent memory
68
+ * leaks. Pass the disposing instance's emitter so a short-lived instance
69
+ * (e.g. a worker sub-agent) only clears the bridge when it actually owns
70
+ * it — never yanking a host instance's live log bridge.
71
+ *
72
+ * @param ifEmitter - When provided, clear only if it is the current emitter
68
73
  */
69
- clearEventEmitter() {
74
+ clearEventEmitter(ifEmitter) {
75
+ if (ifEmitter !== undefined && this.eventEmitter !== ifEmitter) {
76
+ return;
77
+ }
70
78
  this.eventEmitter = undefined;
71
79
  }
72
80
  /**
@@ -462,7 +470,7 @@ export const logger = {
462
470
  getLogs: (level) => neuroLinkLogger.getLogs(level),
463
471
  clearLogs: () => neuroLinkLogger.clearLogs(),
464
472
  setEventEmitter: (emitter) => neuroLinkLogger.setEventEmitter(emitter),
465
- clearEventEmitter: () => neuroLinkLogger.clearEventEmitter(),
473
+ clearEventEmitter: (ifEmitter) => neuroLinkLogger.clearEventEmitter(ifEmitter),
466
474
  };
467
475
  /**
468
476
  * MCP compatibility exports - all use the same unified logger instance.
@@ -34,6 +34,20 @@ export declare function transformToolExecutionsForMCP(toolExecutions?: unknown[]
34
34
  success: boolean;
35
35
  serverId?: string;
36
36
  }>;
37
+ /**
38
+ * Convert ToolExecutionRecord entries (or legacy-shaped entries) to the
39
+ * TaskRunResult.toolCalls shape. Single source for the task executors so the
40
+ * name fallback (`toolName` → legacy `name`) can't drift between them.
41
+ */
42
+ export declare function toolExecutionRecordsToToolCalls(records: Array<{
43
+ toolName?: string;
44
+ params?: unknown;
45
+ resultText?: string;
46
+ }> | undefined): Array<{
47
+ name: string;
48
+ input: unknown;
49
+ output: unknown;
50
+ }> | undefined;
37
51
  /**
38
52
  * Transform available tools from internal format to GenerateResult format
39
53
  * Ensures consistent tool information structure across the API with schema normalization
@@ -60,8 +60,9 @@ export function transformToolExecutions(toolExecutions) {
60
60
  rawRecordKeys: Object.keys(teRecord),
61
61
  };
62
62
  logger.debug("[TransformationUtils] Tool parameter extraction analysis", parameterExtractionData);
63
- // Enhanced input extraction
63
+ // Enhanced input extraction (params = ToolExecutionRecord)
64
64
  let input = teRecord.input ||
65
+ teRecord.params ||
65
66
  teRecord.parameters ||
66
67
  teRecord.args ||
67
68
  {};
@@ -149,12 +150,15 @@ export function transformToolExecutions(toolExecutions) {
149
150
  };
150
151
  logger.debug("[TransformationUtils] Final parameter extraction result", finalExtractionSummary);
151
152
  // Enhanced output extraction with success indication
152
- const output = teRecord.output ||
153
- teRecord.result ||
154
- teRecord.response ||
153
+ // (resultText = ToolExecutionRecord — preserve the captured result)
154
+ const output = teRecord.output ??
155
+ teRecord.result ??
156
+ teRecord.response ??
157
+ teRecord.resultText ??
155
158
  "success";
156
- // Enhanced duration extraction
157
- const duration = teRecord.duration ??
159
+ // Enhanced duration extraction (durationMs = ToolExecutionRecord)
160
+ const duration = teRecord.durationMs ??
161
+ teRecord.duration ??
158
162
  teRecord.executionTime ??
159
163
  teRecord.responseTime ??
160
164
  0;
@@ -193,15 +197,19 @@ export function transformToolExecutionsForMCP(toolExecutions) {
193
197
  if (!toolName) {
194
198
  toolName = `mcp_tool_execution_${index}`;
195
199
  }
196
- // Enhanced execution time extraction
197
- const executionTime = teRecord.duration ??
200
+ // Enhanced execution time extraction (durationMs = ToolExecutionRecord)
201
+ const executionTime = teRecord.durationMs ??
202
+ teRecord.duration ??
198
203
  teRecord.executionTime ??
199
204
  teRecord.responseTime ??
200
205
  0;
201
206
  // Enhanced success detection - check for actual success indicators
202
207
  let success = true; // Default to true
203
- // Check for explicit success/error indicators
204
- if (teRecord.success !== undefined) {
208
+ // Check for explicit success/error indicators (isError = ToolExecutionRecord)
209
+ if (teRecord.isError !== undefined) {
210
+ success = !teRecord.isError;
211
+ }
212
+ else if (teRecord.success !== undefined) {
205
213
  success = Boolean(teRecord.success);
206
214
  }
207
215
  else if (teRecord.error !== undefined) {
@@ -234,6 +242,21 @@ export function transformToolExecutionsForMCP(toolExecutions) {
234
242
  };
235
243
  });
236
244
  }
245
+ /**
246
+ * Convert ToolExecutionRecord entries (or legacy-shaped entries) to the
247
+ * TaskRunResult.toolCalls shape. Single source for the task executors so the
248
+ * name fallback (`toolName` → legacy `name`) can't drift between them.
249
+ */
250
+ export function toolExecutionRecordsToToolCalls(records) {
251
+ return records?.map((te) => {
252
+ const legacy = te;
253
+ return {
254
+ name: te.toolName ?? legacy.name ?? "unknown",
255
+ input: te.params ?? legacy.input,
256
+ output: te.resultText ?? legacy.output,
257
+ };
258
+ });
259
+ }
237
260
  // ============================================================================
238
261
  // AVAILABLE TOOLS TRANSFORMATIONS
239
262
  // ============================================================================
@@ -163,7 +163,7 @@ export function defineRealtimeVoiceAgent(config = {}) {
163
163
  const sinceConnect = () => Date.now() - connectedAt;
164
164
  if (onLog) {
165
165
  const room = ctx.room.name ?? "unknown";
166
- logger.setEventEmitter({
166
+ const voiceLogEmitter = {
167
167
  emit: (event, ...args) => {
168
168
  if (event === "log-event") {
169
169
  const decoded = realtimeLogEventSchema.safeParse(args[0]);
@@ -178,9 +178,12 @@ export function defineRealtimeVoiceAgent(config = {}) {
178
178
  }
179
179
  return true;
180
180
  },
181
- });
181
+ };
182
+ logger.setEventEmitter(voiceLogEmitter);
182
183
  ctx.addShutdownCallback(async () => {
183
- logger.clearEventEmitter();
184
+ // Clear only if this agent's emitter is still the active sink —
185
+ // never yank a bridge some other instance installed since.
186
+ logger.clearEventEmitter(voiceLogEmitter);
184
187
  });
185
188
  }
186
189
  logger.info("realtime.room.joined", {
@@ -33,6 +33,29 @@ export declare function getModelById(id: string): ModelInfo | undefined;
33
33
  * custom models retain the existing behavior until capability data is added.
34
34
  */
35
35
  export declare function modelSupports(capability: keyof ModelCapabilities, provider: string, model: string): boolean;
36
+ /**
37
+ * Whether a model accepts classic sampling parameters
38
+ * (`temperature` / `topP`).
39
+ *
40
+ * Resolution order: an explicit `capabilities.samplingParams` on a matching
41
+ * registry entry wins; otherwise the known rejecting-family patterns decide.
42
+ * Unknown models default to supported (same fail-open contract as
43
+ * `modelSupports`). Providers strip the parameters — including on
44
+ * retry/fallback request rebuilds — when this returns false.
45
+ */
46
+ export declare function modelSupportsSamplingParams(provider: string, model: string | undefined): boolean;
47
+ /**
48
+ * Sampling params to actually send for a model: passthrough when supported,
49
+ * `{}` (with a debug log) when the model rejects them. Apply at every
50
+ * request-build site, including retry/fallback rebuilds.
51
+ */
52
+ export declare function resolveSamplingParams(provider: string, model: string | undefined, params: {
53
+ temperature?: number;
54
+ topP?: number;
55
+ }, site: string): {
56
+ temperature?: number;
57
+ topP?: number;
58
+ };
36
59
  /**
37
60
  * Get models by provider
38
61
  */