@sschepis/oboto-agent 0.1.2 → 0.1.4
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 +10 -1
- package/dist/index.js +57 -14
- package/dist/index.js.map +1 -1
- package/package.json +6 -5
package/dist/index.d.ts
CHANGED
|
@@ -23,8 +23,10 @@ interface ObotoAgentConfig {
|
|
|
23
23
|
maxIterations?: number;
|
|
24
24
|
/** System prompt prepended to all LLM calls */
|
|
25
25
|
systemPrompt?: string;
|
|
26
|
+
/** Called with each token chunk during LLM streaming. Enables real-time output. */
|
|
27
|
+
onToken?: (token: string) => void;
|
|
26
28
|
}
|
|
27
|
-
type AgentEventType = "user_input" | "agent_thought" | "triage_result" | "tool_execution_start" | "tool_execution_complete" | "state_updated" | "interruption" | "error" | "turn_complete";
|
|
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";
|
|
28
30
|
interface AgentEvent<T = unknown> {
|
|
29
31
|
type: AgentEventType;
|
|
30
32
|
payload: T;
|
|
@@ -72,6 +74,7 @@ declare class ObotoAgent {
|
|
|
72
74
|
private systemPrompt;
|
|
73
75
|
private maxIterations;
|
|
74
76
|
private config;
|
|
77
|
+
private onToken?;
|
|
75
78
|
constructor(config: ObotoAgentConfig);
|
|
76
79
|
/** Subscribe to agent events. Returns an unsubscribe function. */
|
|
77
80
|
on(type: AgentEventType, handler: EventHandler$1): () => void;
|
|
@@ -98,9 +101,15 @@ declare class ObotoAgent {
|
|
|
98
101
|
private static readonly MAX_DUPLICATE_CALLS;
|
|
99
102
|
/**
|
|
100
103
|
* Execute the agent loop using llm-wrapper directly.
|
|
104
|
+
* When onToken is configured, uses streaming for real-time token output.
|
|
101
105
|
* No JSON mode, no schema enforcement — just natural chat with tool calling.
|
|
102
106
|
*/
|
|
103
107
|
private executeWithModel;
|
|
108
|
+
/**
|
|
109
|
+
* Stream an LLM call, emitting tokens in real-time, then aggregate into
|
|
110
|
+
* a full StandardChatResponse (including accumulated tool calls).
|
|
111
|
+
*/
|
|
112
|
+
private streamAndAggregate;
|
|
104
113
|
}
|
|
105
114
|
|
|
106
115
|
type EventHandler = (event: AgentEvent) => void;
|
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
// src/oboto-agent.ts
|
|
2
2
|
import { LScriptRuntime } from "@sschepis/lmscript";
|
|
3
|
+
import { aggregateStream } from "@sschepis/llm-wrapper";
|
|
4
|
+
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
3
5
|
import { MessageRole as MessageRole2 } from "@sschepis/as-agent";
|
|
4
6
|
|
|
5
7
|
// src/event-bus.ts
|
|
@@ -272,6 +274,7 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
272
274
|
systemPrompt;
|
|
273
275
|
maxIterations;
|
|
274
276
|
config;
|
|
277
|
+
onToken;
|
|
275
278
|
constructor(config) {
|
|
276
279
|
this.config = config;
|
|
277
280
|
this.localProvider = config.localModel;
|
|
@@ -281,6 +284,7 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
281
284
|
this.session = config.session ?? createEmptySession();
|
|
282
285
|
this.systemPrompt = config.systemPrompt ?? "You are a helpful AI assistant with access to tools.";
|
|
283
286
|
this.maxIterations = config.maxIterations ?? 10;
|
|
287
|
+
this.onToken = config.onToken;
|
|
284
288
|
this.contextManager = new ContextManager(
|
|
285
289
|
this.localRuntime,
|
|
286
290
|
config.localModelName,
|
|
@@ -406,6 +410,7 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
406
410
|
static MAX_DUPLICATE_CALLS = 2;
|
|
407
411
|
/**
|
|
408
412
|
* Execute the agent loop using llm-wrapper directly.
|
|
413
|
+
* When onToken is configured, uses streaming for real-time token output.
|
|
409
414
|
* No JSON mode, no schema enforcement — just natural chat with tool calling.
|
|
410
415
|
*/
|
|
411
416
|
async executeWithModel(provider, modelName, _userInput) {
|
|
@@ -415,47 +420,55 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
415
420
|
content: typeof m.content === "string" ? m.content : m.content.filter((b) => b.type === "text").map((b) => b.text ?? "").join("\n")
|
|
416
421
|
}));
|
|
417
422
|
const tool = this.routerTool;
|
|
423
|
+
const parametersSchema = tool.parameters ? zodToJsonSchema(tool.parameters, { target: "openApi3" }) : { type: "object", properties: {} };
|
|
418
424
|
const tools = [
|
|
419
425
|
{
|
|
420
426
|
type: "function",
|
|
421
427
|
function: {
|
|
422
428
|
name: tool.name,
|
|
423
429
|
description: tool.description,
|
|
424
|
-
parameters:
|
|
430
|
+
parameters: parametersSchema
|
|
425
431
|
}
|
|
426
432
|
}
|
|
427
433
|
];
|
|
428
434
|
let totalToolCalls = 0;
|
|
429
435
|
const callHistory = [];
|
|
436
|
+
const useStreaming = !!this.onToken;
|
|
430
437
|
for (let iteration = 1; iteration <= this.maxIterations; iteration++) {
|
|
431
438
|
if (this.interrupted) break;
|
|
432
439
|
const isLastIteration = iteration === this.maxIterations;
|
|
440
|
+
if (isLastIteration) {
|
|
441
|
+
messages.push({
|
|
442
|
+
role: "user",
|
|
443
|
+
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."
|
|
444
|
+
});
|
|
445
|
+
}
|
|
433
446
|
const params = {
|
|
434
447
|
model: modelName,
|
|
435
448
|
messages: [...messages],
|
|
436
449
|
temperature: 0.7,
|
|
437
450
|
...isLastIteration ? {} : { tools, tool_choice: "auto" }
|
|
438
451
|
};
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
452
|
+
let response;
|
|
453
|
+
if (useStreaming) {
|
|
454
|
+
response = await this.streamAndAggregate(provider, params);
|
|
455
|
+
} else {
|
|
456
|
+
response = await provider.chat(params);
|
|
444
457
|
}
|
|
445
|
-
const response = await provider.chat(params);
|
|
446
458
|
const choice = response.choices[0];
|
|
447
459
|
const content = choice?.message?.content ?? "";
|
|
448
|
-
this.bus.emit("agent_thought", {
|
|
449
|
-
text: content,
|
|
450
|
-
model: modelName,
|
|
451
|
-
iteration
|
|
452
|
-
});
|
|
453
460
|
const toolCalls = choice?.message?.tool_calls;
|
|
461
|
+
if (content) {
|
|
462
|
+
this.bus.emit("agent_thought", {
|
|
463
|
+
text: content,
|
|
464
|
+
model: modelName,
|
|
465
|
+
iteration
|
|
466
|
+
});
|
|
467
|
+
}
|
|
454
468
|
if (!toolCalls || toolCalls.length === 0) {
|
|
455
|
-
const responseText = content;
|
|
456
469
|
const assistantMsg = {
|
|
457
470
|
role: MessageRole2.Assistant,
|
|
458
|
-
blocks: [{ kind: "text", text:
|
|
471
|
+
blocks: [{ kind: "text", text: content }]
|
|
459
472
|
};
|
|
460
473
|
this.session.messages.push(assistantMsg);
|
|
461
474
|
await this.contextManager.push(toChat(assistantMsg));
|
|
@@ -473,6 +486,7 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
473
486
|
content: content || null,
|
|
474
487
|
tool_calls: toolCalls
|
|
475
488
|
});
|
|
489
|
+
const toolResults = [];
|
|
476
490
|
for (const tc of toolCalls) {
|
|
477
491
|
if (this.interrupted) break;
|
|
478
492
|
let args;
|
|
@@ -497,21 +511,25 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
497
511
|
kwargs,
|
|
498
512
|
result: "[duplicate call blocked]"
|
|
499
513
|
});
|
|
514
|
+
toolResults.push({ command, success: false });
|
|
500
515
|
totalToolCalls++;
|
|
501
516
|
continue;
|
|
502
517
|
}
|
|
503
518
|
this.bus.emit("tool_execution_start", { command, kwargs });
|
|
504
519
|
let result;
|
|
520
|
+
let success = true;
|
|
505
521
|
try {
|
|
506
522
|
result = await tool.execute(args);
|
|
507
523
|
} catch (err) {
|
|
508
524
|
result = `Error: ${err instanceof Error ? err.message : String(err)}`;
|
|
525
|
+
success = false;
|
|
509
526
|
}
|
|
510
527
|
const resultStr = typeof result === "string" ? result : JSON.stringify(result);
|
|
511
528
|
const truncated = resultStr.length > _ObotoAgent.MAX_TOOL_RESULT_CHARS ? resultStr.slice(0, _ObotoAgent.MAX_TOOL_RESULT_CHARS) + `
|
|
512
529
|
|
|
513
530
|
[... truncated ${resultStr.length - _ObotoAgent.MAX_TOOL_RESULT_CHARS} characters. Use the data above to proceed.]` : resultStr;
|
|
514
531
|
this.bus.emit("tool_execution_complete", { command, kwargs, result: truncated });
|
|
532
|
+
toolResults.push({ command, success });
|
|
515
533
|
totalToolCalls++;
|
|
516
534
|
messages.push({
|
|
517
535
|
role: "tool",
|
|
@@ -519,6 +537,11 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
519
537
|
content: truncated
|
|
520
538
|
});
|
|
521
539
|
}
|
|
540
|
+
this.bus.emit("tool_round_complete", {
|
|
541
|
+
iteration,
|
|
542
|
+
tools: toolResults,
|
|
543
|
+
totalToolCalls
|
|
544
|
+
});
|
|
522
545
|
}
|
|
523
546
|
const fallbackMsg = {
|
|
524
547
|
role: MessageRole2.Assistant,
|
|
@@ -534,6 +557,26 @@ var ObotoAgent = class _ObotoAgent {
|
|
|
534
557
|
toolCalls: totalToolCalls
|
|
535
558
|
});
|
|
536
559
|
}
|
|
560
|
+
/**
|
|
561
|
+
* Stream an LLM call, emitting tokens in real-time, then aggregate into
|
|
562
|
+
* a full StandardChatResponse (including accumulated tool calls).
|
|
563
|
+
*/
|
|
564
|
+
async streamAndAggregate(provider, params) {
|
|
565
|
+
const stream = provider.stream({ ...params, stream: true });
|
|
566
|
+
const chunks = [];
|
|
567
|
+
for await (const chunk of stream) {
|
|
568
|
+
chunks.push(chunk);
|
|
569
|
+
const delta = chunk.choices?.[0]?.delta;
|
|
570
|
+
if (delta?.content) {
|
|
571
|
+
this.onToken(delta.content);
|
|
572
|
+
this.bus.emit("token", { text: delta.content });
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
async function* replay() {
|
|
576
|
+
for (const c of chunks) yield c;
|
|
577
|
+
}
|
|
578
|
+
return aggregateStream(replay());
|
|
579
|
+
}
|
|
537
580
|
};
|
|
538
581
|
export {
|
|
539
582
|
AgentEventBus,
|
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/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"]}
|
|
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 StandardChatChunk,\n Message as WrapperMessage,\n ToolCall as WrapperToolCall,\n ToolDefinition as WrapperToolDef,\n StandardChatResponse,\n} from \"@sschepis/llm-wrapper\";\nimport { aggregateStream } from \"@sschepis/llm-wrapper\";\nimport { zodToJsonSchema } from \"zod-to-json-schema\";\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 private onToken?: (token: string) => void;\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 this.onToken = config.onToken;\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 * When onToken is configured, uses streaming for real-time token output.\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 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 const tool = this.routerTool;\n // Convert Zod schema → JSON Schema for the LLM\n const parametersSchema = tool.parameters\n ? (zodToJsonSchema(tool.parameters, { target: \"openApi3\" }) as Record<string, unknown>)\n : { type: \"object\", properties: {} };\n const tools: WrapperToolDef[] = [\n {\n type: \"function\",\n function: {\n name: tool.name,\n description: tool.description,\n parameters: parametersSchema,\n },\n },\n ];\n\n let totalToolCalls = 0;\n const callHistory: string[] = [];\n const useStreaming = !!this.onToken;\n\n for (let iteration = 1; iteration <= this.maxIterations; iteration++) {\n if (this.interrupted) break;\n\n const isLastIteration = iteration === this.maxIterations;\n\n if (isLastIteration) {\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 params: StandardChatParams = {\n model: modelName,\n messages: [...messages],\n temperature: 0.7,\n ...(isLastIteration\n ? {}\n : { tools, tool_choice: \"auto\" as const }),\n };\n\n // Call LLM — streaming or non-streaming\n let response: StandardChatResponse;\n if (useStreaming) {\n response = await this.streamAndAggregate(provider, params);\n } else {\n response = await provider.chat(params);\n }\n\n const choice = response.choices[0];\n const content = (choice?.message?.content as string) ?? \"\";\n const toolCalls = choice?.message?.tool_calls;\n\n // Emit thought (the full text for this iteration)\n if (content) {\n this.bus.emit(\"agent_thought\", {\n text: content,\n model: modelName,\n iteration,\n });\n }\n\n // If no tool calls, this is the final response\n if (!toolCalls || toolCalls.length === 0) {\n const assistantMsg: ConversationMessage = {\n role: MessageRole.Assistant,\n blocks: [{ kind: \"text\", text: content }],\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\n const toolResults: Array<{ command: string; success: boolean }> = [];\n\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\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 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 toolResults.push({ command, success: false });\n totalToolCalls++;\n continue;\n }\n\n this.bus.emit(\"tool_execution_start\", { command, kwargs });\n\n let result: string;\n let success = true;\n try {\n result = await tool.execute(args);\n } catch (err) {\n result = `Error: ${err instanceof Error ? err.message : String(err)}`;\n success = false;\n }\n\n // Truncate large results\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 toolResults.push({ command, success });\n totalToolCalls++;\n\n messages.push({\n role: \"tool\",\n tool_call_id: tc.id,\n content: truncated,\n });\n }\n\n // Emit tool round summary\n this.bus.emit(\"tool_round_complete\", {\n iteration,\n tools: toolResults,\n totalToolCalls,\n });\n }\n\n // Exhausted iterations fallback\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 /**\n * Stream an LLM call, emitting tokens in real-time, then aggregate into\n * a full StandardChatResponse (including accumulated tool calls).\n */\n private async streamAndAggregate(\n provider: BaseProvider,\n params: StandardChatParams\n ): Promise<StandardChatResponse> {\n const stream = provider.stream({ ...params, stream: true });\n\n // Collect chunks while emitting tokens\n const chunks: StandardChatChunk[] = [];\n for await (const chunk of stream) {\n chunks.push(chunk);\n\n // Emit text tokens in real-time\n const delta = chunk.choices?.[0]?.delta;\n if (delta?.content) {\n this.onToken!(delta.content);\n this.bus.emit(\"token\", { text: delta.content });\n }\n }\n\n // Replay collected chunks through aggregateStream to build full response\n async function* replay(): AsyncIterable<StandardChatChunk> {\n for (const c of chunks) yield c;\n }\n return aggregateStream(replay());\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.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Event-driven dual-LLM orchestration library for autonomous AI agents",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -40,23 +40,24 @@
|
|
|
40
40
|
"dist"
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
|
-
"zod": "^3.23.0"
|
|
43
|
+
"zod": "^3.23.0",
|
|
44
|
+
"zod-to-json-schema": "^3.25.2"
|
|
44
45
|
},
|
|
45
46
|
"peerDependencies": {
|
|
47
|
+
"@sschepis/as-agent": "^0.1.0",
|
|
46
48
|
"@sschepis/llm-wrapper": "^0.1.0",
|
|
47
49
|
"@sschepis/lmscript": "^0.1.0",
|
|
48
|
-
"@sschepis/swiss-army-tool": "^0.1.0"
|
|
49
|
-
"@sschepis/as-agent": "^0.1.0"
|
|
50
|
+
"@sschepis/swiss-army-tool": "^0.1.0"
|
|
50
51
|
},
|
|
51
52
|
"optionalDependencies": {
|
|
52
53
|
"@aleph-ai/tinyaleph": "^1.7.0",
|
|
53
54
|
"@sschepis/resolang": "^0.5.0"
|
|
54
55
|
},
|
|
55
56
|
"devDependencies": {
|
|
57
|
+
"@sschepis/as-agent": "file:../claw-code/assembly",
|
|
56
58
|
"@sschepis/llm-wrapper": "file:../llm-wrapper",
|
|
57
59
|
"@sschepis/lmscript": "file:../lmscript",
|
|
58
60
|
"@sschepis/swiss-army-tool": "file:../swiss-army-tool",
|
|
59
|
-
"@sschepis/as-agent": "file:../claw-code/assembly",
|
|
60
61
|
"tsup": "^8.0.0",
|
|
61
62
|
"typescript": "^5.5.0",
|
|
62
63
|
"vitest": "^2.0.0"
|