lemura 1.4.4 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -5,6 +5,22 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.5.0] - 2026-05-27
9
+
10
+ ### Added
11
+
12
+ - **`SessionManager.stream()`**: New `async *stream(userMessage)` method that runs the full ReAct loop (tool calls, goal verification, corrections) and then streams the final assistant response token-by-token as an `AsyncIterable<string>`. All tool use and verification completes before the first token is yielded, so callers always receive a clean, final response.
13
+
14
+ - **`GoalVerifierResult` interface** (`src/types/agent.ts`): Return type for `goalVerifier` callbacks and the built-in LLM-based checker. Fields: `achieved: boolean`, `missing?: string` (injected as a follow-up user message when false), `reason?: string` (surfaced in trace events).
15
+
16
+ - **`SessionConfig.goalVerifier`**: Optional user-supplied async callback `(goal: Goal, turns: Turn[]) => Promise<GoalVerifierResult> | GoalVerifierResult`. Called after the ReAct loop reaches a `stop` finish reason when `enableGoalPlanning` is `true`. Returning `{ achieved: false, missing: '...' }` injects a silent correction loop (capped at one retry). When omitted and `successCriteria` is non-empty, Lemura falls back to a built-in LLM check.
17
+
18
+ - **`SessionConfig.enableGoalVerification`**: Boolean flag to opt out of post-run goal verification. Defaults to `true` when `enableGoalPlanning` is set. Set to `false` to skip the verifier step entirely without removing `enableGoalPlanning`.
19
+
20
+ - **`SessionManager._executeLoop()`**: Internal refactor — `run()` and `stream()` now share a single `_executeLoop()` core that handles tool dispatch, goal injection, step budgets, and verification. Only the final-response step differs between the two public methods.
21
+
22
+ - **`GoalVerification.test.ts`**: Unit tests covering the `goalVerifier` callback path, the built-in LLM verifier fallback, and the `enableGoalVerification: false` opt-out.
23
+
8
24
  ## [1.4.4] - 2026-05-21
9
25
 
10
26
  ### Added
package/README.md CHANGED
@@ -86,6 +86,11 @@ async function main() {
86
86
 
87
87
  const response = await session.run('What is lemura?');
88
88
  console.log(response);
89
+
90
+ // Or stream the final response token-by-token
91
+ for await (const token of session.stream('What is lemura?')) {
92
+ process.stdout.write(token);
93
+ }
89
94
  }
90
95
 
91
96
  main();
@@ -1,4 +1,4 @@
1
- import { a as IProviderAdapter, l as CompletionRequest, m as CompletionResponse, k as CompletionChunk, M as ModelInfo, T as TranscriptionRequest, d as TranscriptionResponse, e as SynthesisRequest, A as AudioChunk, V as VisionRequest, f as VisionResponse, g as ImageGenRequest, h as ImageGenResponse } from '../adapters-BhTAnrOM.mjs';
1
+ import { a as IProviderAdapter, l as CompletionRequest, m as CompletionResponse, k as CompletionChunk, M as ModelInfo, d as TranscriptionRequest, e as TranscriptionResponse, f as SynthesisRequest, A as AudioChunk, V as VisionRequest, g as VisionResponse, h as ImageGenRequest, i as ImageGenResponse } from '../adapters-S96Ka9wt.mjs';
2
2
  import '../rag-La_Bo-J8.mjs';
3
3
  import '../logger-DxvKliuk.mjs';
4
4
 
@@ -1,4 +1,4 @@
1
- import { a as IProviderAdapter, l as CompletionRequest, m as CompletionResponse, k as CompletionChunk, M as ModelInfo, T as TranscriptionRequest, d as TranscriptionResponse, e as SynthesisRequest, A as AudioChunk, V as VisionRequest, f as VisionResponse, g as ImageGenRequest, h as ImageGenResponse } from '../adapters-CVcfWf85.js';
1
+ import { a as IProviderAdapter, l as CompletionRequest, m as CompletionResponse, k as CompletionChunk, M as ModelInfo, d as TranscriptionRequest, e as TranscriptionResponse, f as SynthesisRequest, A as AudioChunk, V as VisionRequest, g as VisionResponse, h as ImageGenRequest, i as ImageGenResponse } from '../adapters-DHQOGl8Y.js';
2
2
  import '../rag-La_Bo-J8.js';
3
3
  import '../logger-DxvKliuk.js';
4
4
 
@@ -363,4 +363,4 @@ interface IProviderAdapter {
363
363
  healthCheck(): Promise<boolean>;
364
364
  }
365
365
 
366
- export { type AudioChunk as A, type ContextWindow as C, type IToolDefinition as I, type ModelInfo as M, type NormalizedMessage as N, ShortTermMemoryRegistry as S, type TranscriptionRequest as T, type VisionRequest as V, type IProviderAdapter as a, type IContextStrategy as b, type IScratchpadAdapter as c, type TranscriptionResponse as d, type SynthesisRequest as e, type VisionResponse as f, type ImageGenRequest as g, type ImageGenResponse as h, type Turn as i, type ContentBlock as j, type CompletionChunk as k, type CompletionRequest as l, type CompletionResponse as m, type IStorageAdapter as n, type STMItem as o, type STMRegistryConfig as p, type TokenUsage as q, type ToolCall as r, type ToolContext as s, type ToolResult as t };
366
+ export { type AudioChunk as A, type ContextWindow as C, type IToolDefinition as I, type ModelInfo as M, type NormalizedMessage as N, ShortTermMemoryRegistry as S, type Turn as T, type VisionRequest as V, type IProviderAdapter as a, type IContextStrategy as b, type IScratchpadAdapter as c, type TranscriptionRequest as d, type TranscriptionResponse as e, type SynthesisRequest as f, type VisionResponse as g, type ImageGenRequest as h, type ImageGenResponse as i, type ContentBlock as j, type CompletionChunk as k, type CompletionRequest as l, type CompletionResponse as m, type IStorageAdapter as n, type STMItem as o, type STMRegistryConfig as p, type TokenUsage as q, type ToolCall as r, type ToolContext as s, type ToolResult as t };
@@ -363,4 +363,4 @@ interface IProviderAdapter {
363
363
  healthCheck(): Promise<boolean>;
364
364
  }
365
365
 
366
- export { type AudioChunk as A, type ContextWindow as C, type IToolDefinition as I, type ModelInfo as M, type NormalizedMessage as N, ShortTermMemoryRegistry as S, type TranscriptionRequest as T, type VisionRequest as V, type IProviderAdapter as a, type IContextStrategy as b, type IScratchpadAdapter as c, type TranscriptionResponse as d, type SynthesisRequest as e, type VisionResponse as f, type ImageGenRequest as g, type ImageGenResponse as h, type Turn as i, type ContentBlock as j, type CompletionChunk as k, type CompletionRequest as l, type CompletionResponse as m, type IStorageAdapter as n, type STMItem as o, type STMRegistryConfig as p, type TokenUsage as q, type ToolCall as r, type ToolContext as s, type ToolResult as t };
366
+ export { type AudioChunk as A, type ContextWindow as C, type IToolDefinition as I, type ModelInfo as M, type NormalizedMessage as N, ShortTermMemoryRegistry as S, type Turn as T, type VisionRequest as V, type IProviderAdapter as a, type IContextStrategy as b, type IScratchpadAdapter as c, type TranscriptionRequest as d, type TranscriptionResponse as e, type SynthesisRequest as f, type VisionResponse as g, type ImageGenRequest as h, type ImageGenResponse as i, type ContentBlock as j, type CompletionChunk as k, type CompletionRequest as l, type CompletionResponse as m, type IStorageAdapter as n, type STMItem as o, type STMRegistryConfig as p, type TokenUsage as q, type ToolCall as r, type ToolContext as s, type ToolResult as t };
@@ -1,4 +1,4 @@
1
- import { I as IToolDefinition, a as IProviderAdapter, b as IContextStrategy, S as ShortTermMemoryRegistry, c as IScratchpadAdapter } from './adapters-BhTAnrOM.mjs';
1
+ import { I as IToolDefinition, a as IProviderAdapter, b as IContextStrategy, S as ShortTermMemoryRegistry, c as IScratchpadAdapter, T as Turn } from './adapters-S96Ka9wt.mjs';
2
2
  import { I as ILogger } from './logger-DxvKliuk.mjs';
3
3
  import { I as ISkill } from './skills-Y6D7zSSw.mjs';
4
4
  import { I as IRAGAdapter } from './rag-La_Bo-J8.mjs';
@@ -102,6 +102,67 @@ interface MCPJsonRpcResponse {
102
102
  };
103
103
  }
104
104
 
105
+ interface Goal {
106
+ id: string;
107
+ statement: string;
108
+ /** High-level sub-goals decomposed from the main statement */
109
+ decomposition: string[];
110
+ successCriteria: string[];
111
+ injectionFrequency: 'always' | 'every_N_turns' | 'on_compression';
112
+ injectionPosition: 'system_prompt' | 'pre_turn';
113
+ /** Sub-goals already completed — updated via `markSubGoalDone()` */
114
+ completedSubGoals?: string[];
115
+ }
116
+ /**
117
+ * GoalInjector keeps the original task objective visible throughout the ReAct loop,
118
+ * preventing goal drift after many tool calls and context compressions.
119
+ *
120
+ * Usage in SessionManager:
121
+ * - For `system_prompt` position: call `injectInto(prompt)` which appends the goal block.
122
+ * - For `pre_turn` position: call `getFormattedBlock()` and push as a system message.
123
+ */
124
+ declare class GoalInjector {
125
+ private goal;
126
+ private turnsSinceInjection;
127
+ constructor(goal: Goal);
128
+ /**
129
+ * Returns the formatted `[CURRENT GOAL]` block string — without caring about
130
+ * where it will be placed. Callers decide whether to append to a system prompt
131
+ * or push as a separate message.
132
+ */
133
+ getFormattedBlock(): string;
134
+ /**
135
+ * Appends the goal block to the given prompt string (for `system_prompt` position).
136
+ * For `pre_turn` position, use `getFormattedBlock()` directly.
137
+ *
138
+ * @param prompt - The existing system prompt to append to.
139
+ */
140
+ injectInto(prompt: string): string;
141
+ /**
142
+ * Returns true when the goal should be re-injected this turn,
143
+ * based on `injectionFrequency`.
144
+ *
145
+ * @param turnIndex - The current turn index in the ReAct loop (0-based)
146
+ * @param compressionOccurred - Whether context was compressed this iteration
147
+ * @param injectionN - The N for 'every_N_turns' frequency (default: 3)
148
+ */
149
+ shouldInjectThisTurn(turnIndex: number, compressionOccurred?: boolean, injectionN?: number): boolean;
150
+ /**
151
+ * Updates the goal with new sub-goal decomposition and success criteria,
152
+ * typically populated by the mini-planning LLM call.
153
+ */
154
+ updateDecomposition(decomposition: string[], successCriteria?: string[]): void;
155
+ /**
156
+ * Marks a sub-goal as completed so it moves to the "completed" section
157
+ * in subsequent injections.
158
+ */
159
+ markSubGoalDone(subGoal: string): void;
160
+ /** Returns a snapshot of the current goal state (safe to store in context.metadata). */
161
+ getGoal(): Goal;
162
+ /** Increments the internal turn counter (used for `every_N_turns` frequency). */
163
+ incrementTurn(): void;
164
+ }
165
+
105
166
  interface ToolResponseEvaluation {
106
167
  relevanceScore: number;
107
168
  sizeClass: 'small' | 'medium' | 'large' | 'oversized';
@@ -160,6 +221,22 @@ interface ToolExecutionBudget {
160
221
  /** Maximum simultaneous parallel tool executions (default: unlimited) */
161
222
  maxConcurrentCalls?: number;
162
223
  }
224
+ /**
225
+ * Result returned by a `goalVerifier` callback or the built-in `successCriteria` checker.
226
+ *
227
+ * @since 1.5.0
228
+ */
229
+ interface GoalVerifierResult {
230
+ /** Whether the original goal was fully achieved */
231
+ achieved: boolean;
232
+ /**
233
+ * When `achieved` is false, describes what is still missing.
234
+ * This text is injected as a follow-up user message to continue the loop.
235
+ */
236
+ missing?: string;
237
+ /** Short human-readable reason for the verdict — surfaced in trace events */
238
+ reason?: string;
239
+ }
163
240
  /** Configuration for a lemura Session */
164
241
  interface SessionConfig {
165
242
  /** The provider adapter to use */
@@ -215,6 +292,13 @@ interface SessionConfig {
215
292
  continuationStrategy?: 'sequential' | 'parallel' | 'conditional';
216
293
  /** Enable goal planning */
217
294
  enableGoalPlanning?: boolean;
295
+ /**
296
+ * Enable post-run goal verification (Option A + C).
297
+ * When true, Lemura checks whether the goal was actually achieved after each stop.
298
+ * Requires `enableGoalPlanning` to also be true. Defaults to true.
299
+ * @since 1.5.0
300
+ */
301
+ enableGoalVerification?: boolean;
218
302
  goalInjectionFrequency?: 'always' | 'every_N_turns' | 'on_compression';
219
303
  goalInjectionPosition?: 'system_prompt' | 'pre_turn';
220
304
  /** Skill budget — max tokens the skill injection block may consume */
@@ -255,6 +339,27 @@ interface SessionConfig {
255
339
  toolRegistryTimeoutMs?: number;
256
340
  /** Callback for granular trace events (planning, budgets, tools, etc.) */
257
341
  onTrace?: (event: TraceEvent) => void;
342
+ /**
343
+ * Optional callback invoked after the ReAct loop reaches a `stop` finish reason.
344
+ *
345
+ * Return `{ achieved: false, missing: '...' }` to continue the loop with the
346
+ * missing work injected as a follow-up user message (capped at one retry).
347
+ * Return `{ achieved: true }` to stop normally.
348
+ *
349
+ * Only called when `enableGoalPlanning` is `true` and a goal statement exists.
350
+ * When omitted and `successCriteria` is non-empty, Lemura falls back to a
351
+ * built-in LLM-based check against those criteria.
352
+ *
353
+ * @since 1.5.0
354
+ * @example
355
+ * goalVerifier: async (goal, turns) => {
356
+ * const last = turns.at(-1)?.content ?? '';
357
+ * return last.includes('DONE')
358
+ * ? { achieved: true }
359
+ * : { achieved: false, missing: 'Final DONE marker not found in output' };
360
+ * }
361
+ */
362
+ goalVerifier?: (goal: Goal, turns: Turn[]) => Promise<GoalVerifierResult> | GoalVerifierResult;
258
363
  /**
259
364
  * MCP (Model Context Protocol) server configurations.
260
365
  * Each server is connected at session construction, its tools are discovered
@@ -281,4 +386,4 @@ interface TraceEvent {
281
386
  metadata?: Record<string, any>;
282
387
  }
283
388
 
284
- export type { IToolResponseProcessor as I, MCPServerConfig as M, SessionConfig as S, ToolResponseEvaluation as T, MCPToolDefinition as a, MCPJsonRpcRequest as b, MCPJsonRpcResponse as c, MCPTransportType as d, MediaConfig as e, ToolDecision as f, ToolExecutionBudget as g, ToolFirewallConfig as h, ToolFirewallRule as i, TraceEvent as j };
389
+ export { type Goal as G, type IToolResponseProcessor as I, type MCPServerConfig as M, type SessionConfig as S, type ToolResponseEvaluation as T, type MCPToolDefinition as a, GoalInjector as b, type GoalVerifierResult as c, type MCPJsonRpcRequest as d, type MCPJsonRpcResponse as e, type MCPTransportType as f, type MediaConfig as g, type ToolDecision as h, type ToolExecutionBudget as i, type ToolFirewallConfig as j, type ToolFirewallRule as k, type TraceEvent as l };
@@ -1,4 +1,4 @@
1
- import { I as IToolDefinition, a as IProviderAdapter, b as IContextStrategy, S as ShortTermMemoryRegistry, c as IScratchpadAdapter } from './adapters-CVcfWf85.js';
1
+ import { I as IToolDefinition, a as IProviderAdapter, b as IContextStrategy, S as ShortTermMemoryRegistry, c as IScratchpadAdapter, T as Turn } from './adapters-DHQOGl8Y.js';
2
2
  import { I as ILogger } from './logger-DxvKliuk.js';
3
3
  import { I as ISkill } from './skills-Y6D7zSSw.js';
4
4
  import { I as IRAGAdapter } from './rag-La_Bo-J8.js';
@@ -102,6 +102,67 @@ interface MCPJsonRpcResponse {
102
102
  };
103
103
  }
104
104
 
105
+ interface Goal {
106
+ id: string;
107
+ statement: string;
108
+ /** High-level sub-goals decomposed from the main statement */
109
+ decomposition: string[];
110
+ successCriteria: string[];
111
+ injectionFrequency: 'always' | 'every_N_turns' | 'on_compression';
112
+ injectionPosition: 'system_prompt' | 'pre_turn';
113
+ /** Sub-goals already completed — updated via `markSubGoalDone()` */
114
+ completedSubGoals?: string[];
115
+ }
116
+ /**
117
+ * GoalInjector keeps the original task objective visible throughout the ReAct loop,
118
+ * preventing goal drift after many tool calls and context compressions.
119
+ *
120
+ * Usage in SessionManager:
121
+ * - For `system_prompt` position: call `injectInto(prompt)` which appends the goal block.
122
+ * - For `pre_turn` position: call `getFormattedBlock()` and push as a system message.
123
+ */
124
+ declare class GoalInjector {
125
+ private goal;
126
+ private turnsSinceInjection;
127
+ constructor(goal: Goal);
128
+ /**
129
+ * Returns the formatted `[CURRENT GOAL]` block string — without caring about
130
+ * where it will be placed. Callers decide whether to append to a system prompt
131
+ * or push as a separate message.
132
+ */
133
+ getFormattedBlock(): string;
134
+ /**
135
+ * Appends the goal block to the given prompt string (for `system_prompt` position).
136
+ * For `pre_turn` position, use `getFormattedBlock()` directly.
137
+ *
138
+ * @param prompt - The existing system prompt to append to.
139
+ */
140
+ injectInto(prompt: string): string;
141
+ /**
142
+ * Returns true when the goal should be re-injected this turn,
143
+ * based on `injectionFrequency`.
144
+ *
145
+ * @param turnIndex - The current turn index in the ReAct loop (0-based)
146
+ * @param compressionOccurred - Whether context was compressed this iteration
147
+ * @param injectionN - The N for 'every_N_turns' frequency (default: 3)
148
+ */
149
+ shouldInjectThisTurn(turnIndex: number, compressionOccurred?: boolean, injectionN?: number): boolean;
150
+ /**
151
+ * Updates the goal with new sub-goal decomposition and success criteria,
152
+ * typically populated by the mini-planning LLM call.
153
+ */
154
+ updateDecomposition(decomposition: string[], successCriteria?: string[]): void;
155
+ /**
156
+ * Marks a sub-goal as completed so it moves to the "completed" section
157
+ * in subsequent injections.
158
+ */
159
+ markSubGoalDone(subGoal: string): void;
160
+ /** Returns a snapshot of the current goal state (safe to store in context.metadata). */
161
+ getGoal(): Goal;
162
+ /** Increments the internal turn counter (used for `every_N_turns` frequency). */
163
+ incrementTurn(): void;
164
+ }
165
+
105
166
  interface ToolResponseEvaluation {
106
167
  relevanceScore: number;
107
168
  sizeClass: 'small' | 'medium' | 'large' | 'oversized';
@@ -160,6 +221,22 @@ interface ToolExecutionBudget {
160
221
  /** Maximum simultaneous parallel tool executions (default: unlimited) */
161
222
  maxConcurrentCalls?: number;
162
223
  }
224
+ /**
225
+ * Result returned by a `goalVerifier` callback or the built-in `successCriteria` checker.
226
+ *
227
+ * @since 1.5.0
228
+ */
229
+ interface GoalVerifierResult {
230
+ /** Whether the original goal was fully achieved */
231
+ achieved: boolean;
232
+ /**
233
+ * When `achieved` is false, describes what is still missing.
234
+ * This text is injected as a follow-up user message to continue the loop.
235
+ */
236
+ missing?: string;
237
+ /** Short human-readable reason for the verdict — surfaced in trace events */
238
+ reason?: string;
239
+ }
163
240
  /** Configuration for a lemura Session */
164
241
  interface SessionConfig {
165
242
  /** The provider adapter to use */
@@ -215,6 +292,13 @@ interface SessionConfig {
215
292
  continuationStrategy?: 'sequential' | 'parallel' | 'conditional';
216
293
  /** Enable goal planning */
217
294
  enableGoalPlanning?: boolean;
295
+ /**
296
+ * Enable post-run goal verification (Option A + C).
297
+ * When true, Lemura checks whether the goal was actually achieved after each stop.
298
+ * Requires `enableGoalPlanning` to also be true. Defaults to true.
299
+ * @since 1.5.0
300
+ */
301
+ enableGoalVerification?: boolean;
218
302
  goalInjectionFrequency?: 'always' | 'every_N_turns' | 'on_compression';
219
303
  goalInjectionPosition?: 'system_prompt' | 'pre_turn';
220
304
  /** Skill budget — max tokens the skill injection block may consume */
@@ -255,6 +339,27 @@ interface SessionConfig {
255
339
  toolRegistryTimeoutMs?: number;
256
340
  /** Callback for granular trace events (planning, budgets, tools, etc.) */
257
341
  onTrace?: (event: TraceEvent) => void;
342
+ /**
343
+ * Optional callback invoked after the ReAct loop reaches a `stop` finish reason.
344
+ *
345
+ * Return `{ achieved: false, missing: '...' }` to continue the loop with the
346
+ * missing work injected as a follow-up user message (capped at one retry).
347
+ * Return `{ achieved: true }` to stop normally.
348
+ *
349
+ * Only called when `enableGoalPlanning` is `true` and a goal statement exists.
350
+ * When omitted and `successCriteria` is non-empty, Lemura falls back to a
351
+ * built-in LLM-based check against those criteria.
352
+ *
353
+ * @since 1.5.0
354
+ * @example
355
+ * goalVerifier: async (goal, turns) => {
356
+ * const last = turns.at(-1)?.content ?? '';
357
+ * return last.includes('DONE')
358
+ * ? { achieved: true }
359
+ * : { achieved: false, missing: 'Final DONE marker not found in output' };
360
+ * }
361
+ */
362
+ goalVerifier?: (goal: Goal, turns: Turn[]) => Promise<GoalVerifierResult> | GoalVerifierResult;
258
363
  /**
259
364
  * MCP (Model Context Protocol) server configurations.
260
365
  * Each server is connected at session construction, its tools are discovered
@@ -281,4 +386,4 @@ interface TraceEvent {
281
386
  metadata?: Record<string, any>;
282
387
  }
283
388
 
284
- export type { IToolResponseProcessor as I, MCPServerConfig as M, SessionConfig as S, ToolResponseEvaluation as T, MCPToolDefinition as a, MCPJsonRpcRequest as b, MCPJsonRpcResponse as c, MCPTransportType as d, MediaConfig as e, ToolDecision as f, ToolExecutionBudget as g, ToolFirewallConfig as h, ToolFirewallRule as i, TraceEvent as j };
389
+ export { type Goal as G, type IToolResponseProcessor as I, type MCPServerConfig as M, type SessionConfig as S, type ToolResponseEvaluation as T, type MCPToolDefinition as a, GoalInjector as b, type GoalVerifierResult as c, type MCPJsonRpcRequest as d, type MCPJsonRpcResponse as e, type MCPTransportType as f, type MediaConfig as g, type ToolDecision as h, type ToolExecutionBudget as i, type ToolFirewallConfig as j, type ToolFirewallRule as k, type TraceEvent as l };
@@ -1,5 +1,5 @@
1
- import { b as IContextStrategy, C as ContextWindow, a as IProviderAdapter, n as IStorageAdapter, c as IScratchpadAdapter } from '../adapters-BhTAnrOM.mjs';
2
- export { p as STMRegistryConfig, S as ShortTermMemoryRegistry } from '../adapters-BhTAnrOM.mjs';
1
+ import { b as IContextStrategy, C as ContextWindow, a as IProviderAdapter, n as IStorageAdapter, c as IScratchpadAdapter } from '../adapters-S96Ka9wt.mjs';
2
+ export { p as STMRegistryConfig, S as ShortTermMemoryRegistry } from '../adapters-S96Ka9wt.mjs';
3
3
  import '../rag-La_Bo-J8.mjs';
4
4
  import '../logger-DxvKliuk.mjs';
5
5
 
@@ -1,5 +1,5 @@
1
- import { b as IContextStrategy, C as ContextWindow, a as IProviderAdapter, n as IStorageAdapter, c as IScratchpadAdapter } from '../adapters-CVcfWf85.js';
2
- export { p as STMRegistryConfig, S as ShortTermMemoryRegistry } from '../adapters-CVcfWf85.js';
1
+ import { b as IContextStrategy, C as ContextWindow, a as IProviderAdapter, n as IStorageAdapter, c as IScratchpadAdapter } from '../adapters-DHQOGl8Y.js';
2
+ export { p as STMRegistryConfig, S as ShortTermMemoryRegistry } from '../adapters-DHQOGl8Y.js';
3
3
  import '../rag-La_Bo-J8.js';
4
4
  import '../logger-DxvKliuk.js';
5
5
 
package/dist/index.d.mts CHANGED
@@ -1,7 +1,7 @@
1
- import { a as IProviderAdapter, T as TranscriptionRequest, d as TranscriptionResponse, e as SynthesisRequest, A as AudioChunk, V as VisionRequest, f as VisionResponse, g as ImageGenRequest, h as ImageGenResponse, M as ModelInfo, C as ContextWindow, i as Turn, j as ContentBlock, I as IToolDefinition } from './adapters-BhTAnrOM.mjs';
2
- export { k as CompletionChunk, l as CompletionRequest, m as CompletionResponse, b as IContextStrategy, c as IScratchpadAdapter, n as IStorageAdapter, N as NormalizedMessage, o as STMItem, p as STMRegistryConfig, S as ShortTermMemoryRegistry, q as TokenUsage, r as ToolCall, s as ToolContext, t as ToolResult } from './adapters-BhTAnrOM.mjs';
3
- import { S as SessionConfig, I as IToolResponseProcessor, T as ToolResponseEvaluation, M as MCPServerConfig, a as MCPToolDefinition } from './agent-81ZUiP-T.mjs';
4
- export { b as MCPJsonRpcRequest, c as MCPJsonRpcResponse, d as MCPTransportType, e as MediaConfig, f as ToolDecision, g as ToolExecutionBudget, h as ToolFirewallConfig, i as ToolFirewallRule, j as TraceEvent } from './agent-81ZUiP-T.mjs';
1
+ import { a as IProviderAdapter, d as TranscriptionRequest, e as TranscriptionResponse, f as SynthesisRequest, A as AudioChunk, V as VisionRequest, g as VisionResponse, h as ImageGenRequest, i as ImageGenResponse, M as ModelInfo, C as ContextWindow, T as Turn, j as ContentBlock, I as IToolDefinition } from './adapters-S96Ka9wt.mjs';
2
+ export { k as CompletionChunk, l as CompletionRequest, m as CompletionResponse, b as IContextStrategy, c as IScratchpadAdapter, n as IStorageAdapter, N as NormalizedMessage, o as STMItem, p as STMRegistryConfig, S as ShortTermMemoryRegistry, q as TokenUsage, r as ToolCall, s as ToolContext, t as ToolResult } from './adapters-S96Ka9wt.mjs';
3
+ import { S as SessionConfig, G as Goal, I as IToolResponseProcessor, T as ToolResponseEvaluation, M as MCPServerConfig, a as MCPToolDefinition } from './agent-BefjpRHZ.mjs';
4
+ export { b as GoalInjector, c as GoalVerifierResult, d as MCPJsonRpcRequest, e as MCPJsonRpcResponse, f as MCPTransportType, g as MediaConfig, h as ToolDecision, i as ToolExecutionBudget, j as ToolFirewallConfig, k as ToolFirewallRule, l as TraceEvent } from './agent-BefjpRHZ.mjs';
5
5
  export { LemuraAdapterError, LemuraContextOverflowError, LemuraError, LemuraMCPConnectionError, LemuraMCPError, LemuraMCPTimeoutError, LemuraMaxIterationsError, LemuraSkillInjectionError, LemuraToolNotFoundError, LemuraToolTimeoutError, LemuraToolValidationError } from './types/index.mjs';
6
6
  import { I as ILogger } from './logger-DxvKliuk.mjs';
7
7
  export { L as LogLevel, a as LogMetadata, S as Severity } from './logger-DxvKliuk.mjs';
@@ -188,67 +188,6 @@ declare class ContinuationPlanner {
188
188
  private _advanceIndex;
189
189
  }
190
190
 
191
- interface Goal {
192
- id: string;
193
- statement: string;
194
- /** High-level sub-goals decomposed from the main statement */
195
- decomposition: string[];
196
- successCriteria: string[];
197
- injectionFrequency: 'always' | 'every_N_turns' | 'on_compression';
198
- injectionPosition: 'system_prompt' | 'pre_turn';
199
- /** Sub-goals already completed — updated via `markSubGoalDone()` */
200
- completedSubGoals?: string[];
201
- }
202
- /**
203
- * GoalInjector keeps the original task objective visible throughout the ReAct loop,
204
- * preventing goal drift after many tool calls and context compressions.
205
- *
206
- * Usage in SessionManager:
207
- * - For `system_prompt` position: call `injectInto(prompt)` which appends the goal block.
208
- * - For `pre_turn` position: call `getFormattedBlock()` and push as a system message.
209
- */
210
- declare class GoalInjector {
211
- private goal;
212
- private turnsSinceInjection;
213
- constructor(goal: Goal);
214
- /**
215
- * Returns the formatted `[CURRENT GOAL]` block string — without caring about
216
- * where it will be placed. Callers decide whether to append to a system prompt
217
- * or push as a separate message.
218
- */
219
- getFormattedBlock(): string;
220
- /**
221
- * Appends the goal block to the given prompt string (for `system_prompt` position).
222
- * For `pre_turn` position, use `getFormattedBlock()` directly.
223
- *
224
- * @param prompt - The existing system prompt to append to.
225
- */
226
- injectInto(prompt: string): string;
227
- /**
228
- * Returns true when the goal should be re-injected this turn,
229
- * based on `injectionFrequency`.
230
- *
231
- * @param turnIndex - The current turn index in the ReAct loop (0-based)
232
- * @param compressionOccurred - Whether context was compressed this iteration
233
- * @param injectionN - The N for 'every_N_turns' frequency (default: 3)
234
- */
235
- shouldInjectThisTurn(turnIndex: number, compressionOccurred?: boolean, injectionN?: number): boolean;
236
- /**
237
- * Updates the goal with new sub-goal decomposition and success criteria,
238
- * typically populated by the mini-planning LLM call.
239
- */
240
- updateDecomposition(decomposition: string[], successCriteria?: string[]): void;
241
- /**
242
- * Marks a sub-goal as completed so it moves to the "completed" section
243
- * in subsequent injections.
244
- */
245
- markSubGoalDone(subGoal: string): void;
246
- /** Returns a snapshot of the current goal state (safe to store in context.metadata). */
247
- getGoal(): Goal;
248
- /** Increments the internal turn counter (used for `every_N_turns` frequency). */
249
- incrementTurn(): void;
250
- }
251
-
252
191
  /**
253
192
  * Core entry point for lemura agent sessions.
254
193
  *
@@ -449,9 +388,6 @@ declare class SessionManager {
449
388
  /**
450
389
  * Runs the full ReAct loop for a user message and returns the final assistant response.
451
390
  *
452
- * When `enableGoalPlanning` is true and no goal has been manually set, a mini-planning
453
- * LLM call is made before the first iteration to decompose the task into sub-goals.
454
- *
455
391
  * @param userMessage - The user's message (string or multimodal content blocks)
456
392
  * @returns The assistant's final response string
457
393
  * @throws {LemuraMaxIterationsError} When the loop exceeds `maxIterations`
@@ -460,8 +396,8 @@ declare class SessionManager {
460
396
  /**
461
397
  * Runs the ReAct loop and streams the final assistant response token-by-token.
462
398
  *
463
- * Tool calls within the loop are still executed synchronously (they must complete
464
- * before streaming the conclusion). Only the final LLM text output is streamed.
399
+ * All tool calls, goal verification, and corrections complete before any token
400
+ * is yielded the stream delivers only the clean final response.
465
401
  *
466
402
  * @param userMessage - The user's message (string or multimodal content blocks)
467
403
  * @returns An `AsyncIterable<string>` of delta tokens from the final response
@@ -474,6 +410,29 @@ declare class SessionManager {
474
410
  * ```
475
411
  */
476
412
  stream(userMessage: string | ContentBlock[]): AsyncIterable<string>;
413
+ /**
414
+ * Core ReAct execution loop shared by `run()` and `stream()`.
415
+ *
416
+ * Uses `adapter.complete()` exclusively — no streaming occurs here.
417
+ * Goal verification and silent corrections run inside this method,
418
+ * fully isolated from the caller's delivery path.
419
+ *
420
+ * @returns The final assistant response string
421
+ * @throws {LemuraMaxIterationsError} When the loop exceeds `maxIterations`
422
+ */
423
+ private _executeLoop;
424
+ /**
425
+ * Verifies whether the goal was achieved after a `stop` finish.
426
+ *
427
+ * Priority:
428
+ * 1. `config.goalVerifier` callback (Option A — user-supplied)
429
+ * 2. Built-in LLM check against `successCriteria` (Option C — fallback)
430
+ *
431
+ * Returns `null` when verification is skipped (no goal, planning disabled, etc.).
432
+ *
433
+ * @since 1.5.0
434
+ */
435
+ private _verifyGoal;
477
436
  /**
478
437
  * Resets the session: clears conversation history, resets iteration counters,
479
438
  * tool execution budget tallies, and goal/plan state.
@@ -687,4 +646,4 @@ declare class MCPClientRegistry {
687
646
  private _bridge;
688
647
  }
689
648
 
690
- export { AudioChunk, ContentBlock, ContextWindow, type ContinuationPlan, ContinuationPlanner, type ContinuationStep, FinalResponseFormatter, type Goal, GoalInjector, ILogger, IProviderAdapter, IToolDefinition, IToolResponseProcessor, ImageGenRequest, ImageGenResponse, MCPClient, MCPClientRegistry, MCPServerConfig, MCPToolDefinition, MediaBridge, ModelInfo, SessionConfig, SessionManager, SkillInjector, type StepCondition, StepCounter, type StepVerifier, type StepVerifierResult, SynthesisRequest, ToolRegistry, ToolResponseEvaluation, ToolResponseProcessor, type ToolResponseProcessorConfig, TranscriptionRequest, TranscriptionResponse, Turn, VisionRequest, VisionResponse };
649
+ export { AudioChunk, ContentBlock, ContextWindow, type ContinuationPlan, ContinuationPlanner, type ContinuationStep, FinalResponseFormatter, Goal, ILogger, IProviderAdapter, IToolDefinition, IToolResponseProcessor, ImageGenRequest, ImageGenResponse, MCPClient, MCPClientRegistry, MCPServerConfig, MCPToolDefinition, MediaBridge, ModelInfo, SessionConfig, SessionManager, SkillInjector, type StepCondition, StepCounter, type StepVerifier, type StepVerifierResult, SynthesisRequest, ToolRegistry, ToolResponseEvaluation, ToolResponseProcessor, type ToolResponseProcessorConfig, TranscriptionRequest, TranscriptionResponse, Turn, VisionRequest, VisionResponse };