@sschepis/oboto-agent 0.1.4 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +999 -45
- package/dist/index.js +1705 -162
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
package/dist/index.d.ts
CHANGED
|
@@ -1,14 +1,22 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
3
|
-
import
|
|
1
|
+
import * as _sschepis_as_agent from '@sschepis/as-agent';
|
|
2
|
+
import { Session, PermissionPolicy, PermissionPrompter, CompactionConfig, HookRunner, AgentRuntime, ConversationMessage, UsageTracker, TokenUsage, HookRunResult, SlashCommandSpec, PermissionOutcome, PermissionMode, CompactionResult, UsageCostEstimate, ModelPricing as ModelPricing$1 } from '@sschepis/as-agent';
|
|
3
|
+
import * as _sschepis_llm_wrapper from '@sschepis/llm-wrapper';
|
|
4
|
+
import { BaseProvider, LLMRouter, HealthState, StandardChatParams } from '@sschepis/llm-wrapper';
|
|
5
|
+
import { Router, Middleware, BranchNode, DynamicBranchNode, SessionManager } from '@sschepis/swiss-army-tool';
|
|
6
|
+
import { MiddlewareHooks, ModelPricing, BudgetConfig, RateLimitConfig, EmbeddingProvider, VectorStore, VectorSearchResult, LScriptRuntime, LScriptFunction, ExecutionResult, RAGPipeline, CostTracker, ToolDefinition, ChatMessage, LLMProvider, Pipeline, PipelineResult } from '@sschepis/lmscript';
|
|
7
|
+
import * as zod from 'zod';
|
|
4
8
|
import { z } from 'zod';
|
|
5
|
-
import { ToolDefinition, ChatMessage, LLMProvider, LScriptRuntime, LScriptFunction } from '@sschepis/lmscript';
|
|
6
9
|
|
|
10
|
+
/**
|
|
11
|
+
* A provider-like object that has `chat()` and `stream()` methods.
|
|
12
|
+
* Accepts both llm-wrapper `BaseProvider` and `LLMRouter`.
|
|
13
|
+
*/
|
|
14
|
+
type ProviderLike$1 = BaseProvider | LLMRouter;
|
|
7
15
|
interface ObotoAgentConfig {
|
|
8
16
|
/** Small, fast model for triage and summarization (e.g. Ollama, LMStudio) */
|
|
9
|
-
localModel:
|
|
17
|
+
localModel: ProviderLike$1;
|
|
10
18
|
/** Powerful model for complex reasoning (e.g. Anthropic, OpenAI, Gemini) */
|
|
11
|
-
remoteModel:
|
|
19
|
+
remoteModel: ProviderLike$1;
|
|
12
20
|
/** Model identifier for the local provider (e.g. "llama3:8b") */
|
|
13
21
|
localModelName: string;
|
|
14
22
|
/** Model identifier for the remote provider (e.g. "claude-sonnet-4-20250514") */
|
|
@@ -25,8 +33,48 @@ interface ObotoAgentConfig {
|
|
|
25
33
|
systemPrompt?: string;
|
|
26
34
|
/** Called with each token chunk during LLM streaming. Enables real-time output. */
|
|
27
35
|
onToken?: (token: string) => void;
|
|
36
|
+
/** Middleware hooks for the lmscript execution lifecycle */
|
|
37
|
+
middleware?: MiddlewareHooks[];
|
|
38
|
+
/** Model pricing map for cost tracking (model name -> per-1k-token costs) */
|
|
39
|
+
modelPricing?: ModelPricing;
|
|
40
|
+
/** Budget limits for the remote runtime */
|
|
41
|
+
budget?: BudgetConfig;
|
|
42
|
+
/** Rate limiting configuration for remote API calls */
|
|
43
|
+
rateLimit?: RateLimitConfig;
|
|
44
|
+
/** TTL in ms for execution cache. 0 or undefined disables caching. Default: 0 */
|
|
45
|
+
cacheTtlMs?: number;
|
|
46
|
+
/** TTL in ms for triage cache. Separate from main cache. Default: 60000 */
|
|
47
|
+
triageCacheTtlMs?: number;
|
|
48
|
+
/** Middleware to apply to the swiss-army-tool Router */
|
|
49
|
+
toolMiddleware?: Middleware[];
|
|
50
|
+
/** Embedding provider for RAG-augmented conversation retrieval */
|
|
51
|
+
embeddingProvider?: EmbeddingProvider;
|
|
52
|
+
/** Custom vector store for RAG. Defaults to MemoryVectorStore. */
|
|
53
|
+
vectorStore?: VectorStore;
|
|
54
|
+
/** Number of past context chunks to retrieve via RAG. Default: 5 */
|
|
55
|
+
ragTopK?: number;
|
|
56
|
+
/** Minimum similarity score for RAG retrieval (0-1). Default: 0.3 */
|
|
57
|
+
ragMinScore?: number;
|
|
58
|
+
/** Embedding model identifier for RAG. Default: provider's default */
|
|
59
|
+
ragEmbeddingModel?: string;
|
|
60
|
+
/** Whether to automatically index conversation messages for RAG. Default: true */
|
|
61
|
+
ragAutoIndex?: boolean;
|
|
62
|
+
/** Whether to index tool execution results for RAG. Default: true */
|
|
63
|
+
ragIndexToolResults?: boolean;
|
|
64
|
+
/** Custom formatter for RAG-retrieved context */
|
|
65
|
+
ragFormatContext?: (results: VectorSearchResult[]) => string;
|
|
66
|
+
/** Permission policy for tool authorization (from @sschepis/as-agent) */
|
|
67
|
+
permissionPolicy?: PermissionPolicy;
|
|
68
|
+
/** Permission prompter for interactive permission decisions */
|
|
69
|
+
permissionPrompter?: PermissionPrompter;
|
|
70
|
+
/** Session compaction config — auto-compact when estimated tokens exceed limit */
|
|
71
|
+
compactionConfig?: CompactionConfig;
|
|
72
|
+
/** Hook runner for pre/post tool-use shell hooks */
|
|
73
|
+
hookRunner?: HookRunner;
|
|
74
|
+
/** as-agent Wasm runtime for slash commands and utilities */
|
|
75
|
+
agentRuntime?: AgentRuntime;
|
|
28
76
|
}
|
|
29
|
-
type AgentEventType = "user_input" | "agent_thought" | "token" | "triage_result" | "tool_execution_start" | "tool_execution_complete" | "tool_round_complete" | "state_updated" | "interruption" | "error" | "turn_complete";
|
|
77
|
+
type AgentEventType = "user_input" | "agent_thought" | "token" | "triage_result" | "tool_execution_start" | "tool_execution_complete" | "tool_round_complete" | "state_updated" | "interruption" | "error" | "cost_update" | "turn_complete" | "permission_denied" | "session_compacted" | "hook_denied" | "hook_message" | "router_event" | "slash_command";
|
|
30
78
|
interface AgentEvent<T = unknown> {
|
|
31
79
|
type: AgentEventType;
|
|
32
80
|
payload: T;
|
|
@@ -48,21 +96,555 @@ interface ToolExecutionEvent {
|
|
|
48
96
|
durationMs?: number;
|
|
49
97
|
}
|
|
50
98
|
|
|
99
|
+
interface ConversationRAGConfig {
|
|
100
|
+
/** The embedding provider (e.g. OpenAI, local model) */
|
|
101
|
+
embeddingProvider: EmbeddingProvider;
|
|
102
|
+
/** Optional custom vector store. Defaults to MemoryVectorStore. */
|
|
103
|
+
vectorStore?: VectorStore;
|
|
104
|
+
/** Number of past context chunks to retrieve. Default: 5 */
|
|
105
|
+
topK?: number;
|
|
106
|
+
/** Minimum similarity score (0-1). Default: 0.3 */
|
|
107
|
+
minScore?: number;
|
|
108
|
+
/** Embedding model identifier. Default: provider's default */
|
|
109
|
+
embeddingModel?: string;
|
|
110
|
+
/**
|
|
111
|
+
* Whether to automatically index conversation messages as they're added.
|
|
112
|
+
* Default: true
|
|
113
|
+
*/
|
|
114
|
+
autoIndex?: boolean;
|
|
115
|
+
/**
|
|
116
|
+
* Whether to index tool execution results.
|
|
117
|
+
* Default: true
|
|
118
|
+
*/
|
|
119
|
+
indexToolResults?: boolean;
|
|
120
|
+
/** Maximum characters per indexed chunk. Longer messages are split. Default: 2000 */
|
|
121
|
+
maxChunkSize?: number;
|
|
122
|
+
/**
|
|
123
|
+
* Custom context formatter for retrieved documents.
|
|
124
|
+
* Default: numbered list with scores.
|
|
125
|
+
*/
|
|
126
|
+
formatContext?: (results: VectorSearchResult[]) => string;
|
|
127
|
+
}
|
|
128
|
+
interface RAGRetrievalResult {
|
|
129
|
+
/** Retrieved context string ready for prompt injection */
|
|
130
|
+
context: string;
|
|
131
|
+
/** Raw search results */
|
|
132
|
+
results: VectorSearchResult[];
|
|
133
|
+
/** Number of documents in the store */
|
|
134
|
+
totalDocuments: number;
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* ConversationRAG bridges lmscript's RAG pipeline with the agent's
|
|
138
|
+
* conversation history and tool results.
|
|
139
|
+
*
|
|
140
|
+
* It maintains a vector store of conversation chunks and can retrieve
|
|
141
|
+
* relevant past context for new queries. This is useful for:
|
|
142
|
+
* - Long-running agent sessions where early context is pruned
|
|
143
|
+
* - Multi-topic conversations where relevant past decisions need retrieval
|
|
144
|
+
* - Tool result recall without re-execution
|
|
145
|
+
*
|
|
146
|
+
* ```ts
|
|
147
|
+
* const rag = new ConversationRAG(runtime, {
|
|
148
|
+
* embeddingProvider: openaiEmbeddings,
|
|
149
|
+
* topK: 5,
|
|
150
|
+
* minScore: 0.3,
|
|
151
|
+
* });
|
|
152
|
+
*
|
|
153
|
+
* // Index existing session history
|
|
154
|
+
* await rag.indexSession(session);
|
|
155
|
+
*
|
|
156
|
+
* // Retrieve relevant context for a new query
|
|
157
|
+
* const { context } = await rag.retrieve("What database schema did we discuss?");
|
|
158
|
+
*
|
|
159
|
+
* // Or use RAG-augmented execution directly
|
|
160
|
+
* const result = await rag.executeWithContext(myFn, input, "search query");
|
|
161
|
+
* ```
|
|
162
|
+
*/
|
|
163
|
+
declare class ConversationRAG {
|
|
164
|
+
private vectorStore;
|
|
165
|
+
private embeddingProvider;
|
|
166
|
+
private ragPipeline;
|
|
167
|
+
private config;
|
|
168
|
+
private indexedMessageCount;
|
|
169
|
+
private runtime;
|
|
170
|
+
constructor(runtime: LScriptRuntime, config: ConversationRAGConfig);
|
|
171
|
+
/**
|
|
172
|
+
* Index an entire as-agent Session into the vector store.
|
|
173
|
+
* Each message becomes one or more chunks (split by maxChunkSize).
|
|
174
|
+
*/
|
|
175
|
+
indexSession(session: Session): Promise<number>;
|
|
176
|
+
/**
|
|
177
|
+
* Index a single conversation message.
|
|
178
|
+
* Call this after adding a message to the session for real-time indexing.
|
|
179
|
+
*/
|
|
180
|
+
indexMessage(msg: ConversationMessage, messageIndex?: number): Promise<void>;
|
|
181
|
+
/**
|
|
182
|
+
* Index a tool execution result for later retrieval.
|
|
183
|
+
*/
|
|
184
|
+
indexToolResult(command: string, kwargs: Record<string, unknown>, result: string): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Retrieve relevant past context for a query.
|
|
187
|
+
* Returns formatted context string and raw results.
|
|
188
|
+
*/
|
|
189
|
+
retrieve(query: string): Promise<RAGRetrievalResult>;
|
|
190
|
+
/**
|
|
191
|
+
* Execute an lmscript function with RAG-augmented context from the
|
|
192
|
+
* conversation history.
|
|
193
|
+
*
|
|
194
|
+
* This is the primary integration point — it uses lmscript's RAGPipeline
|
|
195
|
+
* to inject relevant past conversation into the function's system prompt.
|
|
196
|
+
*/
|
|
197
|
+
executeWithContext<I, O extends zod.ZodType>(fn: LScriptFunction<I, O>, input: I, queryText?: string): Promise<{
|
|
198
|
+
result: ExecutionResult<zod.infer<O>>;
|
|
199
|
+
retrievedDocuments: VectorSearchResult[];
|
|
200
|
+
context: string;
|
|
201
|
+
}>;
|
|
202
|
+
/** Get the number of indexed messages. */
|
|
203
|
+
get messageCount(): number;
|
|
204
|
+
/** Get the total number of document chunks in the vector store. */
|
|
205
|
+
documentCount(): Promise<number>;
|
|
206
|
+
/** Clear the vector store and reset counters. */
|
|
207
|
+
clear(): Promise<void>;
|
|
208
|
+
/** Get the underlying vector store (for advanced usage). */
|
|
209
|
+
getVectorStore(): VectorStore;
|
|
210
|
+
/** Get the underlying RAG pipeline (for advanced usage). */
|
|
211
|
+
getRagPipeline(): RAGPipeline;
|
|
212
|
+
private messageToChunks;
|
|
213
|
+
private splitChunks;
|
|
214
|
+
}
|
|
215
|
+
|
|
51
216
|
type EventHandler$1 = (event: AgentEvent) => void;
|
|
217
|
+
/**
|
|
218
|
+
* Platform-agnostic typed event bus.
|
|
219
|
+
* Uses a plain Map instead of Node.js EventEmitter for browser/Deno/Bun compatibility.
|
|
220
|
+
*/
|
|
221
|
+
declare class AgentEventBus {
|
|
222
|
+
private listeners;
|
|
223
|
+
/** Subscribe to an event type. Returns an unsubscribe function. */
|
|
224
|
+
on(type: AgentEventType, handler: EventHandler$1): () => void;
|
|
225
|
+
/** Unsubscribe a handler from an event type. */
|
|
226
|
+
off(type: AgentEventType, handler: EventHandler$1): void;
|
|
227
|
+
/** Subscribe to an event type for a single emission. */
|
|
228
|
+
once(type: AgentEventType, handler: EventHandler$1): () => void;
|
|
229
|
+
/** Emit an event to all subscribers. */
|
|
230
|
+
emit(type: AgentEventType, payload: unknown): void;
|
|
231
|
+
/** Remove all listeners for all event types. */
|
|
232
|
+
removeAllListeners(): void;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* as-agent-features.ts — Deep integration of @sschepis/as-agent's advanced features.
|
|
237
|
+
*
|
|
238
|
+
* This module bridges the following as-agent subsystems into oboto-agent:
|
|
239
|
+
*
|
|
240
|
+
* 1. **Permissions** — PermissionPolicy + PermissionPrompter for tool authorization
|
|
241
|
+
* 2. **Session Compaction** — CompactionConfig for auto-compacting long sessions
|
|
242
|
+
* 3. **Hooks** — HookRunner for pre/post tool-use shell hooks
|
|
243
|
+
* 4. **Slash Commands** — AgentRuntime's slash command registry
|
|
244
|
+
* 5. **Usage Tracking** — UsageTracker bridge (detailed impl in Task 11)
|
|
245
|
+
*/
|
|
246
|
+
|
|
247
|
+
/**
|
|
248
|
+
* Wraps an as-agent PermissionPolicy to provide tool-call authorization
|
|
249
|
+
* that integrates with the agent's event bus.
|
|
250
|
+
*
|
|
251
|
+
* Before each tool execution, `authorize()` is called. If the policy
|
|
252
|
+
* denies the call, a `permission_denied` event is emitted and the tool
|
|
253
|
+
* execution is skipped.
|
|
254
|
+
*
|
|
255
|
+
* ```ts
|
|
256
|
+
* const guard = new PermissionGuard(policy, prompter, bus);
|
|
257
|
+
* const outcome = guard.checkPermission("bash", '{"cmd":"rm -rf /"}');
|
|
258
|
+
* if (outcome.kind === "deny") { ... }
|
|
259
|
+
* ```
|
|
260
|
+
*/
|
|
261
|
+
declare class PermissionGuard {
|
|
262
|
+
private policy;
|
|
263
|
+
private prompter;
|
|
264
|
+
private bus?;
|
|
265
|
+
constructor(policy: PermissionPolicy, prompter: PermissionPrompter | null, bus?: AgentEventBus | undefined);
|
|
266
|
+
/**
|
|
267
|
+
* Check whether a tool call is authorized.
|
|
268
|
+
* Emits `permission_denied` on the event bus if denied.
|
|
269
|
+
*/
|
|
270
|
+
checkPermission(toolName: string, toolInput: string): PermissionOutcome;
|
|
271
|
+
/** Get the current active permission mode. */
|
|
272
|
+
get activeMode(): PermissionMode;
|
|
273
|
+
/** Get the required permission mode for a specific tool. */
|
|
274
|
+
requiredModeFor(toolName: string): PermissionMode;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Manages automatic and manual session compaction using as-agent's
|
|
278
|
+
* CompactionConfig. Compaction summarizes older messages to stay within
|
|
279
|
+
* token limits while preserving recent context.
|
|
280
|
+
*
|
|
281
|
+
* ```ts
|
|
282
|
+
* const compactor = new SessionCompactor(bus, {
|
|
283
|
+
* preserveRecentMessages: 10,
|
|
284
|
+
* maxEstimatedTokens: 100_000,
|
|
285
|
+
* });
|
|
286
|
+
*
|
|
287
|
+
* // Check and compact if needed
|
|
288
|
+
* const result = compactor.compactIfNeeded(session, estimatedTokens);
|
|
289
|
+
* ```
|
|
290
|
+
*/
|
|
291
|
+
declare class SessionCompactor {
|
|
292
|
+
private config;
|
|
293
|
+
private bus?;
|
|
294
|
+
private compactionCount;
|
|
295
|
+
private totalRemovedMessages;
|
|
296
|
+
constructor(bus: AgentEventBus | undefined, config: CompactionConfig);
|
|
297
|
+
/**
|
|
298
|
+
* Check if the session needs compaction and perform it if so.
|
|
299
|
+
* Uses a simple heuristic: ~4 chars per token for estimation.
|
|
300
|
+
*
|
|
301
|
+
* Since the actual compaction logic lives in the Wasm runtime
|
|
302
|
+
* (ConversationRuntime.compact()), this method provides a JS-side
|
|
303
|
+
* implementation that creates a summary of older messages and
|
|
304
|
+
* preserves recent ones.
|
|
305
|
+
*
|
|
306
|
+
* Returns null if compaction is not needed.
|
|
307
|
+
*/
|
|
308
|
+
compactIfNeeded(session: Session, estimatedTokens?: number): CompactionResult | null;
|
|
309
|
+
/**
|
|
310
|
+
* Force compaction of the session regardless of token count.
|
|
311
|
+
*/
|
|
312
|
+
compact(session: Session): CompactionResult;
|
|
313
|
+
/** Get compaction statistics. */
|
|
314
|
+
get stats(): {
|
|
315
|
+
compactionCount: number;
|
|
316
|
+
totalRemovedMessages: number;
|
|
317
|
+
};
|
|
318
|
+
/** Update the compaction config at runtime. */
|
|
319
|
+
updateConfig(config: Partial<CompactionConfig>): void;
|
|
320
|
+
/** Estimate token count for a session (~4 chars per token). */
|
|
321
|
+
private estimateTokens;
|
|
322
|
+
}
|
|
323
|
+
/**
|
|
324
|
+
* Wraps an as-agent HookRunner and integrates it with the agent's
|
|
325
|
+
* event bus. Hooks are shell commands that run before and after
|
|
326
|
+
* tool executions, allowing external validation/transformation.
|
|
327
|
+
*
|
|
328
|
+
* ```ts
|
|
329
|
+
* const hooks = new HookIntegration(hookRunner, bus);
|
|
330
|
+
* const pre = hooks.runPreToolUse("bash", '{"cmd":"ls"}');
|
|
331
|
+
* if (pre.denied) { /* skip tool call *\/ }
|
|
332
|
+
*
|
|
333
|
+
* // After tool executes:
|
|
334
|
+
* const post = hooks.runPostToolUse("bash", '{"cmd":"ls"}', "file1\nfile2", false);
|
|
335
|
+
* ```
|
|
336
|
+
*/
|
|
337
|
+
declare class HookIntegration {
|
|
338
|
+
private runner;
|
|
339
|
+
private bus?;
|
|
340
|
+
constructor(runner: HookRunner, bus?: AgentEventBus | undefined);
|
|
341
|
+
/**
|
|
342
|
+
* Run pre-tool-use hooks. If any hook denies the call,
|
|
343
|
+
* the tool execution should be skipped.
|
|
344
|
+
*/
|
|
345
|
+
runPreToolUse(toolName: string, toolInput: string): HookRunResult;
|
|
346
|
+
/**
|
|
347
|
+
* Run post-tool-use hooks. These can log, transform, or audit
|
|
348
|
+
* tool results but cannot retroactively deny execution.
|
|
349
|
+
*/
|
|
350
|
+
runPostToolUse(toolName: string, toolInput: string, toolOutput: string, isError: boolean): HookRunResult;
|
|
351
|
+
}
|
|
352
|
+
/**
|
|
353
|
+
* Bridges the as-agent Wasm runtime's slash command system with
|
|
354
|
+
* oboto-agent. The Wasm runtime provides 21 built-in slash commands
|
|
355
|
+
* (e.g. /help, /compact, /clear, /model, etc.).
|
|
356
|
+
*
|
|
357
|
+
* This class provides:
|
|
358
|
+
* - Access to command specs and help text from the Wasm runtime
|
|
359
|
+
* - An extensible registry for adding custom slash commands
|
|
360
|
+
* - Parsing and dispatching of slash command input
|
|
361
|
+
*
|
|
362
|
+
* ```ts
|
|
363
|
+
* const registry = new SlashCommandRegistry(agentRuntime);
|
|
364
|
+
* const specs = registry.getCommandSpecs();
|
|
365
|
+
* const help = registry.getHelpText();
|
|
366
|
+
*
|
|
367
|
+
* // Add custom commands
|
|
368
|
+
* registry.registerCommand({
|
|
369
|
+
* name: "status",
|
|
370
|
+
* summary: "Show agent status",
|
|
371
|
+
* argumentHint: "",
|
|
372
|
+
* resumeSupported: false,
|
|
373
|
+
* }, async (args) => "Agent is running");
|
|
374
|
+
* ```
|
|
375
|
+
*/
|
|
376
|
+
declare class SlashCommandRegistry {
|
|
377
|
+
private customCommands;
|
|
378
|
+
private wasmRuntime?;
|
|
379
|
+
constructor(wasmRuntime?: AgentRuntime);
|
|
380
|
+
/**
|
|
381
|
+
* Get all slash command specs (built-in from Wasm + custom).
|
|
382
|
+
*/
|
|
383
|
+
getCommandSpecs(): SlashCommandSpec[];
|
|
384
|
+
/**
|
|
385
|
+
* Get the full help text for all commands.
|
|
386
|
+
* Uses the Wasm runtime's formatted help if available.
|
|
387
|
+
*/
|
|
388
|
+
getHelpText(): string;
|
|
389
|
+
/**
|
|
390
|
+
* Register a custom slash command.
|
|
391
|
+
*/
|
|
392
|
+
registerCommand(spec: SlashCommandSpec, handler: (args: string) => string | Promise<string>): void;
|
|
393
|
+
/**
|
|
394
|
+
* Unregister a custom slash command.
|
|
395
|
+
*/
|
|
396
|
+
unregisterCommand(name: string): boolean;
|
|
397
|
+
/**
|
|
398
|
+
* Parse a user input string to check if it's a slash command.
|
|
399
|
+
* Returns the command name and arguments, or null if not a command.
|
|
400
|
+
*/
|
|
401
|
+
parseCommand(input: string): {
|
|
402
|
+
name: string;
|
|
403
|
+
args: string;
|
|
404
|
+
} | null;
|
|
405
|
+
/**
|
|
406
|
+
* Execute a custom slash command by name.
|
|
407
|
+
* Returns the command output, or null if the command is not found
|
|
408
|
+
* in the custom registry (it may be a built-in Wasm command).
|
|
409
|
+
*/
|
|
410
|
+
executeCustomCommand(name: string, args: string): Promise<string | null>;
|
|
411
|
+
/**
|
|
412
|
+
* Check if a command name exists (either built-in or custom).
|
|
413
|
+
*/
|
|
414
|
+
hasCommand(name: string): boolean;
|
|
415
|
+
/**
|
|
416
|
+
* Get only commands that support resume (useful for session restoration).
|
|
417
|
+
*/
|
|
418
|
+
getResumeSupportedCommands(): SlashCommandSpec[];
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* A JS-side implementation of the as-agent UsageTracker interface.
|
|
422
|
+
* This adapter accumulates token usage across turns, matching the
|
|
423
|
+
* as-agent contract (inputTokens, outputTokens, cache tokens).
|
|
424
|
+
*
|
|
425
|
+
* The bridge to lmscript's CostTracker (which uses different field names)
|
|
426
|
+
* is handled in Task 11.
|
|
427
|
+
*/
|
|
428
|
+
declare class AgentUsageTracker implements UsageTracker {
|
|
429
|
+
private turnUsages;
|
|
430
|
+
private currentTurn;
|
|
431
|
+
record(usage: TokenUsage): void;
|
|
432
|
+
currentTurnUsage(): TokenUsage;
|
|
433
|
+
cumulativeUsage(): TokenUsage;
|
|
434
|
+
turns(): number;
|
|
435
|
+
/**
|
|
436
|
+
* Finalize the current turn and start a new one.
|
|
437
|
+
* Call this at the end of each agent turn.
|
|
438
|
+
*/
|
|
439
|
+
endTurn(): void;
|
|
440
|
+
/** Reset all usage data. */
|
|
441
|
+
reset(): void;
|
|
442
|
+
private hasTurnActivity;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
/**
|
|
446
|
+
* router-events.ts — Bridge LLMRouter health/failover events into the agent event bus.
|
|
447
|
+
*
|
|
448
|
+
* The LLMRouter (from @sschepis/llm-wrapper) exposes a `RouterEventEmitter` that
|
|
449
|
+
* fires typed events for routing decisions, fallbacks, circuit breaker state changes,
|
|
450
|
+
* and request completions/errors.
|
|
451
|
+
*
|
|
452
|
+
* This module:
|
|
453
|
+
* 1. Subscribes to all LLMRouter events
|
|
454
|
+
* 2. Forwards them to the agent's AgentEventBus as `router_event` events
|
|
455
|
+
* 3. Provides a health snapshot method for observability
|
|
456
|
+
*/
|
|
457
|
+
|
|
458
|
+
/**
|
|
459
|
+
* Bridge that forwards LLMRouter events to the agent event bus.
|
|
460
|
+
*
|
|
461
|
+
* Usage:
|
|
462
|
+
* ```ts
|
|
463
|
+
* const bridge = new RouterEventBridge(bus);
|
|
464
|
+
* bridge.attach(localRouter, "local");
|
|
465
|
+
* bridge.attach(remoteRouter, "remote");
|
|
466
|
+
*
|
|
467
|
+
* // Later, get a health snapshot
|
|
468
|
+
* const health = bridge.getHealthSnapshot();
|
|
469
|
+
* ```
|
|
470
|
+
*/
|
|
471
|
+
declare class RouterEventBridge {
|
|
472
|
+
private bus;
|
|
473
|
+
private attachedRouters;
|
|
474
|
+
constructor(bus: AgentEventBus);
|
|
475
|
+
/**
|
|
476
|
+
* Attach an LLMRouter and forward all its events to the agent bus.
|
|
477
|
+
*
|
|
478
|
+
* @param router - The LLMRouter to monitor
|
|
479
|
+
* @param label - A label to identify this router in events (e.g. "local", "remote")
|
|
480
|
+
*/
|
|
481
|
+
attach(router: LLMRouter, label: string): void;
|
|
482
|
+
/**
|
|
483
|
+
* Detach a previously attached router.
|
|
484
|
+
*/
|
|
485
|
+
detach(label: string): void;
|
|
486
|
+
/**
|
|
487
|
+
* Detach all attached routers.
|
|
488
|
+
*/
|
|
489
|
+
detachAll(): void;
|
|
490
|
+
/**
|
|
491
|
+
* Get a health snapshot from all attached routers.
|
|
492
|
+
* Returns a map of router label -> endpoint name -> HealthState.
|
|
493
|
+
*/
|
|
494
|
+
getHealthSnapshot(): Map<string, Map<string, HealthState>>;
|
|
495
|
+
/**
|
|
496
|
+
* Check if any attached router has an endpoint in "open" (tripped) circuit state.
|
|
497
|
+
*/
|
|
498
|
+
hasTrippedCircuits(): boolean;
|
|
499
|
+
/**
|
|
500
|
+
* Get the labels of all attached routers.
|
|
501
|
+
*/
|
|
502
|
+
get labels(): string[];
|
|
503
|
+
}
|
|
504
|
+
/**
|
|
505
|
+
* Helper to check if a ProviderLike is an LLMRouter (has `events` property).
|
|
506
|
+
*/
|
|
507
|
+
declare function isLLMRouter(provider: unknown): provider is LLMRouter;
|
|
508
|
+
|
|
509
|
+
/**
|
|
510
|
+
* usage-bridge.ts — Bidirectional bridge between as-agent's UsageTracker
|
|
511
|
+
* and lmscript's CostTracker.
|
|
512
|
+
*
|
|
513
|
+
* Field mapping:
|
|
514
|
+
* as-agent lmscript
|
|
515
|
+
* ───────── ────────
|
|
516
|
+
* inputTokens → promptTokens
|
|
517
|
+
* outputTokens → completionTokens
|
|
518
|
+
* cacheCreationInputTokens → (no equivalent, tracked separately)
|
|
519
|
+
* cacheReadInputTokens → (no equivalent, tracked separately)
|
|
520
|
+
* (sum of all) → totalTokens
|
|
521
|
+
*
|
|
522
|
+
* The bridge records every usage event into both systems, ensuring
|
|
523
|
+
* unified cost accounting regardless of which subsystem reports usage.
|
|
524
|
+
*/
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Convert as-agent TokenUsage to lmscript usage format.
|
|
528
|
+
*/
|
|
529
|
+
declare function asTokenUsageToLmscript(usage: TokenUsage): {
|
|
530
|
+
promptTokens: number;
|
|
531
|
+
completionTokens: number;
|
|
532
|
+
totalTokens: number;
|
|
533
|
+
};
|
|
534
|
+
/**
|
|
535
|
+
* Convert lmscript usage format to as-agent TokenUsage.
|
|
536
|
+
* Cache tokens default to 0 since lmscript doesn't track them separately.
|
|
537
|
+
*/
|
|
538
|
+
declare function lmscriptToAsTokenUsage(usage: {
|
|
539
|
+
promptTokens: number;
|
|
540
|
+
completionTokens: number;
|
|
541
|
+
totalTokens: number;
|
|
542
|
+
}): TokenUsage;
|
|
543
|
+
/**
|
|
544
|
+
* Estimate costs using as-agent's ModelPricing (per-million-token pricing).
|
|
545
|
+
*/
|
|
546
|
+
declare function estimateCostFromAsAgent(usage: TokenUsage, pricing: ModelPricing$1): UsageCostEstimate;
|
|
547
|
+
/**
|
|
548
|
+
* Bidirectional bridge that keeps an as-agent UsageTracker and an
|
|
549
|
+
* lmscript CostTracker in sync.
|
|
550
|
+
*
|
|
551
|
+
* When usage is reported from either side, the bridge records it in
|
|
552
|
+
* both tracking systems.
|
|
553
|
+
*
|
|
554
|
+
* ```ts
|
|
555
|
+
* const bridge = new UsageBridge(usageTracker, costTracker);
|
|
556
|
+
*
|
|
557
|
+
* // Record from LLM response (lmscript format)
|
|
558
|
+
* bridge.recordFromLmscript("gpt-4", { promptTokens: 100, completionTokens: 50, totalTokens: 150 });
|
|
559
|
+
*
|
|
560
|
+
* // Record from API response (as-agent format)
|
|
561
|
+
* bridge.recordFromAsAgent({ inputTokens: 100, outputTokens: 50, cacheCreationInputTokens: 0, cacheReadInputTokens: 0 });
|
|
562
|
+
*
|
|
563
|
+
* // Get unified cost summary
|
|
564
|
+
* const summary = bridge.getCostSummary(lmModelPricing, asModelPricing);
|
|
565
|
+
* ```
|
|
566
|
+
*/
|
|
567
|
+
declare class UsageBridge {
|
|
568
|
+
private asTracker;
|
|
569
|
+
private lmTracker?;
|
|
570
|
+
constructor(asTracker: AgentUsageTracker, lmTracker?: CostTracker | undefined);
|
|
571
|
+
/**
|
|
572
|
+
* Record usage from an lmscript-format source (e.g. from the streaming path
|
|
573
|
+
* or AgentLoop result).
|
|
574
|
+
*
|
|
575
|
+
* Converts to as-agent format and records in both trackers.
|
|
576
|
+
*/
|
|
577
|
+
recordFromLmscript(functionName: string, usage: {
|
|
578
|
+
promptTokens: number;
|
|
579
|
+
completionTokens: number;
|
|
580
|
+
totalTokens: number;
|
|
581
|
+
}): void;
|
|
582
|
+
/**
|
|
583
|
+
* Record usage from an as-agent-format source (e.g. from ConversationRuntime
|
|
584
|
+
* or the Wasm runtime).
|
|
585
|
+
*
|
|
586
|
+
* Converts to lmscript format and records in both trackers.
|
|
587
|
+
*/
|
|
588
|
+
recordFromAsAgent(usage: TokenUsage, functionName?: string): void;
|
|
589
|
+
/**
|
|
590
|
+
* End the current turn in the as-agent tracker.
|
|
591
|
+
*/
|
|
592
|
+
endTurn(): void;
|
|
593
|
+
/**
|
|
594
|
+
* Get unified cost summary combining both tracking systems.
|
|
595
|
+
*/
|
|
596
|
+
getCostSummary(lmPricing?: ModelPricing, asPricing?: ModelPricing$1): UnifiedCostSummary;
|
|
597
|
+
/**
|
|
598
|
+
* Reset both tracking systems.
|
|
599
|
+
*/
|
|
600
|
+
reset(): void;
|
|
601
|
+
/** Get the as-agent usage tracker. */
|
|
602
|
+
getAsTracker(): AgentUsageTracker;
|
|
603
|
+
/** Get the lmscript cost tracker (if available). */
|
|
604
|
+
getLmTracker(): CostTracker | undefined;
|
|
605
|
+
}
|
|
606
|
+
interface UnifiedCostSummary {
|
|
607
|
+
/** as-agent's view: per-turn token counts and optional cost estimate. */
|
|
608
|
+
asAgent: {
|
|
609
|
+
usage: TokenUsage;
|
|
610
|
+
turns: number;
|
|
611
|
+
costEstimate?: UsageCostEstimate;
|
|
612
|
+
};
|
|
613
|
+
/** lmscript's view: total tokens, cost, and per-function breakdown. */
|
|
614
|
+
lmscript?: {
|
|
615
|
+
totalTokens: number;
|
|
616
|
+
totalCost: number;
|
|
617
|
+
byFunction: Record<string, {
|
|
618
|
+
calls: number;
|
|
619
|
+
totalTokens: number;
|
|
620
|
+
promptTokens: number;
|
|
621
|
+
completionTokens: number;
|
|
622
|
+
}>;
|
|
623
|
+
};
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
type EventHandler = (event: AgentEvent) => void;
|
|
52
627
|
/**
|
|
53
628
|
* ObotoAgent is the central orchestrator for dual-LLM agent execution.
|
|
54
629
|
*
|
|
55
630
|
* It binds together:
|
|
56
|
-
* - llm-wrapper (LLM communication via local and remote providers)
|
|
57
|
-
* - lmscript (structured/schema-validated calls
|
|
631
|
+
* - llm-wrapper (LLM communication via local and remote providers / LLMRouter)
|
|
632
|
+
* - lmscript (structured/schema-validated calls, agent loop, infrastructure)
|
|
58
633
|
* - swiss-army-tool (tool execution via Router)
|
|
59
634
|
* - as-agent (session state and conversation history)
|
|
60
635
|
*
|
|
61
636
|
* All interaction flows through an event-driven architecture.
|
|
637
|
+
*
|
|
638
|
+
* Key integration improvements (v0.2):
|
|
639
|
+
* - Accepts LLMRouter for automatic failover and health tracking
|
|
640
|
+
* - Uses lmscript's AgentLoop instead of a custom tool-calling loop
|
|
641
|
+
* - Wires lmscript infrastructure: cache, cost tracking, rate limiting, middleware
|
|
642
|
+
* - Bridges streaming via chatStream through the full lmscript stack
|
|
62
643
|
*/
|
|
63
644
|
declare class ObotoAgent {
|
|
64
645
|
private bus;
|
|
65
646
|
private localRuntime;
|
|
647
|
+
private remoteRuntime;
|
|
66
648
|
private localProvider;
|
|
67
649
|
private remoteProvider;
|
|
68
650
|
private contextManager;
|
|
@@ -75,36 +657,116 @@ declare class ObotoAgent {
|
|
|
75
657
|
private maxIterations;
|
|
76
658
|
private config;
|
|
77
659
|
private onToken?;
|
|
660
|
+
private costTracker?;
|
|
661
|
+
private modelPricing?;
|
|
662
|
+
private rateLimiter?;
|
|
663
|
+
private middleware;
|
|
664
|
+
private budget?;
|
|
665
|
+
private conversationRAG?;
|
|
666
|
+
private permissionGuard?;
|
|
667
|
+
private sessionCompactor?;
|
|
668
|
+
private hookIntegration?;
|
|
669
|
+
private slashCommands;
|
|
670
|
+
private usageTracker;
|
|
671
|
+
private usageBridge;
|
|
672
|
+
private routerEventBridge;
|
|
78
673
|
constructor(config: ObotoAgentConfig);
|
|
79
674
|
/** Subscribe to agent events. Returns an unsubscribe function. */
|
|
80
|
-
on(type: AgentEventType, handler: EventHandler
|
|
675
|
+
on(type: AgentEventType, handler: EventHandler): () => void;
|
|
81
676
|
/** Subscribe to an event for a single emission. */
|
|
82
|
-
once(type: AgentEventType, handler: EventHandler
|
|
677
|
+
once(type: AgentEventType, handler: EventHandler): () => void;
|
|
83
678
|
/** Submit user input to the agent. Triggers the execution loop. */
|
|
84
679
|
submitInput(text: string): Promise<void>;
|
|
85
680
|
/**
|
|
86
681
|
* Interrupt the current execution loop.
|
|
87
682
|
* Optionally inject new directives into the context.
|
|
88
683
|
*/
|
|
89
|
-
interrupt(newDirectives?: string): void
|
|
684
|
+
interrupt(newDirectives?: string): Promise<void>;
|
|
90
685
|
/** Get the current session state. */
|
|
91
686
|
getSession(): Session;
|
|
92
687
|
/** Whether the agent is currently processing input. */
|
|
93
688
|
get processing(): boolean;
|
|
94
|
-
/**
|
|
689
|
+
/** Get cost tracking summary (if cost tracking is enabled). */
|
|
690
|
+
getCostSummary(): {
|
|
691
|
+
totalCost: number;
|
|
692
|
+
totalTokens: number;
|
|
693
|
+
byFunction: Record<string, {
|
|
694
|
+
calls: number;
|
|
695
|
+
totalTokens: number;
|
|
696
|
+
promptTokens: number;
|
|
697
|
+
completionTokens: number;
|
|
698
|
+
}>;
|
|
699
|
+
} | undefined;
|
|
700
|
+
/**
|
|
701
|
+
* Get unified cost summary combining both as-agent and lmscript tracking.
|
|
702
|
+
* Uses the UsageBridge to provide a single view of all token/cost data.
|
|
703
|
+
*/
|
|
704
|
+
getUnifiedCostSummary(asPricing?: _sschepis_as_agent.ModelPricing): UnifiedCostSummary;
|
|
705
|
+
/** Get the usage bridge for direct access to unified tracking. */
|
|
706
|
+
getUsageBridge(): UsageBridge;
|
|
707
|
+
/** Remove all event listeners and detach router event subscriptions. */
|
|
95
708
|
removeAllListeners(): void;
|
|
709
|
+
/** Sync session and repopulate context manager (for reuse across turns). */
|
|
710
|
+
syncSession(session: Session): Promise<void>;
|
|
711
|
+
/** Update the streaming token callback between turns. */
|
|
712
|
+
setOnToken(callback: ((token: string) => void) | undefined): void;
|
|
713
|
+
/** Get the ConversationRAG instance (if RAG is enabled). */
|
|
714
|
+
getConversationRAG(): ConversationRAG | undefined;
|
|
715
|
+
/** Get the slash command registry. */
|
|
716
|
+
getSlashCommands(): SlashCommandRegistry;
|
|
717
|
+
/** Get the as-agent usage tracker. */
|
|
718
|
+
getUsageTracker(): AgentUsageTracker;
|
|
719
|
+
/** Get the permission guard (if permissions are configured). */
|
|
720
|
+
getPermissionGuard(): PermissionGuard | undefined;
|
|
721
|
+
/** Get the session compactor (if compaction is configured). */
|
|
722
|
+
getSessionCompactor(): SessionCompactor | undefined;
|
|
723
|
+
/** Get the router event bridge for observability into LLMRouter health. */
|
|
724
|
+
getRouterEventBridge(): RouterEventBridge;
|
|
725
|
+
/**
|
|
726
|
+
* Manually compact the session. Returns null if compaction is not configured.
|
|
727
|
+
*/
|
|
728
|
+
compactSession(): _sschepis_as_agent.CompactionResult | null;
|
|
729
|
+
/**
|
|
730
|
+
* Retrieve relevant past context for a query via the RAG pipeline.
|
|
731
|
+
* Returns undefined if RAG is not configured.
|
|
732
|
+
*/
|
|
733
|
+
retrieveContext(query: string): Promise<string | undefined>;
|
|
734
|
+
/**
|
|
735
|
+
* Record a message in the session, context manager, and optionally RAG index.
|
|
736
|
+
* Centralizes message recording to ensure RAG indexing stays in sync.
|
|
737
|
+
*/
|
|
738
|
+
private recordMessage;
|
|
739
|
+
/**
|
|
740
|
+
* Record a tool execution result in the RAG index.
|
|
741
|
+
*/
|
|
742
|
+
private recordToolResult;
|
|
96
743
|
private executionLoop;
|
|
97
744
|
private triage;
|
|
98
|
-
/** Maximum characters per tool result before truncation. */
|
|
99
|
-
private static readonly MAX_TOOL_RESULT_CHARS;
|
|
100
|
-
/** Maximum times the same tool+args can repeat before forcing a text response. */
|
|
101
|
-
private static readonly MAX_DUPLICATE_CALLS;
|
|
102
745
|
/**
|
|
103
|
-
* Execute
|
|
104
|
-
*
|
|
105
|
-
*
|
|
746
|
+
* Execute using lmscript's AgentLoop for iterative tool calling.
|
|
747
|
+
* This replaces the old custom tool loop with lmscript's battle-tested implementation.
|
|
748
|
+
*
|
|
749
|
+
* Benefits:
|
|
750
|
+
* - Schema validation on final output
|
|
751
|
+
* - Budget checking via CostTracker
|
|
752
|
+
* - Rate limiting via RateLimiter
|
|
753
|
+
* - Middleware lifecycle hooks
|
|
754
|
+
* - Automatic retry with backoff
|
|
106
755
|
*/
|
|
107
|
-
private
|
|
756
|
+
private executeWithAgentLoop;
|
|
757
|
+
/**
|
|
758
|
+
* Execute with streaming token emission.
|
|
759
|
+
* Uses the raw llm-wrapper provider for streaming, combined with
|
|
760
|
+
* manual tool calling (since streaming + structured agent loops are complex).
|
|
761
|
+
*
|
|
762
|
+
* This preserves real-time token delivery while still leveraging
|
|
763
|
+
* the lmscript infrastructure:
|
|
764
|
+
* - Rate limiting (acquire/reportTokens per call)
|
|
765
|
+
* - Cost tracking (trackUsage per call)
|
|
766
|
+
* - Budget checking (checkBudget before each call)
|
|
767
|
+
* - Middleware lifecycle hooks (onBeforeExecute/onComplete per turn)
|
|
768
|
+
*/
|
|
769
|
+
private executeWithStreaming;
|
|
108
770
|
/**
|
|
109
771
|
* Stream an LLM call, emitting tokens in real-time, then aggregate into
|
|
110
772
|
* a full StandardChatResponse (including accumulated tool calls).
|
|
@@ -112,25 +774,6 @@ declare class ObotoAgent {
|
|
|
112
774
|
private streamAndAggregate;
|
|
113
775
|
}
|
|
114
776
|
|
|
115
|
-
type EventHandler = (event: AgentEvent) => void;
|
|
116
|
-
/**
|
|
117
|
-
* Platform-agnostic typed event bus.
|
|
118
|
-
* Uses a plain Map instead of Node.js EventEmitter for browser/Deno/Bun compatibility.
|
|
119
|
-
*/
|
|
120
|
-
declare class AgentEventBus {
|
|
121
|
-
private listeners;
|
|
122
|
-
/** Subscribe to an event type. Returns an unsubscribe function. */
|
|
123
|
-
on(type: AgentEventType, handler: EventHandler): () => void;
|
|
124
|
-
/** Unsubscribe a handler from an event type. */
|
|
125
|
-
off(type: AgentEventType, handler: EventHandler): void;
|
|
126
|
-
/** Subscribe to an event type for a single emission. */
|
|
127
|
-
once(type: AgentEventType, handler: EventHandler): () => void;
|
|
128
|
-
/** Emit an event to all subscribers. */
|
|
129
|
-
emit(type: AgentEventType, payload: unknown): void;
|
|
130
|
-
/** Remove all listeners for all event types. */
|
|
131
|
-
removeAllListeners(): void;
|
|
132
|
-
}
|
|
133
|
-
|
|
134
777
|
/** Parameter schema for the omni-tool bridge. */
|
|
135
778
|
declare const RouterToolParams: z.ZodObject<{
|
|
136
779
|
command: z.ZodString;
|
|
@@ -160,12 +803,323 @@ declare function sessionToHistory(session: Session): ChatMessage[];
|
|
|
160
803
|
declare function createEmptySession(): Session;
|
|
161
804
|
|
|
162
805
|
/**
|
|
163
|
-
*
|
|
806
|
+
* A provider-like object that has `chat()` and `stream()` methods.
|
|
807
|
+
* Both `BaseProvider` and `LLMRouter` implement this interface.
|
|
808
|
+
*/
|
|
809
|
+
type ProviderLike = {
|
|
810
|
+
chat(params: StandardChatParams): Promise<_sschepis_llm_wrapper.StandardChatResponse>;
|
|
811
|
+
stream(params: StandardChatParams): AsyncIterable<_sschepis_llm_wrapper.StandardChatChunk>;
|
|
812
|
+
readonly providerName?: string;
|
|
813
|
+
};
|
|
814
|
+
/**
|
|
815
|
+
* Adapt a llm-wrapper BaseProvider (or LLMRouter) into lmscript's LLMProvider interface.
|
|
164
816
|
*
|
|
165
817
|
* This allows lmscript's LScriptRuntime to use llm-wrapper providers for
|
|
166
818
|
* structured calls (e.g. triage) that need schema validation.
|
|
819
|
+
*
|
|
820
|
+
* Bridges both `chat()` and `chatStream()` — enabling streaming through the
|
|
821
|
+
* full lmscript stack (including `executeStream()`).
|
|
822
|
+
*/
|
|
823
|
+
declare function toLmscriptProvider(provider: ProviderLike, name?: string): LLMProvider;
|
|
824
|
+
|
|
825
|
+
/**
|
|
826
|
+
* tool-extensions.ts — Swiss-army-tool integration extensions for oboto-agent.
|
|
827
|
+
*
|
|
828
|
+
* This module provides:
|
|
829
|
+
* 1. AgentDynamicTools — A DynamicBranchNode subclass for runtime tool discovery
|
|
830
|
+
* 2. createToolTimingMiddleware — Swiss-army-tool Middleware that emits timing events
|
|
831
|
+
* 3. createAgentToolTree — Helper to build a pre-wired tool tree with memory + dynamic tools
|
|
832
|
+
*/
|
|
833
|
+
|
|
834
|
+
interface DynamicToolProvider {
|
|
835
|
+
/**
|
|
836
|
+
* Called when the branch needs refreshing.
|
|
837
|
+
* Return an array of leaf node configs to populate the dynamic branch.
|
|
838
|
+
*/
|
|
839
|
+
discover(): Promise<DynamicToolEntry[]> | DynamicToolEntry[];
|
|
840
|
+
}
|
|
841
|
+
interface DynamicToolEntry {
|
|
842
|
+
name: string;
|
|
843
|
+
description: string;
|
|
844
|
+
requiredArgs?: string[] | Record<string, {
|
|
845
|
+
type?: string;
|
|
846
|
+
description?: string;
|
|
847
|
+
}>;
|
|
848
|
+
optionalArgs?: string[] | Record<string, {
|
|
849
|
+
type?: string;
|
|
850
|
+
description?: string;
|
|
851
|
+
default?: unknown;
|
|
852
|
+
}>;
|
|
853
|
+
handler: (kwargs: Record<string, unknown>) => string | Promise<string>;
|
|
854
|
+
}
|
|
855
|
+
interface AgentToolTreeConfig {
|
|
856
|
+
/** Session manager for the swiss-army-tool Router */
|
|
857
|
+
session: SessionManager;
|
|
858
|
+
/** Whether to include the memory module (set/get/list/pin). Default: true */
|
|
859
|
+
includeMemory?: boolean;
|
|
860
|
+
/** Additional static branches to add to the tree */
|
|
861
|
+
staticBranches?: BranchNode[];
|
|
862
|
+
/** Dynamic tool providers to register. Each entry becomes a DynamicBranchNode */
|
|
863
|
+
dynamicProviders?: Array<{
|
|
864
|
+
name: string;
|
|
865
|
+
description: string;
|
|
866
|
+
provider: DynamicToolProvider;
|
|
867
|
+
/** TTL in ms before the provider is re-queried. Default: 60000 */
|
|
868
|
+
ttlMs?: number;
|
|
869
|
+
}>;
|
|
870
|
+
}
|
|
871
|
+
/**
|
|
872
|
+
* A DynamicBranchNode that discovers tools at runtime from a provider.
|
|
873
|
+
*
|
|
874
|
+
* Use this to integrate external tool sources (MCP servers, plugin systems,
|
|
875
|
+
* API discovery endpoints, etc.) into the swiss-army-tool command tree.
|
|
876
|
+
*
|
|
877
|
+
* The provider's `discover()` method is called when the TTL expires,
|
|
878
|
+
* and the returned entries are registered as LeafNode children.
|
|
879
|
+
*
|
|
880
|
+
* ```ts
|
|
881
|
+
* const mcpTools = new AgentDynamicTools({
|
|
882
|
+
* name: "mcp",
|
|
883
|
+
* description: "Tools discovered from MCP servers",
|
|
884
|
+
* provider: myMcpProvider,
|
|
885
|
+
* ttlMs: 30_000, // refresh every 30s
|
|
886
|
+
* });
|
|
887
|
+
* ```
|
|
888
|
+
*/
|
|
889
|
+
declare class AgentDynamicTools extends DynamicBranchNode {
|
|
890
|
+
private provider;
|
|
891
|
+
constructor(config: {
|
|
892
|
+
name: string;
|
|
893
|
+
description: string;
|
|
894
|
+
provider: DynamicToolProvider;
|
|
895
|
+
ttlMs?: number;
|
|
896
|
+
});
|
|
897
|
+
protected refresh(): Promise<void>;
|
|
898
|
+
/** Manually register a tool entry without waiting for refresh. */
|
|
899
|
+
registerTool(entry: DynamicToolEntry): void;
|
|
900
|
+
/** Remove a dynamically registered tool by name. */
|
|
901
|
+
unregisterTool(name: string): boolean;
|
|
902
|
+
}
|
|
903
|
+
/**
|
|
904
|
+
* Creates a swiss-army-tool Middleware that emits tool execution timing
|
|
905
|
+
* and results through the agent's event bus.
|
|
906
|
+
*
|
|
907
|
+
* This bridges swiss-army-tool's execution context into oboto-agent's
|
|
908
|
+
* event-driven architecture, enabling:
|
|
909
|
+
* - Real-time tool execution duration monitoring
|
|
910
|
+
* - Tool execution logging / tracing
|
|
911
|
+
* - Performance analytics
|
|
912
|
+
*
|
|
913
|
+
* ```ts
|
|
914
|
+
* const timingMw = createToolTimingMiddleware(agent.bus);
|
|
915
|
+
* router.use(timingMw);
|
|
916
|
+
* ```
|
|
917
|
+
*/
|
|
918
|
+
declare function createToolTimingMiddleware(bus: AgentEventBus): Middleware;
|
|
919
|
+
/**
|
|
920
|
+
* Creates a swiss-army-tool Middleware that enforces a maximum execution
|
|
921
|
+
* time for any tool call. Useful as a safety net.
|
|
922
|
+
*/
|
|
923
|
+
declare function createToolTimeoutMiddleware(maxMs: number): Middleware;
|
|
924
|
+
/**
|
|
925
|
+
* Creates a swiss-army-tool Middleware that logs all tool calls to the
|
|
926
|
+
* session's KV store for later review. The agent can access these via
|
|
927
|
+
* the memory module.
|
|
928
|
+
*/
|
|
929
|
+
declare function createToolAuditMiddleware(session: SessionManager): Middleware;
|
|
930
|
+
/**
|
|
931
|
+
* Build a pre-wired swiss-army-tool command tree that includes:
|
|
932
|
+
* - Memory module (set/get/list/search/pin/unpin/delete/tag)
|
|
933
|
+
* - Dynamic tool branches from providers
|
|
934
|
+
* - Any additional static branches
|
|
935
|
+
*
|
|
936
|
+
* Returns the root BranchNode, ready to be passed to `new Router(root, session)`.
|
|
937
|
+
*
|
|
938
|
+
* ```ts
|
|
939
|
+
* const root = createAgentToolTree({
|
|
940
|
+
* session,
|
|
941
|
+
* includeMemory: true,
|
|
942
|
+
* dynamicProviders: [
|
|
943
|
+
* { name: "mcp", description: "MCP tools", provider: mcpProvider },
|
|
944
|
+
* ],
|
|
945
|
+
* staticBranches: [myFilesystemBranch, myDatabaseBranch],
|
|
946
|
+
* });
|
|
947
|
+
* const router = new Router(root, session);
|
|
948
|
+
* ```
|
|
949
|
+
*/
|
|
950
|
+
declare function createAgentToolTree(config: AgentToolTreeConfig): BranchNode;
|
|
951
|
+
|
|
952
|
+
/**
|
|
953
|
+
* pipeline-workflows.ts — Multi-step agent workflows using lmscript's Pipeline.
|
|
954
|
+
*
|
|
955
|
+
* This module provides pre-built and composable pipeline patterns for
|
|
956
|
+
* chaining LLM calls where the typed output of one step feeds into the next.
|
|
957
|
+
*
|
|
958
|
+
* Key patterns:
|
|
959
|
+
* 1. Triage → Execute → Summarize
|
|
960
|
+
* 2. Analyze → Plan → Execute
|
|
961
|
+
* 3. Custom pipeline builder for agent-specific workflows
|
|
962
|
+
*/
|
|
963
|
+
|
|
964
|
+
/** Output of a triage step — determines routing and intent. */
|
|
965
|
+
declare const TriagePipelineSchema: z.ZodObject<{
|
|
966
|
+
intent: z.ZodString;
|
|
967
|
+
complexity: z.ZodEnum<["simple", "moderate", "complex"]>;
|
|
968
|
+
requiresTools: z.ZodBoolean;
|
|
969
|
+
suggestedApproach: z.ZodString;
|
|
970
|
+
escalate: z.ZodBoolean;
|
|
971
|
+
}, "strip", z.ZodTypeAny, {
|
|
972
|
+
escalate: boolean;
|
|
973
|
+
intent: string;
|
|
974
|
+
complexity: "simple" | "moderate" | "complex";
|
|
975
|
+
requiresTools: boolean;
|
|
976
|
+
suggestedApproach: string;
|
|
977
|
+
}, {
|
|
978
|
+
escalate: boolean;
|
|
979
|
+
intent: string;
|
|
980
|
+
complexity: "simple" | "moderate" | "complex";
|
|
981
|
+
requiresTools: boolean;
|
|
982
|
+
suggestedApproach: string;
|
|
983
|
+
}>;
|
|
984
|
+
type TriagePipelineOutput = z.infer<typeof TriagePipelineSchema>;
|
|
985
|
+
/** Output of a planning step — breaks work into steps. */
|
|
986
|
+
declare const PlanSchema: z.ZodObject<{
|
|
987
|
+
steps: z.ZodArray<z.ZodObject<{
|
|
988
|
+
description: z.ZodString;
|
|
989
|
+
toolRequired: z.ZodOptional<z.ZodString>;
|
|
990
|
+
expectedOutput: z.ZodOptional<z.ZodString>;
|
|
991
|
+
}, "strip", z.ZodTypeAny, {
|
|
992
|
+
description: string;
|
|
993
|
+
toolRequired?: string | undefined;
|
|
994
|
+
expectedOutput?: string | undefined;
|
|
995
|
+
}, {
|
|
996
|
+
description: string;
|
|
997
|
+
toolRequired?: string | undefined;
|
|
998
|
+
expectedOutput?: string | undefined;
|
|
999
|
+
}>, "many">;
|
|
1000
|
+
estimatedComplexity: z.ZodEnum<["low", "medium", "high"]>;
|
|
1001
|
+
reasoning: z.ZodString;
|
|
1002
|
+
}, "strip", z.ZodTypeAny, {
|
|
1003
|
+
reasoning: string;
|
|
1004
|
+
steps: {
|
|
1005
|
+
description: string;
|
|
1006
|
+
toolRequired?: string | undefined;
|
|
1007
|
+
expectedOutput?: string | undefined;
|
|
1008
|
+
}[];
|
|
1009
|
+
estimatedComplexity: "low" | "high" | "medium";
|
|
1010
|
+
}, {
|
|
1011
|
+
reasoning: string;
|
|
1012
|
+
steps: {
|
|
1013
|
+
description: string;
|
|
1014
|
+
toolRequired?: string | undefined;
|
|
1015
|
+
expectedOutput?: string | undefined;
|
|
1016
|
+
}[];
|
|
1017
|
+
estimatedComplexity: "low" | "high" | "medium";
|
|
1018
|
+
}>;
|
|
1019
|
+
type PlanOutput = z.infer<typeof PlanSchema>;
|
|
1020
|
+
/** Output of an execution step — the actual work result. */
|
|
1021
|
+
declare const ExecutionSchema: z.ZodObject<{
|
|
1022
|
+
response: z.ZodString;
|
|
1023
|
+
stepsCompleted: z.ZodNumber;
|
|
1024
|
+
toolsUsed: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1025
|
+
confidence: z.ZodEnum<["low", "medium", "high"]>;
|
|
1026
|
+
}, "strip", z.ZodTypeAny, {
|
|
1027
|
+
response: string;
|
|
1028
|
+
stepsCompleted: number;
|
|
1029
|
+
confidence: "low" | "high" | "medium";
|
|
1030
|
+
toolsUsed?: string[] | undefined;
|
|
1031
|
+
}, {
|
|
1032
|
+
response: string;
|
|
1033
|
+
stepsCompleted: number;
|
|
1034
|
+
confidence: "low" | "high" | "medium";
|
|
1035
|
+
toolsUsed?: string[] | undefined;
|
|
1036
|
+
}>;
|
|
1037
|
+
type ExecutionOutput = z.infer<typeof ExecutionSchema>;
|
|
1038
|
+
/** Output of a summarization step — condenses results. */
|
|
1039
|
+
declare const SummarySchema: z.ZodObject<{
|
|
1040
|
+
summary: z.ZodString;
|
|
1041
|
+
keyPoints: z.ZodArray<z.ZodString, "many">;
|
|
1042
|
+
followUpSuggestions: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
1043
|
+
}, "strip", z.ZodTypeAny, {
|
|
1044
|
+
summary: string;
|
|
1045
|
+
keyPoints: string[];
|
|
1046
|
+
followUpSuggestions?: string[] | undefined;
|
|
1047
|
+
}, {
|
|
1048
|
+
summary: string;
|
|
1049
|
+
keyPoints: string[];
|
|
1050
|
+
followUpSuggestions?: string[] | undefined;
|
|
1051
|
+
}>;
|
|
1052
|
+
type SummaryOutput = z.infer<typeof SummarySchema>;
|
|
1053
|
+
/**
|
|
1054
|
+
* Create a triage step function for the pipeline.
|
|
167
1055
|
*/
|
|
168
|
-
declare function
|
|
1056
|
+
declare function createTriageStep(modelName: string, systemPrompt?: string): LScriptFunction<string, typeof TriagePipelineSchema>;
|
|
1057
|
+
/**
|
|
1058
|
+
* Create a planning step that takes triage output and produces a plan.
|
|
1059
|
+
*/
|
|
1060
|
+
declare function createPlanStep(modelName: string, systemPrompt?: string): LScriptFunction<TriagePipelineOutput, typeof PlanSchema>;
|
|
1061
|
+
/**
|
|
1062
|
+
* Create an execution step that takes a plan and produces results.
|
|
1063
|
+
*/
|
|
1064
|
+
declare function createExecutionStep(modelName: string, tools?: LScriptFunction<any, any>["tools"], systemPrompt?: string): LScriptFunction<PlanOutput, typeof ExecutionSchema>;
|
|
1065
|
+
/**
|
|
1066
|
+
* Create a summarization step that condenses execution results.
|
|
1067
|
+
*/
|
|
1068
|
+
declare function createSummaryStep(modelName: string, systemPrompt?: string): LScriptFunction<ExecutionOutput, typeof SummarySchema>;
|
|
1069
|
+
/**
|
|
1070
|
+
* Build a Triage → Plan → Execute pipeline.
|
|
1071
|
+
*
|
|
1072
|
+
* Takes raw user input, classifies it, plans the approach,
|
|
1073
|
+
* and executes the plan.
|
|
1074
|
+
*
|
|
1075
|
+
* ```ts
|
|
1076
|
+
* const pipeline = createTriagePlanExecutePipeline("gpt-4");
|
|
1077
|
+
* const result = await pipeline.execute(runtime, "Refactor the auth module");
|
|
1078
|
+
* console.log(result.finalData.response);
|
|
1079
|
+
* ```
|
|
1080
|
+
*/
|
|
1081
|
+
declare function createTriagePlanExecutePipeline(modelName: string, tools?: LScriptFunction<any, any>["tools"]): Pipeline<string, ExecutionOutput>;
|
|
1082
|
+
/**
|
|
1083
|
+
* Build a Triage → Plan → Execute → Summarize pipeline.
|
|
1084
|
+
*
|
|
1085
|
+
* Full end-to-end pipeline that classifies, plans, executes,
|
|
1086
|
+
* and then summarizes the results.
|
|
1087
|
+
*
|
|
1088
|
+
* ```ts
|
|
1089
|
+
* const pipeline = createFullPipeline("gpt-4");
|
|
1090
|
+
* const result = await pipeline.execute(runtime, "Build a REST API");
|
|
1091
|
+
* console.log(result.finalData.summary);
|
|
1092
|
+
* console.log(`Total tokens: ${result.totalUsage.totalTokens}`);
|
|
1093
|
+
* ```
|
|
1094
|
+
*/
|
|
1095
|
+
declare function createFullPipeline(modelName: string, tools?: LScriptFunction<any, any>["tools"]): Pipeline<string, SummaryOutput>;
|
|
1096
|
+
/**
|
|
1097
|
+
* Build a simple Analyze → Respond pipeline.
|
|
1098
|
+
* Good for straightforward queries that don't need planning.
|
|
1099
|
+
*/
|
|
1100
|
+
declare function createAnalyzeRespondPipeline(modelName: string): Pipeline<string, ExecutionOutput>;
|
|
1101
|
+
/**
|
|
1102
|
+
* Configuration for running a pipeline within the agent context.
|
|
1103
|
+
*/
|
|
1104
|
+
interface AgentPipelineConfig {
|
|
1105
|
+
/** The lmscript runtime to execute the pipeline on. */
|
|
1106
|
+
runtime: LScriptRuntime;
|
|
1107
|
+
/** The model name for all pipeline steps (can be overridden per-step). */
|
|
1108
|
+
modelName: string;
|
|
1109
|
+
/** Optional tools available to the execution step. */
|
|
1110
|
+
tools?: LScriptFunction<any, any>["tools"];
|
|
1111
|
+
/** Callback for each pipeline step completion. */
|
|
1112
|
+
onStepComplete?: (stepName: string, data: unknown, usage: {
|
|
1113
|
+
promptTokens: number;
|
|
1114
|
+
completionTokens: number;
|
|
1115
|
+
totalTokens: number;
|
|
1116
|
+
} | undefined) => void;
|
|
1117
|
+
}
|
|
1118
|
+
/**
|
|
1119
|
+
* Run a pipeline and emit step completion events.
|
|
1120
|
+
* This is a convenience wrapper that adds observability.
|
|
1121
|
+
*/
|
|
1122
|
+
declare function runAgentPipeline<I, O>(pipeline: Pipeline<I, O>, input: I, config: AgentPipelineConfig): Promise<PipelineResult<O>>;
|
|
169
1123
|
|
|
170
1124
|
/**
|
|
171
1125
|
* Manages the sliding context window with automatic summarization.
|
|
@@ -192,7 +1146,7 @@ declare class ContextManager {
|
|
|
192
1146
|
declare const TriageSchema: z.ZodObject<{
|
|
193
1147
|
escalate: z.ZodBoolean;
|
|
194
1148
|
reasoning: z.ZodString;
|
|
195
|
-
directResponse: z.ZodOptional<z.ZodString>;
|
|
1149
|
+
directResponse: z.ZodEffects<z.ZodOptional<z.ZodNullable<z.ZodString>>, string | undefined, string | null | undefined>;
|
|
196
1150
|
}, "strip", z.ZodTypeAny, {
|
|
197
1151
|
escalate: boolean;
|
|
198
1152
|
reasoning: string;
|
|
@@ -200,7 +1154,7 @@ declare const TriageSchema: z.ZodObject<{
|
|
|
200
1154
|
}, {
|
|
201
1155
|
escalate: boolean;
|
|
202
1156
|
reasoning: string;
|
|
203
|
-
directResponse?: string | undefined;
|
|
1157
|
+
directResponse?: string | null | undefined;
|
|
204
1158
|
}>;
|
|
205
1159
|
type TriageInput = {
|
|
206
1160
|
userInput: string;
|
|
@@ -213,4 +1167,4 @@ type TriageInput = {
|
|
|
213
1167
|
*/
|
|
214
1168
|
declare function createTriageFunction(modelName: string): LScriptFunction<TriageInput, typeof TriageSchema>;
|
|
215
1169
|
|
|
216
|
-
export { type AgentEvent, AgentEventBus, type AgentEventType, ContextManager, ObotoAgent, type ObotoAgentConfig, type ToolExecutionEvent, type TriageResult, TriageSchema, createEmptySession, createRouterTool, createTriageFunction, fromChat, sessionToHistory, toChat, toLmscriptProvider };
|
|
1170
|
+
export { AgentDynamicTools, type AgentEvent, AgentEventBus, type AgentEventType, type AgentPipelineConfig, type AgentToolTreeConfig, AgentUsageTracker, ContextManager, ConversationRAG, type ConversationRAGConfig, type DynamicToolEntry, type DynamicToolProvider, type ExecutionOutput, ExecutionSchema, HookIntegration, ObotoAgent, type ObotoAgentConfig, PermissionGuard, type PlanOutput, PlanSchema, type ProviderLike$1 as ProviderLike, type RAGRetrievalResult, RouterEventBridge, SessionCompactor, SlashCommandRegistry, type SummaryOutput, SummarySchema, type ToolExecutionEvent, type TriagePipelineOutput, TriagePipelineSchema, type TriageResult, TriageSchema, type UnifiedCostSummary, UsageBridge, asTokenUsageToLmscript, createAgentToolTree, createAnalyzeRespondPipeline, createEmptySession, createExecutionStep, createFullPipeline, createPlanStep, createRouterTool, createSummaryStep, createToolAuditMiddleware, createToolTimeoutMiddleware, createToolTimingMiddleware, createTriageFunction, createTriagePlanExecutePipeline, createTriageStep, estimateCostFromAsAgent, fromChat, isLLMRouter, lmscriptToAsTokenUsage, runAgentPipeline, sessionToHistory, toChat, toLmscriptProvider };
|