@tuttiai/core 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -16,10 +16,12 @@ declare class EventBus {
16
16
 
17
17
  declare class TuttiRuntime {
18
18
  readonly events: EventBus;
19
- private sessions;
20
- private runner;
21
- private score;
19
+ private _sessions;
20
+ private _runner;
21
+ private _score;
22
22
  constructor(score: ScoreConfig);
23
+ /** The score configuration this runtime was created with. */
24
+ get score(): ScoreConfig;
23
25
  /**
24
26
  * Run an agent by name with the given user input.
25
27
  * Optionally pass a session_id to continue a conversation.
@@ -38,6 +40,28 @@ declare class AgentRunner {
38
40
  private executeTool;
39
41
  }
40
42
 
43
+ /**
44
+ * AgentRouter wraps TuttiRuntime and adds multi-agent delegation.
45
+ *
46
+ * The entry agent (orchestrator) gets a `delegate_to_agent` tool
47
+ * automatically injected. When the orchestrator calls it, the router
48
+ * runs the specialist agent and returns its output.
49
+ */
50
+ declare class AgentRouter {
51
+ private _score;
52
+ private runtime;
53
+ constructor(_score: ScoreConfig);
54
+ /** EventBus from the underlying runtime — subscribe to all events. */
55
+ get events(): EventBus;
56
+ /**
57
+ * Send input to the entry agent. The orchestrator will delegate
58
+ * to specialists as needed and return the final result.
59
+ */
60
+ run(input: string, session_id?: string): Promise<AgentResult>;
61
+ private buildRoutingScore;
62
+ private createDelegateTool;
63
+ }
64
+
41
65
  declare class InMemorySessionStore implements SessionStore {
42
66
  private sessions;
43
67
  create(agent_name: string): Session;
@@ -68,4 +92,26 @@ declare class AnthropicProvider implements LLMProvider {
68
92
  chat(request: ChatRequest): Promise<ChatResponse>;
69
93
  }
70
94
 
71
- export { AgentRunner, AnthropicProvider, type AnthropicProviderOptions, EventBus, InMemorySessionStore, ScoreLoader, TuttiRuntime, defineScore };
95
+ interface OpenAIProviderOptions {
96
+ /** OpenAI API key. Defaults to OPENAI_API_KEY env var. */
97
+ api_key?: string;
98
+ /** Custom base URL for Azure, proxies, or compatible APIs. */
99
+ base_url?: string;
100
+ }
101
+ declare class OpenAIProvider implements LLMProvider {
102
+ private client;
103
+ constructor(options?: OpenAIProviderOptions);
104
+ chat(request: ChatRequest): Promise<ChatResponse>;
105
+ }
106
+
107
+ interface GeminiProviderOptions {
108
+ /** Gemini API key. Defaults to GEMINI_API_KEY env var. */
109
+ api_key?: string;
110
+ }
111
+ declare class GeminiProvider implements LLMProvider {
112
+ private client;
113
+ constructor(options?: GeminiProviderOptions);
114
+ chat(request: ChatRequest): Promise<ChatResponse>;
115
+ }
116
+
117
+ export { AgentRouter, AgentRunner, AnthropicProvider, type AnthropicProviderOptions, EventBus, GeminiProvider, type GeminiProviderOptions, InMemorySessionStore, OpenAIProvider, type OpenAIProviderOptions, ScoreLoader, TuttiRuntime, defineScore };
package/dist/index.js CHANGED
@@ -233,33 +233,151 @@ var InMemorySessionStore = class {
233
233
  // src/runtime.ts
234
234
  var TuttiRuntime = class {
235
235
  events;
236
- sessions;
237
- runner;
238
- score;
236
+ _sessions;
237
+ _runner;
238
+ _score;
239
239
  constructor(score) {
240
- this.score = score;
240
+ this._score = score;
241
241
  this.events = new EventBus();
242
- this.sessions = new InMemorySessionStore();
243
- this.runner = new AgentRunner(score.provider, this.events, this.sessions);
242
+ this._sessions = new InMemorySessionStore();
243
+ this._runner = new AgentRunner(score.provider, this.events, this._sessions);
244
+ }
245
+ /** The score configuration this runtime was created with. */
246
+ get score() {
247
+ return this._score;
244
248
  }
245
249
  /**
246
250
  * Run an agent by name with the given user input.
247
251
  * Optionally pass a session_id to continue a conversation.
248
252
  */
249
253
  async run(agent_name, input, session_id) {
250
- const agent = this.score.agents[agent_name];
254
+ const agent = this._score.agents[agent_name];
251
255
  if (!agent) {
252
- const available = Object.keys(this.score.agents).join(", ");
256
+ const available = Object.keys(this._score.agents).join(", ");
253
257
  throw new Error(
254
258
  `Agent "${agent_name}" not found. Available agents: ${available}`
255
259
  );
256
260
  }
257
- const resolvedAgent = agent.model ? agent : { ...agent, model: this.score.default_model ?? "claude-sonnet-4-20250514" };
258
- return this.runner.run(resolvedAgent, input, session_id);
261
+ const resolvedAgent = agent.model ? agent : { ...agent, model: this._score.default_model ?? "claude-sonnet-4-20250514" };
262
+ return this._runner.run(resolvedAgent, input, session_id);
259
263
  }
260
264
  /** Retrieve an existing session. */
261
265
  getSession(id) {
262
- return this.sessions.get(id);
266
+ return this._sessions.get(id);
267
+ }
268
+ };
269
+
270
+ // src/agent-router.ts
271
+ import { z } from "zod";
272
+ var AgentRouter = class {
273
+ constructor(_score) {
274
+ this._score = _score;
275
+ const entryId = _score.entry ?? "orchestrator";
276
+ const entryAgent = _score.agents[entryId];
277
+ if (!entryAgent) {
278
+ const available = Object.keys(_score.agents).join(", ");
279
+ throw new Error(
280
+ `Entry agent "${entryId}" not found. Available agents: ${available}`
281
+ );
282
+ }
283
+ if (!entryAgent.delegates || entryAgent.delegates.length === 0) {
284
+ throw new Error(
285
+ `Entry agent "${entryId}" has no delegates. Add a delegates[] array to enable routing.`
286
+ );
287
+ }
288
+ for (const delegateId of entryAgent.delegates) {
289
+ if (!_score.agents[delegateId]) {
290
+ throw new Error(
291
+ `Delegate "${delegateId}" not found in agents. Available: ${Object.keys(_score.agents).join(", ")}`
292
+ );
293
+ }
294
+ }
295
+ const modifiedScore = this.buildRoutingScore(_score, entryId);
296
+ this.runtime = new TuttiRuntime(modifiedScore);
297
+ }
298
+ _score;
299
+ runtime;
300
+ /** EventBus from the underlying runtime — subscribe to all events. */
301
+ get events() {
302
+ return this.runtime.events;
303
+ }
304
+ /**
305
+ * Send input to the entry agent. The orchestrator will delegate
306
+ * to specialists as needed and return the final result.
307
+ */
308
+ async run(input, session_id) {
309
+ const entryId = this._score.entry ?? "orchestrator";
310
+ return this.runtime.run(entryId, input, session_id);
311
+ }
312
+ buildRoutingScore(score, entryId) {
313
+ const entryAgent = score.agents[entryId];
314
+ const delegates = entryAgent.delegates;
315
+ const delegateTool = this.createDelegateTool(score, delegates);
316
+ const routerVoice = {
317
+ name: "__tutti_router",
318
+ tools: [delegateTool]
319
+ };
320
+ const delegateDescriptions = delegates.map((id) => {
321
+ const agent = score.agents[id];
322
+ return ` - "${id}": ${agent.name}${agent.description ? ` \u2014 ${agent.description}` : ""}`;
323
+ }).join("\n");
324
+ const enhancedPrompt = `${entryAgent.system_prompt}
325
+
326
+ You have the following specialist agents available via the delegate_to_agent tool:
327
+ ${delegateDescriptions}
328
+
329
+ When the user's request matches a specialist's expertise, delegate to them with a clear task description. You can delegate to multiple specialists in sequence. After receiving a specialist's response, summarize the result for the user.`;
330
+ return {
331
+ ...score,
332
+ agents: {
333
+ ...score.agents,
334
+ [entryId]: {
335
+ ...entryAgent,
336
+ system_prompt: enhancedPrompt,
337
+ voices: [...entryAgent.voices, routerVoice]
338
+ }
339
+ }
340
+ };
341
+ }
342
+ createDelegateTool(score, delegateIds) {
343
+ const runtime = () => this.runtime;
344
+ const events = () => this.runtime.events;
345
+ const entryName = score.agents[score.entry ?? "orchestrator"]?.name ?? "orchestrator";
346
+ const parameters = z.object({
347
+ agent_id: z.enum(delegateIds).describe("Which specialist agent to delegate to"),
348
+ task: z.string().describe("The specific task description to pass to the specialist")
349
+ });
350
+ return {
351
+ name: "delegate_to_agent",
352
+ description: "Delegate a task to a specialist agent. The specialist will complete the task and return the result.",
353
+ parameters,
354
+ execute: async (input) => {
355
+ events().emit({
356
+ type: "delegate:start",
357
+ from: entryName,
358
+ to: input.agent_id,
359
+ task: input.task
360
+ });
361
+ try {
362
+ const result = await runtime().run(input.agent_id, input.task);
363
+ events().emit({
364
+ type: "delegate:end",
365
+ from: entryName,
366
+ to: input.agent_id,
367
+ output: result.output
368
+ });
369
+ return {
370
+ content: result.output || "(specialist returned no output)"
371
+ };
372
+ } catch (error) {
373
+ const message = error instanceof Error ? error.message : String(error);
374
+ return {
375
+ content: `Delegation to "${input.agent_id}" failed: ${message}`,
376
+ is_error: true
377
+ };
378
+ }
379
+ }
380
+ };
263
381
  }
264
382
  };
265
383
 
@@ -343,11 +461,267 @@ var AnthropicProvider = class {
343
461
  };
344
462
  }
345
463
  };
464
+
465
+ // src/providers/openai.ts
466
+ import OpenAI from "openai";
467
+ var OpenAIProvider = class {
468
+ client;
469
+ constructor(options = {}) {
470
+ this.client = new OpenAI({
471
+ apiKey: options.api_key,
472
+ baseURL: options.base_url
473
+ });
474
+ }
475
+ async chat(request) {
476
+ if (!request.model) {
477
+ throw new Error("OpenAIProvider requires a model on ChatRequest");
478
+ }
479
+ const messages = [];
480
+ if (request.system) {
481
+ messages.push({ role: "system", content: request.system });
482
+ }
483
+ for (const msg of request.messages) {
484
+ if (msg.role === "user") {
485
+ if (typeof msg.content === "string") {
486
+ messages.push({ role: "user", content: msg.content });
487
+ } else {
488
+ for (const block of msg.content) {
489
+ if (block.type === "tool_result") {
490
+ messages.push({
491
+ role: "tool",
492
+ tool_call_id: block.tool_use_id,
493
+ content: block.content
494
+ });
495
+ }
496
+ }
497
+ }
498
+ } else if (msg.role === "assistant") {
499
+ if (typeof msg.content === "string") {
500
+ messages.push({ role: "assistant", content: msg.content });
501
+ } else {
502
+ const textParts = msg.content.filter((b) => b.type === "text").map((b) => b.text).join("\n");
503
+ const toolCalls = msg.content.filter((b) => b.type === "tool_use").map((b) => {
504
+ const block = b;
505
+ return {
506
+ id: block.id,
507
+ type: "function",
508
+ function: {
509
+ name: block.name,
510
+ arguments: JSON.stringify(block.input)
511
+ }
512
+ };
513
+ });
514
+ messages.push({
515
+ role: "assistant",
516
+ content: textParts || null,
517
+ ...toolCalls.length > 0 && { tool_calls: toolCalls }
518
+ });
519
+ }
520
+ }
521
+ }
522
+ const tools = request.tools?.map(
523
+ (tool) => ({
524
+ type: "function",
525
+ function: {
526
+ name: tool.name,
527
+ description: tool.description,
528
+ parameters: tool.input_schema
529
+ }
530
+ })
531
+ );
532
+ const response = await this.client.chat.completions.create({
533
+ model: request.model,
534
+ messages,
535
+ tools: tools && tools.length > 0 ? tools : void 0,
536
+ max_tokens: request.max_tokens,
537
+ temperature: request.temperature,
538
+ stop: request.stop_sequences
539
+ });
540
+ const choice = response.choices[0];
541
+ const content = [];
542
+ if (choice.message.content) {
543
+ content.push({ type: "text", text: choice.message.content });
544
+ }
545
+ if (choice.message.tool_calls) {
546
+ for (const toolCall of choice.message.tool_calls) {
547
+ content.push({
548
+ type: "tool_use",
549
+ id: toolCall.id,
550
+ name: toolCall.function.name,
551
+ input: JSON.parse(toolCall.function.arguments)
552
+ });
553
+ }
554
+ }
555
+ let stopReason;
556
+ switch (choice.finish_reason) {
557
+ case "stop":
558
+ stopReason = "end_turn";
559
+ break;
560
+ case "tool_calls":
561
+ stopReason = "tool_use";
562
+ break;
563
+ case "length":
564
+ stopReason = "max_tokens";
565
+ break;
566
+ default:
567
+ stopReason = "end_turn";
568
+ }
569
+ return {
570
+ id: response.id,
571
+ content,
572
+ stop_reason: stopReason,
573
+ usage: {
574
+ input_tokens: response.usage?.prompt_tokens ?? 0,
575
+ output_tokens: response.usage?.completion_tokens ?? 0
576
+ }
577
+ };
578
+ }
579
+ };
580
+
581
+ // src/providers/gemini.ts
582
+ import {
583
+ GoogleGenerativeAI,
584
+ SchemaType
585
+ } from "@google/generative-ai";
586
+ var GeminiProvider = class {
587
+ client;
588
+ constructor(options = {}) {
589
+ const apiKey = options.api_key ?? process.env.GEMINI_API_KEY;
590
+ if (!apiKey) {
591
+ throw new Error(
592
+ "GeminiProvider requires an API key. Set GEMINI_API_KEY or pass api_key option."
593
+ );
594
+ }
595
+ this.client = new GoogleGenerativeAI(apiKey);
596
+ }
597
+ async chat(request) {
598
+ const model = request.model ?? "gemini-2.0-flash";
599
+ const tools = [];
600
+ if (request.tools && request.tools.length > 0) {
601
+ tools.push({
602
+ functionDeclarations: request.tools.map((tool) => ({
603
+ name: tool.name,
604
+ description: tool.description,
605
+ parameters: convertJsonSchemaToGemini(tool.input_schema)
606
+ }))
607
+ });
608
+ }
609
+ const generativeModel = this.client.getGenerativeModel({
610
+ model,
611
+ systemInstruction: request.system,
612
+ tools: tools.length > 0 ? tools : void 0
613
+ });
614
+ const contents = [];
615
+ for (const msg of request.messages) {
616
+ if (msg.role === "user") {
617
+ if (typeof msg.content === "string") {
618
+ contents.push({ role: "user", parts: [{ text: msg.content }] });
619
+ } else {
620
+ const parts = [];
621
+ for (const block of msg.content) {
622
+ if (block.type === "tool_result") {
623
+ parts.push({
624
+ functionResponse: {
625
+ name: block.tool_use_id,
626
+ // Gemini uses the function name, but we store id
627
+ response: { content: block.content }
628
+ }
629
+ });
630
+ }
631
+ }
632
+ if (parts.length > 0) {
633
+ contents.push({ role: "user", parts });
634
+ }
635
+ }
636
+ } else if (msg.role === "assistant") {
637
+ if (typeof msg.content === "string") {
638
+ contents.push({ role: "model", parts: [{ text: msg.content }] });
639
+ } else {
640
+ const parts = [];
641
+ for (const block of msg.content) {
642
+ if (block.type === "text") {
643
+ parts.push({ text: block.text });
644
+ } else if (block.type === "tool_use") {
645
+ parts.push({
646
+ functionCall: {
647
+ name: block.name,
648
+ args: block.input
649
+ }
650
+ });
651
+ }
652
+ }
653
+ if (parts.length > 0) {
654
+ contents.push({ role: "model", parts });
655
+ }
656
+ }
657
+ }
658
+ }
659
+ const result = await generativeModel.generateContent({
660
+ contents,
661
+ generationConfig: {
662
+ maxOutputTokens: request.max_tokens,
663
+ temperature: request.temperature,
664
+ stopSequences: request.stop_sequences
665
+ }
666
+ });
667
+ const response = result.response;
668
+ const candidate = response.candidates?.[0];
669
+ if (!candidate) {
670
+ return {
671
+ id: "",
672
+ content: [{ type: "text", text: "(no response from Gemini)" }],
673
+ stop_reason: "end_turn",
674
+ usage: { input_tokens: 0, output_tokens: 0 }
675
+ };
676
+ }
677
+ const content = [];
678
+ let hasToolCalls = false;
679
+ for (const part of candidate.content.parts) {
680
+ if ("text" in part && part.text) {
681
+ content.push({ type: "text", text: part.text });
682
+ }
683
+ if ("functionCall" in part && part.functionCall) {
684
+ hasToolCalls = true;
685
+ content.push({
686
+ type: "tool_use",
687
+ id: part.functionCall.name,
688
+ // Gemini doesn't have call IDs — use name
689
+ name: part.functionCall.name,
690
+ input: part.functionCall.args ?? {}
691
+ });
692
+ }
693
+ }
694
+ const stopReason = hasToolCalls ? "tool_use" : "end_turn";
695
+ const usage = response.usageMetadata;
696
+ return {
697
+ id: "",
698
+ content,
699
+ stop_reason: stopReason,
700
+ usage: {
701
+ input_tokens: usage?.promptTokenCount ?? 0,
702
+ output_tokens: usage?.candidatesTokenCount ?? 0
703
+ }
704
+ };
705
+ }
706
+ };
707
+ function convertJsonSchemaToGemini(schema) {
708
+ const type = schema.type;
709
+ const geminiType = type?.toUpperCase();
710
+ return {
711
+ type: SchemaType[geminiType] ?? SchemaType.OBJECT,
712
+ properties: schema.properties,
713
+ required: schema.required,
714
+ description: schema.description
715
+ };
716
+ }
346
717
  export {
718
+ AgentRouter,
347
719
  AgentRunner,
348
720
  AnthropicProvider,
349
721
  EventBus,
722
+ GeminiProvider,
350
723
  InMemorySessionStore,
724
+ OpenAIProvider,
351
725
  ScoreLoader,
352
726
  TuttiRuntime,
353
727
  defineScore
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/agent-runner.ts","../src/event-bus.ts","../src/session-store.ts","../src/runtime.ts","../src/score-loader.ts","../src/define-score.ts","../src/providers/anthropic.ts"],"sourcesContent":["import { zodToJsonSchema } from \"zod-to-json-schema\";\nimport type {\n AgentConfig,\n AgentResult,\n ChatMessage,\n ContentBlock,\n LLMProvider,\n SessionStore,\n Tool,\n ToolContext,\n ToolDefinition,\n ToolResultBlock,\n ToolUseBlock,\n TokenUsage,\n} from \"@tuttiai/types\";\nimport type { EventBus } from \"./event-bus.js\";\n\nconst DEFAULT_MAX_TURNS = 10;\n\nexport class AgentRunner {\n constructor(\n private provider: LLMProvider,\n private events: EventBus,\n private sessions: SessionStore,\n ) {}\n\n async run(\n agent: AgentConfig,\n input: string,\n session_id?: string,\n ): Promise<AgentResult> {\n // Resolve or create session\n const session = session_id\n ? this.sessions.get(session_id)\n : this.sessions.create(agent.name);\n\n if (!session) {\n throw new Error(`Session not found: ${session_id}`);\n }\n\n this.events.emit({\n type: \"agent:start\",\n agent_name: agent.name,\n session_id: session.id,\n });\n\n // Collect all tools from all voices\n const allTools = agent.voices.flatMap((v) => v.tools);\n const toolDefs = allTools.map(toolToDefinition);\n\n // Add user message\n const messages: ChatMessage[] = [\n ...session.messages,\n { role: \"user\", content: input },\n ];\n\n const maxTurns = agent.max_turns ?? DEFAULT_MAX_TURNS;\n const totalUsage: TokenUsage = { input_tokens: 0, output_tokens: 0 };\n let turns = 0;\n\n // Agentic loop\n while (turns < maxTurns) {\n turns++;\n\n this.events.emit({\n type: \"turn:start\",\n agent_name: agent.name,\n session_id: session.id,\n turn: turns,\n });\n\n const request = {\n model: agent.model,\n system: agent.system_prompt,\n messages,\n tools: toolDefs.length > 0 ? toolDefs : undefined,\n };\n\n this.events.emit({\n type: \"llm:request\",\n agent_name: agent.name,\n request,\n });\n\n const response = await this.provider.chat(request);\n\n this.events.emit({\n type: \"llm:response\",\n agent_name: agent.name,\n response,\n });\n\n totalUsage.input_tokens += response.usage.input_tokens;\n totalUsage.output_tokens += response.usage.output_tokens;\n\n // Add assistant message\n messages.push({ role: \"assistant\", content: response.content });\n\n this.events.emit({\n type: \"turn:end\",\n agent_name: agent.name,\n session_id: session.id,\n turn: turns,\n });\n\n // If the model is done talking, exit the loop\n if (response.stop_reason !== \"tool_use\") {\n break;\n }\n\n // Execute tool calls\n const toolUseBlocks = response.content.filter(\n (b): b is ToolUseBlock => b.type === \"tool_use\",\n );\n\n const toolResults: ToolResultBlock[] = await Promise.all(\n toolUseBlocks.map((block) =>\n this.executeTool(allTools, block, {\n session_id: session.id,\n agent_name: agent.name,\n }),\n ),\n );\n\n // Add tool results as a user message (Anthropic API format)\n messages.push({ role: \"user\", content: toolResults });\n }\n\n // Persist updated messages\n this.sessions.update(session.id, messages);\n\n // Extract final text output\n const lastAssistant = messages\n .filter((m) => m.role === \"assistant\")\n .at(-1);\n\n const output = extractText(lastAssistant?.content);\n\n this.events.emit({\n type: \"agent:end\",\n agent_name: agent.name,\n session_id: session.id,\n });\n\n return {\n session_id: session.id,\n output,\n messages,\n turns,\n usage: totalUsage,\n };\n }\n\n private async executeTool(\n tools: Tool[],\n block: ToolUseBlock,\n context: ToolContext,\n ): Promise<ToolResultBlock> {\n const tool = tools.find((t) => t.name === block.name);\n if (!tool) {\n return {\n type: \"tool_result\",\n tool_use_id: block.id,\n content: `Tool not found: ${block.name}`,\n is_error: true,\n };\n }\n\n this.events.emit({\n type: \"tool:start\",\n agent_name: context.agent_name,\n tool_name: block.name,\n input: block.input,\n });\n\n try {\n // Validate input with Zod\n const parsed = tool.parameters.parse(block.input);\n const result = await tool.execute(parsed, context);\n\n this.events.emit({\n type: \"tool:end\",\n agent_name: context.agent_name,\n tool_name: block.name,\n result,\n });\n\n return {\n type: \"tool_result\",\n tool_use_id: block.id,\n content: result.content,\n is_error: result.is_error,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n this.events.emit({\n type: \"tool:error\",\n agent_name: context.agent_name,\n tool_name: block.name,\n error: error instanceof Error ? error : new Error(message),\n });\n\n return {\n type: \"tool_result\",\n tool_use_id: block.id,\n content: `Tool execution error: ${message}`,\n is_error: true,\n };\n }\n }\n}\n\nfunction toolToDefinition(tool: Tool): ToolDefinition {\n const jsonSchema = zodToJsonSchema(tool.parameters, { target: \"openApi3\" });\n return {\n name: tool.name,\n description: tool.description,\n input_schema: jsonSchema as Record<string, unknown>,\n };\n}\n\nfunction extractText(content: string | ContentBlock[] | undefined): string {\n if (!content) return \"\";\n if (typeof content === \"string\") return content;\n return content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n}\n","import type { TuttiEvent, TuttiEventType } from \"@tuttiai/types\";\n\ntype Handler = (event: never) => void;\n\nexport class EventBus {\n private listeners = new Map<string, Set<Handler>>();\n\n on<T extends TuttiEventType>(\n type: T,\n handler: (event: Extract<TuttiEvent, { type: T }>) => void,\n ): () => void {\n if (!this.listeners.has(type)) {\n this.listeners.set(type, new Set());\n }\n const handlers = this.listeners.get(type)!;\n const h = handler as Handler;\n handlers.add(h);\n\n return () => {\n handlers.delete(h);\n };\n }\n\n off<T extends TuttiEventType>(\n type: T,\n handler: (event: Extract<TuttiEvent, { type: T }>) => void,\n ): void {\n this.listeners.get(type)?.delete(handler as Handler);\n }\n\n emit(event: TuttiEvent): void {\n const handlers = this.listeners.get(event.type);\n if (handlers) {\n for (const handler of handlers) {\n (handler as (event: TuttiEvent) => void)(event);\n }\n }\n\n // Also notify wildcard listeners\n const wildcardHandlers = this.listeners.get(\"*\");\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n (handler as (event: TuttiEvent) => void)(event);\n }\n }\n }\n\n /** Subscribe to all events. */\n onAny(handler: (event: TuttiEvent) => void): () => void {\n if (!this.listeners.has(\"*\")) {\n this.listeners.set(\"*\", new Set());\n }\n const handlers = this.listeners.get(\"*\")!;\n const h = handler as Handler;\n handlers.add(h);\n\n return () => {\n handlers.delete(h);\n };\n }\n}\n","import type { Session, SessionStore, ChatMessage } from \"@tuttiai/types\";\nimport { randomUUID } from \"node:crypto\";\n\nexport class InMemorySessionStore implements SessionStore {\n private sessions = new Map<string, Session>();\n\n create(agent_name: string): Session {\n const session: Session = {\n id: randomUUID(),\n agent_name,\n messages: [],\n created_at: new Date(),\n updated_at: new Date(),\n };\n this.sessions.set(session.id, session);\n return session;\n }\n\n get(id: string): Session | undefined {\n return this.sessions.get(id);\n }\n\n update(id: string, messages: ChatMessage[]): void {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Session not found: ${id}`);\n }\n session.messages = messages;\n session.updated_at = new Date();\n }\n}\n","import type { AgentResult, ScoreConfig, Session } from \"@tuttiai/types\";\nimport { AgentRunner } from \"./agent-runner.js\";\nimport { EventBus } from \"./event-bus.js\";\nimport { InMemorySessionStore } from \"./session-store.js\";\n\nexport class TuttiRuntime {\n readonly events: EventBus;\n private sessions: InMemorySessionStore;\n private runner: AgentRunner;\n private score: ScoreConfig;\n\n constructor(score: ScoreConfig) {\n this.score = score;\n this.events = new EventBus();\n this.sessions = new InMemorySessionStore();\n this.runner = new AgentRunner(score.provider, this.events, this.sessions);\n }\n\n /**\n * Run an agent by name with the given user input.\n * Optionally pass a session_id to continue a conversation.\n */\n async run(\n agent_name: string,\n input: string,\n session_id?: string,\n ): Promise<AgentResult> {\n const agent = this.score.agents[agent_name];\n if (!agent) {\n const available = Object.keys(this.score.agents).join(\", \");\n throw new Error(\n `Agent \"${agent_name}\" not found. Available agents: ${available}`,\n );\n }\n\n // Apply default model if agent doesn't specify one\n const resolvedAgent = agent.model\n ? agent\n : { ...agent, model: this.score.default_model ?? \"claude-sonnet-4-20250514\" };\n\n return this.runner.run(resolvedAgent, input, session_id);\n }\n\n /** Retrieve an existing session. */\n getSession(id: string): Session | undefined {\n return this.sessions.get(id);\n }\n}\n","import { pathToFileURL } from \"node:url\";\nimport { resolve } from \"node:path\";\nimport type { ScoreConfig } from \"@tuttiai/types\";\n\nexport class ScoreLoader {\n /**\n * Dynamically import a tutti.score.ts file and return its config.\n * Expects the file to `export default defineScore({ ... })`.\n */\n static async load(path: string): Promise<ScoreConfig> {\n const absolute = resolve(path);\n const url = pathToFileURL(absolute).href;\n\n const mod = (await import(url)) as { default?: ScoreConfig };\n\n if (!mod.default) {\n throw new Error(\n `Score file must have a default export: ${path}`,\n );\n }\n\n return mod.default;\n }\n}\n","import type { ScoreConfig } from \"@tuttiai/types\";\n\n/**\n * Typed identity function for defining a Tutti score.\n * Provides autocomplete and type checking — no runtime magic.\n */\nexport function defineScore(config: ScoreConfig): ScoreConfig {\n return config;\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n LLMProvider,\n ChatRequest,\n ChatResponse,\n ContentBlock,\n} from \"@tuttiai/types\";\n\nexport interface AnthropicProviderOptions {\n api_key?: string;\n}\n\nexport class AnthropicProvider implements LLMProvider {\n private client: Anthropic;\n\n constructor(options: AnthropicProviderOptions = {}) {\n this.client = new Anthropic({\n apiKey: options.api_key,\n });\n }\n\n async chat(request: ChatRequest): Promise<ChatResponse> {\n if (!request.model) {\n throw new Error(\"AnthropicProvider requires a model on ChatRequest\");\n }\n\n const response = await this.client.messages.create({\n model: request.model,\n max_tokens: request.max_tokens ?? 4096,\n system: request.system ?? \"\",\n messages: request.messages.map((msg) => ({\n role: msg.role,\n content: msg.content as Anthropic.MessageCreateParams[\"messages\"][number][\"content\"],\n })),\n tools: request.tools?.map((tool) => ({\n name: tool.name,\n description: tool.description,\n input_schema: tool.input_schema as Anthropic.Tool[\"input_schema\"],\n })),\n ...(request.temperature != null && { temperature: request.temperature }),\n ...(request.stop_sequences && { stop_sequences: request.stop_sequences }),\n });\n\n const content: ContentBlock[] = response.content.map((block) => {\n if (block.type === \"text\") {\n return { type: \"text\" as const, text: block.text };\n }\n if (block.type === \"tool_use\") {\n return {\n type: \"tool_use\" as const,\n id: block.id,\n name: block.name,\n input: block.input,\n };\n }\n throw new Error(`Unexpected content block type: ${(block as { type: string }).type}`);\n });\n\n return {\n id: response.id,\n content,\n stop_reason: response.stop_reason as ChatResponse[\"stop_reason\"],\n usage: {\n input_tokens: response.usage.input_tokens,\n output_tokens: response.usage.output_tokens,\n },\n };\n }\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/agent-runner.ts","../src/event-bus.ts","../src/session-store.ts","../src/runtime.ts","../src/agent-router.ts","../src/score-loader.ts","../src/define-score.ts","../src/providers/anthropic.ts","../src/providers/openai.ts","../src/providers/gemini.ts"],"sourcesContent":["import { zodToJsonSchema } from \"zod-to-json-schema\";\nimport type {\n AgentConfig,\n AgentResult,\n ChatMessage,\n ContentBlock,\n LLMProvider,\n SessionStore,\n Tool,\n ToolContext,\n ToolDefinition,\n ToolResultBlock,\n ToolUseBlock,\n TokenUsage,\n} from \"@tuttiai/types\";\nimport type { EventBus } from \"./event-bus.js\";\n\nconst DEFAULT_MAX_TURNS = 10;\n\nexport class AgentRunner {\n constructor(\n private provider: LLMProvider,\n private events: EventBus,\n private sessions: SessionStore,\n ) {}\n\n async run(\n agent: AgentConfig,\n input: string,\n session_id?: string,\n ): Promise<AgentResult> {\n // Resolve or create session\n const session = session_id\n ? this.sessions.get(session_id)\n : this.sessions.create(agent.name);\n\n if (!session) {\n throw new Error(`Session not found: ${session_id}`);\n }\n\n this.events.emit({\n type: \"agent:start\",\n agent_name: agent.name,\n session_id: session.id,\n });\n\n // Collect all tools from all voices\n const allTools = agent.voices.flatMap((v) => v.tools);\n const toolDefs = allTools.map(toolToDefinition);\n\n // Add user message\n const messages: ChatMessage[] = [\n ...session.messages,\n { role: \"user\", content: input },\n ];\n\n const maxTurns = agent.max_turns ?? DEFAULT_MAX_TURNS;\n const totalUsage: TokenUsage = { input_tokens: 0, output_tokens: 0 };\n let turns = 0;\n\n // Agentic loop\n while (turns < maxTurns) {\n turns++;\n\n this.events.emit({\n type: \"turn:start\",\n agent_name: agent.name,\n session_id: session.id,\n turn: turns,\n });\n\n const request = {\n model: agent.model,\n system: agent.system_prompt,\n messages,\n tools: toolDefs.length > 0 ? toolDefs : undefined,\n };\n\n this.events.emit({\n type: \"llm:request\",\n agent_name: agent.name,\n request,\n });\n\n const response = await this.provider.chat(request);\n\n this.events.emit({\n type: \"llm:response\",\n agent_name: agent.name,\n response,\n });\n\n totalUsage.input_tokens += response.usage.input_tokens;\n totalUsage.output_tokens += response.usage.output_tokens;\n\n // Add assistant message\n messages.push({ role: \"assistant\", content: response.content });\n\n this.events.emit({\n type: \"turn:end\",\n agent_name: agent.name,\n session_id: session.id,\n turn: turns,\n });\n\n // If the model is done talking, exit the loop\n if (response.stop_reason !== \"tool_use\") {\n break;\n }\n\n // Execute tool calls\n const toolUseBlocks = response.content.filter(\n (b): b is ToolUseBlock => b.type === \"tool_use\",\n );\n\n const toolResults: ToolResultBlock[] = await Promise.all(\n toolUseBlocks.map((block) =>\n this.executeTool(allTools, block, {\n session_id: session.id,\n agent_name: agent.name,\n }),\n ),\n );\n\n // Add tool results as a user message (Anthropic API format)\n messages.push({ role: \"user\", content: toolResults });\n }\n\n // Persist updated messages\n this.sessions.update(session.id, messages);\n\n // Extract final text output\n const lastAssistant = messages\n .filter((m) => m.role === \"assistant\")\n .at(-1);\n\n const output = extractText(lastAssistant?.content);\n\n this.events.emit({\n type: \"agent:end\",\n agent_name: agent.name,\n session_id: session.id,\n });\n\n return {\n session_id: session.id,\n output,\n messages,\n turns,\n usage: totalUsage,\n };\n }\n\n private async executeTool(\n tools: Tool[],\n block: ToolUseBlock,\n context: ToolContext,\n ): Promise<ToolResultBlock> {\n const tool = tools.find((t) => t.name === block.name);\n if (!tool) {\n return {\n type: \"tool_result\",\n tool_use_id: block.id,\n content: `Tool not found: ${block.name}`,\n is_error: true,\n };\n }\n\n this.events.emit({\n type: \"tool:start\",\n agent_name: context.agent_name,\n tool_name: block.name,\n input: block.input,\n });\n\n try {\n // Validate input with Zod\n const parsed = tool.parameters.parse(block.input);\n const result = await tool.execute(parsed, context);\n\n this.events.emit({\n type: \"tool:end\",\n agent_name: context.agent_name,\n tool_name: block.name,\n result,\n });\n\n return {\n type: \"tool_result\",\n tool_use_id: block.id,\n content: result.content,\n is_error: result.is_error,\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n\n this.events.emit({\n type: \"tool:error\",\n agent_name: context.agent_name,\n tool_name: block.name,\n error: error instanceof Error ? error : new Error(message),\n });\n\n return {\n type: \"tool_result\",\n tool_use_id: block.id,\n content: `Tool execution error: ${message}`,\n is_error: true,\n };\n }\n }\n}\n\nfunction toolToDefinition(tool: Tool): ToolDefinition {\n const jsonSchema = zodToJsonSchema(tool.parameters, { target: \"openApi3\" });\n return {\n name: tool.name,\n description: tool.description,\n input_schema: jsonSchema as Record<string, unknown>,\n };\n}\n\nfunction extractText(content: string | ContentBlock[] | undefined): string {\n if (!content) return \"\";\n if (typeof content === \"string\") return content;\n return content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n}\n","import type { TuttiEvent, TuttiEventType } from \"@tuttiai/types\";\n\ntype Handler = (event: never) => void;\n\nexport class EventBus {\n private listeners = new Map<string, Set<Handler>>();\n\n on<T extends TuttiEventType>(\n type: T,\n handler: (event: Extract<TuttiEvent, { type: T }>) => void,\n ): () => void {\n if (!this.listeners.has(type)) {\n this.listeners.set(type, new Set());\n }\n const handlers = this.listeners.get(type)!;\n const h = handler as Handler;\n handlers.add(h);\n\n return () => {\n handlers.delete(h);\n };\n }\n\n off<T extends TuttiEventType>(\n type: T,\n handler: (event: Extract<TuttiEvent, { type: T }>) => void,\n ): void {\n this.listeners.get(type)?.delete(handler as Handler);\n }\n\n emit(event: TuttiEvent): void {\n const handlers = this.listeners.get(event.type);\n if (handlers) {\n for (const handler of handlers) {\n (handler as (event: TuttiEvent) => void)(event);\n }\n }\n\n // Also notify wildcard listeners\n const wildcardHandlers = this.listeners.get(\"*\");\n if (wildcardHandlers) {\n for (const handler of wildcardHandlers) {\n (handler as (event: TuttiEvent) => void)(event);\n }\n }\n }\n\n /** Subscribe to all events. */\n onAny(handler: (event: TuttiEvent) => void): () => void {\n if (!this.listeners.has(\"*\")) {\n this.listeners.set(\"*\", new Set());\n }\n const handlers = this.listeners.get(\"*\")!;\n const h = handler as Handler;\n handlers.add(h);\n\n return () => {\n handlers.delete(h);\n };\n }\n}\n","import type { Session, SessionStore, ChatMessage } from \"@tuttiai/types\";\nimport { randomUUID } from \"node:crypto\";\n\nexport class InMemorySessionStore implements SessionStore {\n private sessions = new Map<string, Session>();\n\n create(agent_name: string): Session {\n const session: Session = {\n id: randomUUID(),\n agent_name,\n messages: [],\n created_at: new Date(),\n updated_at: new Date(),\n };\n this.sessions.set(session.id, session);\n return session;\n }\n\n get(id: string): Session | undefined {\n return this.sessions.get(id);\n }\n\n update(id: string, messages: ChatMessage[]): void {\n const session = this.sessions.get(id);\n if (!session) {\n throw new Error(`Session not found: ${id}`);\n }\n session.messages = messages;\n session.updated_at = new Date();\n }\n}\n","import type { AgentResult, ScoreConfig, Session } from \"@tuttiai/types\";\nimport { AgentRunner } from \"./agent-runner.js\";\nimport { EventBus } from \"./event-bus.js\";\nimport { InMemorySessionStore } from \"./session-store.js\";\n\nexport class TuttiRuntime {\n readonly events: EventBus;\n private _sessions: InMemorySessionStore;\n private _runner: AgentRunner;\n private _score: ScoreConfig;\n\n constructor(score: ScoreConfig) {\n this._score = score;\n this.events = new EventBus();\n this._sessions = new InMemorySessionStore();\n this._runner = new AgentRunner(score.provider, this.events, this._sessions);\n }\n\n /** The score configuration this runtime was created with. */\n get score(): ScoreConfig {\n return this._score;\n }\n\n /**\n * Run an agent by name with the given user input.\n * Optionally pass a session_id to continue a conversation.\n */\n async run(\n agent_name: string,\n input: string,\n session_id?: string,\n ): Promise<AgentResult> {\n const agent = this._score.agents[agent_name];\n if (!agent) {\n const available = Object.keys(this._score.agents).join(\", \");\n throw new Error(\n `Agent \"${agent_name}\" not found. Available agents: ${available}`,\n );\n }\n\n // Apply default model if agent doesn't specify one\n const resolvedAgent = agent.model\n ? agent\n : { ...agent, model: this._score.default_model ?? \"claude-sonnet-4-20250514\" };\n\n return this._runner.run(resolvedAgent, input, session_id);\n }\n\n /** Retrieve an existing session. */\n getSession(id: string): Session | undefined {\n return this._sessions.get(id);\n }\n}\n","import { z } from \"zod\";\nimport type { AgentConfig, AgentResult, Tool, Voice } from \"@tuttiai/types\";\nimport { TuttiRuntime } from \"./runtime.js\";\nimport type { EventBus } from \"./event-bus.js\";\nimport type { ScoreConfig } from \"@tuttiai/types\";\n\n/**\n * AgentRouter wraps TuttiRuntime and adds multi-agent delegation.\n *\n * The entry agent (orchestrator) gets a `delegate_to_agent` tool\n * automatically injected. When the orchestrator calls it, the router\n * runs the specialist agent and returns its output.\n */\nexport class AgentRouter {\n private runtime: TuttiRuntime;\n\n constructor(private _score: ScoreConfig) {\n // Build a modified score where the entry agent has the delegate tool\n const entryId = _score.entry ?? \"orchestrator\";\n const entryAgent = _score.agents[entryId];\n\n if (!entryAgent) {\n const available = Object.keys(_score.agents).join(\", \");\n throw new Error(\n `Entry agent \"${entryId}\" not found. Available agents: ${available}`,\n );\n }\n\n if (!entryAgent.delegates || entryAgent.delegates.length === 0) {\n throw new Error(\n `Entry agent \"${entryId}\" has no delegates. Add a delegates[] array to enable routing.`,\n );\n }\n\n // Validate all delegate IDs exist\n for (const delegateId of entryAgent.delegates) {\n if (!_score.agents[delegateId]) {\n throw new Error(\n `Delegate \"${delegateId}\" not found in agents. Available: ${Object.keys(_score.agents).join(\", \")}`,\n );\n }\n }\n\n // Create the runtime with the modified score\n const modifiedScore = this.buildRoutingScore(_score, entryId);\n this.runtime = new TuttiRuntime(modifiedScore);\n }\n\n /** EventBus from the underlying runtime — subscribe to all events. */\n get events(): EventBus {\n return this.runtime.events;\n }\n\n /**\n * Send input to the entry agent. The orchestrator will delegate\n * to specialists as needed and return the final result.\n */\n async run(input: string, session_id?: string): Promise<AgentResult> {\n const entryId = this._score.entry ?? \"orchestrator\";\n return this.runtime.run(entryId, input, session_id);\n }\n\n private buildRoutingScore(\n score: ScoreConfig,\n entryId: string,\n ): ScoreConfig {\n const entryAgent = score.agents[entryId];\n const delegates = entryAgent.delegates!;\n\n // Build the delegate tool\n const delegateTool = this.createDelegateTool(score, delegates);\n\n // Build a voice that carries the delegate tool\n const routerVoice: Voice = {\n name: \"__tutti_router\",\n tools: [delegateTool],\n };\n\n // Enhance the system prompt with delegate info\n const delegateDescriptions = delegates\n .map((id) => {\n const agent = score.agents[id];\n return ` - \"${id}\": ${agent.name}${agent.description ? ` — ${agent.description}` : \"\"}`;\n })\n .join(\"\\n\");\n\n const enhancedPrompt = `${entryAgent.system_prompt}\n\nYou have the following specialist agents available via the delegate_to_agent tool:\n${delegateDescriptions}\n\nWhen the user's request matches a specialist's expertise, delegate to them with a clear task description. You can delegate to multiple specialists in sequence. After receiving a specialist's response, summarize the result for the user.`;\n\n // Return a new score with the modified entry agent\n return {\n ...score,\n agents: {\n ...score.agents,\n [entryId]: {\n ...entryAgent,\n system_prompt: enhancedPrompt,\n voices: [...entryAgent.voices, routerVoice],\n },\n },\n };\n }\n\n private createDelegateTool(\n score: ScoreConfig,\n delegateIds: string[],\n ): Tool<{ agent_id: string; task: string }> {\n const runtime = () => this.runtime;\n const events = () => this.runtime.events;\n const entryName =\n score.agents[score.entry ?? \"orchestrator\"]?.name ?? \"orchestrator\";\n\n const parameters = z.object({\n agent_id: z\n .enum(delegateIds as [string, ...string[]])\n .describe(\"Which specialist agent to delegate to\"),\n task: z\n .string()\n .describe(\"The specific task description to pass to the specialist\"),\n });\n\n return {\n name: \"delegate_to_agent\",\n description:\n \"Delegate a task to a specialist agent. The specialist will complete the task and return the result.\",\n parameters,\n execute: async (input) => {\n events().emit({\n type: \"delegate:start\",\n from: entryName,\n to: input.agent_id,\n task: input.task,\n });\n\n try {\n const result = await runtime().run(input.agent_id, input.task);\n\n events().emit({\n type: \"delegate:end\",\n from: entryName,\n to: input.agent_id,\n output: result.output,\n });\n\n return {\n content: result.output || \"(specialist returned no output)\",\n };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n return {\n content: `Delegation to \"${input.agent_id}\" failed: ${message}`,\n is_error: true,\n };\n }\n },\n };\n }\n}\n","import { pathToFileURL } from \"node:url\";\nimport { resolve } from \"node:path\";\nimport type { ScoreConfig } from \"@tuttiai/types\";\n\nexport class ScoreLoader {\n /**\n * Dynamically import a tutti.score.ts file and return its config.\n * Expects the file to `export default defineScore({ ... })`.\n */\n static async load(path: string): Promise<ScoreConfig> {\n const absolute = resolve(path);\n const url = pathToFileURL(absolute).href;\n\n const mod = (await import(url)) as { default?: ScoreConfig };\n\n if (!mod.default) {\n throw new Error(\n `Score file must have a default export: ${path}`,\n );\n }\n\n return mod.default;\n }\n}\n","import type { ScoreConfig } from \"@tuttiai/types\";\n\n/**\n * Typed identity function for defining a Tutti score.\n * Provides autocomplete and type checking — no runtime magic.\n */\nexport function defineScore(config: ScoreConfig): ScoreConfig {\n return config;\n}\n","import Anthropic from \"@anthropic-ai/sdk\";\nimport type {\n LLMProvider,\n ChatRequest,\n ChatResponse,\n ContentBlock,\n} from \"@tuttiai/types\";\n\nexport interface AnthropicProviderOptions {\n api_key?: string;\n}\n\nexport class AnthropicProvider implements LLMProvider {\n private client: Anthropic;\n\n constructor(options: AnthropicProviderOptions = {}) {\n this.client = new Anthropic({\n apiKey: options.api_key,\n });\n }\n\n async chat(request: ChatRequest): Promise<ChatResponse> {\n if (!request.model) {\n throw new Error(\"AnthropicProvider requires a model on ChatRequest\");\n }\n\n const response = await this.client.messages.create({\n model: request.model,\n max_tokens: request.max_tokens ?? 4096,\n system: request.system ?? \"\",\n messages: request.messages.map((msg) => ({\n role: msg.role,\n content: msg.content as Anthropic.MessageCreateParams[\"messages\"][number][\"content\"],\n })),\n tools: request.tools?.map((tool) => ({\n name: tool.name,\n description: tool.description,\n input_schema: tool.input_schema as Anthropic.Tool[\"input_schema\"],\n })),\n ...(request.temperature != null && { temperature: request.temperature }),\n ...(request.stop_sequences && { stop_sequences: request.stop_sequences }),\n });\n\n const content: ContentBlock[] = response.content.map((block) => {\n if (block.type === \"text\") {\n return { type: \"text\" as const, text: block.text };\n }\n if (block.type === \"tool_use\") {\n return {\n type: \"tool_use\" as const,\n id: block.id,\n name: block.name,\n input: block.input,\n };\n }\n throw new Error(`Unexpected content block type: ${(block as { type: string }).type}`);\n });\n\n return {\n id: response.id,\n content,\n stop_reason: response.stop_reason as ChatResponse[\"stop_reason\"],\n usage: {\n input_tokens: response.usage.input_tokens,\n output_tokens: response.usage.output_tokens,\n },\n };\n }\n}\n","import OpenAI from \"openai\";\nimport type {\n LLMProvider,\n ChatRequest,\n ChatResponse,\n ContentBlock,\n} from \"@tuttiai/types\";\n\nexport interface OpenAIProviderOptions {\n /** OpenAI API key. Defaults to OPENAI_API_KEY env var. */\n api_key?: string;\n /** Custom base URL for Azure, proxies, or compatible APIs. */\n base_url?: string;\n}\n\nexport class OpenAIProvider implements LLMProvider {\n private client: OpenAI;\n\n constructor(options: OpenAIProviderOptions = {}) {\n this.client = new OpenAI({\n apiKey: options.api_key,\n baseURL: options.base_url,\n });\n }\n\n async chat(request: ChatRequest): Promise<ChatResponse> {\n if (!request.model) {\n throw new Error(\"OpenAIProvider requires a model on ChatRequest\");\n }\n\n // Map messages to OpenAI format\n const messages: OpenAI.ChatCompletionMessageParam[] = [];\n\n if (request.system) {\n messages.push({ role: \"system\", content: request.system });\n }\n\n for (const msg of request.messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n messages.push({ role: \"user\", content: msg.content });\n } else {\n // Tool results → map to OpenAI tool message format\n for (const block of msg.content) {\n if (block.type === \"tool_result\") {\n messages.push({\n role: \"tool\",\n tool_call_id: block.tool_use_id,\n content: block.content,\n });\n }\n }\n }\n } else if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n messages.push({ role: \"assistant\", content: msg.content });\n } else {\n // May contain text and/or tool_use blocks\n const textParts = msg.content\n .filter((b) => b.type === \"text\")\n .map((b) => (b as { text: string }).text)\n .join(\"\\n\");\n\n const toolCalls = msg.content\n .filter((b) => b.type === \"tool_use\")\n .map((b) => {\n const block = b as { id: string; name: string; input: unknown };\n return {\n id: block.id,\n type: \"function\" as const,\n function: {\n name: block.name,\n arguments: JSON.stringify(block.input),\n },\n };\n });\n\n messages.push({\n role: \"assistant\",\n content: textParts || null,\n ...(toolCalls.length > 0 && { tool_calls: toolCalls }),\n });\n }\n }\n }\n\n // Map tools to OpenAI function format\n const tools: OpenAI.ChatCompletionTool[] | undefined = request.tools?.map(\n (tool) => ({\n type: \"function\" as const,\n function: {\n name: tool.name,\n description: tool.description,\n parameters: tool.input_schema as Record<string, unknown>,\n },\n }),\n );\n\n const response = await this.client.chat.completions.create({\n model: request.model,\n messages,\n tools: tools && tools.length > 0 ? tools : undefined,\n max_tokens: request.max_tokens,\n temperature: request.temperature,\n stop: request.stop_sequences,\n });\n\n const choice = response.choices[0];\n const content: ContentBlock[] = [];\n\n if (choice.message.content) {\n content.push({ type: \"text\", text: choice.message.content });\n }\n\n if (choice.message.tool_calls) {\n for (const toolCall of choice.message.tool_calls) {\n content.push({\n type: \"tool_use\",\n id: toolCall.id,\n name: toolCall.function.name,\n input: JSON.parse(toolCall.function.arguments),\n });\n }\n }\n\n // Map stop reason\n let stopReason: ChatResponse[\"stop_reason\"];\n switch (choice.finish_reason) {\n case \"stop\":\n stopReason = \"end_turn\";\n break;\n case \"tool_calls\":\n stopReason = \"tool_use\";\n break;\n case \"length\":\n stopReason = \"max_tokens\";\n break;\n default:\n stopReason = \"end_turn\";\n }\n\n return {\n id: response.id,\n content,\n stop_reason: stopReason,\n usage: {\n input_tokens: response.usage?.prompt_tokens ?? 0,\n output_tokens: response.usage?.completion_tokens ?? 0,\n },\n };\n }\n}\n","import {\n GoogleGenerativeAI,\n type Content,\n type FunctionDeclaration,\n type Part,\n SchemaType,\n} from \"@google/generative-ai\";\nimport type {\n LLMProvider,\n ChatRequest,\n ChatResponse,\n ContentBlock,\n} from \"@tuttiai/types\";\n\nexport interface GeminiProviderOptions {\n /** Gemini API key. Defaults to GEMINI_API_KEY env var. */\n api_key?: string;\n}\n\nexport class GeminiProvider implements LLMProvider {\n private client: GoogleGenerativeAI;\n\n constructor(options: GeminiProviderOptions = {}) {\n const apiKey = options.api_key ?? process.env.GEMINI_API_KEY;\n if (!apiKey) {\n throw new Error(\n \"GeminiProvider requires an API key. Set GEMINI_API_KEY or pass api_key option.\",\n );\n }\n this.client = new GoogleGenerativeAI(apiKey);\n }\n\n async chat(request: ChatRequest): Promise<ChatResponse> {\n const model = request.model ?? \"gemini-2.0-flash\";\n\n // Build tool declarations\n const tools: { functionDeclarations: FunctionDeclaration[] }[] = [];\n if (request.tools && request.tools.length > 0) {\n tools.push({\n functionDeclarations: request.tools.map((tool) => ({\n name: tool.name,\n description: tool.description,\n parameters: convertJsonSchemaToGemini(tool.input_schema),\n })),\n });\n }\n\n const generativeModel = this.client.getGenerativeModel({\n model,\n systemInstruction: request.system,\n tools: tools.length > 0 ? tools : undefined,\n });\n\n // Map messages to Gemini contents\n const contents: Content[] = [];\n\n for (const msg of request.messages) {\n if (msg.role === \"user\") {\n if (typeof msg.content === \"string\") {\n contents.push({ role: \"user\", parts: [{ text: msg.content }] });\n } else {\n // Tool results\n const parts: Part[] = [];\n for (const block of msg.content) {\n if (block.type === \"tool_result\") {\n parts.push({\n functionResponse: {\n name: block.tool_use_id, // Gemini uses the function name, but we store id\n response: { content: block.content },\n },\n });\n }\n }\n if (parts.length > 0) {\n contents.push({ role: \"user\", parts });\n }\n }\n } else if (msg.role === \"assistant\") {\n if (typeof msg.content === \"string\") {\n contents.push({ role: \"model\", parts: [{ text: msg.content }] });\n } else {\n const parts: Part[] = [];\n for (const block of msg.content) {\n if (block.type === \"text\") {\n parts.push({ text: block.text });\n } else if (block.type === \"tool_use\") {\n parts.push({\n functionCall: {\n name: block.name,\n args: block.input as Record<string, unknown>,\n },\n });\n }\n }\n if (parts.length > 0) {\n contents.push({ role: \"model\", parts });\n }\n }\n }\n }\n\n const result = await generativeModel.generateContent({\n contents,\n generationConfig: {\n maxOutputTokens: request.max_tokens,\n temperature: request.temperature,\n stopSequences: request.stop_sequences,\n },\n });\n\n const response = result.response;\n const candidate = response.candidates?.[0];\n\n if (!candidate) {\n return {\n id: \"\",\n content: [{ type: \"text\", text: \"(no response from Gemini)\" }],\n stop_reason: \"end_turn\",\n usage: { input_tokens: 0, output_tokens: 0 },\n };\n }\n\n // Map response parts to ContentBlocks\n const content: ContentBlock[] = [];\n let hasToolCalls = false;\n\n for (const part of candidate.content.parts) {\n if (\"text\" in part && part.text) {\n content.push({ type: \"text\", text: part.text });\n }\n if (\"functionCall\" in part && part.functionCall) {\n hasToolCalls = true;\n content.push({\n type: \"tool_use\",\n id: part.functionCall.name, // Gemini doesn't have call IDs — use name\n name: part.functionCall.name,\n input: part.functionCall.args ?? {},\n });\n }\n }\n\n const stopReason = hasToolCalls ? \"tool_use\" : \"end_turn\";\n const usage = response.usageMetadata;\n\n return {\n id: \"\",\n content,\n stop_reason: stopReason,\n usage: {\n input_tokens: usage?.promptTokenCount ?? 0,\n output_tokens: usage?.candidatesTokenCount ?? 0,\n },\n };\n }\n}\n\n/**\n * Convert a JSON Schema object into a shape Gemini's API accepts.\n * Gemini uses its own SchemaType enum for type values.\n */\nfunction convertJsonSchemaToGemini(\n schema: Record<string, unknown>,\n): FunctionDeclaration[\"parameters\"] {\n const type = schema.type as string;\n const geminiType = type?.toUpperCase() as keyof typeof SchemaType;\n\n return {\n type: SchemaType[geminiType] ?? SchemaType.OBJECT,\n properties: schema.properties as Record<string, unknown> | undefined,\n required: schema.required as string[] | undefined,\n description: schema.description as string | undefined,\n } as FunctionDeclaration[\"parameters\"];\n}\n"],"mappings":"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","names":[]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tuttiai/core",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "Tutti runtime — multi-agent orchestration for TypeScript",
5
5
  "type": "module",
6
6
  "exports": {
@@ -21,11 +21,13 @@
21
21
  },
22
22
  "dependencies": {
23
23
  "@anthropic-ai/sdk": "^0.39.0",
24
- "@tuttiai/types": "^0.1.0",
24
+ "@google/generative-ai": "^0.21.0",
25
+ "@tuttiai/types": "^0.2.0",
26
+ "openai": "^4.0.0",
25
27
  "zod": "^3.24.0",
26
28
  "zod-to-json-schema": "^3.24.0"
27
29
  },
28
- "keywords": ["tutti", "ai", "agents", "orchestration", "runtime", "llm", "anthropic"],
30
+ "keywords": ["tutti", "ai", "agents", "orchestration", "runtime", "llm", "anthropic", "openai", "gemini"],
29
31
  "license": "MIT",
30
32
  "repository": {
31
33
  "type": "git",