@sschepis/oboto-agent 0.1.0 → 0.1.2

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 CHANGED
@@ -1,13 +1,14 @@
1
1
  import { Session, ConversationMessage } from '@sschepis/as-agent';
2
- import { LLMProvider, ToolDefinition, ChatMessage, LScriptRuntime, LScriptFunction } from '@sschepis/lmscript';
2
+ import { BaseProvider } from '@sschepis/llm-wrapper';
3
3
  import { Router, BranchNode } from '@sschepis/swiss-army-tool';
4
4
  import { z } from 'zod';
5
+ import { ToolDefinition, ChatMessage, LLMProvider, LScriptRuntime, LScriptFunction } from '@sschepis/lmscript';
5
6
 
6
7
  interface ObotoAgentConfig {
7
8
  /** Small, fast model for triage and summarization (e.g. Ollama, LMStudio) */
8
- localModel: LLMProvider;
9
+ localModel: BaseProvider;
9
10
  /** Powerful model for complex reasoning (e.g. Anthropic, OpenAI, Gemini) */
10
- remoteModel: LLMProvider;
11
+ remoteModel: BaseProvider;
11
12
  /** Model identifier for the local provider (e.g. "llama3:8b") */
12
13
  localModelName: string;
13
14
  /** Model identifier for the remote provider (e.g. "claude-sonnet-4-20250514") */
@@ -50,7 +51,8 @@ type EventHandler$1 = (event: AgentEvent) => void;
50
51
  * ObotoAgent is the central orchestrator for dual-LLM agent execution.
51
52
  *
52
53
  * It binds together:
53
- * - lmscript (LLM I/O via local and remote providers)
54
+ * - llm-wrapper (LLM communication via local and remote providers)
55
+ * - lmscript (structured/schema-validated calls for triage)
54
56
  * - swiss-army-tool (tool execution via Router)
55
57
  * - as-agent (session state and conversation history)
56
58
  *
@@ -59,7 +61,8 @@ type EventHandler$1 = (event: AgentEvent) => void;
59
61
  declare class ObotoAgent {
60
62
  private bus;
61
63
  private localRuntime;
62
- private remoteRuntime;
64
+ private localProvider;
65
+ private remoteProvider;
63
66
  private contextManager;
64
67
  private routerTool;
65
68
  private triageFn;
@@ -89,6 +92,14 @@ declare class ObotoAgent {
89
92
  removeAllListeners(): void;
90
93
  private executionLoop;
91
94
  private triage;
95
+ /** Maximum characters per tool result before truncation. */
96
+ private static readonly MAX_TOOL_RESULT_CHARS;
97
+ /** Maximum times the same tool+args can repeat before forcing a text response. */
98
+ private static readonly MAX_DUPLICATE_CALLS;
99
+ /**
100
+ * Execute the agent loop using llm-wrapper directly.
101
+ * No JSON mode, no schema enforcement — just natural chat with tool calling.
102
+ */
92
103
  private executeWithModel;
93
104
  }
94
105
 
@@ -139,6 +150,14 @@ declare function sessionToHistory(session: Session): ChatMessage[];
139
150
  /** Create an empty as-agent Session. */
140
151
  declare function createEmptySession(): Session;
141
152
 
153
+ /**
154
+ * Adapt a llm-wrapper BaseProvider into lmscript's LLMProvider interface.
155
+ *
156
+ * This allows lmscript's LScriptRuntime to use llm-wrapper providers for
157
+ * structured calls (e.g. triage) that need schema validation.
158
+ */
159
+ declare function toLmscriptProvider(provider: BaseProvider, name?: string): LLMProvider;
160
+
142
161
  /**
143
162
  * Manages the sliding context window with automatic summarization.
144
163
  * Wraps lmscript's ContextStack and uses the local LLM for compression.
@@ -185,4 +204,4 @@ type TriageInput = {
185
204
  */
186
205
  declare function createTriageFunction(modelName: string): LScriptFunction<TriageInput, typeof TriageSchema>;
187
206
 
188
- export { type AgentEvent, AgentEventBus, type AgentEventType, ContextManager, ObotoAgent, type ObotoAgentConfig, type ToolExecutionEvent, type TriageResult, TriageSchema, createEmptySession, createRouterTool, createTriageFunction, fromChat, sessionToHistory, toChat };
207
+ export { type AgentEvent, AgentEventBus, type AgentEventType, ContextManager, ObotoAgent, type ObotoAgentConfig, type ToolExecutionEvent, type TriageResult, TriageSchema, createEmptySession, createRouterTool, createTriageFunction, fromChat, sessionToHistory, toChat, toLmscriptProvider };
package/dist/index.js CHANGED
@@ -1,9 +1,5 @@
1
1
  // src/oboto-agent.ts
2
- import { z as z4 } from "zod";
3
- import {
4
- LScriptRuntime,
5
- AgentLoop
6
- } from "@sschepis/lmscript";
2
+ import { LScriptRuntime } from "@sschepis/lmscript";
7
3
  import { MessageRole as MessageRole2 } from "@sschepis/as-agent";
8
4
 
9
5
  // src/event-bus.ts
@@ -164,6 +160,56 @@ function createRouterTool(router, root) {
164
160
  };
165
161
  }
166
162
 
163
+ // src/adapters/llm-wrapper.ts
164
+ function toLmscriptProvider(provider, name) {
165
+ return {
166
+ name: name ?? provider.providerName,
167
+ async chat(request) {
168
+ const messages = request.messages.map((m) => ({
169
+ role: m.role,
170
+ content: typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => b.text).join("\n")
171
+ }));
172
+ let tools;
173
+ if (request.tools && request.tools.length > 0) {
174
+ tools = request.tools.map((t) => ({
175
+ type: "function",
176
+ function: {
177
+ name: t.name,
178
+ description: t.description,
179
+ parameters: t.parameters
180
+ }
181
+ }));
182
+ }
183
+ const params = {
184
+ model: request.model,
185
+ messages,
186
+ temperature: request.temperature,
187
+ ...tools ? { tools } : {},
188
+ ...request.jsonMode ? { response_format: { type: "json_object" } } : {}
189
+ };
190
+ const response = await provider.chat(params);
191
+ const choice = response.choices[0];
192
+ let toolCalls;
193
+ if (choice?.message?.tool_calls) {
194
+ toolCalls = choice.message.tool_calls.map((tc) => ({
195
+ id: tc.id,
196
+ name: tc.function.name,
197
+ arguments: tc.function.arguments
198
+ }));
199
+ }
200
+ return {
201
+ content: choice?.message?.content ?? "",
202
+ usage: response.usage ? {
203
+ promptTokens: response.usage.prompt_tokens,
204
+ completionTokens: response.usage.completion_tokens,
205
+ totalTokens: response.usage.total_tokens
206
+ } : void 0,
207
+ toolCalls
208
+ };
209
+ }
210
+ };
211
+ }
212
+
167
213
  // src/adapters/memory.ts
168
214
  import {
169
215
  MessageRole
@@ -212,13 +258,11 @@ function createEmptySession() {
212
258
  }
213
259
 
214
260
  // src/oboto-agent.ts
215
- var AgentResponseSchema = z4.object({
216
- response: z4.string().describe("The agent's response to the user")
217
- });
218
- var ObotoAgent = class {
261
+ var ObotoAgent = class _ObotoAgent {
219
262
  bus = new AgentEventBus();
220
263
  localRuntime;
221
- remoteRuntime;
264
+ localProvider;
265
+ remoteProvider;
222
266
  contextManager;
223
267
  routerTool;
224
268
  triageFn;
@@ -230,8 +274,10 @@ var ObotoAgent = class {
230
274
  config;
231
275
  constructor(config) {
232
276
  this.config = config;
233
- this.localRuntime = new LScriptRuntime({ provider: config.localModel });
234
- this.remoteRuntime = new LScriptRuntime({ provider: config.remoteModel });
277
+ this.localProvider = config.localModel;
278
+ this.remoteProvider = config.remoteModel;
279
+ const localLmscript = toLmscriptProvider(config.localModel, "local");
280
+ this.localRuntime = new LScriptRuntime({ provider: localLmscript });
235
281
  this.session = config.session ?? createEmptySession();
236
282
  this.systemPrompt = config.systemPrompt ?? "You are a helpful AI assistant with access to tools.";
237
283
  this.maxIterations = config.maxIterations ?? 10;
@@ -330,7 +376,7 @@ var ObotoAgent = class {
330
376
  this.bus.emit("turn_complete", { model: "local", escalated: false });
331
377
  return;
332
378
  }
333
- const runtime = triageResult.escalate ? this.remoteRuntime : this.localRuntime;
379
+ const provider = triageResult.escalate ? this.remoteProvider : this.localProvider;
334
380
  const modelName = triageResult.escalate ? this.config.remoteModelName : this.config.localModelName;
335
381
  if (triageResult.escalate) {
336
382
  this.bus.emit("agent_thought", {
@@ -339,7 +385,7 @@ var ObotoAgent = class {
339
385
  escalating: true
340
386
  });
341
387
  }
342
- await this.executeWithModel(runtime, modelName, userInput);
388
+ await this.executeWithModel(provider, modelName, userInput);
343
389
  }
344
390
  async triage(userInput) {
345
391
  const recentMessages = this.contextManager.getMessages().slice(-5);
@@ -354,65 +400,138 @@ var ObotoAgent = class {
354
400
  });
355
401
  return result.data;
356
402
  }
357
- async executeWithModel(runtime, modelName, userInput) {
403
+ /** Maximum characters per tool result before truncation. */
404
+ static MAX_TOOL_RESULT_CHARS = 8e3;
405
+ /** Maximum times the same tool+args can repeat before forcing a text response. */
406
+ static MAX_DUPLICATE_CALLS = 2;
407
+ /**
408
+ * Execute the agent loop using llm-wrapper directly.
409
+ * No JSON mode, no schema enforcement — just natural chat with tool calling.
410
+ */
411
+ async executeWithModel(provider, modelName, _userInput) {
358
412
  const contextMessages = this.contextManager.getMessages();
359
- const contextStr = contextMessages.filter((m) => m.role !== "system").map((m) => {
360
- const text = typeof m.content === "string" ? m.content : "[complex content]";
361
- return `${m.role}: ${text}`;
362
- }).join("\n");
363
- const agentFn = {
364
- name: "agent_execute",
365
- model: modelName,
366
- system: this.systemPrompt,
367
- prompt: ({ context }) => context ? `Conversation so far:
368
- ${context}
369
-
370
- Respond to the user's latest message. Use tools when needed.` : `Respond to the user.`,
371
- schema: AgentResponseSchema,
372
- temperature: 0.7,
373
- tools: [this.routerTool]
374
- };
375
- const agent = new AgentLoop(runtime, {
376
- maxIterations: this.maxIterations,
377
- onToolCall: (toolCall) => {
378
- const args = toolCall.arguments;
379
- this.bus.emit("tool_execution_start", {
380
- command: args?.command ?? toolCall.name,
381
- kwargs: args?.kwargs ?? {}
382
- });
383
- this.bus.emit("tool_execution_complete", {
384
- command: args?.command ?? toolCall.name,
385
- kwargs: args?.kwargs ?? {},
386
- result: toolCall.result
413
+ const messages = contextMessages.map((m) => ({
414
+ role: m.role,
415
+ content: typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n")
416
+ }));
417
+ const tool = this.routerTool;
418
+ const tools = [
419
+ {
420
+ type: "function",
421
+ function: {
422
+ name: tool.name,
423
+ description: tool.description,
424
+ parameters: tool.parameters ? JSON.parse(JSON.stringify(tool.parameters)) : { type: "object", properties: {} }
425
+ }
426
+ }
427
+ ];
428
+ let totalToolCalls = 0;
429
+ const callHistory = [];
430
+ for (let iteration = 1; iteration <= this.maxIterations; iteration++) {
431
+ if (this.interrupted) break;
432
+ const isLastIteration = iteration === this.maxIterations;
433
+ const params = {
434
+ model: modelName,
435
+ messages: [...messages],
436
+ temperature: 0.7,
437
+ ...isLastIteration ? {} : { tools, tool_choice: "auto" }
438
+ };
439
+ if (isLastIteration) {
440
+ messages.push({
441
+ role: "user",
442
+ content: "You have used all available tool iterations. Please provide your final response now based on what you have gathered so far. Do not call any more tools."
387
443
  });
388
- if (this.interrupted) return false;
389
- },
390
- onIteration: (_iteration, response) => {
391
- this.bus.emit("agent_thought", {
392
- text: response,
444
+ }
445
+ const response = await provider.chat(params);
446
+ const choice = response.choices[0];
447
+ const content = choice?.message?.content ?? "";
448
+ this.bus.emit("agent_thought", {
449
+ text: content,
450
+ model: modelName,
451
+ iteration
452
+ });
453
+ const toolCalls = choice?.message?.tool_calls;
454
+ if (!toolCalls || toolCalls.length === 0) {
455
+ const responseText = content;
456
+ const assistantMsg = {
457
+ role: MessageRole2.Assistant,
458
+ blocks: [{ kind: "text", text: responseText }]
459
+ };
460
+ this.session.messages.push(assistantMsg);
461
+ await this.contextManager.push(toChat(assistantMsg));
462
+ this.bus.emit("state_updated", { reason: "assistant_response" });
463
+ this.bus.emit("turn_complete", {
393
464
  model: modelName,
394
- iteration: _iteration
465
+ escalated: true,
466
+ iterations: iteration,
467
+ toolCalls: totalToolCalls
395
468
  });
396
- if (this.interrupted) return false;
469
+ return;
397
470
  }
398
- });
399
- const result = await agent.run(agentFn, {
400
- userInput,
401
- context: contextStr
402
- });
403
- const responseText = result.data.response;
404
- const assistantMsg = {
471
+ messages.push({
472
+ role: "assistant",
473
+ content: content || null,
474
+ tool_calls: toolCalls
475
+ });
476
+ for (const tc of toolCalls) {
477
+ if (this.interrupted) break;
478
+ let args;
479
+ try {
480
+ args = JSON.parse(tc.function.arguments);
481
+ } catch {
482
+ args = {};
483
+ }
484
+ const command = args.command ?? tc.function.name;
485
+ const kwargs = args.kwargs ?? {};
486
+ const callSig = JSON.stringify({ command, kwargs });
487
+ const dupeCount = callHistory.filter((s) => s === callSig).length;
488
+ callHistory.push(callSig);
489
+ if (dupeCount >= _ObotoAgent.MAX_DUPLICATE_CALLS) {
490
+ messages.push({
491
+ role: "tool",
492
+ tool_call_id: tc.id,
493
+ content: `You already called "${command}" with these arguments ${dupeCount} time(s) and received the result. Do not repeat this call. Use the data you already have to proceed.`
494
+ });
495
+ this.bus.emit("tool_execution_complete", {
496
+ command,
497
+ kwargs,
498
+ result: "[duplicate call blocked]"
499
+ });
500
+ totalToolCalls++;
501
+ continue;
502
+ }
503
+ this.bus.emit("tool_execution_start", { command, kwargs });
504
+ let result;
505
+ try {
506
+ result = await tool.execute(args);
507
+ } catch (err) {
508
+ result = `Error: ${err instanceof Error ? err.message : String(err)}`;
509
+ }
510
+ const resultStr = typeof result === "string" ? result : JSON.stringify(result);
511
+ const truncated = resultStr.length > _ObotoAgent.MAX_TOOL_RESULT_CHARS ? resultStr.slice(0, _ObotoAgent.MAX_TOOL_RESULT_CHARS) + `
512
+
513
+ [... truncated ${resultStr.length - _ObotoAgent.MAX_TOOL_RESULT_CHARS} characters. Use the data above to proceed.]` : resultStr;
514
+ this.bus.emit("tool_execution_complete", { command, kwargs, result: truncated });
515
+ totalToolCalls++;
516
+ messages.push({
517
+ role: "tool",
518
+ tool_call_id: tc.id,
519
+ content: truncated
520
+ });
521
+ }
522
+ }
523
+ const fallbackMsg = {
405
524
  role: MessageRole2.Assistant,
406
- blocks: [{ kind: "text", text: responseText }]
525
+ blocks: [{ kind: "text", text: "I reached the maximum number of iterations. Here is what I have so far." }]
407
526
  };
408
- this.session.messages.push(assistantMsg);
409
- await this.contextManager.push(toChat(assistantMsg));
410
- this.bus.emit("state_updated", { reason: "assistant_response" });
527
+ this.session.messages.push(fallbackMsg);
528
+ await this.contextManager.push(toChat(fallbackMsg));
529
+ this.bus.emit("state_updated", { reason: "max_iterations" });
411
530
  this.bus.emit("turn_complete", {
412
531
  model: modelName,
413
532
  escalated: true,
414
- iterations: result.iterations,
415
- toolCalls: result.toolCalls.length
533
+ iterations: this.maxIterations,
534
+ toolCalls: totalToolCalls
416
535
  });
417
536
  }
418
537
  };
@@ -426,6 +545,7 @@ export {
426
545
  createTriageFunction,
427
546
  fromChat,
428
547
  sessionToHistory,
429
- toChat
548
+ toChat,
549
+ toLmscriptProvider
430
550
  };
431
551
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/oboto-agent.ts","../src/event-bus.ts","../src/context-manager.ts","../src/triage.ts","../src/adapters/tools.ts","../src/adapters/memory.ts"],"sourcesContent":["import { z } from \"zod\";\nimport {\n LScriptRuntime,\n AgentLoop,\n type LScriptFunction,\n type ToolDefinition,\n type ChatMessage,\n type ToolCall,\n} from \"@sschepis/lmscript\";\nimport type { Session, ConversationMessage } from \"@sschepis/as-agent\";\nimport { MessageRole } from \"@sschepis/as-agent\";\nimport type { ObotoAgentConfig, AgentEventType, AgentEvent, TriageResult } from \"./types.js\";\nimport { AgentEventBus } from \"./event-bus.js\";\nimport { ContextManager } from \"./context-manager.js\";\nimport { createTriageFunction, type TriageInput } from \"./triage.js\";\nimport { createRouterTool } from \"./adapters/tools.js\";\nimport { toChat, fromChat, createEmptySession } from \"./adapters/memory.js\";\n\ntype EventHandler = (event: AgentEvent) => void;\n\n/** Free-form response schema for the main agent loop. */\nconst AgentResponseSchema = z.object({\n response: z.string().describe(\"The agent's response to the user\"),\n});\n\ntype AgentInput = { userInput: string; context: string };\n\n/**\n * ObotoAgent is the central orchestrator for dual-LLM agent execution.\n *\n * It binds together:\n * - lmscript (LLM I/O via local and remote providers)\n * - swiss-army-tool (tool execution via Router)\n * - as-agent (session state and conversation history)\n *\n * All interaction flows through an event-driven architecture.\n */\nexport class ObotoAgent {\n private bus = new AgentEventBus();\n private localRuntime: LScriptRuntime;\n private remoteRuntime: LScriptRuntime;\n private contextManager: ContextManager;\n private routerTool: ToolDefinition<any, any>;\n private triageFn: ReturnType<typeof createTriageFunction>;\n private session: Session;\n private isProcessing = false;\n private interrupted = false;\n private systemPrompt: string;\n private maxIterations: number;\n private config: ObotoAgentConfig;\n\n constructor(config: ObotoAgentConfig) {\n this.config = config;\n this.localRuntime = new LScriptRuntime({ provider: config.localModel });\n this.remoteRuntime = new LScriptRuntime({ provider: config.remoteModel });\n this.session = config.session ?? createEmptySession();\n this.systemPrompt = config.systemPrompt ?? \"You are a helpful AI assistant with access to tools.\";\n this.maxIterations = config.maxIterations ?? 10;\n\n this.contextManager = new ContextManager(\n this.localRuntime,\n config.localModelName,\n config.maxContextTokens ?? 8192\n );\n\n this.routerTool = createRouterTool(config.router);\n this.triageFn = createTriageFunction(config.localModelName);\n\n // Push system prompt into context\n this.contextManager.push({\n role: \"system\",\n content: this.systemPrompt,\n });\n }\n\n // ── Public API ─────────────────────────────────────────────────────\n\n /** Subscribe to agent events. Returns an unsubscribe function. */\n on(type: AgentEventType, handler: EventHandler): () => void {\n return this.bus.on(type, handler);\n }\n\n /** Subscribe to an event for a single emission. */\n once(type: AgentEventType, handler: EventHandler): () => void {\n return this.bus.once(type, handler);\n }\n\n /** Submit user input to the agent. Triggers the execution loop. */\n async submitInput(text: string): Promise<void> {\n if (this.isProcessing) {\n this.interrupt(text);\n return;\n }\n\n this.isProcessing = true;\n this.interrupted = false;\n\n try {\n await this.executionLoop(text);\n } catch (err) {\n this.bus.emit(\"error\", {\n message: err instanceof Error ? err.message : String(err),\n error: err,\n });\n } finally {\n this.isProcessing = false;\n }\n }\n\n /**\n * Interrupt the current execution loop.\n * Optionally inject new directives into the context.\n */\n interrupt(newDirectives?: string): void {\n this.interrupted = true;\n this.bus.emit(\"interruption\", { newDirectives });\n\n if (newDirectives) {\n const msg: ConversationMessage = {\n role: MessageRole.User,\n blocks: [{ kind: \"text\", text: `[INTERRUPTION] ${newDirectives}` }],\n };\n this.session.messages.push(msg);\n this.contextManager.push(toChat(msg));\n this.bus.emit(\"state_updated\", { reason: \"interruption\" });\n }\n }\n\n /** Get the current session state. */\n getSession(): Session {\n return this.session;\n }\n\n /** Whether the agent is currently processing input. */\n get processing(): boolean {\n return this.isProcessing;\n }\n\n /** Remove all event listeners. */\n removeAllListeners(): void {\n this.bus.removeAllListeners();\n }\n\n // ── Internal ───────────────────────────────────────────────────────\n\n private async executionLoop(userInput: string): Promise<void> {\n // 1. Emit user_input and record in session + context\n this.bus.emit(\"user_input\", { text: userInput });\n\n const userMsg: ConversationMessage = {\n role: MessageRole.User,\n blocks: [{ kind: \"text\", text: userInput }],\n };\n this.session.messages.push(userMsg);\n await this.contextManager.push(toChat(userMsg));\n this.bus.emit(\"state_updated\", { reason: \"user_input\" });\n\n // 2. Triage via local LLM\n const triageResult = await this.triage(userInput);\n this.bus.emit(\"triage_result\", triageResult);\n\n if (this.interrupted) return;\n\n // 3. If local can handle directly, emit and return\n if (!triageResult.escalate && triageResult.directResponse) {\n const response = triageResult.directResponse;\n this.bus.emit(\"agent_thought\", { text: response, model: \"local\" });\n\n const assistantMsg: ConversationMessage = {\n role: MessageRole.Assistant,\n blocks: [{ kind: \"text\", text: response }],\n };\n this.session.messages.push(assistantMsg);\n await this.contextManager.push(toChat(assistantMsg));\n this.bus.emit(\"state_updated\", { reason: \"assistant_response\" });\n this.bus.emit(\"turn_complete\", { model: \"local\", escalated: false });\n return;\n }\n\n // 4. Escalate to remote model with tool access\n const runtime = triageResult.escalate ? this.remoteRuntime : this.localRuntime;\n const modelName = triageResult.escalate\n ? this.config.remoteModelName\n : this.config.localModelName;\n\n if (triageResult.escalate) {\n this.bus.emit(\"agent_thought\", {\n text: triageResult.reasoning,\n model: \"local\",\n escalating: true,\n });\n }\n\n await this.executeWithModel(runtime, modelName, userInput);\n }\n\n private async triage(userInput: string): Promise<TriageResult> {\n const recentMessages = this.contextManager.getMessages().slice(-5);\n const recentContext = recentMessages\n .map((m) => {\n const text = typeof m.content === \"string\" ? m.content : \"[complex content]\";\n return `${m.role}: ${text}`;\n })\n .join(\"\\n\");\n\n const result = await this.localRuntime.execute(this.triageFn, {\n userInput,\n recentContext,\n availableTools: this.routerTool.description,\n });\n\n return result.data;\n }\n\n private async executeWithModel(\n runtime: LScriptRuntime,\n modelName: string,\n userInput: string\n ): Promise<void> {\n const contextMessages = this.contextManager.getMessages();\n const contextStr = contextMessages\n .filter((m) => m.role !== \"system\")\n .map((m) => {\n const text = typeof m.content === \"string\" ? m.content : \"[complex content]\";\n return `${m.role}: ${text}`;\n })\n .join(\"\\n\");\n\n const agentFn: LScriptFunction<AgentInput, typeof AgentResponseSchema> = {\n name: \"agent_execute\",\n model: modelName,\n system: this.systemPrompt,\n prompt: ({ context }) =>\n context\n ? `Conversation so far:\\n${context}\\n\\nRespond to the user's latest message. Use tools when needed.`\n : `Respond to the user.`,\n schema: AgentResponseSchema,\n temperature: 0.7,\n tools: [this.routerTool],\n };\n\n const agent = new AgentLoop(runtime, {\n maxIterations: this.maxIterations,\n onToolCall: (toolCall: ToolCall) => {\n const args = toolCall.arguments as { command?: string; kwargs?: Record<string, unknown> } | undefined;\n this.bus.emit(\"tool_execution_start\", {\n command: args?.command ?? toolCall.name,\n kwargs: args?.kwargs ?? {},\n });\n this.bus.emit(\"tool_execution_complete\", {\n command: args?.command ?? toolCall.name,\n kwargs: args?.kwargs ?? {},\n result: toolCall.result,\n });\n\n // Check for interruption\n if (this.interrupted) return false;\n },\n onIteration: (_iteration: number, response: string) => {\n this.bus.emit(\"agent_thought\", {\n text: response,\n model: modelName,\n iteration: _iteration,\n });\n if (this.interrupted) return false;\n },\n });\n\n const result = await agent.run(agentFn, {\n userInput,\n context: contextStr,\n });\n\n // Record final response in session and context\n const responseText = result.data.response;\n const assistantMsg: ConversationMessage = {\n role: MessageRole.Assistant,\n blocks: [{ kind: \"text\", text: responseText }],\n };\n this.session.messages.push(assistantMsg);\n await this.contextManager.push(toChat(assistantMsg));\n this.bus.emit(\"state_updated\", { reason: \"assistant_response\" });\n this.bus.emit(\"turn_complete\", {\n model: modelName,\n escalated: true,\n iterations: result.iterations,\n toolCalls: result.toolCalls.length,\n });\n }\n}\n","import type { AgentEventType, AgentEvent } from \"./types.js\";\n\ntype EventHandler = (event: AgentEvent) => void;\n\n/**\n * Platform-agnostic typed event bus.\n * Uses a plain Map instead of Node.js EventEmitter for browser/Deno/Bun compatibility.\n */\nexport class AgentEventBus {\n private listeners = new Map<AgentEventType, Set<EventHandler>>();\n\n /** Subscribe to an event type. Returns an unsubscribe function. */\n on(type: AgentEventType, handler: EventHandler): () => void {\n if (!this.listeners.has(type)) {\n this.listeners.set(type, new Set());\n }\n this.listeners.get(type)!.add(handler);\n return () => this.off(type, handler);\n }\n\n /** Unsubscribe a handler from an event type. */\n off(type: AgentEventType, handler: EventHandler): void {\n this.listeners.get(type)?.delete(handler);\n }\n\n /** Subscribe to an event type for a single emission. */\n once(type: AgentEventType, handler: EventHandler): () => void {\n const wrapper: EventHandler = (event) => {\n this.off(type, wrapper);\n handler(event);\n };\n return this.on(type, wrapper);\n }\n\n /** Emit an event to all subscribers. */\n emit(type: AgentEventType, payload: unknown): void {\n const event: AgentEvent = {\n type,\n payload,\n timestamp: Date.now(),\n };\n const handlers = this.listeners.get(type);\n if (handlers) {\n for (const handler of handlers) {\n handler(event);\n }\n }\n }\n\n /** Remove all listeners for all event types. */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import { z } from \"zod\";\nimport { ContextStack, type LScriptRuntime, type ChatMessage, type LScriptFunction } from \"@sschepis/lmscript\";\n\nconst SummarySchema = z.object({\n summary: z.string().describe(\"A dense summary of the conversation so far\"),\n});\n\ntype SummaryInput = { conversation: string };\n\n/**\n * Manages the sliding context window with automatic summarization.\n * Wraps lmscript's ContextStack and uses the local LLM for compression.\n */\nexport class ContextManager {\n private stack: ContextStack;\n private summarizeFn: LScriptFunction<SummaryInput, typeof SummarySchema>;\n\n constructor(\n private localRuntime: LScriptRuntime,\n localModelName: string,\n maxTokens: number\n ) {\n this.stack = new ContextStack({\n maxTokens,\n pruneStrategy: \"summarize\",\n });\n\n this.summarizeFn = {\n name: \"summarize_context\",\n model: localModelName,\n system:\n \"You are a summarization engine. Compress the given conversation into a dense, factual summary that preserves all key information, decisions, and context needed for continued operation. Be concise but thorough.\",\n prompt: ({ conversation }) => conversation,\n schema: SummarySchema,\n temperature: 0.2,\n maxRetries: 1,\n };\n\n this.stack.setSummarizer(async (messages: ChatMessage[]) => {\n const conversation = messages\n .map((m) => {\n const text =\n typeof m.content === \"string\"\n ? m.content\n : m.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\" \");\n return `${m.role}: ${text}`;\n })\n .join(\"\\n\");\n\n const result = await this.localRuntime.execute(this.summarizeFn, {\n conversation,\n });\n return result.data.summary;\n });\n }\n\n /** Append a message to the context. Triggers pruning if over budget. */\n async push(message: ChatMessage): Promise<void> {\n await this.stack.push(message);\n }\n\n /** Append multiple messages. */\n async pushAll(messages: ChatMessage[]): Promise<void> {\n await this.stack.pushAll(messages);\n }\n\n /** Get all messages in the current context window. */\n getMessages(): ChatMessage[] {\n return this.stack.getMessages();\n }\n\n /** Get estimated token count. */\n getTokenCount(): number {\n return this.stack.getTokenCount();\n }\n\n /** Clear all context. */\n clear(): void {\n this.stack.clear();\n }\n}\n","import { z } from \"zod\";\nimport type { LScriptFunction } from \"@sschepis/lmscript\";\n\n/** Zod schema for structured triage output. */\nexport const TriageSchema = z.object({\n escalate: z\n .boolean()\n .describe(\"True if the request needs a powerful model, false if answerable directly\"),\n reasoning: z\n .string()\n .describe(\"Brief explanation of the triage decision\"),\n directResponse: z\n .string()\n .optional()\n .describe(\"Direct answer if the request can be handled without escalation\"),\n});\n\nexport type TriageInput = {\n userInput: string;\n recentContext: string;\n availableTools: string;\n};\n\nconst TRIAGE_SYSTEM = `You are a fast triage classifier for an AI agent system.\nYour job is to decide whether a user's request can be answered directly (simple queries,\ncasual chat, short lookups) or needs to be escalated to a more powerful model\n(complex reasoning, multi-step tool usage, code generation, analysis).\n\nRules:\n- If the request is a greeting, simple question, or casual conversation: respond directly.\n- If the request needs tool calls, code analysis, or multi-step reasoning: escalate.\n- If unsure, escalate. It's better to over-escalate than to give a poor direct answer.\n- Keep directResponse under 200 words when answering directly.\n\nRespond with JSON matching the schema.`;\n\n/**\n * Create an LScriptFunction for local-LLM triage classification.\n * The local model evaluates whether input needs escalation to the remote model.\n */\nexport function createTriageFunction(\n modelName: string\n): LScriptFunction<TriageInput, typeof TriageSchema> {\n return {\n name: \"triage\",\n model: modelName,\n system: TRIAGE_SYSTEM,\n prompt: ({ userInput, recentContext, availableTools }) =>\n `Recent context:\\n${recentContext}\\n\\nAvailable tools: ${availableTools}\\n\\nUser: ${userInput}`,\n schema: TriageSchema,\n temperature: 0.1,\n maxRetries: 1,\n };\n}\n","import { z } from \"zod\";\nimport type { Router } from \"@sschepis/swiss-army-tool\";\nimport { generateToolSchema } from \"@sschepis/swiss-army-tool\";\nimport type { ToolDefinition } from \"@sschepis/lmscript\";\nimport type { BranchNode } from \"@sschepis/swiss-army-tool\";\n\n/** Parameter schema for the omni-tool bridge. */\nconst RouterToolParams = z.object({\n command: z.string().describe(\n \"The command or menu path (e.g., 'help', 'filesystem read', 'db query')\"\n ),\n kwargs: z\n .record(z.unknown())\n .optional()\n .default({})\n .describe(\"Key-value arguments for the command\"),\n});\n\n/**\n * Bridge a swiss-army-tool Router into an lmscript ToolDefinition.\n *\n * The LLM sees a single tool (\"terminal_interface\") with `command` and `kwargs`\n * parameters. When called, it routes through the swiss-army-tool command tree.\n */\nexport function createRouterTool(\n router: Router,\n root?: BranchNode\n): ToolDefinition<typeof RouterToolParams, string> {\n const schema = generateToolSchema({ root });\n\n return {\n name: schema.name,\n description: schema.description,\n parameters: RouterToolParams,\n execute: async (params) => {\n return router.execute(params.command, params.kwargs ?? {});\n },\n };\n}\n","import {\n MessageRole,\n type ConversationMessage,\n type ContentBlock as AsContentBlock,\n type Session,\n} from \"@sschepis/as-agent\";\nimport type { ChatMessage, Role } from \"@sschepis/lmscript\";\n\nconst ROLE_TO_STRING: Record<MessageRole, Role> = {\n [MessageRole.System]: \"system\",\n [MessageRole.User]: \"user\",\n [MessageRole.Assistant]: \"assistant\",\n [MessageRole.Tool]: \"user\",\n};\n\nconst STRING_TO_ROLE: Record<Role, MessageRole> = {\n system: MessageRole.System,\n user: MessageRole.User,\n assistant: MessageRole.Assistant,\n};\n\n/** Extract plain text from as-agent content blocks. */\nfunction blocksToText(blocks: AsContentBlock[]): string {\n return blocks\n .map((b) => {\n switch (b.kind) {\n case \"text\":\n return b.text;\n case \"tool_use\":\n return `[Tool call: ${b.name}(${b.input})]`;\n case \"tool_result\":\n return b.isError\n ? `[Tool error (${b.toolName}): ${b.output}]`\n : `[Tool result (${b.toolName}): ${b.output}]`;\n }\n })\n .join(\"\\n\");\n}\n\n/** Convert an as-agent ConversationMessage to an lmscript ChatMessage. */\nexport function toChat(msg: ConversationMessage): ChatMessage {\n return {\n role: ROLE_TO_STRING[msg.role] ?? \"user\",\n content: blocksToText(msg.blocks),\n };\n}\n\n/** Convert an lmscript ChatMessage to an as-agent ConversationMessage. */\nexport function fromChat(msg: ChatMessage): ConversationMessage {\n const text = typeof msg.content === \"string\"\n ? msg.content\n : msg.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n\n return {\n role: STRING_TO_ROLE[msg.role] ?? MessageRole.User,\n blocks: [{ kind: \"text\", text }],\n };\n}\n\n/** Convert an entire as-agent Session to an array of lmscript ChatMessages. */\nexport function sessionToHistory(session: Session): ChatMessage[] {\n return session.messages.map(toChat);\n}\n\n/** Create an empty as-agent Session. */\nexport function createEmptySession(): Session {\n return { version: 1, messages: [] };\n}\n"],"mappings":";AAAA,SAAS,KAAAA,UAAS;AAClB;AAAA,EACE;AAAA,EACA;AAAA,OAKK;AAEP,SAAS,eAAAC,oBAAmB;;;ACFrB,IAAM,gBAAN,MAAoB;AAAA,EACjB,YAAY,oBAAI,IAAuC;AAAA;AAAA,EAG/D,GAAG,MAAsB,SAAmC;AAC1D,QAAI,CAAC,KAAK,UAAU,IAAI,IAAI,GAAG;AAC7B,WAAK,UAAU,IAAI,MAAM,oBAAI,IAAI,CAAC;AAAA,IACpC;AACA,SAAK,UAAU,IAAI,IAAI,EAAG,IAAI,OAAO;AACrC,WAAO,MAAM,KAAK,IAAI,MAAM,OAAO;AAAA,EACrC;AAAA;AAAA,EAGA,IAAI,MAAsB,SAA6B;AACrD,SAAK,UAAU,IAAI,IAAI,GAAG,OAAO,OAAO;AAAA,EAC1C;AAAA;AAAA,EAGA,KAAK,MAAsB,SAAmC;AAC5D,UAAM,UAAwB,CAAC,UAAU;AACvC,WAAK,IAAI,MAAM,OAAO;AACtB,cAAQ,KAAK;AAAA,IACf;AACA,WAAO,KAAK,GAAG,MAAM,OAAO;AAAA,EAC9B;AAAA;AAAA,EAGA,KAAK,MAAsB,SAAwB;AACjD,UAAM,QAAoB;AAAA,MACxB;AAAA,MACA;AAAA,MACA,WAAW,KAAK,IAAI;AAAA,IACtB;AACA,UAAM,WAAW,KAAK,UAAU,IAAI,IAAI;AACxC,QAAI,UAAU;AACZ,iBAAW,WAAW,UAAU;AAC9B,gBAAQ,KAAK;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA;AAAA,EAGA,qBAA2B;AACzB,SAAK,UAAU,MAAM;AAAA,EACvB;AACF;;;ACrDA,SAAS,SAAS;AAClB,SAAS,oBAAiF;AAE1F,IAAM,gBAAgB,EAAE,OAAO;AAAA,EAC7B,SAAS,EAAE,OAAO,EAAE,SAAS,4CAA4C;AAC3E,CAAC;AAQM,IAAM,iBAAN,MAAqB;AAAA,EAI1B,YACU,cACR,gBACA,WACA;AAHQ;AAIR,SAAK,QAAQ,IAAI,aAAa;AAAA,MAC5B;AAAA,MACA,eAAe;AAAA,IACjB,CAAC;AAED,SAAK,cAAc;AAAA,MACjB,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QACE;AAAA,MACF,QAAQ,CAAC,EAAE,aAAa,MAAM;AAAA,MAC9B,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,YAAY;AAAA,IACd;AAEA,SAAK,MAAM,cAAc,OAAO,aAA4B;AAC1D,YAAM,eAAe,SAClB,IAAI,CAAC,MAAM;AACV,cAAM,OACJ,OAAO,EAAE,YAAY,WACjB,EAAE,UACF,EAAE,QACC,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAuB,IAAI,EACvC,KAAK,GAAG;AACjB,eAAO,GAAG,EAAE,IAAI,KAAK,IAAI;AAAA,MAC3B,CAAC,EACA,KAAK,IAAI;AAEZ,YAAM,SAAS,MAAM,KAAK,aAAa,QAAQ,KAAK,aAAa;AAAA,QAC/D;AAAA,MACF,CAAC;AACD,aAAO,OAAO,KAAK;AAAA,IACrB,CAAC;AAAA,EACH;AAAA,EAvCU;AAAA,EAJF;AAAA,EACA;AAAA;AAAA,EA6CR,MAAM,KAAK,SAAqC;AAC9C,UAAM,KAAK,MAAM,KAAK,OAAO;AAAA,EAC/B;AAAA;AAAA,EAGA,MAAM,QAAQ,UAAwC;AACpD,UAAM,KAAK,MAAM,QAAQ,QAAQ;AAAA,EACnC;AAAA;AAAA,EAGA,cAA6B;AAC3B,WAAO,KAAK,MAAM,YAAY;AAAA,EAChC;AAAA;AAAA,EAGA,gBAAwB;AACtB,WAAO,KAAK,MAAM,cAAc;AAAA,EAClC;AAAA;AAAA,EAGA,QAAc;AACZ,SAAK,MAAM,MAAM;AAAA,EACnB;AACF;;;ACnFA,SAAS,KAAAC,UAAS;AAIX,IAAM,eAAeA,GAAE,OAAO;AAAA,EACnC,UAAUA,GACP,QAAQ,EACR,SAAS,0EAA0E;AAAA,EACtF,WAAWA,GACR,OAAO,EACP,SAAS,0CAA0C;AAAA,EACtD,gBAAgBA,GACb,OAAO,EACP,SAAS,EACT,SAAS,gEAAgE;AAC9E,CAAC;AAQD,IAAM,gBAAgB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAiBf,SAAS,qBACd,WACmD;AACnD,SAAO;AAAA,IACL,MAAM;AAAA,IACN,OAAO;AAAA,IACP,QAAQ;AAAA,IACR,QAAQ,CAAC,EAAE,WAAW,eAAe,eAAe,MAClD;AAAA,EAAoB,aAAa;AAAA;AAAA,mBAAwB,cAAc;AAAA;AAAA,QAAa,SAAS;AAAA,IAC/F,QAAQ;AAAA,IACR,aAAa;AAAA,IACb,YAAY;AAAA,EACd;AACF;;;ACrDA,SAAS,KAAAC,UAAS;AAElB,SAAS,0BAA0B;AAKnC,IAAM,mBAAmBA,GAAE,OAAO;AAAA,EAChC,SAASA,GAAE,OAAO,EAAE;AAAA,IAClB;AAAA,EACF;AAAA,EACA,QAAQA,GACL,OAAOA,GAAE,QAAQ,CAAC,EAClB,SAAS,EACT,QAAQ,CAAC,CAAC,EACV,SAAS,qCAAqC;AACnD,CAAC;AAQM,SAAS,iBACd,QACA,MACiD;AACjD,QAAM,SAAS,mBAAmB,EAAE,KAAK,CAAC;AAE1C,SAAO;AAAA,IACL,MAAM,OAAO;AAAA,IACb,aAAa,OAAO;AAAA,IACpB,YAAY;AAAA,IACZ,SAAS,OAAO,WAAW;AACzB,aAAO,OAAO,QAAQ,OAAO,SAAS,OAAO,UAAU,CAAC,CAAC;AAAA,IAC3D;AAAA,EACF;AACF;;;ACtCA;AAAA,EACE;AAAA,OAIK;AAGP,IAAM,iBAA4C;AAAA,EAChD,CAAC,YAAY,MAAM,GAAG;AAAA,EACtB,CAAC,YAAY,IAAI,GAAG;AAAA,EACpB,CAAC,YAAY,SAAS,GAAG;AAAA,EACzB,CAAC,YAAY,IAAI,GAAG;AACtB;AAEA,IAAM,iBAA4C;AAAA,EAChD,QAAQ,YAAY;AAAA,EACpB,MAAM,YAAY;AAAA,EAClB,WAAW,YAAY;AACzB;AAGA,SAAS,aAAa,QAAkC;AACtD,SAAO,OACJ,IAAI,CAAC,MAAM;AACV,YAAQ,EAAE,MAAM;AAAA,MACd,KAAK;AACH,eAAO,EAAE;AAAA,MACX,KAAK;AACH,eAAO,eAAe,EAAE,IAAI,IAAI,EAAE,KAAK;AAAA,MACzC,KAAK;AACH,eAAO,EAAE,UACL,gBAAgB,EAAE,QAAQ,MAAM,EAAE,MAAM,MACxC,iBAAiB,EAAE,QAAQ,MAAM,EAAE,MAAM;AAAA,IACjD;AAAA,EACF,CAAC,EACA,KAAK,IAAI;AACd;AAGO,SAAS,OAAO,KAAuC;AAC5D,SAAO;AAAA,IACL,MAAM,eAAe,IAAI,IAAI,KAAK;AAAA,IAClC,SAAS,aAAa,IAAI,MAAM;AAAA,EAClC;AACF;AAGO,SAAS,SAAS,KAAuC;AAC9D,QAAM,OAAO,OAAO,IAAI,YAAY,WAChC,IAAI,UACJ,IAAI,QACD,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM,EAC/B,IAAI,CAAC,MAAO,EAAuB,IAAI,EACvC,KAAK,IAAI;AAEhB,SAAO;AAAA,IACL,MAAM,eAAe,IAAI,IAAI,KAAK,YAAY;AAAA,IAC9C,QAAQ,CAAC,EAAE,MAAM,QAAQ,KAAK,CAAC;AAAA,EACjC;AACF;AAGO,SAAS,iBAAiB,SAAiC;AAChE,SAAO,QAAQ,SAAS,IAAI,MAAM;AACpC;AAGO,SAAS,qBAA8B;AAC5C,SAAO,EAAE,SAAS,GAAG,UAAU,CAAC,EAAE;AACpC;;;ALjDA,IAAM,sBAAsBC,GAAE,OAAO;AAAA,EACnC,UAAUA,GAAE,OAAO,EAAE,SAAS,kCAAkC;AAClE,CAAC;AAcM,IAAM,aAAN,MAAiB;AAAA,EACd,MAAM,IAAI,cAAc;AAAA,EACxB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AAAA,EACf,cAAc;AAAA,EACd;AAAA,EACA;AAAA,EACA;AAAA,EAER,YAAY,QAA0B;AACpC,SAAK,SAAS;AACd,SAAK,eAAe,IAAI,eAAe,EAAE,UAAU,OAAO,WAAW,CAAC;AACtE,SAAK,gBAAgB,IAAI,eAAe,EAAE,UAAU,OAAO,YAAY,CAAC;AACxE,SAAK,UAAU,OAAO,WAAW,mBAAmB;AACpD,SAAK,eAAe,OAAO,gBAAgB;AAC3C,SAAK,gBAAgB,OAAO,iBAAiB;AAE7C,SAAK,iBAAiB,IAAI;AAAA,MACxB,KAAK;AAAA,MACL,OAAO;AAAA,MACP,OAAO,oBAAoB;AAAA,IAC7B;AAEA,SAAK,aAAa,iBAAiB,OAAO,MAAM;AAChD,SAAK,WAAW,qBAAqB,OAAO,cAAc;AAG1D,SAAK,eAAe,KAAK;AAAA,MACvB,MAAM;AAAA,MACN,SAAS,KAAK;AAAA,IAChB,CAAC;AAAA,EACH;AAAA;AAAA;AAAA,EAKA,GAAG,MAAsB,SAAmC;AAC1D,WAAO,KAAK,IAAI,GAAG,MAAM,OAAO;AAAA,EAClC;AAAA;AAAA,EAGA,KAAK,MAAsB,SAAmC;AAC5D,WAAO,KAAK,IAAI,KAAK,MAAM,OAAO;AAAA,EACpC;AAAA;AAAA,EAGA,MAAM,YAAY,MAA6B;AAC7C,QAAI,KAAK,cAAc;AACrB,WAAK,UAAU,IAAI;AACnB;AAAA,IACF;AAEA,SAAK,eAAe;AACpB,SAAK,cAAc;AAEnB,QAAI;AACF,YAAM,KAAK,cAAc,IAAI;AAAA,IAC/B,SAAS,KAAK;AACZ,WAAK,IAAI,KAAK,SAAS;AAAA,QACrB,SAAS,eAAe,QAAQ,IAAI,UAAU,OAAO,GAAG;AAAA,QACxD,OAAO;AAAA,MACT,CAAC;AAAA,IACH,UAAE;AACA,WAAK,eAAe;AAAA,IACtB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA,EAMA,UAAU,eAA8B;AACtC,SAAK,cAAc;AACnB,SAAK,IAAI,KAAK,gBAAgB,EAAE,cAAc,CAAC;AAE/C,QAAI,eAAe;AACjB,YAAM,MAA2B;AAAA,QAC/B,MAAMC,aAAY;AAAA,QAClB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,kBAAkB,aAAa,GAAG,CAAC;AAAA,MACpE;AACA,WAAK,QAAQ,SAAS,KAAK,GAAG;AAC9B,WAAK,eAAe,KAAK,OAAO,GAAG,CAAC;AACpC,WAAK,IAAI,KAAK,iBAAiB,EAAE,QAAQ,eAAe,CAAC;AAAA,IAC3D;AAAA,EACF;AAAA;AAAA,EAGA,aAAsB;AACpB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,IAAI,aAAsB;AACxB,WAAO,KAAK;AAAA,EACd;AAAA;AAAA,EAGA,qBAA2B;AACzB,SAAK,IAAI,mBAAmB;AAAA,EAC9B;AAAA;AAAA,EAIA,MAAc,cAAc,WAAkC;AAE5D,SAAK,IAAI,KAAK,cAAc,EAAE,MAAM,UAAU,CAAC;AAE/C,UAAM,UAA+B;AAAA,MACnC,MAAMA,aAAY;AAAA,MAClB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,UAAU,CAAC;AAAA,IAC5C;AACA,SAAK,QAAQ,SAAS,KAAK,OAAO;AAClC,UAAM,KAAK,eAAe,KAAK,OAAO,OAAO,CAAC;AAC9C,SAAK,IAAI,KAAK,iBAAiB,EAAE,QAAQ,aAAa,CAAC;AAGvD,UAAM,eAAe,MAAM,KAAK,OAAO,SAAS;AAChD,SAAK,IAAI,KAAK,iBAAiB,YAAY;AAE3C,QAAI,KAAK,YAAa;AAGtB,QAAI,CAAC,aAAa,YAAY,aAAa,gBAAgB;AACzD,YAAM,WAAW,aAAa;AAC9B,WAAK,IAAI,KAAK,iBAAiB,EAAE,MAAM,UAAU,OAAO,QAAQ,CAAC;AAEjE,YAAM,eAAoC;AAAA,QACxC,MAAMA,aAAY;AAAA,QAClB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,SAAS,CAAC;AAAA,MAC3C;AACA,WAAK,QAAQ,SAAS,KAAK,YAAY;AACvC,YAAM,KAAK,eAAe,KAAK,OAAO,YAAY,CAAC;AACnD,WAAK,IAAI,KAAK,iBAAiB,EAAE,QAAQ,qBAAqB,CAAC;AAC/D,WAAK,IAAI,KAAK,iBAAiB,EAAE,OAAO,SAAS,WAAW,MAAM,CAAC;AACnE;AAAA,IACF;AAGA,UAAM,UAAU,aAAa,WAAW,KAAK,gBAAgB,KAAK;AAClE,UAAM,YAAY,aAAa,WAC3B,KAAK,OAAO,kBACZ,KAAK,OAAO;AAEhB,QAAI,aAAa,UAAU;AACzB,WAAK,IAAI,KAAK,iBAAiB;AAAA,QAC7B,MAAM,aAAa;AAAA,QACnB,OAAO;AAAA,QACP,YAAY;AAAA,MACd,CAAC;AAAA,IACH;AAEA,UAAM,KAAK,iBAAiB,SAAS,WAAW,SAAS;AAAA,EAC3D;AAAA,EAEA,MAAc,OAAO,WAA0C;AAC7D,UAAM,iBAAiB,KAAK,eAAe,YAAY,EAAE,MAAM,EAAE;AACjE,UAAM,gBAAgB,eACnB,IAAI,CAAC,MAAM;AACV,YAAM,OAAO,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU;AACzD,aAAO,GAAG,EAAE,IAAI,KAAK,IAAI;AAAA,IAC3B,CAAC,EACA,KAAK,IAAI;AAEZ,UAAM,SAAS,MAAM,KAAK,aAAa,QAAQ,KAAK,UAAU;AAAA,MAC5D;AAAA,MACA;AAAA,MACA,gBAAgB,KAAK,WAAW;AAAA,IAClC,CAAC;AAED,WAAO,OAAO;AAAA,EAChB;AAAA,EAEA,MAAc,iBACZ,SACA,WACA,WACe;AACf,UAAM,kBAAkB,KAAK,eAAe,YAAY;AACxD,UAAM,aAAa,gBAChB,OAAO,CAAC,MAAM,EAAE,SAAS,QAAQ,EACjC,IAAI,CAAC,MAAM;AACV,YAAM,OAAO,OAAO,EAAE,YAAY,WAAW,EAAE,UAAU;AACzD,aAAO,GAAG,EAAE,IAAI,KAAK,IAAI;AAAA,IAC3B,CAAC,EACA,KAAK,IAAI;AAEZ,UAAM,UAAmE;AAAA,MACvE,MAAM;AAAA,MACN,OAAO;AAAA,MACP,QAAQ,KAAK;AAAA,MACb,QAAQ,CAAC,EAAE,QAAQ,MACjB,UACI;AAAA,EAAyB,OAAO;AAAA;AAAA,gEAChC;AAAA,MACN,QAAQ;AAAA,MACR,aAAa;AAAA,MACb,OAAO,CAAC,KAAK,UAAU;AAAA,IACzB;AAEA,UAAM,QAAQ,IAAI,UAAU,SAAS;AAAA,MACnC,eAAe,KAAK;AAAA,MACpB,YAAY,CAAC,aAAuB;AAClC,cAAM,OAAO,SAAS;AACtB,aAAK,IAAI,KAAK,wBAAwB;AAAA,UACpC,SAAS,MAAM,WAAW,SAAS;AAAA,UACnC,QAAQ,MAAM,UAAU,CAAC;AAAA,QAC3B,CAAC;AACD,aAAK,IAAI,KAAK,2BAA2B;AAAA,UACvC,SAAS,MAAM,WAAW,SAAS;AAAA,UACnC,QAAQ,MAAM,UAAU,CAAC;AAAA,UACzB,QAAQ,SAAS;AAAA,QACnB,CAAC;AAGD,YAAI,KAAK,YAAa,QAAO;AAAA,MAC/B;AAAA,MACA,aAAa,CAAC,YAAoB,aAAqB;AACrD,aAAK,IAAI,KAAK,iBAAiB;AAAA,UAC7B,MAAM;AAAA,UACN,OAAO;AAAA,UACP,WAAW;AAAA,QACb,CAAC;AACD,YAAI,KAAK,YAAa,QAAO;AAAA,MAC/B;AAAA,IACF,CAAC;AAED,UAAM,SAAS,MAAM,MAAM,IAAI,SAAS;AAAA,MACtC;AAAA,MACA,SAAS;AAAA,IACX,CAAC;AAGD,UAAM,eAAe,OAAO,KAAK;AACjC,UAAM,eAAoC;AAAA,MACxC,MAAMA,aAAY;AAAA,MAClB,QAAQ,CAAC,EAAE,MAAM,QAAQ,MAAM,aAAa,CAAC;AAAA,IAC/C;AACA,SAAK,QAAQ,SAAS,KAAK,YAAY;AACvC,UAAM,KAAK,eAAe,KAAK,OAAO,YAAY,CAAC;AACnD,SAAK,IAAI,KAAK,iBAAiB,EAAE,QAAQ,qBAAqB,CAAC;AAC/D,SAAK,IAAI,KAAK,iBAAiB;AAAA,MAC7B,OAAO;AAAA,MACP,WAAW;AAAA,MACX,YAAY,OAAO;AAAA,MACnB,WAAW,OAAO,UAAU;AAAA,IAC9B,CAAC;AAAA,EACH;AACF;","names":["z","MessageRole","z","z","z","MessageRole"]}
1
+ {"version":3,"sources":["../src/oboto-agent.ts","../src/event-bus.ts","../src/context-manager.ts","../src/triage.ts","../src/adapters/tools.ts","../src/adapters/llm-wrapper.ts","../src/adapters/memory.ts"],"sourcesContent":["import { LScriptRuntime, type ToolDefinition, type ChatMessage } from \"@sschepis/lmscript\";\nimport type {\n BaseProvider,\n StandardChatParams,\n Message as WrapperMessage,\n ToolDefinition as WrapperToolDef,\n StandardChatResponse,\n} from \"@sschepis/llm-wrapper\";\nimport type { Session, ConversationMessage } from \"@sschepis/as-agent\";\nimport { MessageRole } from \"@sschepis/as-agent\";\nimport type { ObotoAgentConfig, AgentEventType, AgentEvent, TriageResult } from \"./types.js\";\nimport { AgentEventBus } from \"./event-bus.js\";\nimport { ContextManager } from \"./context-manager.js\";\nimport { createTriageFunction } from \"./triage.js\";\nimport { createRouterTool } from \"./adapters/tools.js\";\nimport { toLmscriptProvider } from \"./adapters/llm-wrapper.js\";\nimport { toChat, createEmptySession } from \"./adapters/memory.js\";\n\ntype EventHandler = (event: AgentEvent) => void;\n\n/**\n * ObotoAgent is the central orchestrator for dual-LLM agent execution.\n *\n * It binds together:\n * - llm-wrapper (LLM communication via local and remote providers)\n * - lmscript (structured/schema-validated calls for triage)\n * - swiss-army-tool (tool execution via Router)\n * - as-agent (session state and conversation history)\n *\n * All interaction flows through an event-driven architecture.\n */\nexport class ObotoAgent {\n private bus = new AgentEventBus();\n private localRuntime: LScriptRuntime;\n private localProvider: BaseProvider;\n private remoteProvider: BaseProvider;\n private contextManager: ContextManager;\n private routerTool: ToolDefinition<any, any>;\n private triageFn: ReturnType<typeof createTriageFunction>;\n private session: Session;\n private isProcessing = false;\n private interrupted = false;\n private systemPrompt: string;\n private maxIterations: number;\n private config: ObotoAgentConfig;\n\n constructor(config: ObotoAgentConfig) {\n this.config = config;\n this.localProvider = config.localModel;\n this.remoteProvider = config.remoteModel;\n\n // Wrap llm-wrapper providers into lmscript LLMProvider for structured calls (triage)\n const localLmscript = toLmscriptProvider(config.localModel, \"local\");\n this.localRuntime = new LScriptRuntime({ provider: localLmscript });\n\n this.session = config.session ?? createEmptySession();\n this.systemPrompt = config.systemPrompt ?? \"You are a helpful AI assistant with access to tools.\";\n this.maxIterations = config.maxIterations ?? 10;\n\n this.contextManager = new ContextManager(\n this.localRuntime,\n config.localModelName,\n config.maxContextTokens ?? 8192\n );\n\n this.routerTool = createRouterTool(config.router);\n this.triageFn = createTriageFunction(config.localModelName);\n\n // Push system prompt into context\n this.contextManager.push({\n role: \"system\",\n content: this.systemPrompt,\n });\n }\n\n // ── Public API ─────────────────────────────────────────────────────\n\n /** Subscribe to agent events. Returns an unsubscribe function. */\n on(type: AgentEventType, handler: EventHandler): () => void {\n return this.bus.on(type, handler);\n }\n\n /** Subscribe to an event for a single emission. */\n once(type: AgentEventType, handler: EventHandler): () => void {\n return this.bus.once(type, handler);\n }\n\n /** Submit user input to the agent. Triggers the execution loop. */\n async submitInput(text: string): Promise<void> {\n if (this.isProcessing) {\n this.interrupt(text);\n return;\n }\n\n this.isProcessing = true;\n this.interrupted = false;\n\n try {\n await this.executionLoop(text);\n } catch (err) {\n this.bus.emit(\"error\", {\n message: err instanceof Error ? err.message : String(err),\n error: err,\n });\n } finally {\n this.isProcessing = false;\n }\n }\n\n /**\n * Interrupt the current execution loop.\n * Optionally inject new directives into the context.\n */\n interrupt(newDirectives?: string): void {\n this.interrupted = true;\n this.bus.emit(\"interruption\", { newDirectives });\n\n if (newDirectives) {\n const msg: ConversationMessage = {\n role: MessageRole.User,\n blocks: [{ kind: \"text\", text: `[INTERRUPTION] ${newDirectives}` }],\n };\n this.session.messages.push(msg);\n this.contextManager.push(toChat(msg));\n this.bus.emit(\"state_updated\", { reason: \"interruption\" });\n }\n }\n\n /** Get the current session state. */\n getSession(): Session {\n return this.session;\n }\n\n /** Whether the agent is currently processing input. */\n get processing(): boolean {\n return this.isProcessing;\n }\n\n /** Remove all event listeners. */\n removeAllListeners(): void {\n this.bus.removeAllListeners();\n }\n\n // ── Internal ───────────────────────────────────────────────────────\n\n private async executionLoop(userInput: string): Promise<void> {\n // 1. Emit user_input and record in session + context\n this.bus.emit(\"user_input\", { text: userInput });\n\n const userMsg: ConversationMessage = {\n role: MessageRole.User,\n blocks: [{ kind: \"text\", text: userInput }],\n };\n this.session.messages.push(userMsg);\n await this.contextManager.push(toChat(userMsg));\n this.bus.emit(\"state_updated\", { reason: \"user_input\" });\n\n // 2. Triage via local LLM (uses lmscript for structured output)\n const triageResult = await this.triage(userInput);\n this.bus.emit(\"triage_result\", triageResult);\n\n if (this.interrupted) return;\n\n // 3. If local can handle directly, emit and return\n if (!triageResult.escalate && triageResult.directResponse) {\n const response = triageResult.directResponse;\n this.bus.emit(\"agent_thought\", { text: response, model: \"local\" });\n\n const assistantMsg: ConversationMessage = {\n role: MessageRole.Assistant,\n blocks: [{ kind: \"text\", text: response }],\n };\n this.session.messages.push(assistantMsg);\n await this.contextManager.push(toChat(assistantMsg));\n this.bus.emit(\"state_updated\", { reason: \"assistant_response\" });\n this.bus.emit(\"turn_complete\", { model: \"local\", escalated: false });\n return;\n }\n\n // 4. Escalate to remote model with tool access\n const provider = triageResult.escalate ? this.remoteProvider : this.localProvider;\n const modelName = triageResult.escalate\n ? this.config.remoteModelName\n : this.config.localModelName;\n\n if (triageResult.escalate) {\n this.bus.emit(\"agent_thought\", {\n text: triageResult.reasoning,\n model: \"local\",\n escalating: true,\n });\n }\n\n await this.executeWithModel(provider, modelName, userInput);\n }\n\n private async triage(userInput: string): Promise<TriageResult> {\n const recentMessages = this.contextManager.getMessages().slice(-5);\n const recentContext = recentMessages\n .map((m) => {\n const text = typeof m.content === \"string\" ? m.content : \"[complex content]\";\n return `${m.role}: ${text}`;\n })\n .join(\"\\n\");\n\n const result = await this.localRuntime.execute(this.triageFn, {\n userInput,\n recentContext,\n availableTools: this.routerTool.description,\n });\n\n return result.data;\n }\n\n /** Maximum characters per tool result before truncation. */\n private static readonly MAX_TOOL_RESULT_CHARS = 8000;\n\n /** Maximum times the same tool+args can repeat before forcing a text response. */\n private static readonly MAX_DUPLICATE_CALLS = 2;\n\n /**\n * Execute the agent loop using llm-wrapper directly.\n * No JSON mode, no schema enforcement — just natural chat with tool calling.\n */\n private async executeWithModel(\n provider: BaseProvider,\n modelName: string,\n _userInput: string\n ): Promise<void> {\n // Build messages from context manager (includes system prompt + history)\n const contextMessages = this.contextManager.getMessages();\n\n // Convert lmscript ChatMessages → llm-wrapper Messages\n const messages: WrapperMessage[] = contextMessages.map((m) => ({\n role: m.role,\n content:\n typeof m.content === \"string\"\n ? m.content\n : (m.content as Array<{ type: string; text?: string }>)\n .filter((b) => b.type === \"text\")\n .map((b) => b.text ?? \"\")\n .join(\"\\n\"),\n }));\n\n // Build llm-wrapper tool definitions from the router tool\n const tool = this.routerTool;\n const tools: WrapperToolDef[] = [\n {\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.parameters\n ? JSON.parse(JSON.stringify(tool.parameters))\n : { type: \"object\", properties: {} },\n },\n },\n ];\n\n let totalToolCalls = 0;\n // Track tool call signatures to detect loops\n const callHistory: string[] = [];\n\n for (let iteration = 1; iteration <= this.maxIterations; iteration++) {\n if (this.interrupted) break;\n\n // On the last iteration, force a text response by dropping tools\n const isLastIteration = iteration === this.maxIterations;\n\n const params: StandardChatParams = {\n model: modelName,\n messages: [...messages],\n temperature: 0.7,\n ...(isLastIteration\n ? {} // No tools on last iteration — force text response\n : { tools, tool_choice: \"auto\" as const }),\n };\n\n if (isLastIteration) {\n // Nudge the model to synthesize a final answer\n messages.push({\n role: \"user\",\n content:\n \"You have used all available tool iterations. Please provide your final response now based on what you have gathered so far. Do not call any more tools.\",\n });\n }\n\n const response: StandardChatResponse = await provider.chat(params);\n const choice = response.choices[0];\n const content = (choice?.message?.content as string) ?? \"\";\n\n // Emit thought for each iteration\n this.bus.emit(\"agent_thought\", {\n text: content,\n model: modelName,\n iteration,\n });\n\n // If no tool calls, this is the final response\n const toolCalls = choice?.message?.tool_calls;\n if (!toolCalls || toolCalls.length === 0) {\n const responseText = content;\n\n const assistantMsg: ConversationMessage = {\n role: MessageRole.Assistant,\n blocks: [{ kind: \"text\", text: responseText }],\n };\n this.session.messages.push(assistantMsg);\n await this.contextManager.push(toChat(assistantMsg));\n this.bus.emit(\"state_updated\", { reason: \"assistant_response\" });\n this.bus.emit(\"turn_complete\", {\n model: modelName,\n escalated: true,\n iterations: iteration,\n toolCalls: totalToolCalls,\n });\n return;\n }\n\n // Append assistant message (with tool_calls) to conversation\n messages.push({\n role: \"assistant\",\n content: content || null,\n tool_calls: toolCalls,\n });\n\n // Execute each tool call and feed results back\n for (const tc of toolCalls) {\n if (this.interrupted) break;\n\n let args: Record<string, unknown>;\n try {\n args = JSON.parse(tc.function.arguments);\n } catch {\n args = {};\n }\n\n const command = (args.command as string) ?? tc.function.name;\n const kwargs = (args.kwargs as Record<string, unknown>) ?? {};\n\n // Detect duplicate tool calls (same command + same args)\n const callSig = JSON.stringify({ command, kwargs });\n const dupeCount = callHistory.filter((s) => s === callSig).length;\n callHistory.push(callSig);\n\n if (dupeCount >= ObotoAgent.MAX_DUPLICATE_CALLS) {\n // Feed back an error instead of re-executing\n messages.push({\n role: \"tool\",\n tool_call_id: tc.id,\n content: `You already called \"${command}\" with these arguments ${dupeCount} time(s) and received the result. Do not repeat this call. Use the data you already have to proceed.`,\n });\n this.bus.emit(\"tool_execution_complete\", {\n command,\n kwargs,\n result: \"[duplicate call blocked]\",\n });\n totalToolCalls++;\n continue;\n }\n\n this.bus.emit(\"tool_execution_start\", { command, kwargs });\n\n let result: string;\n try {\n result = await tool.execute(args);\n } catch (err) {\n result = `Error: ${err instanceof Error ? err.message : String(err)}`;\n }\n\n // Truncate large tool results to prevent context overflow\n const resultStr = typeof result === \"string\" ? result : JSON.stringify(result);\n const truncated =\n resultStr.length > ObotoAgent.MAX_TOOL_RESULT_CHARS\n ? resultStr.slice(0, ObotoAgent.MAX_TOOL_RESULT_CHARS) +\n `\\n\\n[... truncated ${resultStr.length - ObotoAgent.MAX_TOOL_RESULT_CHARS} characters. Use the data above to proceed.]`\n : resultStr;\n\n this.bus.emit(\"tool_execution_complete\", { command, kwargs, result: truncated });\n totalToolCalls++;\n\n // Feed tool result back as a tool message (OpenAI format)\n messages.push({\n role: \"tool\",\n tool_call_id: tc.id,\n content: truncated,\n });\n }\n }\n\n // Exhausted iterations — should not normally reach here since last iteration\n // forces text, but handle gracefully\n const fallbackMsg: ConversationMessage = {\n role: MessageRole.Assistant,\n blocks: [{ kind: \"text\", text: \"I reached the maximum number of iterations. Here is what I have so far.\" }],\n };\n this.session.messages.push(fallbackMsg);\n await this.contextManager.push(toChat(fallbackMsg));\n this.bus.emit(\"state_updated\", { reason: \"max_iterations\" });\n this.bus.emit(\"turn_complete\", {\n model: modelName,\n escalated: true,\n iterations: this.maxIterations,\n toolCalls: totalToolCalls,\n });\n }\n}\n","import type { AgentEventType, AgentEvent } from \"./types.js\";\n\ntype EventHandler = (event: AgentEvent) => void;\n\n/**\n * Platform-agnostic typed event bus.\n * Uses a plain Map instead of Node.js EventEmitter for browser/Deno/Bun compatibility.\n */\nexport class AgentEventBus {\n private listeners = new Map<AgentEventType, Set<EventHandler>>();\n\n /** Subscribe to an event type. Returns an unsubscribe function. */\n on(type: AgentEventType, handler: EventHandler): () => void {\n if (!this.listeners.has(type)) {\n this.listeners.set(type, new Set());\n }\n this.listeners.get(type)!.add(handler);\n return () => this.off(type, handler);\n }\n\n /** Unsubscribe a handler from an event type. */\n off(type: AgentEventType, handler: EventHandler): void {\n this.listeners.get(type)?.delete(handler);\n }\n\n /** Subscribe to an event type for a single emission. */\n once(type: AgentEventType, handler: EventHandler): () => void {\n const wrapper: EventHandler = (event) => {\n this.off(type, wrapper);\n handler(event);\n };\n return this.on(type, wrapper);\n }\n\n /** Emit an event to all subscribers. */\n emit(type: AgentEventType, payload: unknown): void {\n const event: AgentEvent = {\n type,\n payload,\n timestamp: Date.now(),\n };\n const handlers = this.listeners.get(type);\n if (handlers) {\n for (const handler of handlers) {\n handler(event);\n }\n }\n }\n\n /** Remove all listeners for all event types. */\n removeAllListeners(): void {\n this.listeners.clear();\n }\n}\n","import { z } from \"zod\";\nimport { ContextStack, type LScriptRuntime, type ChatMessage, type LScriptFunction } from \"@sschepis/lmscript\";\n\nconst SummarySchema = z.object({\n summary: z.string().describe(\"A dense summary of the conversation so far\"),\n});\n\ntype SummaryInput = { conversation: string };\n\n/**\n * Manages the sliding context window with automatic summarization.\n * Wraps lmscript's ContextStack and uses the local LLM for compression.\n */\nexport class ContextManager {\n private stack: ContextStack;\n private summarizeFn: LScriptFunction<SummaryInput, typeof SummarySchema>;\n\n constructor(\n private localRuntime: LScriptRuntime,\n localModelName: string,\n maxTokens: number\n ) {\n this.stack = new ContextStack({\n maxTokens,\n pruneStrategy: \"summarize\",\n });\n\n this.summarizeFn = {\n name: \"summarize_context\",\n model: localModelName,\n system:\n \"You are a summarization engine. Compress the given conversation into a dense, factual summary that preserves all key information, decisions, and context needed for continued operation. Be concise but thorough.\",\n prompt: ({ conversation }) => conversation,\n schema: SummarySchema,\n temperature: 0.2,\n maxRetries: 1,\n };\n\n this.stack.setSummarizer(async (messages: ChatMessage[]) => {\n const conversation = messages\n .map((m) => {\n const text =\n typeof m.content === \"string\"\n ? m.content\n : m.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\" \");\n return `${m.role}: ${text}`;\n })\n .join(\"\\n\");\n\n const result = await this.localRuntime.execute(this.summarizeFn, {\n conversation,\n });\n return result.data.summary;\n });\n }\n\n /** Append a message to the context. Triggers pruning if over budget. */\n async push(message: ChatMessage): Promise<void> {\n await this.stack.push(message);\n }\n\n /** Append multiple messages. */\n async pushAll(messages: ChatMessage[]): Promise<void> {\n await this.stack.pushAll(messages);\n }\n\n /** Get all messages in the current context window. */\n getMessages(): ChatMessage[] {\n return this.stack.getMessages();\n }\n\n /** Get estimated token count. */\n getTokenCount(): number {\n return this.stack.getTokenCount();\n }\n\n /** Clear all context. */\n clear(): void {\n this.stack.clear();\n }\n}\n","import { z } from \"zod\";\nimport type { LScriptFunction } from \"@sschepis/lmscript\";\n\n/** Zod schema for structured triage output. */\nexport const TriageSchema = z.object({\n escalate: z\n .boolean()\n .describe(\"True if the request needs a powerful model, false if answerable directly\"),\n reasoning: z\n .string()\n .describe(\"Brief explanation of the triage decision\"),\n directResponse: z\n .string()\n .optional()\n .describe(\"Direct answer if the request can be handled without escalation\"),\n});\n\nexport type TriageInput = {\n userInput: string;\n recentContext: string;\n availableTools: string;\n};\n\nconst TRIAGE_SYSTEM = `You are a fast triage classifier for an AI agent system.\nYour job is to decide whether a user's request can be answered directly (simple queries,\ncasual chat, short lookups) or needs to be escalated to a more powerful model\n(complex reasoning, multi-step tool usage, code generation, analysis).\n\nRules:\n- If the request is a greeting, simple question, or casual conversation: respond directly.\n- If the request needs tool calls, code analysis, or multi-step reasoning: escalate.\n- If unsure, escalate. It's better to over-escalate than to give a poor direct answer.\n- Keep directResponse under 200 words when answering directly.\n\nRespond with JSON matching the schema.`;\n\n/**\n * Create an LScriptFunction for local-LLM triage classification.\n * The local model evaluates whether input needs escalation to the remote model.\n */\nexport function createTriageFunction(\n modelName: string\n): LScriptFunction<TriageInput, typeof TriageSchema> {\n return {\n name: \"triage\",\n model: modelName,\n system: TRIAGE_SYSTEM,\n prompt: ({ userInput, recentContext, availableTools }) =>\n `Recent context:\\n${recentContext}\\n\\nAvailable tools: ${availableTools}\\n\\nUser: ${userInput}`,\n schema: TriageSchema,\n temperature: 0.1,\n maxRetries: 1,\n };\n}\n","import { z } from \"zod\";\nimport type { Router } from \"@sschepis/swiss-army-tool\";\nimport { generateToolSchema } from \"@sschepis/swiss-army-tool\";\nimport type { ToolDefinition } from \"@sschepis/lmscript\";\nimport type { BranchNode } from \"@sschepis/swiss-army-tool\";\n\n/** Parameter schema for the omni-tool bridge. */\nconst RouterToolParams = z.object({\n command: z.string().describe(\n \"The command or menu path (e.g., 'help', 'filesystem read', 'db query')\"\n ),\n kwargs: z\n .record(z.unknown())\n .optional()\n .default({})\n .describe(\"Key-value arguments for the command\"),\n});\n\n/**\n * Bridge a swiss-army-tool Router into an lmscript ToolDefinition.\n *\n * The LLM sees a single tool (\"terminal_interface\") with `command` and `kwargs`\n * parameters. When called, it routes through the swiss-army-tool command tree.\n */\nexport function createRouterTool(\n router: Router,\n root?: BranchNode\n): ToolDefinition<typeof RouterToolParams, string> {\n const schema = generateToolSchema({ root });\n\n return {\n name: schema.name,\n description: schema.description,\n parameters: RouterToolParams,\n execute: async (params) => {\n return router.execute(params.command, params.kwargs ?? {});\n },\n };\n}\n","import type { LLMProvider, LLMRequest, LLMResponse } from \"@sschepis/lmscript\";\nimport type {\n BaseProvider,\n StandardChatParams,\n Message,\n ToolDefinition as WrapperToolDef,\n} from \"@sschepis/llm-wrapper\";\n\n/**\n * Adapt a llm-wrapper BaseProvider into lmscript's LLMProvider interface.\n *\n * This allows lmscript's LScriptRuntime to use llm-wrapper providers for\n * structured calls (e.g. triage) that need schema validation.\n */\nexport function toLmscriptProvider(\n provider: BaseProvider,\n name?: string\n): LLMProvider {\n return {\n name: name ?? provider.providerName,\n\n async chat(request: LLMRequest): Promise<LLMResponse> {\n // Convert lmscript messages → llm-wrapper messages\n const messages: Message[] = request.messages.map((m) => ({\n role: m.role,\n content:\n typeof m.content === \"string\"\n ? m.content\n : m.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { type: \"text\"; text: string }).text)\n .join(\"\\n\"),\n }));\n\n // Convert lmscript tools → llm-wrapper tool definitions\n let tools: WrapperToolDef[] | undefined;\n if (request.tools && request.tools.length > 0) {\n tools = request.tools.map((t) => ({\n type: \"function\" as const,\n function: {\n name: t.name,\n description: t.description,\n parameters: t.parameters as Record<string, unknown>,\n },\n }));\n }\n\n const params: StandardChatParams = {\n model: request.model,\n messages,\n temperature: request.temperature,\n ...(tools ? { tools } : {}),\n ...(request.jsonMode\n ? { response_format: { type: \"json_object\" as const } }\n : {}),\n };\n\n const response = await provider.chat(params);\n const choice = response.choices[0];\n\n // Convert tool calls back to lmscript format\n let toolCalls: LLMResponse[\"toolCalls\"];\n if (choice?.message?.tool_calls) {\n toolCalls = choice.message.tool_calls.map((tc) => ({\n id: tc.id,\n name: tc.function.name,\n arguments: tc.function.arguments,\n }));\n }\n\n return {\n content: (choice?.message?.content as string) ?? \"\",\n usage: response.usage\n ? {\n promptTokens: response.usage.prompt_tokens,\n completionTokens: response.usage.completion_tokens,\n totalTokens: response.usage.total_tokens,\n }\n : undefined,\n toolCalls,\n };\n },\n };\n}\n","import {\n MessageRole,\n type ConversationMessage,\n type ContentBlock as AsContentBlock,\n type Session,\n} from \"@sschepis/as-agent\";\nimport type { ChatMessage, Role } from \"@sschepis/lmscript\";\n\nconst ROLE_TO_STRING: Record<MessageRole, Role> = {\n [MessageRole.System]: \"system\",\n [MessageRole.User]: \"user\",\n [MessageRole.Assistant]: \"assistant\",\n [MessageRole.Tool]: \"user\",\n};\n\nconst STRING_TO_ROLE: Record<Role, MessageRole> = {\n system: MessageRole.System,\n user: MessageRole.User,\n assistant: MessageRole.Assistant,\n};\n\n/** Extract plain text from as-agent content blocks. */\nfunction blocksToText(blocks: AsContentBlock[]): string {\n return blocks\n .map((b) => {\n switch (b.kind) {\n case \"text\":\n return b.text;\n case \"tool_use\":\n return `[Tool call: ${b.name}(${b.input})]`;\n case \"tool_result\":\n return b.isError\n ? `[Tool error (${b.toolName}): ${b.output}]`\n : `[Tool result (${b.toolName}): ${b.output}]`;\n }\n })\n .join(\"\\n\");\n}\n\n/** Convert an as-agent ConversationMessage to an lmscript ChatMessage. */\nexport function toChat(msg: ConversationMessage): ChatMessage {\n return {\n role: ROLE_TO_STRING[msg.role] ?? \"user\",\n content: blocksToText(msg.blocks),\n };\n}\n\n/** Convert an lmscript ChatMessage to an as-agent ConversationMessage. */\nexport function fromChat(msg: ChatMessage): ConversationMessage {\n const text = typeof msg.content === \"string\"\n ? msg.content\n : msg.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n\n return {\n role: STRING_TO_ROLE[msg.role] ?? MessageRole.User,\n blocks: [{ kind: \"text\", text }],\n };\n}\n\n/** Convert an entire as-agent Session to an array of lmscript ChatMessages. */\nexport function sessionToHistory(session: Session): ChatMessage[] {\n return session.messages.map(toChat);\n}\n\n/** Create an empty as-agent Session. */\nexport function createEmptySession(): Session {\n return { version: 1, messages: [] };\n}\n"],"mappings":"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","names":["MessageRole","z","z","MessageRole"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sschepis/oboto-agent",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Event-driven dual-LLM orchestration library for autonomous AI agents",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -43,6 +43,7 @@
43
43
  "zod": "^3.23.0"
44
44
  },
45
45
  "peerDependencies": {
46
+ "@sschepis/llm-wrapper": "^0.1.0",
46
47
  "@sschepis/lmscript": "^0.1.0",
47
48
  "@sschepis/swiss-army-tool": "^0.1.0",
48
49
  "@sschepis/as-agent": "^0.1.0"
@@ -52,6 +53,7 @@
52
53
  "@sschepis/resolang": "^0.5.0"
53
54
  },
54
55
  "devDependencies": {
56
+ "@sschepis/llm-wrapper": "file:../llm-wrapper",
55
57
  "@sschepis/lmscript": "file:../lmscript",
56
58
  "@sschepis/swiss-army-tool": "file:../swiss-army-tool",
57
59
  "@sschepis/as-agent": "file:../claw-code/assembly",