@dudko.dev/agent-web 0.0.5 → 0.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -3,6 +3,39 @@ import { LanguageModel, ToolSet, Tool, ModelMessage, generateText, streamText }
3
3
  import { z, ZodType } from 'zod';
4
4
  import { IDBPDatabase } from 'idb';
5
5
 
6
+ /** A single step of a plan. Mirrors the Node sibling's IPlanStep. */
7
+ interface IPlanStep {
8
+ id: string;
9
+ description: string;
10
+ expectedOutcome?: string;
11
+ /** Tools the planner thinks this step needs (drives 'plan-narrowed' selection). */
12
+ suggestedTools?: string[];
13
+ /** Set by the pipeline when suggestedTools were named but all were unknown. */
14
+ requiresTools?: boolean;
15
+ }
16
+ interface IPlan {
17
+ thought: string;
18
+ steps: IPlanStep[];
19
+ }
20
+ interface IUsage {
21
+ inputTokens: number;
22
+ outputTokens: number;
23
+ totalTokens: number;
24
+ }
25
+ interface IToolCall {
26
+ name: string;
27
+ input: unknown;
28
+ output: unknown;
29
+ ok: boolean;
30
+ }
31
+ interface IStepResult {
32
+ step: IPlanStep;
33
+ summary: string;
34
+ toolCalls: IToolCall[];
35
+ /** True when the executor signalled it could not complete the step ([BLOCKER]). */
36
+ blocked: boolean;
37
+ }
38
+
6
39
  interface StoredMessage {
7
40
  role: 'system' | 'user' | 'assistant';
8
41
  content: string;
@@ -245,6 +278,15 @@ declare const promptHintOf: (tool: Tool) => string | undefined;
245
278
 
246
279
  /** Force a tool-calling strategy, or let the agent pick per model ('auto'). */
247
280
  type ToolMode = 'auto' | 'native' | 'prompted';
281
+ /**
282
+ * When to consult the replanner after an executed step (given `replan` is on):
283
+ * 'failure' — after a blocked step or a failed tool call (default);
284
+ * 'always' — after every step, so the replanner can react to problems the host
285
+ * surfaces via `describeState` (one extra model call per step);
286
+ * predicate — decides per step result; closes over host state if needed, and
287
+ * falls back to 'failure' behaviour if it throws.
288
+ */
289
+ type ReplanTrigger = 'failure' | 'always' | ((result: IStepResult) => boolean | Promise<boolean>);
248
290
  /**
249
291
  * 'all' — the executor sees the full ToolSet on every step.
250
292
  * 'plan-narrowed' — the executor sees only a step's suggestedTools (the planner
@@ -292,7 +334,7 @@ interface BrowserAgentConfig {
292
334
  sessionId?: string;
293
335
  /** Hard cap on executed steps incl. replans (default 8). */
294
336
  maxIterations?: number;
295
- /** Cap on LLM steps inside a single native executor call (default 4). */
337
+ /** Cap on tool-calling rounds inside one executor call, both modes (default 4). */
296
338
  maxStepsPerTask?: number;
297
339
  /** Cap on replanner "revise" decisions per run (default 2). */
298
340
  maxRevisions?: number;
@@ -300,8 +342,10 @@ interface BrowserAgentConfig {
300
342
  chatTimeoutMs?: number;
301
343
  budgets?: PhaseBudgets;
302
344
  temperature?: number;
303
- /** Replan after a blocked/failed step (default true). */
345
+ /** Master switch for the replan phase (default true). */
304
346
  replan?: boolean;
347
+ /** What triggers the replanner when it is on (default 'failure'). */
348
+ replanAfter?: ReplanTrigger;
305
349
  /** Write a final natural-language summary (default true). */
306
350
  synthesize?: boolean;
307
351
  /** Compress stored history past this many chars (0 = off, default 12000). */
@@ -323,45 +367,13 @@ interface ResolvedConfig {
323
367
  budgets: Required<PhaseBudgets>;
324
368
  temperature: number | undefined;
325
369
  replan: boolean;
370
+ replanAfter: ReplanTrigger;
326
371
  synthesize: boolean;
327
372
  compressAfterChars: number;
328
373
  logLevel: LogLevel;
329
374
  }
330
375
  declare const resolveConfig: (c: BrowserAgentConfig) => ResolvedConfig;
331
376
 
332
- /** A single step of a plan. Mirrors the Node sibling's IPlanStep. */
333
- interface IPlanStep {
334
- id: string;
335
- description: string;
336
- expectedOutcome?: string;
337
- /** Tools the planner thinks this step needs (drives 'plan-narrowed' selection). */
338
- suggestedTools?: string[];
339
- /** Set by the pipeline when suggestedTools were named but all were unknown. */
340
- requiresTools?: boolean;
341
- }
342
- interface IPlan {
343
- thought: string;
344
- steps: IPlanStep[];
345
- }
346
- interface IUsage {
347
- inputTokens: number;
348
- outputTokens: number;
349
- totalTokens: number;
350
- }
351
- interface IToolCall {
352
- name: string;
353
- input: unknown;
354
- output: unknown;
355
- ok: boolean;
356
- }
357
- interface IStepResult {
358
- step: IPlanStep;
359
- summary: string;
360
- toolCalls: IToolCall[];
361
- /** True when the executor signalled it could not complete the step ([BLOCKER]). */
362
- blocked: boolean;
363
- }
364
-
365
377
  type ReplanMode = 'continue' | 'revise' | 'finish';
366
378
  type Phase = 'plan' | 'execute' | 'replan' | 'synthesize';
367
379
  /**
@@ -560,8 +572,28 @@ declare const executeStep: (ctx: AgentContext, goal: string, step: IPlanStep, in
560
572
  result: IStepResult;
561
573
  usage: IUsage;
562
574
  }>;
563
- /** The replanner runs when a step was blocked or any of its tool calls failed. */
575
+ /**
576
+ * The replanner runs when a step was blocked or a tool call failed and stayed
577
+ * failed. A failure that a LATER call to the same tool retried successfully is
578
+ * resolved — the prompted feedback loop (and native multi-step) let the model
579
+ * self-correct within the step, so it must not force a replan.
580
+ */
564
581
  declare const shouldReplan: (result: IStepResult) => boolean;
582
+ /** Bound a host `replanAfter` predicate by the same watchdog/abort as a model call. */
583
+ interface ReplanWantedOptions {
584
+ signal?: AbortSignal;
585
+ timeoutMs?: number;
586
+ /** Called with whatever a host predicate threw before falling back to 'failure'. */
587
+ onError?: (err: unknown) => void;
588
+ }
589
+ /**
590
+ * Resolve the configured `replanAfter` trigger for one step result. 'failure'
591
+ * is the classic `shouldReplan`; 'always' consults the replanner after every
592
+ * step; a host predicate decides per result. A predicate that throws, rejects,
593
+ * or outlives the watchdog/abort falls back to 'failure' behaviour so a buggy
594
+ * or hung predicate can never stall the run (its throw is surfaced via onError).
595
+ */
596
+ declare const replanWanted: (trigger: ReplanTrigger, result: IStepResult, opts?: ReplanWantedOptions) => Promise<boolean>;
565
597
 
566
598
  /**
567
599
  * Robust parsing of model output. Small in-browser models emit JSON wrapped in
@@ -803,7 +835,7 @@ interface ToolLoopOptions {
803
835
  * them to the SDK's `activeTools`; prompted mode bounds `dispatch` to them.
804
836
  */
805
837
  activeTools?: string[];
806
- /** Native mode: cap on internal tool-calling steps (default 4). */
838
+ /** Cap on tool-calling rounds within this call, in both modes (default 4). */
807
839
  maxSteps?: number;
808
840
  maxOutputTokens?: number;
809
841
  temperature?: number;
@@ -817,11 +849,12 @@ interface ToolLoopResult {
817
849
  usage: IUsage;
818
850
  }
819
851
  /**
820
- * Run one round of tool-calling in whichever mode the model needs, returning a
821
- * normalised result. Native mode streams the SDK's multi-step function-calling;
822
- * prompted mode does a single generation, salvages a `{ reply, actions }` JSON
823
- * from the text, and dispatches each action through the tool's own execute.
824
- * Both call the exact same tool implementations.
852
+ * Run tool-calling in whichever mode the model needs, returning a normalised
853
+ * result. Native mode streams the SDK's multi-step function-calling; prompted
854
+ * mode salvages `{ reply, actions }` JSON out of plain text, dispatches each
855
+ * action through the tool's own execute, then feeds the TOOL RESULTS back and
856
+ * lets the model continue the same task — up to `maxSteps` rounds in both
857
+ * modes. Both modes call the exact same tool implementations.
825
858
  */
826
859
  declare const runToolLoop: (model: LanguageModel, opts: ToolLoopOptions) => Promise<ToolLoopResult>;
827
860
 
@@ -926,4 +959,4 @@ interface CompressOptions {
926
959
  */
927
960
  declare const compressHistory: (messages: StoredMessage[], model: LanguageModel, opts?: CompressOptions) => Promise<StoredMessage[]>;
928
961
 
929
- export { type Agent, type AgentContext, type AgentEvent, type AgentEventHandler, type AgentLogger, type AgentLoggerSink, type AgentTool, type AgentToolSet, type AgentWebDBOptions, type BrowserAgentConfig, type CompressOptions, type ContextStore, type CredentialStore, type EncryptedBlob, type ExecutorPromptContext, type ExecutorResult, type GenerateOptions, type IPlan, type IPlanStep, type IStepResult, type IToolCall, type IUsage, IndexedDBStore, type IndexedDBStoreOptions, IndexedDBVault, KEYS_STORE, type LogLevel, MemoryCredentialStore, MemoryStore, type ModelInput, type Phase, type PhaseBudgets, PlanSchema, type PlanShape, PlanStepSchema, type PlannerPromptContext, type PlannerResult, type PromptParts, type Prompts, type ProviderModelSpec, type ProviderType, type RawAction, type ReplanDecision, type ReplanMode, ReplanSchema, type ReplanShape, type ReplannerPromptContext, type ReplannerResult, type ResolvedConfig, type ResolvedStage, type RunOptions, type RunResult, SECRETS_STORE, SESSIONS_STORE, type StageInput, type StageOverride, type StoredMessage, type SynthesizerPromptContext, type ToolCallMode, type ToolLoopCallbacks, type ToolLoopOptions, type ToolLoopResult, type ToolMode, type ToolSelectionStrategy, VaultCredentialStore, type VaultOptions, type WebLLMModelOptions, buildModelFromStage, compressHistory, createAgent, createLogger, createPlan, createWebLLMModel, decideReplan, decryptJSON, defaultPrompts, defineTool, directBrowserOk, dispatch, encryptJSON, executeStep, generate, generateStructured, getOrCreateVaultKey, isDirectModel, isProviderSpec, isWebGPUAvailable, looksLikeJson, normalizeSteps, normalizeUsage, openAgentWebDB, parseExecutorResponse, parsePlainText, parsePlannerResponse, parseReplannerResponse, preloadWebLLMModel, promptHintOf, renderCatalog, resolveConfig, resolveModel, resolveStage, runToolLoop, selectToolMode, shouldReplan, splitBlocker, stream, supportsNativeTools, supportsStructuredOutput, synthesizeAnswer, unloadWebLLMModel, withSystem };
962
+ export { type Agent, type AgentContext, type AgentEvent, type AgentEventHandler, type AgentLogger, type AgentLoggerSink, type AgentTool, type AgentToolSet, type AgentWebDBOptions, type BrowserAgentConfig, type CompressOptions, type ContextStore, type CredentialStore, type EncryptedBlob, type ExecutorPromptContext, type ExecutorResult, type GenerateOptions, type IPlan, type IPlanStep, type IStepResult, type IToolCall, type IUsage, IndexedDBStore, type IndexedDBStoreOptions, IndexedDBVault, KEYS_STORE, type LogLevel, MemoryCredentialStore, MemoryStore, type ModelInput, type Phase, type PhaseBudgets, PlanSchema, type PlanShape, PlanStepSchema, type PlannerPromptContext, type PlannerResult, type PromptParts, type Prompts, type ProviderModelSpec, type ProviderType, type RawAction, type ReplanDecision, type ReplanMode, ReplanSchema, type ReplanShape, type ReplanTrigger, type ReplannerPromptContext, type ReplannerResult, type ResolvedConfig, type ResolvedStage, type RunOptions, type RunResult, SECRETS_STORE, SESSIONS_STORE, type StageInput, type StageOverride, type StoredMessage, type SynthesizerPromptContext, type ToolCallMode, type ToolLoopCallbacks, type ToolLoopOptions, type ToolLoopResult, type ToolMode, type ToolSelectionStrategy, VaultCredentialStore, type VaultOptions, type WebLLMModelOptions, buildModelFromStage, compressHistory, createAgent, createLogger, createPlan, createWebLLMModel, decideReplan, decryptJSON, defaultPrompts, defineTool, directBrowserOk, dispatch, encryptJSON, executeStep, generate, generateStructured, getOrCreateVaultKey, isDirectModel, isProviderSpec, isWebGPUAvailable, looksLikeJson, normalizeSteps, normalizeUsage, openAgentWebDB, parseExecutorResponse, parsePlainText, parsePlannerResponse, parseReplannerResponse, preloadWebLLMModel, promptHintOf, renderCatalog, replanWanted, resolveConfig, resolveModel, resolveStage, runToolLoop, selectToolMode, shouldReplan, splitBlocker, stream, supportsNativeTools, supportsStructuredOutput, synthesizeAnswer, unloadWebLLMModel, withSystem };
package/dist/index.d.ts CHANGED
@@ -3,6 +3,39 @@ import { LanguageModel, ToolSet, Tool, ModelMessage, generateText, streamText }
3
3
  import { z, ZodType } from 'zod';
4
4
  import { IDBPDatabase } from 'idb';
5
5
 
6
+ /** A single step of a plan. Mirrors the Node sibling's IPlanStep. */
7
+ interface IPlanStep {
8
+ id: string;
9
+ description: string;
10
+ expectedOutcome?: string;
11
+ /** Tools the planner thinks this step needs (drives 'plan-narrowed' selection). */
12
+ suggestedTools?: string[];
13
+ /** Set by the pipeline when suggestedTools were named but all were unknown. */
14
+ requiresTools?: boolean;
15
+ }
16
+ interface IPlan {
17
+ thought: string;
18
+ steps: IPlanStep[];
19
+ }
20
+ interface IUsage {
21
+ inputTokens: number;
22
+ outputTokens: number;
23
+ totalTokens: number;
24
+ }
25
+ interface IToolCall {
26
+ name: string;
27
+ input: unknown;
28
+ output: unknown;
29
+ ok: boolean;
30
+ }
31
+ interface IStepResult {
32
+ step: IPlanStep;
33
+ summary: string;
34
+ toolCalls: IToolCall[];
35
+ /** True when the executor signalled it could not complete the step ([BLOCKER]). */
36
+ blocked: boolean;
37
+ }
38
+
6
39
  interface StoredMessage {
7
40
  role: 'system' | 'user' | 'assistant';
8
41
  content: string;
@@ -245,6 +278,15 @@ declare const promptHintOf: (tool: Tool) => string | undefined;
245
278
 
246
279
  /** Force a tool-calling strategy, or let the agent pick per model ('auto'). */
247
280
  type ToolMode = 'auto' | 'native' | 'prompted';
281
+ /**
282
+ * When to consult the replanner after an executed step (given `replan` is on):
283
+ * 'failure' — after a blocked step or a failed tool call (default);
284
+ * 'always' — after every step, so the replanner can react to problems the host
285
+ * surfaces via `describeState` (one extra model call per step);
286
+ * predicate — decides per step result; closes over host state if needed, and
287
+ * falls back to 'failure' behaviour if it throws.
288
+ */
289
+ type ReplanTrigger = 'failure' | 'always' | ((result: IStepResult) => boolean | Promise<boolean>);
248
290
  /**
249
291
  * 'all' — the executor sees the full ToolSet on every step.
250
292
  * 'plan-narrowed' — the executor sees only a step's suggestedTools (the planner
@@ -292,7 +334,7 @@ interface BrowserAgentConfig {
292
334
  sessionId?: string;
293
335
  /** Hard cap on executed steps incl. replans (default 8). */
294
336
  maxIterations?: number;
295
- /** Cap on LLM steps inside a single native executor call (default 4). */
337
+ /** Cap on tool-calling rounds inside one executor call, both modes (default 4). */
296
338
  maxStepsPerTask?: number;
297
339
  /** Cap on replanner "revise" decisions per run (default 2). */
298
340
  maxRevisions?: number;
@@ -300,8 +342,10 @@ interface BrowserAgentConfig {
300
342
  chatTimeoutMs?: number;
301
343
  budgets?: PhaseBudgets;
302
344
  temperature?: number;
303
- /** Replan after a blocked/failed step (default true). */
345
+ /** Master switch for the replan phase (default true). */
304
346
  replan?: boolean;
347
+ /** What triggers the replanner when it is on (default 'failure'). */
348
+ replanAfter?: ReplanTrigger;
305
349
  /** Write a final natural-language summary (default true). */
306
350
  synthesize?: boolean;
307
351
  /** Compress stored history past this many chars (0 = off, default 12000). */
@@ -323,45 +367,13 @@ interface ResolvedConfig {
323
367
  budgets: Required<PhaseBudgets>;
324
368
  temperature: number | undefined;
325
369
  replan: boolean;
370
+ replanAfter: ReplanTrigger;
326
371
  synthesize: boolean;
327
372
  compressAfterChars: number;
328
373
  logLevel: LogLevel;
329
374
  }
330
375
  declare const resolveConfig: (c: BrowserAgentConfig) => ResolvedConfig;
331
376
 
332
- /** A single step of a plan. Mirrors the Node sibling's IPlanStep. */
333
- interface IPlanStep {
334
- id: string;
335
- description: string;
336
- expectedOutcome?: string;
337
- /** Tools the planner thinks this step needs (drives 'plan-narrowed' selection). */
338
- suggestedTools?: string[];
339
- /** Set by the pipeline when suggestedTools were named but all were unknown. */
340
- requiresTools?: boolean;
341
- }
342
- interface IPlan {
343
- thought: string;
344
- steps: IPlanStep[];
345
- }
346
- interface IUsage {
347
- inputTokens: number;
348
- outputTokens: number;
349
- totalTokens: number;
350
- }
351
- interface IToolCall {
352
- name: string;
353
- input: unknown;
354
- output: unknown;
355
- ok: boolean;
356
- }
357
- interface IStepResult {
358
- step: IPlanStep;
359
- summary: string;
360
- toolCalls: IToolCall[];
361
- /** True when the executor signalled it could not complete the step ([BLOCKER]). */
362
- blocked: boolean;
363
- }
364
-
365
377
  type ReplanMode = 'continue' | 'revise' | 'finish';
366
378
  type Phase = 'plan' | 'execute' | 'replan' | 'synthesize';
367
379
  /**
@@ -560,8 +572,28 @@ declare const executeStep: (ctx: AgentContext, goal: string, step: IPlanStep, in
560
572
  result: IStepResult;
561
573
  usage: IUsage;
562
574
  }>;
563
- /** The replanner runs when a step was blocked or any of its tool calls failed. */
575
+ /**
576
+ * The replanner runs when a step was blocked or a tool call failed and stayed
577
+ * failed. A failure that a LATER call to the same tool retried successfully is
578
+ * resolved — the prompted feedback loop (and native multi-step) let the model
579
+ * self-correct within the step, so it must not force a replan.
580
+ */
564
581
  declare const shouldReplan: (result: IStepResult) => boolean;
582
+ /** Bound a host `replanAfter` predicate by the same watchdog/abort as a model call. */
583
+ interface ReplanWantedOptions {
584
+ signal?: AbortSignal;
585
+ timeoutMs?: number;
586
+ /** Called with whatever a host predicate threw before falling back to 'failure'. */
587
+ onError?: (err: unknown) => void;
588
+ }
589
+ /**
590
+ * Resolve the configured `replanAfter` trigger for one step result. 'failure'
591
+ * is the classic `shouldReplan`; 'always' consults the replanner after every
592
+ * step; a host predicate decides per result. A predicate that throws, rejects,
593
+ * or outlives the watchdog/abort falls back to 'failure' behaviour so a buggy
594
+ * or hung predicate can never stall the run (its throw is surfaced via onError).
595
+ */
596
+ declare const replanWanted: (trigger: ReplanTrigger, result: IStepResult, opts?: ReplanWantedOptions) => Promise<boolean>;
565
597
 
566
598
  /**
567
599
  * Robust parsing of model output. Small in-browser models emit JSON wrapped in
@@ -803,7 +835,7 @@ interface ToolLoopOptions {
803
835
  * them to the SDK's `activeTools`; prompted mode bounds `dispatch` to them.
804
836
  */
805
837
  activeTools?: string[];
806
- /** Native mode: cap on internal tool-calling steps (default 4). */
838
+ /** Cap on tool-calling rounds within this call, in both modes (default 4). */
807
839
  maxSteps?: number;
808
840
  maxOutputTokens?: number;
809
841
  temperature?: number;
@@ -817,11 +849,12 @@ interface ToolLoopResult {
817
849
  usage: IUsage;
818
850
  }
819
851
  /**
820
- * Run one round of tool-calling in whichever mode the model needs, returning a
821
- * normalised result. Native mode streams the SDK's multi-step function-calling;
822
- * prompted mode does a single generation, salvages a `{ reply, actions }` JSON
823
- * from the text, and dispatches each action through the tool's own execute.
824
- * Both call the exact same tool implementations.
852
+ * Run tool-calling in whichever mode the model needs, returning a normalised
853
+ * result. Native mode streams the SDK's multi-step function-calling; prompted
854
+ * mode salvages `{ reply, actions }` JSON out of plain text, dispatches each
855
+ * action through the tool's own execute, then feeds the TOOL RESULTS back and
856
+ * lets the model continue the same task — up to `maxSteps` rounds in both
857
+ * modes. Both modes call the exact same tool implementations.
825
858
  */
826
859
  declare const runToolLoop: (model: LanguageModel, opts: ToolLoopOptions) => Promise<ToolLoopResult>;
827
860
 
@@ -926,4 +959,4 @@ interface CompressOptions {
926
959
  */
927
960
  declare const compressHistory: (messages: StoredMessage[], model: LanguageModel, opts?: CompressOptions) => Promise<StoredMessage[]>;
928
961
 
929
- export { type Agent, type AgentContext, type AgentEvent, type AgentEventHandler, type AgentLogger, type AgentLoggerSink, type AgentTool, type AgentToolSet, type AgentWebDBOptions, type BrowserAgentConfig, type CompressOptions, type ContextStore, type CredentialStore, type EncryptedBlob, type ExecutorPromptContext, type ExecutorResult, type GenerateOptions, type IPlan, type IPlanStep, type IStepResult, type IToolCall, type IUsage, IndexedDBStore, type IndexedDBStoreOptions, IndexedDBVault, KEYS_STORE, type LogLevel, MemoryCredentialStore, MemoryStore, type ModelInput, type Phase, type PhaseBudgets, PlanSchema, type PlanShape, PlanStepSchema, type PlannerPromptContext, type PlannerResult, type PromptParts, type Prompts, type ProviderModelSpec, type ProviderType, type RawAction, type ReplanDecision, type ReplanMode, ReplanSchema, type ReplanShape, type ReplannerPromptContext, type ReplannerResult, type ResolvedConfig, type ResolvedStage, type RunOptions, type RunResult, SECRETS_STORE, SESSIONS_STORE, type StageInput, type StageOverride, type StoredMessage, type SynthesizerPromptContext, type ToolCallMode, type ToolLoopCallbacks, type ToolLoopOptions, type ToolLoopResult, type ToolMode, type ToolSelectionStrategy, VaultCredentialStore, type VaultOptions, type WebLLMModelOptions, buildModelFromStage, compressHistory, createAgent, createLogger, createPlan, createWebLLMModel, decideReplan, decryptJSON, defaultPrompts, defineTool, directBrowserOk, dispatch, encryptJSON, executeStep, generate, generateStructured, getOrCreateVaultKey, isDirectModel, isProviderSpec, isWebGPUAvailable, looksLikeJson, normalizeSteps, normalizeUsage, openAgentWebDB, parseExecutorResponse, parsePlainText, parsePlannerResponse, parseReplannerResponse, preloadWebLLMModel, promptHintOf, renderCatalog, resolveConfig, resolveModel, resolveStage, runToolLoop, selectToolMode, shouldReplan, splitBlocker, stream, supportsNativeTools, supportsStructuredOutput, synthesizeAnswer, unloadWebLLMModel, withSystem };
962
+ export { type Agent, type AgentContext, type AgentEvent, type AgentEventHandler, type AgentLogger, type AgentLoggerSink, type AgentTool, type AgentToolSet, type AgentWebDBOptions, type BrowserAgentConfig, type CompressOptions, type ContextStore, type CredentialStore, type EncryptedBlob, type ExecutorPromptContext, type ExecutorResult, type GenerateOptions, type IPlan, type IPlanStep, type IStepResult, type IToolCall, type IUsage, IndexedDBStore, type IndexedDBStoreOptions, IndexedDBVault, KEYS_STORE, type LogLevel, MemoryCredentialStore, MemoryStore, type ModelInput, type Phase, type PhaseBudgets, PlanSchema, type PlanShape, PlanStepSchema, type PlannerPromptContext, type PlannerResult, type PromptParts, type Prompts, type ProviderModelSpec, type ProviderType, type RawAction, type ReplanDecision, type ReplanMode, ReplanSchema, type ReplanShape, type ReplanTrigger, type ReplannerPromptContext, type ReplannerResult, type ResolvedConfig, type ResolvedStage, type RunOptions, type RunResult, SECRETS_STORE, SESSIONS_STORE, type StageInput, type StageOverride, type StoredMessage, type SynthesizerPromptContext, type ToolCallMode, type ToolLoopCallbacks, type ToolLoopOptions, type ToolLoopResult, type ToolMode, type ToolSelectionStrategy, VaultCredentialStore, type VaultOptions, type WebLLMModelOptions, buildModelFromStage, compressHistory, createAgent, createLogger, createPlan, createWebLLMModel, decideReplan, decryptJSON, defaultPrompts, defineTool, directBrowserOk, dispatch, encryptJSON, executeStep, generate, generateStructured, getOrCreateVaultKey, isDirectModel, isProviderSpec, isWebGPUAvailable, looksLikeJson, normalizeSteps, normalizeUsage, openAgentWebDB, parseExecutorResponse, parsePlainText, parsePlannerResponse, parseReplannerResponse, preloadWebLLMModel, promptHintOf, renderCatalog, replanWanted, resolveConfig, resolveModel, resolveStage, runToolLoop, selectToolMode, shouldReplan, splitBlocker, stream, supportsNativeTools, supportsStructuredOutput, synthesizeAnswer, unloadWebLLMModel, withSystem };
package/dist/index.js CHANGED
@@ -23,6 +23,7 @@ var resolveConfig = (c) => ({
23
23
  },
24
24
  temperature: c.temperature,
25
25
  replan: c.replan ?? true,
26
+ replanAfter: c.replanAfter ?? "failure",
26
27
  synthesize: c.synthesize ?? true,
27
28
  compressAfterChars: c.compressAfterChars ?? 12e3,
28
29
  logLevel: c.logLevel ?? "warn"
@@ -36,6 +37,7 @@ import {
36
37
  } from "ai";
37
38
 
38
39
  // src/llm/util.ts
40
+ var clip = (s, max) => s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
39
41
  var promptOf = (opts) => opts.messages ? { messages: opts.messages } : { prompt: opts.prompt ?? "" };
40
42
  var normalizeUsage = (u) => {
41
43
  const inputTokens = u?.inputTokens ?? 0;
@@ -308,7 +310,6 @@ var stateBlock = (state) => state && state.trim() ? `
308
310
 
309
311
  STATE:
310
312
  ${state}` : "";
311
- var clip = (s, max) => s.length > max ? `${s.slice(0, max - 1)}\u2026` : s;
312
313
  var historyBlock = (history) => {
313
314
  if (!history || history.length === 0) return "";
314
315
  const lines = history.slice(-8).map((m) => `${m.role}: ${clip(m.content, 400)}`);
@@ -341,8 +342,9 @@ Reply with a single JSON object, nothing else:
341
342
  - "actions" are the tool calls for THIS step ([] if none are needed). Use ONLY tools from the TOOLS list; "args" must match the tool's parameters.
342
343
  - Build on the current STATE \u2014 do not repeat work that is already there.
343
344
  - "reply" is one short human sentence (no JSON) describing what you did.
345
+ - After your actions run you will see their TOOL RESULTS and may continue the same step; finish with "actions": [] once it is done.
344
346
  - If you CANNOT complete the step, set "actions": [] and put the token [BLOCKER] in "reply" with a short reason.`;
345
- var REPLANNER_NATIVE = `You are the REPLANNER. After a step that was blocked or had a failed tool call, decide whether to keep going, revise the remaining steps, or finish.
347
+ var REPLANNER_NATIVE = `You are the REPLANNER. After an executed step, decide whether to keep going, revise the remaining steps, or finish.
346
348
  "continue": the remaining steps still fit. "revise": provide a better "plan" for the REMAINING work (never repeat done work). "finish": the goal is already met.
347
349
  Judge from the current STATE vs the goal. Prefer "continue".`;
348
350
  var REPLANNER_PROMPTED = `You are the REPLANNER. After each executed step you decide whether to keep going, revise the remaining steps, or finish.
@@ -476,6 +478,15 @@ import {
476
478
  streamText as streamText2
477
479
  } from "ai";
478
480
 
481
+ // src/agent/loop-types.ts
482
+ var BLOCKER = "[BLOCKER]";
483
+ var emptyUsage = () => ({ inputTokens: 0, outputTokens: 0, totalTokens: 0 });
484
+ var addUsage = (a, b) => ({
485
+ inputTokens: a.inputTokens + b.inputTokens,
486
+ outputTokens: a.outputTokens + b.outputTokens,
487
+ totalTokens: a.totalTokens + b.totalTokens
488
+ });
489
+
479
490
  // src/parse.ts
480
491
  var stripFences = (text) => (text || "").replace(/```(?:json)?/gi, "").trim();
481
492
  var extractBalanced = (text, open) => {
@@ -674,34 +685,74 @@ var runNative = async (model, opts) => {
674
685
  const [text, usage] = await Promise.all([result.text, result.usage]);
675
686
  return { text: text.trim(), toolCalls, usage: normalizeUsage(usage) };
676
687
  };
688
+ var asJson = (value) => {
689
+ try {
690
+ return JSON.stringify(value) ?? String(value);
691
+ } catch {
692
+ return String(value);
693
+ }
694
+ };
695
+ var toolResultsPrompt = (results) => {
696
+ const lines = results.map(
697
+ (r) => `- ${r.name} ${clip(asJson(r.input), 160)} \u2192 ${r.ok ? "ok" : "FAILED"}: ${clip(asJson(r.output), 400)}`
698
+ );
699
+ return `TOOL RESULTS:
700
+ ${lines.join("\n")}
701
+
702
+ Continue THIS step using the results above. Reply with a single JSON object, nothing else:
703
+ { "reply": string, "actions": [ { "tool": string, "args": object } ] }
704
+ - If the step is now complete: "actions": [] and a short outcome in "reply".
705
+ - Otherwise emit ONLY the remaining or corrective calls \u2014 never repeat a successful call.`;
706
+ };
677
707
  var runPrompted = async (model, opts) => {
678
- const result = await generateText2({
679
- model,
680
- system: opts.system,
681
- ...promptOf(opts),
682
- maxOutputTokens: opts.maxOutputTokens,
683
- temperature: opts.temperature,
684
- abortSignal: timeoutSignal(opts.abortSignal, opts.timeoutMs)
685
- });
686
- const parsed = parseExecutorResponse(result.text);
687
- if (parsed.reply) opts.callbacks?.onTextDelta?.(parsed.reply);
708
+ const maxRounds = Math.max(1, opts.maxSteps ?? 4);
688
709
  const active = opts.activeTools;
689
710
  const tools = active ? Object.fromEntries(Object.entries(opts.tools).filter(([name]) => active.includes(name))) : opts.tools;
711
+ const signal = timeoutSignal(opts.abortSignal, opts.timeoutMs);
712
+ const messages = opts.messages ? [...opts.messages] : [{ role: "user", content: opts.prompt ?? "" }];
690
713
  const toolCalls = [];
691
- for (const action of parsed.actions) {
692
- opts.callbacks?.onToolCall?.(action.tool, action.args);
693
- const rec = await dispatch(action, tools, { abortSignal: opts.abortSignal });
694
- toolCalls.push(rec);
695
- opts.callbacks?.onToolResult?.(rec.name, rec.output, rec.ok);
714
+ const seen = /* @__PURE__ */ new Set();
715
+ let usage = emptyUsage();
716
+ let text = "";
717
+ for (let round = 1; round <= maxRounds; round += 1) {
718
+ if (signal?.aborted) break;
719
+ const result = await generateText2({
720
+ model,
721
+ system: opts.system,
722
+ messages,
723
+ maxOutputTokens: opts.maxOutputTokens,
724
+ temperature: opts.temperature,
725
+ abortSignal: signal
726
+ });
727
+ usage = addUsage(usage, normalizeUsage(result.usage));
728
+ const parsed = parseExecutorResponse(result.text);
729
+ text = parsed.reply;
730
+ if (parsed.reply.includes(BLOCKER)) break;
731
+ if (parsed.actions.length === 0) break;
732
+ const batch = asJson(parsed.actions);
733
+ if (seen.has(batch)) break;
734
+ seen.add(batch);
735
+ const results = [];
736
+ for (const action of parsed.actions) {
737
+ if (signal?.aborted) break;
738
+ opts.callbacks?.onToolCall?.(action.tool, action.args);
739
+ const rec = await dispatch(action, tools, { abortSignal: signal });
740
+ toolCalls.push(rec);
741
+ results.push(rec);
742
+ opts.callbacks?.onToolResult?.(rec.name, rec.output, rec.ok);
743
+ }
744
+ if (round === maxRounds || signal?.aborted) break;
745
+ messages.push({ role: "assistant", content: result.text });
746
+ messages.push({ role: "user", content: toolResultsPrompt(results) });
696
747
  }
697
- return { text: parsed.reply, toolCalls, usage: normalizeUsage(result.usage) };
748
+ if (text) opts.callbacks?.onTextDelta?.(text);
749
+ return { text, toolCalls, usage };
698
750
  };
699
751
 
700
752
  // src/agent/internal.ts
701
753
  var systemFor = (ctx, base) => withSystem(base, ctx.raw.systemPrompt);
702
754
 
703
755
  // src/agent/executor.ts
704
- var BLOCKER = "[BLOCKER]";
705
756
  var splitBlocker = (raw) => {
706
757
  if (!raw.includes(BLOCKER)) return { summary: raw.trim(), blocked: false };
707
758
  return { summary: raw.split(BLOCKER).join("").trim(), blocked: true };
@@ -766,15 +817,35 @@ var executeStep = async (ctx, goal, step, index, total, done) => {
766
817
  usage: loop.usage
767
818
  };
768
819
  };
769
- var shouldReplan = (result) => result.blocked || result.toolCalls.some((c) => !c.ok);
770
-
771
- // src/agent/loop-types.ts
772
- var emptyUsage = () => ({ inputTokens: 0, outputTokens: 0, totalTokens: 0 });
773
- var addUsage = (a, b) => ({
774
- inputTokens: a.inputTokens + b.inputTokens,
775
- outputTokens: a.outputTokens + b.outputTokens,
776
- totalTokens: a.totalTokens + b.totalTokens
777
- });
820
+ var shouldReplan = (result) => {
821
+ if (result.blocked) return true;
822
+ const { toolCalls } = result;
823
+ return toolCalls.some(
824
+ (c, i) => !c.ok && !toolCalls.slice(i + 1).some((later) => later.ok && later.name === c.name)
825
+ );
826
+ };
827
+ var replanWanted = async (trigger, result, opts = {}) => {
828
+ if (trigger === "always") return true;
829
+ if (typeof trigger !== "function") return shouldReplan(result);
830
+ const fallback = () => shouldReplan(result);
831
+ const decided = (async () => {
832
+ try {
833
+ return Boolean(await trigger(result));
834
+ } catch (err) {
835
+ opts.onError?.(err);
836
+ return fallback();
837
+ }
838
+ })();
839
+ const guard = timeoutSignal(opts.signal, opts.timeoutMs);
840
+ if (!guard) return decided;
841
+ return Promise.race([
842
+ decided,
843
+ new Promise((resolve) => {
844
+ if (guard.aborted) resolve(fallback());
845
+ else guard.addEventListener("abort", () => resolve(fallback()), { once: true });
846
+ })
847
+ ]);
848
+ };
778
849
 
779
850
  // src/agent/schemas.ts
780
851
  import { z } from "zod";
@@ -1127,7 +1198,12 @@ var createAgent = async (config) => {
1127
1198
  done.push(
1128
1199
  `${step.description} \u2014 ${applied} applied${failed ? `, ${failed} failed` : ""}${stepResult.blocked ? ", blocked" : ""}`
1129
1200
  );
1130
- if (cfg.replan && iter < cfg.maxIterations && revisions < cfg.maxRevisions && !isAborted() && shouldReplan(stepResult)) {
1201
+ const wantReplan = cfg.replan && iter < cfg.maxIterations && revisions < cfg.maxRevisions && !isAborted() && await replanWanted(cfg.replanAfter, stepResult, {
1202
+ signal: ctx.signal,
1203
+ timeoutMs: cfg.chatTimeoutMs,
1204
+ onError: (err) => log.warn("replanAfter predicate threw \u2014 using the failure rule", err)
1205
+ });
1206
+ if (wantReplan && !isAborted()) {
1131
1207
  const decision = await decideReplan(
1132
1208
  ctx,
1133
1209
  text,
@@ -1452,6 +1528,7 @@ export {
1452
1528
  preloadWebLLMModel,
1453
1529
  promptHintOf,
1454
1530
  renderCatalog,
1531
+ replanWanted,
1455
1532
  resolveConfig,
1456
1533
  resolveModel,
1457
1534
  resolveStage,