@atgs/tapeworm 0.1.6 → 0.1.8-canary.5.d0bf7ab

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/README.md CHANGED
@@ -1,13 +1,11 @@
1
1
  ![Tapeworm Logo](https://raw.githubusercontent.com/andygrace227/tapeworm/main/tapeworm.svg)
2
2
 
3
- # Tapeworm
3
+ # Tapeworm Core
4
4
 
5
- <h3>In-browser and Node agent framework.</h3>
5
+ <h3>In-browser and Node Agent Framework.</h3>
6
6
 
7
7
  [![npm version](https://img.shields.io/npm/v/@atgs/tapeworm.svg?style=flat-square)](https://www.npmjs.org/package/@atgs/tapeworm.svg)
8
-
9
8
  [![npm downloads](https://img.shields.io/npm/dm/@atgs/tapeworm?style=flat-square)](https://npm-stat.com/charts.html?package=@atgs/tapeworm)
10
-
11
9
  [repo link](https://github.com/andygrace227/tapeworm)
12
10
 
13
11
  This is the root package for Tapeworm. You can consume other packages like @atgs/tapeworm_bedrock for AWS Bedrock support.
@@ -18,13 +16,22 @@ It provides an object-oriented API to create agents that run either on Node or w
18
16
 
19
17
  ## Current Features
20
18
 
21
- - Base API Defined.
22
19
  - Supports `function` tools.
23
20
  - Supports Ollama models.
24
- - Has a Babel plugin to make tool creation really easy.
21
+ - Has a Babel plugin to make tool creation easy.
22
+ - Has TS decorators to make tool creation really easy, too!
23
+ - Supports browser and Node.
24
+
25
+ ## Tapeworm's Tenets
26
+
27
+ - **Be the most ergonomic agentic solution for Node and the browser.** Each commit should make it easier to develop and deploy agentic AI solutions.
28
+ - **Be as model-agnostic as possible.** Use your own machine, AWS, Google, a literal potato... we don't care.
29
+ - **Keep things light.** We already waste so much water and energy with AI. The overhead from Tapeworm should be kept to a minimum when possible.
25
30
 
26
31
  ## Examples
27
32
 
33
+ ### How do I define a tool?
34
+
28
35
  #### With the babel plugin (@atgs/@atgs/babel-plugin-tapeworm-decorator) (recommended, super concise)
29
36
 
30
37
  ```js
@@ -50,22 +57,37 @@ class AdditionTool extends Tool {
50
57
  return a + b;
51
58
  }
52
59
  }
60
+ ```
53
61
 
54
- const ollama = new OllamaModel("http://localhost:11434", "gpt-oss:20b", {
55
- stream: false,
56
- });
57
-
58
- const agent = Agent.builder()
59
- .name("calculatorAgent")
60
- .tools([new AdditionTool()])
61
- .systemPrompt("You are an agent that runs math operations.")
62
- .model(ollama)
63
- .build();
64
-
65
- await agent.invoke("What is 9 + 10?");
62
+ #### With Typescript Decorators
63
+
64
+ ```ts
65
+ @ToolName("AdditionTool")
66
+ @ToolDescription("Adds two numbers together.")
67
+ @ToolParameter({
68
+ name: "a",
69
+ description: "The first number to add",
70
+ required: true,
71
+ type: "number",
72
+ })
73
+ @ToolParameter({
74
+ name: "b",
75
+ description: "The second number to add",
76
+ required: true,
77
+ type: "number",
78
+ })
79
+ @ToolOutput("The sum of inputs a and b")
80
+ class AdditionTool extends Tool {
81
+ execute(input: any) {
82
+ let a = +input.a;
83
+ let b = +input.b;
84
+ console.log("Adding " + a + " and " + b + ": " + (a + b));
85
+ return a + b;
86
+ }
87
+ }
66
88
  ```
67
89
 
68
- #### Without the plugin (still pretty readable.)
90
+ #### Without the plugin (still pretty readable)
69
91
 
70
92
  ```js
71
93
  import {
@@ -77,18 +99,10 @@ import {
77
99
  } from "../../dist/tapeworm.es.js";
78
100
 
79
101
  class AdditionTool extends Tool {
80
- /**
81
- * Unique name used to reference this tool.
82
- * @returns Tool identifier string.
83
- */
84
102
  getName() {
85
103
  return "AdditionTool";
86
104
  }
87
105
 
88
- /**
89
- * Short description provided to the model.
90
- * @returns Human-readable explanation of the tool.
91
- */
92
106
  getDescription() {
93
107
  return "Adds two numbers together.";
94
108
  }
@@ -117,9 +131,11 @@ class AdditionTool extends Tool {
117
131
  return a + b;
118
132
  }
119
133
  }
134
+ ```
120
135
 
121
- // Because this is a test file, we are going to run this locally using Ollama
136
+ #### Then calling the agent:
122
137
 
138
+ ```js
123
139
  const ollama = new OllamaModel("http://localhost:11434", "gpt-oss:20b", {
124
140
  stream: false,
125
141
  });
@@ -131,15 +147,9 @@ const agent = Agent.builder()
131
147
  .model(ollama)
132
148
  .build();
133
149
 
134
- await agent.invoke("What is 9 + 10");
150
+ await agent.invoke("What is 9 + 10?");
135
151
  ```
136
152
 
137
- ## Tapeworm's Tenets
138
-
139
- - **Be the most ergonomic agentic solution for Node and the browser.** Each commit should make it easier to develop and deploy agentic AI solutions.
140
- - **Be as model-agnostic as possible.** Use your own machine, AWS, Google, a literal potato... we don't care.
141
- - **Keep things light.** We already waste so much water and energy with AI. The overhead from Tapeworm should be kept to a minimum when possible.
142
-
143
153
  ## Roadmap
144
154
 
145
155
  Tapeworm seeks to be the most ergonomic agentic solution for Node and the browser.
@@ -1,27 +1,90 @@
1
+ /**
2
+ * The Agent module contains all things related to Agents, including:
3
+ * - the Agent class
4
+ * - the AgentBuilder class
5
+ * - the default callback handler for an Agent.
6
+ *
7
+ * This module contains most of the business logic for running the main agent loop.
8
+ *
9
+ * @module
10
+ */
1
11
  import Conversation, { ConversationManager } from "../conversation/conversation";
2
12
  import Message from "../conversation/message";
3
13
  import { type Model } from "../model/model";
4
14
  import type Tool from "../tool/tool";
5
15
  import type ToolCall from "../tool/toolCall";
6
16
  /**
7
- * Coordinates a model, its tools, and the running conversation to fulfill user queries.
17
+ * Agents combine a model with your tools.
18
+ *
19
+ * To build an agent, use the AgentBuilder class:
20
+ *
21
+ * ```ts
22
+ * const agent = Agent.builder()
23
+ * .name("yourAgent")
24
+ * .tools([new YourTool()])
25
+ * .systemPrompt("You are an agent.")
26
+ * .model(yourModel)
27
+ * .build();
28
+ * ```
29
+ *
8
30
  */
9
31
  export default class Agent {
32
+ /**
33
+ * The name of the agent.
34
+ */
10
35
  name: string;
36
+ /**
37
+ * The system prompt (if any) for the agent.
38
+ */
11
39
  systemPrompt?: string;
40
+ /**
41
+ * The tools this agent knows about and can run.
42
+ */
12
43
  tools: Tool[];
44
+ /**
45
+ * The underlying model for the agent.
46
+ */
13
47
  model: Model;
48
+ /**
49
+ * The conversation for the agent.
50
+ * You do not normally need to set this parameter unless you are building a use case
51
+ * where you have a persistent session with an agent.
52
+ */
14
53
  conversation: Conversation;
54
+ /**
55
+ * The conversation manager for the agent.
56
+ * Normally, a converstation manager that does nothing will be used.
57
+ * When SummarizingConversationManager or RAGConversationManager is implemented, these will help you avoid
58
+ * token overflow.
59
+ */
15
60
  conversationManager?: ConversationManager;
16
- toolNameToIndexMap: any | undefined;
61
+ /**
62
+ * A cache for looking up tools in the Tools array.
63
+ * DO NOT MANUALLY SET THIS VALUE. AGENT AUTOMATICALLY TAKES CARE OF IT.
64
+ */
65
+ private toolNameToIndexMap;
66
+ /**
67
+ * The callback function, invoked for every response from the model.
68
+ * The default implementation just prints to std.out or your console.
69
+ */
17
70
  callback: (m: Message) => void;
71
+ /**
72
+ * This is the constructor for an Agent.
73
+ *
74
+ * i IMPLORE YOU not to use this method. You CAN, but you should be using the Builder instead
75
+ * for the best results, as this method WILL change with future updates.
76
+ *
77
+ * Builder will be a lot more stable and will always be backwards compatible.
78
+ */
18
79
  constructor(name: string, tools: Tool[], model: Model, conversationManager: ConversationManager, callback: (m: Message) => void);
19
80
  /**
20
81
  * Run the full agent loop for a user query: seed the conversation, invoke the model,
21
82
  * and execute any returned tool calls until completion.
83
+ * *
22
84
  * @param query User-provided input to hand to the agent.
85
+ * @param callback A function that handles the messages coming from the agent.
23
86
  */
24
- invoke(query: string): Promise<void>;
87
+ invoke(query: string, callback?: (m: Message) => void): Promise<void>;
25
88
  /**
26
89
  * Ask the backing model for the next response given the current conversation state.
27
90
  * @returns Parsed model response including content, thinking, and tool calls.
@@ -37,9 +100,12 @@ export default class Agent {
37
100
  * Build a lookup from tool name to index for efficient resolution of tool calls.
38
101
  */
39
102
  generateToolNameToIndexMap(): void;
103
+ /**
104
+ * Get a builder to build an Agent.
105
+ */
40
106
  static builder(): AgentBuilder;
41
107
  }
42
- declare class AgentBuilder {
108
+ export declare class AgentBuilder {
43
109
  _name: string;
44
110
  _systemPrompt?: string;
45
111
  _tools: Tool[];
@@ -48,14 +114,45 @@ declare class AgentBuilder {
48
114
  _conversationManager: ConversationManager;
49
115
  _toolNameToIndexMap: any | undefined;
50
116
  _callback: (m: Message) => void;
117
+ /**
118
+ * Set the name of the agent.
119
+ */
51
120
  name(name: string): AgentBuilder;
121
+ /**
122
+ * Set the system prompt of the agent.
123
+ */
52
124
  systemPrompt(systemPrompt: string | undefined): AgentBuilder;
125
+ /**
126
+ * Set the tools of the agent, if you already have an array of tools.
127
+ */
53
128
  tools(tools: Tool[]): AgentBuilder;
129
+ /**
130
+ * Add a tool, 1 by 1, to the agent..
131
+ */
54
132
  addTool(tool: Tool): AgentBuilder;
133
+ /**
134
+ * Set the underlying model for the agent.
135
+ */
55
136
  model(model: Model): AgentBuilder;
137
+ /**
138
+ * Set the conversation manager for the agent.
139
+ */
56
140
  conversationManager(mgr: ConversationManager): AgentBuilder;
141
+ /**
142
+ * Set the callback for the agent.
143
+ */
57
144
  callback(callback: (m: Message) => void): AgentBuilder;
145
+ /**
146
+ * Build the agent.
147
+ */
58
148
  build(): Agent;
59
149
  }
150
+ /**
151
+ * This function is Tapeworm's default callback function.
152
+ * If you do not specify your own callback function, then this will be called and all
153
+ * it will do is log output to the screen.
154
+ *
155
+ * You can override this per invocation or on the Agent itself to do other things
156
+ * with the LLM output.
157
+ */
60
158
  export declare function defaultCallback(m: Message): void;
61
- export {};
@@ -1,7 +1,20 @@
1
+ /**
2
+ * The Conversation module contains the Conversation class and the ConversationManager prototypes.
3
+ *
4
+ * The Conversation is a wrapper around both a manager and an array of messages.
5
+ *
6
+ * The Conversation Manager is an object that can perform operations on only the conversation.
7
+ *
8
+ * While no Conversation Managers have been implemented yet, they will allow resilience to overflowing context windows.
9
+ *
10
+ * @module
11
+ */
1
12
  import type { Message } from "..";
2
13
  import type { Model } from "../model/model";
3
14
  /**
4
- * Maintains ordered chat messages and delegates to a conversation manager for compaction.
15
+ * A Conversation holds an array of messages and its associated manager.
16
+ *
17
+ * Conversations are (mostly) immutable, until the manager steps in and compacts the conversation.
5
18
  */
6
19
  export default class Conversation {
7
20
  messages: Message[];
@@ -17,7 +30,7 @@ export default class Conversation {
17
30
  append(message: Message): void;
18
31
  }
19
32
  /**
20
- * Strategy interface for pruning or transforming a conversation history.
33
+ * Interface for compacting a Conversation. Future implementations can summarize or do RAG-based compaction
21
34
  */
22
35
  export declare class ConversationManager {
23
36
  /**
@@ -1,3 +1,15 @@
1
+ /**
2
+ * The Messages module contains all the shapes that make up a single Message.
3
+ * - The actual Message class, which is a role + an array of MessageComponents
4
+ * - And a builder, too, which you should use 99.999% of the time!
5
+ * - An enum called MessageComponentType
6
+ * - The MessageComponents
7
+ * - **Content** - normal text from the LLM
8
+ * - **Thinking** - chain-of-thought reasoning from the LLM
9
+ * - **ToolCall** is not technically contained here, but it is a message component type
10
+ * - **ToolResult** - encodes the result of a tool call.
11
+ * @module
12
+ */
1
13
  import type ToolCall from "../tool/toolCall";
2
14
  /**
3
15
  * Messages are the units of a Conversation
package/dist/index.d.ts CHANGED
@@ -1,3 +1,10 @@
1
+ /**
2
+ * The index module gathers the exports from Tapeworm.
3
+ *
4
+ * This file should be modified when new classes are introduced to Tapeworm
5
+ *
6
+ * @module
7
+ */
1
8
  export { default as Agent } from "./agent/agent";
2
9
  export { default as Conversation, ConversationManager, DefaultConversationManager, } from "./conversation/conversation";
3
10
  export { Model, ModelRequest, ModelRequestBuilder } from "./model/model";
@@ -1,8 +1,18 @@
1
+ /**
2
+ * Tapeworm's first mostly-working model is OllamaModel,
3
+ * which routes model requests to an Ollama endpoint on your local machine.
4
+ *
5
+ * Other Models will be housed in separate NPM packages to allow better portability
6
+ * and to leverage the existing NPM packages (for example, the AWS SDK in the case of Bedrock)
7
+ * for those models.
8
+ *
9
+ * @module
10
+ */
1
11
  import { Message } from "..";
2
12
  import ToolCall from "../tool/toolCall";
3
13
  import { Model, ModelRequest } from "./model";
4
14
  /**
5
- * Model adapter that translates between Tapeworm message/tool shapes and the Ollama chat API.
15
+ * The Ollama Model class. This translates between Tapeworm message/tool shapes and the Ollama chat API.
6
16
  */
7
17
  export default class OllamaModel extends Model {
8
18
  endpoint: string;
@@ -1,3 +1,13 @@
1
+ /**
2
+ * The Model module lays out the interface for a Tapeworm model.
3
+ *
4
+ * It contains the base Model class, which doesn't do anything other than throw errors and specify an interface,
5
+ * and also the ModelRequest and ModelRequestBuilder classes, which show what kind of shape a model expects to
6
+ * recieve upon invocation.
7
+ *
8
+ *
9
+ * @module
10
+ */
1
11
  import type Message from "../conversation/message";
2
12
  import type Tool from "../tool/tool";
3
13
  /**
@@ -1 +1 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class w{messages;manager;constructor(){this.messages=[],this.manager=new g}append(e){this.messages.push(e),this.messages=this.manager.compact(this.messages)}}class M{compact(e){throw new y("No implementation for conversation manager!")}configure(e){throw new y("No implementation for conversation manager!")}}class g extends M{compact(e){return e}configure(e){}}class y extends Error{constructor(e){super(e),this.name="ConversationManagerNotImplemented"}}class u{role;content;constructor(e,o){this.role=e,this.content=o}static builder(){return new b}filter(e){return this.content.filter(o=>o.getMessageComponentType()==e)}}class b{_role;_content;role(e){return this._role=e,this}init(){this._content==null&&(this._content=[])}toolCall(e){return e==null?this:(this.init(),this._content.push(e),this)}toolCalls(e){if(e==null)return this;this.init();for(const o of e)this._content.push(o);return this}toolResult(e){return e==null?this:(this.init(),this._content.push(e),this)}thinking(e){return e==null?this:(this.init(),this._content.push(C.of(e)),this)}content(e){return e==null?this:(this.init(),this._content.push(N.of(e)),this)}build(){if(this._content==null||this._content.length==0)throw new Error("Role-only messages are not supported by Tapeworm.");return new u(this._role,this._content)}}const a={Content:"content",Thinking:"thinking",ToolCall:"toolcall",ToolResult:"toolresult"};class m{getMessageComponentType(){throw new Error("Message components that do not have a message component type are not allowed.")}}class N extends m{text;constructor(e){super(),this.text=e}getMessageComponentType(){return a.Content}get(){return this.text}static of(e){return new this(e)}}class C extends m{thought;constructor(e){super(),this.thought=e}getMessageComponentType(){return a.Thinking}get(){return this.thought}static of(e){return new this(e)}}class c extends m{id;toolName;toolResult;constructor(e,o,s){super(),this.id=e,this.toolName=o,this.toolResult=s}getMessageComponentType(){return a.ToolResult}static of(e,o){return new this(e.id,e.name,o)}}class P{async invoke(e){throw new v("The invoke function for this model was not correctly implemented.")}tokenLimit(){throw new v("The tokenLimit function for this model was not correctly implemented.")}}class q{messages;tools;constructor(e,o){this.messages=e,this.tools=o}static builder(){return new f}}class f{_messages;_tools;messages(e){return this._messages=e,this}tools(e){return this._tools=e,this}build(){if(this._tools==null&&(this._tools=[]),this._messages==null)throw new j("Requests to the model should include content.");return new q(this._messages,this._tools)}}class v extends Error{constructor(e){super(e),this.name="ModelNotImplementedError"}}class j extends Error{constructor(e){super(e),this.name="MessagesNotDefinedError"}}class _ extends m{sequence;name;parameters;type;id;getMessageComponentType(){return a.ToolCall}constructor(e,o,s,n,r){super(),this.sequence=e,this.name=o,this.parameters=s,this.type=n,this.id=r}static builder(){return new x}}class x{_sequence;_name;_parameters;_type;_id;sequence(e){return this._sequence=e,this}name(e){return this._name=e,this}parameters(e){return this._parameters=e,this}type(e){return this._type=e,this}id(e){return e!=null&&(this._id=e),this}build(){return this._sequence==null&&(this._sequence=0),this._id==null&&(this._id=(Math.random()+1).toString(36).slice(2,7)),new _(this._sequence,this._name,this._parameters,this._type,this._id)}}class D extends Error{constructor(e){super(e),this.name="ToolNotFoundError"}}class k{name;systemPrompt;tools;model;conversation;conversationManager;toolNameToIndexMap;callback;constructor(e,o,s,n,r){this.name=e,this.model=s,this.conversationManager=n,this.tools=o,this.callback=r,this.conversationManager.configure(s)}async invoke(e){this.conversation==null&&(this.conversation=new w,this.conversationManager!=null&&(this.conversation.manager=this.conversationManager),this.systemPrompt!=null&&this.conversation.append(u.builder().role("system").content(this.systemPrompt).build())),this.conversation.append(u.builder().role("user").content(e).build());let o=!1;for(;!o;){let s=await this._runQuery();this.callback(s),this.conversation.append(s),o=!0;const n=s.filter(a.ToolCall);if(n!=null&&n.length!=0){o=!1,n.sort((r,l)=>(r.sequence??0)<(l.sequence??0)?-1:1);for(let r of n)await this._runTool(r)}}}async _runQuery(){return await this.model.invoke(new f().messages(this.conversation?.messages).tools(this.tools).build())}async _runTool(e){if(this.generateToolNameToIndexMap(),!(e.name in this.toolNameToIndexMap)){this.conversation.append(u.builder().role("tool").toolResult(c.of(e,new D("Agent does not have a tool with this name."))).build());return}let o=this.tools[this.toolNameToIndexMap[e.name]];try{let s=await o.execute(e.parameters);this.conversation.append(u.builder().role("tool").toolResult(c.of(e,s)).build())}catch(s){this.conversation.append(u.builder().role("tool").toolResult(c.of(e,JSON.stringify(s))).build())}}generateToolNameToIndexMap(){if(this.toolNameToIndexMap==null){this.toolNameToIndexMap={};for(let e=0;e<this.tools.length;e++)this.toolNameToIndexMap[this.tools[e].getName()]=e}}static builder(){return new A}}class A{_name;_systemPrompt;_tools;_model;_conversation;_conversationManager=new g;_toolNameToIndexMap;_callback=e=>J(e);name(e){return this._name=e,this}systemPrompt(e){return this._systemPrompt=e,this}tools(e){return this._tools=e,this}addTool(e){return this._tools==null&&(this._tools=[]),this._tools.push(e),this}model(e){return this._model=e,this}conversationManager(e){return this._conversationManager=e,this}callback(e){return this._callback=e,this}build(){let e=new k(this._name,this._tools,this._model,this._conversationManager,this._callback);return this._conversation!=null&&(e.conversation=this._conversation),this._systemPrompt!=null&&(e.systemPrompt=this._systemPrompt),e}}function J(t){for(const e of t.filter(a.Thinking))console.log("\x1B[90m"+e.get()+"\x1B[0m");for(const e of t.filter(a.Content))console.log(e.get());for(const e of t.filter(a.ToolCall))console.log("\x1B[32mCalling Tool: "+e.name+"\x1B[0m")}class d extends Error{constructor(e){super(e),this.name="ToolNotDefinedError"}}class F{name;description;tool_schema;constructor(){this.name=this.getName(),this.description=this.getDescription(),this.tool_schema=this.getToolSchema()}getName(){throw new d("Tool name not defined.")}getDescription(){throw new d("Tool description not defined.")}getToolSchema(){throw new d("Tool parameter schema not defined.")}execute(e){return null}}class p{parameters;output;constructor(e,o){this.parameters=e,this.output=o}static builder(){return new O}}class O{_parameters;_output;addParameter(e){return this._parameters==null&&(this._parameters=[]),this._parameters.push(e),this}output(e){return this._output=e,this}build(){return this._parameters==null&&(this._parameters=[]),new p(this._parameters,this._output)}}class T{name;description;type;required;constructor(e,o,s,n){this.name=e,this.description=o,this.type=s,this.required=n,this.assertValidType()}assertValidType(){}static builder(){return new S}}class S{_name;_description;_type;_required;name(e){return this._name=e,this}description(e){return this._description=e,this}type(e){return this._type=e,this}required(e){return this._required=e,this}build(){return this._required==null&&(this._required=!1),new T(this._name,this._description,this._type,this._required)}}class L extends P{endpoint;model;options;constructor(e,o,s){super(),this.endpoint=e,this.model=o,this.options=s}async invoke(e){let o={model:this.model,messages:this._formatMessages(e),tools:this._formatTools(e),...this.options},s=await fetch(this.endpoint+"/api/chat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!s.ok)throw new Error(`HTTP error! status: ${s.status}`);let n=await s.json(),r=[];if(n.message.tool_calls)for(let l in n.message.tool_calls){const i=n.message.tool_calls[l];let h="function",R=i[h]?.name,E=i[h]?.index,B=i.id??void 0,I=typeof i[h]?.arguments=="string"?JSON.parse(i[h]?.arguments):i[h]?.arguments;r.push(_.builder().name(R).type(h).parameters(I).sequence(E).id(B).build())}return u.builder().toolCalls(r).role(n.message.role).content(n.message.content).thinking(n.message.thinking).build()}_formatTools(e){let o=[];for(let s of e.tools){let n={},r=[];for(let i of s.getToolSchema().parameters)n[i.name]={},n[i.name].type=i.type,n[i.name].description=i.description,i.required&&r.push(i.name);let l={type:"function",function:{name:s.getName(),description:s.getDescription(),parameters:{type:"object",properties:n,required:r}}};o.push(l)}return o}_formatMessages(e){let o=[];for(let s of e.messages){if(s.role=="assistant"||s.role=="system"||s.role=="user"){o.push(this._formatSingleMessage(s));continue}if(s.role=="tool"){for(const n of s.content)if(n.getMessageComponentType()==a.ToolResult){const r=n;o.push({role:s.role,name:r.toolName,content:JSON.stringify(r.toolResult)})}}}return o}_formatSingleMessage(e){let o={role:e.role},s,n,r;for(const l of e.content){if(l.getMessageComponentType()==a.Content){const i=l;s==null&&(s=""),s+=i.get()}if(l.getMessageComponentType()==a.Thinking){const i=l;r==null&&(r=""),r+=i.get()}if(l.getMessageComponentType()==a.ToolCall){const i=l;n==null&&(n=[]),n.push(this._formatToolCall(i))}}return s!=null&&(o.content=s),n!=null&&(o.tool_calls=n),r!=null&&(o.thinking=r),o}_formatToolCall(e){return{function:{name:e.name,arguments:e.parameters}}}}function Q(t){return e=>{e.prototype.getName=()=>t}}function V(t){return e=>{Object.defineProperty(e.prototype,"getDescription",{value:function(){return t},enumerable:!0,configurable:!0,writable:!0})}}function H(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParams.push(T.builder().name(t.name).description(t.description).required(t.required).type(t.type).build()),e.prototype.getToolSchema=()=>new p(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}function K(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParamsOutput=t,e.prototype.getToolSchema=()=>new p(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}exports.Agent=k;exports.Content=N;exports.Conversation=w;exports.ConversationManager=M;exports.DefaultConversationManager=g;exports.Message=u;exports.MessageBuilder=b;exports.MessageComponent=m;exports.MessageComponentType=a;exports.Model=P;exports.ModelRequest=q;exports.ModelRequestBuilder=f;exports.OllamaModel=L;exports.Parameter=T;exports.ParameterBuilder=S;exports.Thinking=C;exports.Tool=F;exports.ToolCall=_;exports.ToolCallBuilder=x;exports.ToolDescription=V;exports.ToolName=Q;exports.ToolOutput=K;exports.ToolParameter=H;exports.ToolResult=c;exports.ToolSchema=p;exports.ToolSchemaBuilder=O;
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});class w{messages;manager;constructor(){this.messages=[],this.manager=new g}append(e){this.messages.push(e),this.messages=this.manager.compact(this.messages)}}class M{compact(e){throw new T("No implementation for conversation manager!")}configure(e){throw new T("No implementation for conversation manager!")}}class g extends M{compact(e){return e}configure(e){}}class T extends Error{constructor(e){super(e),this.name="ConversationManagerNotImplemented"}}class u{role;content;constructor(e,s){this.role=e,this.content=s}static builder(){return new b}filter(e){return this.content.filter(s=>s.getMessageComponentType()==e)}}class b{_role;_content;role(e){return this._role=e,this}init(){this._content==null&&(this._content=[])}toolCall(e){return e==null?this:(this.init(),this._content.push(e),this)}toolCalls(e){if(e==null)return this;this.init();for(const s of e)this._content.push(s);return this}toolResult(e){return e==null?this:(this.init(),this._content.push(e),this)}thinking(e){return e==null?this:(this.init(),this._content.push(N.of(e)),this)}content(e){return e==null?this:(this.init(),this._content.push(C.of(e)),this)}build(){if(this._content==null||this._content.length==0)throw new Error("Role-only messages are not supported by Tapeworm.");return new u(this._role,this._content)}}const l={Content:"content",Thinking:"thinking",ToolCall:"toolcall",ToolResult:"toolresult"};class m{getMessageComponentType(){throw new Error("Message components that do not have a message component type are not allowed.")}}class C extends m{text;constructor(e){super(),this.text=e}getMessageComponentType(){return l.Content}get(){return this.text}static of(e){return new this(e)}}class N extends m{thought;constructor(e){super(),this.thought=e}getMessageComponentType(){return l.Thinking}get(){return this.thought}static of(e){return new this(e)}}class c extends m{id;toolName;toolResult;constructor(e,s,o){super(),this.id=e,this.toolName=s,this.toolResult=o}getMessageComponentType(){return l.ToolResult}static of(e,s){return new this(e.id,e.name,s)}}class P{async invoke(e){throw new v("The invoke function for this model was not correctly implemented.")}tokenLimit(){throw new v("The tokenLimit function for this model was not correctly implemented.")}}class q{messages;tools;constructor(e,s){this.messages=e,this.tools=s}static builder(){return new f}}class f{_messages;_tools;messages(e){return this._messages=e,this}tools(e){return this._tools=e,this}build(){if(this._tools==null&&(this._tools=[]),this._messages==null)throw new j("Requests to the model should include content.");return new q(this._messages,this._tools)}}class v extends Error{constructor(e){super(e),this.name="ModelNotImplementedError"}}class j extends Error{constructor(e){super(e),this.name="MessagesNotDefinedError"}}class _ extends m{sequence;name;parameters;type;id;getMessageComponentType(){return l.ToolCall}constructor(e,s,o,r,n){super(),this.sequence=e,this.name=s,this.parameters=o,this.type=r,this.id=n}static builder(){return new x}}class x{_sequence;_name;_parameters;_type;_id;sequence(e){return this._sequence=e,this}name(e){return this._name=e,this}parameters(e){return this._parameters=e,this}type(e){return this._type=e,this}id(e){return e!=null&&(this._id=e),this}build(){return this._sequence==null&&(this._sequence=0),this._id==null&&(this._id=(Math.random()+1).toString(36).slice(2,7)),new _(this._sequence,this._name,this._parameters,this._type,this._id)}}class D extends Error{constructor(e){super(e),this.name="ToolNotFoundError"}}class k{name;systemPrompt;tools;model;conversation;conversationManager;toolNameToIndexMap;callback;constructor(e,s,o,r,n){this.name=e,this.model=o,this.conversationManager=r,this.tools=s,this.callback=n,this.conversationManager.configure(o)}async invoke(e,s=this.callback){this.conversation==null&&(this.conversation=new w,this.conversationManager!=null&&(this.conversation.manager=this.conversationManager),this.systemPrompt!=null&&this.conversation.append(u.builder().role("system").content(this.systemPrompt).build())),this.conversation.append(u.builder().role("user").content(e).build());let o=!1;for(;!o;){let r=await this._runQuery();s(r),this.conversation.append(r),o=!0;const n=r.filter(l.ToolCall);if(n!=null&&n.length!=0){o=!1,n.sort((a,i)=>(a.sequence??0)<(i.sequence??0)?-1:1);for(let a of n)await this._runTool(a)}}}async _runQuery(){return await this.model.invoke(new f().messages(this.conversation?.messages).tools(this.tools).build())}async _runTool(e){if(this.generateToolNameToIndexMap(),!(e.name in this.toolNameToIndexMap)){this.conversation.append(u.builder().role("tool").toolResult(c.of(e,new D("Agent does not have a tool with this name."))).build());return}let s=this.tools[this.toolNameToIndexMap[e.name]];try{let o=await s.execute(e.parameters);this.conversation.append(u.builder().role("tool").toolResult(c.of(e,o)).build())}catch(o){this.conversation.append(u.builder().role("tool").toolResult(c.of(e,JSON.stringify(o))).build())}}generateToolNameToIndexMap(){if(this.toolNameToIndexMap==null){this.toolNameToIndexMap={};for(let e=0;e<this.tools.length;e++)this.toolNameToIndexMap[this.tools[e].getName()]=e}}static builder(){return new A}}class A{_name;_systemPrompt;_tools;_model;_conversation;_conversationManager=new g;_toolNameToIndexMap;_callback=e=>J(e);name(e){return this._name=e,this}systemPrompt(e){return this._systemPrompt=e,this}tools(e){return this._tools=e,this}addTool(e){return this._tools==null&&(this._tools=[]),this._tools.push(e),this}model(e){return this._model=e,this}conversationManager(e){return this._conversationManager=e,this}callback(e){return this._callback=e,this}build(){let e=new k(this._name,this._tools,this._model,this._conversationManager,this._callback);return this._conversation!=null&&(e.conversation=this._conversation),this._systemPrompt!=null&&(e.systemPrompt=this._systemPrompt),e}}function J(t){for(const e of t.filter(l.Thinking))console.log("\x1B[90m"+e.get()+"\x1B[0m");for(const e of t.filter(l.Content))console.log(e.get());for(const e of t.filter(l.ToolCall))console.log("\x1B[32mCalling Tool: "+e.name+"\x1B[0m")}class d extends Error{constructor(e){super(e),this.name="ToolNotDefinedError"}}class F{getName(){throw new d("Tool name not defined.")}getDescription(){throw new d("Tool description not defined.")}getToolSchema(){throw new d("Tool parameter schema not defined.")}execute(e){return null}}class p{parameters;output;constructor(e,s){this.parameters=e,this.output=s}static builder(){return new O}}class O{_parameters;_output;addParameter(e){return this._parameters==null&&(this._parameters=[]),this._parameters.push(e),this}output(e){return this._output=e,this}build(){return this._parameters==null&&(this._parameters=[]),new p(this._parameters,this._output)}}class y{name;description;type;required;constructor(e,s,o,r){this.name=e,this.description=s,this.type=o,this.required=r,this.assertValidType()}assertValidType(){}static builder(){return new R}}class R{_name;_description;_type;_required;name(e){return this._name=e,this}description(e){return this._description=e,this}type(e){return this._type=e,this}required(e){return this._required=e,this}build(){return this._required==null&&(this._required=!1),new y(this._name,this._description,this._type,this._required)}}class L extends P{endpoint;model;options;constructor(e,s,o){super(),this.endpoint=e,this.model=s,this.options=o}async invoke(e){let s={model:this.model,messages:this._formatMessages(e),tools:this._formatTools(e),...this.options},o=await fetch(this.endpoint+"/api/chat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw new Error(`HTTP error! status: ${o.status}`);let r=await o.json(),n=[];if(r.message.tool_calls)for(let a in r.message.tool_calls){const i=r.message.tool_calls[a];let h="function",S=i[h]?.name,E=i[h]?.index,B=i.id??void 0,I=typeof i[h]?.arguments=="string"?JSON.parse(i[h]?.arguments):i[h]?.arguments;n.push(_.builder().name(S).type(h).parameters(I).sequence(E).id(B).build())}return u.builder().toolCalls(n).role(r.message.role).content(r.message.content).thinking(r.message.thinking).build()}_formatTools(e){let s=[];for(let o of e.tools){let r={},n=[];for(let i of o.getToolSchema().parameters)r[i.name]={},r[i.name].type=i.type,r[i.name].description=i.description,i.required&&n.push(i.name);let a={type:"function",function:{name:o.getName(),description:o.getDescription(),parameters:{type:"object",properties:r,required:n}}};s.push(a)}return s}_formatMessages(e){let s=[];for(let o of e.messages){if(o.role=="assistant"||o.role=="system"||o.role=="user"){s.push(this._formatSingleMessage(o));continue}if(o.role=="tool"){for(const r of o.content)if(r.getMessageComponentType()==l.ToolResult){const n=r;s.push({role:o.role,name:n.toolName,content:JSON.stringify(n.toolResult)})}}}return s}_formatSingleMessage(e){let s={role:e.role},o,r,n;for(const a of e.content){if(a.getMessageComponentType()==l.Content){const i=a;o==null&&(o=""),o+=i.get()}if(a.getMessageComponentType()==l.Thinking){const i=a;n==null&&(n=""),n+=i.get()}if(a.getMessageComponentType()==l.ToolCall){const i=a;r==null&&(r=[]),r.push(this._formatToolCall(i))}}return o!=null&&(s.content=o),r!=null&&(s.tool_calls=r),n!=null&&(s.thinking=n),s}_formatToolCall(e){return{function:{name:e.name,arguments:e.parameters}}}}function Q(t){return e=>{e.prototype.getName=()=>t}}function V(t){return e=>{Object.defineProperty(e.prototype,"getDescription",{value:function(){return t},enumerable:!0,configurable:!0,writable:!0})}}function H(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParams.push(y.builder().name(t.name).description(t.description).required(t.required).type(t.type).build()),e.prototype.getToolSchema=()=>new p(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}function K(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParamsOutput=t,e.prototype.getToolSchema=()=>new p(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}exports.Agent=k;exports.Content=C;exports.Conversation=w;exports.ConversationManager=M;exports.DefaultConversationManager=g;exports.Message=u;exports.MessageBuilder=b;exports.MessageComponent=m;exports.MessageComponentType=l;exports.Model=P;exports.ModelRequest=q;exports.ModelRequestBuilder=f;exports.OllamaModel=L;exports.Parameter=y;exports.ParameterBuilder=R;exports.Thinking=N;exports.Tool=F;exports.ToolCall=_;exports.ToolCallBuilder=x;exports.ToolDescription=V;exports.ToolName=Q;exports.ToolOutput=K;exports.ToolParameter=H;exports.ToolResult=c;exports.ToolSchema=p;exports.ToolSchemaBuilder=O;
@@ -54,7 +54,7 @@ class g extends Error {
54
54
  super(e), this.name = "ConversationManagerNotImplemented";
55
55
  }
56
56
  }
57
- class h {
57
+ class u {
58
58
  role;
59
59
  content;
60
60
  /**
@@ -62,8 +62,8 @@ class h {
62
62
  * @param role Source of the message (e.g., user, assistant, tool).
63
63
  * @param content Ordered list of message components that make up the message body.
64
64
  */
65
- constructor(e, o) {
66
- this.role = e, this.content = o;
65
+ constructor(e, s) {
66
+ this.role = e, this.content = s;
67
67
  }
68
68
  /**
69
69
  * Create a new message builder for ergonomic construction.
@@ -76,7 +76,7 @@ class h {
76
76
  * Filters the message contents based on the message type.
77
77
  */
78
78
  filter(e) {
79
- return this.content.filter((o) => o.getMessageComponentType() == e);
79
+ return this.content.filter((s) => s.getMessageComponentType() == e);
80
80
  }
81
81
  }
82
82
  class k {
@@ -113,8 +113,8 @@ class k {
113
113
  if (e == null)
114
114
  return this;
115
115
  this.init();
116
- for (const o of e)
117
- this._content.push(o);
116
+ for (const s of e)
117
+ this._content.push(s);
118
118
  return this;
119
119
  }
120
120
  /**
@@ -148,7 +148,7 @@ class k {
148
148
  build() {
149
149
  if (this._content == null || this._content.length == 0)
150
150
  throw new Error("Role-only messages are not supported by Tapeworm.");
151
- return new h(this._role, this._content);
151
+ return new u(this._role, this._content);
152
152
  }
153
153
  }
154
154
  const l = {
@@ -241,8 +241,8 @@ class m extends c {
241
241
  * @param toolName Name of the tool that produced the result.
242
242
  * @param toolResult Output returned by the tool.
243
243
  */
244
- constructor(e, o, s) {
245
- super(), this.id = e, this.toolName = o, this.toolResult = s;
244
+ constructor(e, s, o) {
245
+ super(), this.id = e, this.toolName = s, this.toolResult = o;
246
246
  }
247
247
  /**
248
248
  * Get the type of this message component, as defined in MessageComponentType.
@@ -257,8 +257,8 @@ class m extends c {
257
257
  * @param toolResult Output to attach to the tool result component.
258
258
  * @returns a new ToolResult component mirroring the provided tool call.
259
259
  */
260
- static of(e, o) {
261
- return new this(e.id, e.name, o);
260
+ static of(e, s) {
261
+ return new this(e.id, e.name, s);
262
262
  }
263
263
  }
264
264
  class O {
@@ -288,8 +288,8 @@ class E {
288
288
  * @param messages Conversation history to send to the model.
289
289
  * @param tools Tool definitions available for function calling.
290
290
  */
291
- constructor(e, o) {
292
- this.messages = e, this.tools = o;
291
+ constructor(e, s) {
292
+ this.messages = e, this.tools = s;
293
293
  }
294
294
  /**
295
295
  * Create a builder for composing a model request.
@@ -359,8 +359,8 @@ class v extends c {
359
359
  * @param type Type of tool call (e.g., function).
360
360
  * @param id Provider-generated identifier for correlating results.
361
361
  */
362
- constructor(e, o, s, n, r) {
363
- super(), this.sequence = e, this.name = o, this.parameters = s, this.type = n, this.id = r;
362
+ constructor(e, s, o, r, n) {
363
+ super(), this.sequence = e, this.name = s, this.parameters = o, this.type = r, this.id = n;
364
364
  }
365
365
  /**
366
366
  * Convenience factory for a ToolCallBuilder.
@@ -436,39 +436,80 @@ class I extends Error {
436
436
  }
437
437
  }
438
438
  class j {
439
+ /**
440
+ * The name of the agent.
441
+ */
439
442
  name;
443
+ /**
444
+ * The system prompt (if any) for the agent.
445
+ */
440
446
  systemPrompt;
447
+ /**
448
+ * The tools this agent knows about and can run.
449
+ */
441
450
  tools;
451
+ /**
452
+ * The underlying model for the agent.
453
+ */
442
454
  model;
455
+ /**
456
+ * The conversation for the agent.
457
+ * You do not normally need to set this parameter unless you are building a use case
458
+ * where you have a persistent session with an agent.
459
+ */
443
460
  conversation;
461
+ /**
462
+ * The conversation manager for the agent.
463
+ * Normally, a converstation manager that does nothing will be used.
464
+ * When SummarizingConversationManager or RAGConversationManager is implemented, these will help you avoid
465
+ * token overflow.
466
+ */
444
467
  conversationManager;
468
+ /**
469
+ * A cache for looking up tools in the Tools array.
470
+ * DO NOT MANUALLY SET THIS VALUE. AGENT AUTOMATICALLY TAKES CARE OF IT.
471
+ */
445
472
  toolNameToIndexMap;
473
+ /**
474
+ * The callback function, invoked for every response from the model.
475
+ * The default implementation just prints to std.out or your console.
476
+ */
446
477
  callback;
447
- constructor(e, o, s, n, r) {
448
- this.name = e, this.model = s, this.conversationManager = n, this.tools = o, this.callback = r, this.conversationManager.configure(s);
478
+ /**
479
+ * This is the constructor for an Agent.
480
+ *
481
+ * i IMPLORE YOU not to use this method. You CAN, but you should be using the Builder instead
482
+ * for the best results, as this method WILL change with future updates.
483
+ *
484
+ * Builder will be a lot more stable and will always be backwards compatible.
485
+ */
486
+ constructor(e, s, o, r, n) {
487
+ this.name = e, this.model = o, this.conversationManager = r, this.tools = s, this.callback = n, this.conversationManager.configure(o);
449
488
  }
450
489
  /**
451
490
  * Run the full agent loop for a user query: seed the conversation, invoke the model,
452
491
  * and execute any returned tool calls until completion.
492
+ * *
453
493
  * @param query User-provided input to hand to the agent.
494
+ * @param callback A function that handles the messages coming from the agent.
454
495
  */
455
- async invoke(e) {
496
+ async invoke(e, s = this.callback) {
456
497
  this.conversation == null && (this.conversation = new x(), this.conversationManager != null && (this.conversation.manager = this.conversationManager), this.systemPrompt != null && this.conversation.append(
457
- h.builder().role("system").content(this.systemPrompt).build()
498
+ u.builder().role("system").content(this.systemPrompt).build()
458
499
  )), this.conversation.append(
459
- h.builder().role("user").content(e).build()
500
+ u.builder().role("user").content(e).build()
460
501
  );
461
502
  let o = !1;
462
503
  for (; !o; ) {
463
- let s = await this._runQuery();
464
- this.callback(s), this.conversation.append(s), o = !0;
465
- const n = s.filter(
504
+ let r = await this._runQuery();
505
+ s(r), this.conversation.append(r), o = !0;
506
+ const n = r.filter(
466
507
  l.ToolCall
467
508
  );
468
509
  if (n != null && n.length != 0) {
469
- o = !1, n.sort((r, a) => (r.sequence ?? 0) < (a.sequence ?? 0) ? -1 : 1);
470
- for (let r of n)
471
- await this._runTool(r);
510
+ o = !1, n.sort((a, i) => (a.sequence ?? 0) < (i.sequence ?? 0) ? -1 : 1);
511
+ for (let a of n)
512
+ await this._runTool(a);
472
513
  }
473
514
  }
474
515
  }
@@ -489,7 +530,7 @@ class j {
489
530
  async _runTool(e) {
490
531
  if (this.generateToolNameToIndexMap(), !(e.name in this.toolNameToIndexMap)) {
491
532
  this.conversation.append(
492
- h.builder().role("tool").toolResult(
533
+ u.builder().role("tool").toolResult(
493
534
  m.of(
494
535
  e,
495
536
  new I(
@@ -500,15 +541,15 @@ class j {
500
541
  );
501
542
  return;
502
543
  }
503
- let o = this.tools[this.toolNameToIndexMap[e.name]];
544
+ let s = this.tools[this.toolNameToIndexMap[e.name]];
504
545
  try {
505
- let s = await o.execute(e.parameters);
546
+ let o = await s.execute(e.parameters);
506
547
  this.conversation.append(
507
- h.builder().role("tool").toolResult(m.of(e, s)).build()
548
+ u.builder().role("tool").toolResult(m.of(e, o)).build()
508
549
  );
509
- } catch (s) {
550
+ } catch (o) {
510
551
  this.conversation.append(
511
- h.builder().role("tool").toolResult(m.of(e, JSON.stringify(s))).build()
552
+ u.builder().role("tool").toolResult(m.of(e, JSON.stringify(o))).build()
512
553
  );
513
554
  }
514
555
  }
@@ -522,6 +563,9 @@ class j {
522
563
  this.toolNameToIndexMap[this.tools[e].getName()] = e;
523
564
  }
524
565
  }
566
+ /**
567
+ * Get a builder to build an Agent.
568
+ */
525
569
  static builder() {
526
570
  return new B();
527
571
  }
@@ -535,27 +579,51 @@ class B {
535
579
  _conversationManager = new _();
536
580
  _toolNameToIndexMap;
537
581
  _callback = (e) => D(e);
582
+ /**
583
+ * Set the name of the agent.
584
+ */
538
585
  name(e) {
539
586
  return this._name = e, this;
540
587
  }
588
+ /**
589
+ * Set the system prompt of the agent.
590
+ */
541
591
  systemPrompt(e) {
542
592
  return this._systemPrompt = e, this;
543
593
  }
594
+ /**
595
+ * Set the tools of the agent, if you already have an array of tools.
596
+ */
544
597
  tools(e) {
545
598
  return this._tools = e, this;
546
599
  }
600
+ /**
601
+ * Add a tool, 1 by 1, to the agent..
602
+ */
547
603
  addTool(e) {
548
604
  return this._tools == null && (this._tools = []), this._tools.push(e), this;
549
605
  }
606
+ /**
607
+ * Set the underlying model for the agent.
608
+ */
550
609
  model(e) {
551
610
  return this._model = e, this;
552
611
  }
612
+ /**
613
+ * Set the conversation manager for the agent.
614
+ */
553
615
  conversationManager(e) {
554
616
  return this._conversationManager = e, this;
555
617
  }
618
+ /**
619
+ * Set the callback for the agent.
620
+ */
556
621
  callback(e) {
557
622
  return this._callback = e, this;
558
623
  }
624
+ /**
625
+ * Build the agent.
626
+ */
559
627
  build() {
560
628
  let e = new j(
561
629
  this._name,
@@ -581,15 +649,6 @@ class p extends Error {
581
649
  }
582
650
  }
583
651
  class F {
584
- name;
585
- description;
586
- tool_schema;
587
- /**
588
- * Initialize tool metadata from subclass implementations.
589
- */
590
- constructor() {
591
- this.name = this.getName(), this.description = this.getDescription(), this.tool_schema = this.getToolSchema();
592
- }
593
652
  /**
594
653
  * Name that uniquely identifies this tool.
595
654
  * @returns A short, stable identifier string.
@@ -629,8 +688,8 @@ class d {
629
688
  * @param parameters Ordered list of input parameters the tool accepts.
630
689
  * @param output Human-readable description of the tool output.
631
690
  */
632
- constructor(e, o) {
633
- this.parameters = e, this.output = o;
691
+ constructor(e, s) {
692
+ this.parameters = e, this.output = s;
634
693
  }
635
694
  /**
636
695
  * Return a tool schema builder, so you can properly construct tools instead of dealing with the constructor
@@ -679,8 +738,8 @@ class T {
679
738
  * @param type JSON-serializable type name (e.g., string, number).
680
739
  * @param required Whether the parameter must be provided.
681
740
  */
682
- constructor(e, o, s, n) {
683
- this.name = e, this.description = o, this.type = s, this.required = n, this.assertValidType();
741
+ constructor(e, s, o, r) {
742
+ this.name = e, this.description = s, this.type = o, this.required = r, this.assertValidType();
684
743
  }
685
744
  /**
686
745
  * Placeholder for validating supported parameter types.
@@ -751,38 +810,38 @@ class L extends O {
751
810
  * @param model Model name/tag to use for inference.
752
811
  * @param options Additional Ollama options passed through to the API.
753
812
  */
754
- constructor(e, o, s) {
755
- super(), this.endpoint = e, this.model = o, this.options = s;
813
+ constructor(e, s, o) {
814
+ super(), this.endpoint = e, this.model = s, this.options = o;
756
815
  }
757
816
  /**
758
817
  * Call the Ollama chat API with the provided conversation and tools.
759
818
  * Formats the request, performs the HTTP POST, and translates the response into a ModelResponse.
760
819
  */
761
820
  async invoke(e) {
762
- let o = {
821
+ let s = {
763
822
  model: this.model,
764
823
  messages: this._formatMessages(e),
765
824
  tools: this._formatTools(e),
766
825
  ...this.options
767
- }, s = await fetch(this.endpoint + "/api/chat", {
826
+ }, o = await fetch(this.endpoint + "/api/chat", {
768
827
  method: "POST",
769
828
  headers: {
770
829
  "Content-Type": "application/json"
771
830
  },
772
- body: JSON.stringify(o)
831
+ body: JSON.stringify(s)
773
832
  });
774
- if (!s.ok)
775
- throw new Error(`HTTP error! status: ${s.status}`);
776
- let n = await s.json(), r = [];
777
- if (n.message.tool_calls)
778
- for (let a in n.message.tool_calls) {
779
- const i = n.message.tool_calls[a];
780
- let u = "function", w = i[u]?.name, b = i[u]?.index, M = i.id ?? void 0, N = typeof i[u]?.arguments == "string" ? JSON.parse(i[u]?.arguments) : i[u]?.arguments;
781
- r.push(
782
- v.builder().name(w).type(u).parameters(N).sequence(b).id(M).build()
833
+ if (!o.ok)
834
+ throw new Error(`HTTP error! status: ${o.status}`);
835
+ let r = await o.json(), n = [];
836
+ if (r.message.tool_calls)
837
+ for (let a in r.message.tool_calls) {
838
+ const i = r.message.tool_calls[a];
839
+ let h = "function", w = i[h]?.name, b = i[h]?.index, M = i.id ?? void 0, N = typeof i[h]?.arguments == "string" ? JSON.parse(i[h]?.arguments) : i[h]?.arguments;
840
+ n.push(
841
+ v.builder().name(w).type(h).parameters(N).sequence(b).id(M).build()
783
842
  );
784
843
  }
785
- return h.builder().toolCalls(r).role(n.message.role).content(n.message.content).thinking(n.message.thinking).build();
844
+ return u.builder().toolCalls(n).role(r.message.role).content(r.message.content).thinking(r.message.thinking).build();
786
845
  }
787
846
  /**
788
847
  * Convert internal tool definitions into the JSON schema format expected by Ollama.
@@ -790,26 +849,26 @@ class L extends O {
790
849
  * @returns Array of tool schema objects formatted for the Ollama API.
791
850
  */
792
851
  _formatTools(e) {
793
- let o = [];
794
- for (let s of e.tools) {
795
- let n = {}, r = [];
796
- for (let i of s.getToolSchema().parameters)
797
- n[i.name] = {}, n[i.name].type = i.type, n[i.name].description = i.description, i.required && r.push(i.name);
852
+ let s = [];
853
+ for (let o of e.tools) {
854
+ let r = {}, n = [];
855
+ for (let i of o.getToolSchema().parameters)
856
+ r[i.name] = {}, r[i.name].type = i.type, r[i.name].description = i.description, i.required && n.push(i.name);
798
857
  let a = {
799
858
  type: "function",
800
859
  function: {
801
- name: s.getName(),
802
- description: s.getDescription(),
860
+ name: o.getName(),
861
+ description: o.getDescription(),
803
862
  parameters: {
804
863
  type: "object",
805
- properties: n,
806
- required: r
864
+ properties: r,
865
+ required: n
807
866
  }
808
867
  }
809
868
  };
810
- o.push(a);
869
+ s.push(a);
811
870
  }
812
- return o;
871
+ return s;
813
872
  }
814
873
  /**
815
874
  * Convert internal message objects into Ollama's chat message shape.
@@ -818,25 +877,25 @@ class L extends O {
818
877
  * @returns Array of serialized messages ready for Ollama.
819
878
  */
820
879
  _formatMessages(e) {
821
- let o = [];
822
- for (let s of e.messages) {
823
- if (s.role == "assistant" || s.role == "system" || s.role == "user") {
824
- o.push(this._formatSingleMessage(s));
880
+ let s = [];
881
+ for (let o of e.messages) {
882
+ if (o.role == "assistant" || o.role == "system" || o.role == "user") {
883
+ s.push(this._formatSingleMessage(o));
825
884
  continue;
826
885
  }
827
- if (s.role == "tool") {
828
- for (const n of s.content)
829
- if (n.getMessageComponentType() == l.ToolResult) {
830
- const r = n;
831
- o.push({
832
- role: s.role,
833
- name: r.toolName,
834
- content: JSON.stringify(r.toolResult)
886
+ if (o.role == "tool") {
887
+ for (const r of o.content)
888
+ if (r.getMessageComponentType() == l.ToolResult) {
889
+ const n = r;
890
+ s.push({
891
+ role: o.role,
892
+ name: n.toolName,
893
+ content: JSON.stringify(n.toolResult)
835
894
  });
836
895
  }
837
896
  }
838
897
  }
839
- return o;
898
+ return s;
840
899
  }
841
900
  /**
842
901
  * Format everything sent by a user or LLM (no tools)
@@ -844,24 +903,24 @@ class L extends O {
844
903
  * @returns Serialized message payload.
845
904
  */
846
905
  _formatSingleMessage(e) {
847
- let o = {
906
+ let s = {
848
907
  role: e.role
849
- }, s, n, r;
908
+ }, o, r, n;
850
909
  for (const a of e.content) {
851
910
  if (a.getMessageComponentType() == l.Content) {
852
911
  const i = a;
853
- s == null && (s = ""), s += i.get();
912
+ o == null && (o = ""), o += i.get();
854
913
  }
855
914
  if (a.getMessageComponentType() == l.Thinking) {
856
915
  const i = a;
857
- r == null && (r = ""), r += i.get();
916
+ n == null && (n = ""), n += i.get();
858
917
  }
859
918
  if (a.getMessageComponentType() == l.ToolCall) {
860
919
  const i = a;
861
- n == null && (n = []), n.push(this._formatToolCall(i));
920
+ r == null && (r = []), r.push(this._formatToolCall(i));
862
921
  }
863
922
  }
864
- return s != null && (o.content = s), n != null && (o.tool_calls = n), r != null && (o.thinking = r), o;
923
+ return o != null && (s.content = o), r != null && (s.tool_calls = r), n != null && (s.thinking = n), s;
865
924
  }
866
925
  /**
867
926
  * Convert a ToolCall into the structure Ollama expects.
@@ -918,7 +977,7 @@ export {
918
977
  x as Conversation,
919
978
  P as ConversationManager,
920
979
  _ as DefaultConversationManager,
921
- h as Message,
980
+ u as Message,
922
981
  k as MessageBuilder,
923
982
  c as MessageComponent,
924
983
  l as MessageComponentType,
@@ -1 +1 @@
1
- (function(n,m){typeof exports=="object"&&typeof module<"u"?m(exports):typeof define=="function"&&define.amd?define(["exports"],m):(n=typeof globalThis<"u"?globalThis:n||self,m(n.Tapeworm={}))})(this,(function(n){"use strict";class m{messages;manager;constructor(){this.messages=[],this.manager=new f}append(e){this.messages.push(e),this.messages=this.manager.compact(this.messages)}}class w{compact(e){throw new M("No implementation for conversation manager!")}configure(e){throw new M("No implementation for conversation manager!")}}class f extends w{compact(e){return e}configure(e){}}class M extends Error{constructor(e){super(e),this.name="ConversationManagerNotImplemented"}}class h{role;content;constructor(e,o){this.role=e,this.content=o}static builder(){return new b}filter(e){return this.content.filter(o=>o.getMessageComponentType()==e)}}class b{_role;_content;role(e){return this._role=e,this}init(){this._content==null&&(this._content=[])}toolCall(e){return e==null?this:(this.init(),this._content.push(e),this)}toolCalls(e){if(e==null)return this;this.init();for(const o of e)this._content.push(o);return this}toolResult(e){return e==null?this:(this.init(),this._content.push(e),this)}thinking(e){return e==null?this:(this.init(),this._content.push(C.of(e)),this)}content(e){return e==null?this:(this.init(),this._content.push(N.of(e)),this)}build(){if(this._content==null||this._content.length==0)throw new Error("Role-only messages are not supported by Tapeworm.");return new h(this._role,this._content)}}const l={Content:"content",Thinking:"thinking",ToolCall:"toolcall",ToolResult:"toolresult"};class p{getMessageComponentType(){throw new Error("Message components that do not have a message component type are not allowed.")}}class N extends p{text;constructor(e){super(),this.text=e}getMessageComponentType(){return l.Content}get(){return this.text}static of(e){return new this(e)}}class C extends p{thought;constructor(e){super(),this.thought=e}getMessageComponentType(){return l.Thinking}get(){return this.thought}static of(e){return new this(e)}}class d extends p{id;toolName;toolResult;constructor(e,o,s){super(),this.id=e,this.toolName=o,this.toolResult=s}getMessageComponentType(){return l.ToolResult}static of(e,o){return new this(e.id,e.name,o)}}class P{async invoke(e){throw new k("The invoke function for this model was not correctly implemented.")}tokenLimit(){throw new k("The tokenLimit function for this model was not correctly implemented.")}}class q{messages;tools;constructor(e,o){this.messages=e,this.tools=o}static builder(){return new _}}class _{_messages;_tools;messages(e){return this._messages=e,this}tools(e){return this._tools=e,this}build(){if(this._tools==null&&(this._tools=[]),this._messages==null)throw new B("Requests to the model should include content.");return new q(this._messages,this._tools)}}class k extends Error{constructor(e){super(e),this.name="ModelNotImplementedError"}}class B extends Error{constructor(e){super(e),this.name="MessagesNotDefinedError"}}class T extends p{sequence;name;parameters;type;id;getMessageComponentType(){return l.ToolCall}constructor(e,o,s,r,i){super(),this.sequence=e,this.name=o,this.parameters=s,this.type=r,this.id=i}static builder(){return new O}}class O{_sequence;_name;_parameters;_type;_id;sequence(e){return this._sequence=e,this}name(e){return this._name=e,this}parameters(e){return this._parameters=e,this}type(e){return this._type=e,this}id(e){return e!=null&&(this._id=e),this}build(){return this._sequence==null&&(this._sequence=0),this._id==null&&(this._id=(Math.random()+1).toString(36).slice(2,7)),new T(this._sequence,this._name,this._parameters,this._type,this._id)}}class j extends Error{constructor(e){super(e),this.name="ToolNotFoundError"}}class S{name;systemPrompt;tools;model;conversation;conversationManager;toolNameToIndexMap;callback;constructor(e,o,s,r,i){this.name=e,this.model=s,this.conversationManager=r,this.tools=o,this.callback=i,this.conversationManager.configure(s)}async invoke(e){this.conversation==null&&(this.conversation=new m,this.conversationManager!=null&&(this.conversation.manager=this.conversationManager),this.systemPrompt!=null&&this.conversation.append(h.builder().role("system").content(this.systemPrompt).build())),this.conversation.append(h.builder().role("user").content(e).build());let o=!1;for(;!o;){let s=await this._runQuery();this.callback(s),this.conversation.append(s),o=!0;const r=s.filter(l.ToolCall);if(r!=null&&r.length!=0){o=!1,r.sort((i,u)=>(i.sequence??0)<(u.sequence??0)?-1:1);for(let i of r)await this._runTool(i)}}}async _runQuery(){return await this.model.invoke(new _().messages(this.conversation?.messages).tools(this.tools).build())}async _runTool(e){if(this.generateToolNameToIndexMap(),!(e.name in this.toolNameToIndexMap)){this.conversation.append(h.builder().role("tool").toolResult(d.of(e,new j("Agent does not have a tool with this name."))).build());return}let o=this.tools[this.toolNameToIndexMap[e.name]];try{let s=await o.execute(e.parameters);this.conversation.append(h.builder().role("tool").toolResult(d.of(e,s)).build())}catch(s){this.conversation.append(h.builder().role("tool").toolResult(d.of(e,JSON.stringify(s))).build())}}generateToolNameToIndexMap(){if(this.toolNameToIndexMap==null){this.toolNameToIndexMap={};for(let e=0;e<this.tools.length;e++)this.toolNameToIndexMap[this.tools[e].getName()]=e}}static builder(){return new I}}class I{_name;_systemPrompt;_tools;_model;_conversation;_conversationManager=new f;_toolNameToIndexMap;_callback=e=>D(e);name(e){return this._name=e,this}systemPrompt(e){return this._systemPrompt=e,this}tools(e){return this._tools=e,this}addTool(e){return this._tools==null&&(this._tools=[]),this._tools.push(e),this}model(e){return this._model=e,this}conversationManager(e){return this._conversationManager=e,this}callback(e){return this._callback=e,this}build(){let e=new S(this._name,this._tools,this._model,this._conversationManager,this._callback);return this._conversation!=null&&(e.conversation=this._conversation),this._systemPrompt!=null&&(e.systemPrompt=this._systemPrompt),e}}function D(t){for(const e of t.filter(l.Thinking))console.log("\x1B[90m"+e.get()+"\x1B[0m");for(const e of t.filter(l.Content))console.log(e.get());for(const e of t.filter(l.ToolCall))console.log("\x1B[32mCalling Tool: "+e.name+"\x1B[0m")}class y extends Error{constructor(e){super(e),this.name="ToolNotDefinedError"}}class x{name;description;tool_schema;constructor(){this.name=this.getName(),this.description=this.getDescription(),this.tool_schema=this.getToolSchema()}getName(){throw new y("Tool name not defined.")}getDescription(){throw new y("Tool description not defined.")}getToolSchema(){throw new y("Tool parameter schema not defined.")}execute(e){return null}}class g{parameters;output;constructor(e,o){this.parameters=e,this.output=o}static builder(){return new R}}class R{_parameters;_output;addParameter(e){return this._parameters==null&&(this._parameters=[]),this._parameters.push(e),this}output(e){return this._output=e,this}build(){return this._parameters==null&&(this._parameters=[]),new g(this._parameters,this._output)}}class v{name;description;type;required;constructor(e,o,s,r){this.name=e,this.description=o,this.type=s,this.required=r,this.assertValidType()}assertValidType(){}static builder(){return new E}}class E{_name;_description;_type;_required;name(e){return this._name=e,this}description(e){return this._description=e,this}type(e){return this._type=e,this}required(e){return this._required=e,this}build(){return this._required==null&&(this._required=!1),new v(this._name,this._description,this._type,this._required)}}class A extends P{endpoint;model;options;constructor(e,o,s){super(),this.endpoint=e,this.model=o,this.options=s}async invoke(e){let o={model:this.model,messages:this._formatMessages(e),tools:this._formatTools(e),...this.options},s=await fetch(this.endpoint+"/api/chat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(o)});if(!s.ok)throw new Error(`HTTP error! status: ${s.status}`);let r=await s.json(),i=[];if(r.message.tool_calls)for(let u in r.message.tool_calls){const a=r.message.tool_calls[u];let c="function",V=a[c]?.name,H=a[c]?.index,K=a.id??void 0,W=typeof a[c]?.arguments=="string"?JSON.parse(a[c]?.arguments):a[c]?.arguments;i.push(T.builder().name(V).type(c).parameters(W).sequence(H).id(K).build())}return h.builder().toolCalls(i).role(r.message.role).content(r.message.content).thinking(r.message.thinking).build()}_formatTools(e){let o=[];for(let s of e.tools){let r={},i=[];for(let a of s.getToolSchema().parameters)r[a.name]={},r[a.name].type=a.type,r[a.name].description=a.description,a.required&&i.push(a.name);let u={type:"function",function:{name:s.getName(),description:s.getDescription(),parameters:{type:"object",properties:r,required:i}}};o.push(u)}return o}_formatMessages(e){let o=[];for(let s of e.messages){if(s.role=="assistant"||s.role=="system"||s.role=="user"){o.push(this._formatSingleMessage(s));continue}if(s.role=="tool"){for(const r of s.content)if(r.getMessageComponentType()==l.ToolResult){const i=r;o.push({role:s.role,name:i.toolName,content:JSON.stringify(i.toolResult)})}}}return o}_formatSingleMessage(e){let o={role:e.role},s,r,i;for(const u of e.content){if(u.getMessageComponentType()==l.Content){const a=u;s==null&&(s=""),s+=a.get()}if(u.getMessageComponentType()==l.Thinking){const a=u;i==null&&(i=""),i+=a.get()}if(u.getMessageComponentType()==l.ToolCall){const a=u;r==null&&(r=[]),r.push(this._formatToolCall(a))}}return s!=null&&(o.content=s),r!=null&&(o.tool_calls=r),i!=null&&(o.thinking=i),o}_formatToolCall(e){return{function:{name:e.name,arguments:e.parameters}}}}function J(t){return e=>{e.prototype.getName=()=>t}}function F(t){return e=>{Object.defineProperty(e.prototype,"getDescription",{value:function(){return t},enumerable:!0,configurable:!0,writable:!0})}}function L(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParams.push(v.builder().name(t.name).description(t.description).required(t.required).type(t.type).build()),e.prototype.getToolSchema=()=>new g(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}function Q(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParamsOutput=t,e.prototype.getToolSchema=()=>new g(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}n.Agent=S,n.Content=N,n.Conversation=m,n.ConversationManager=w,n.DefaultConversationManager=f,n.Message=h,n.MessageBuilder=b,n.MessageComponent=p,n.MessageComponentType=l,n.Model=P,n.ModelRequest=q,n.ModelRequestBuilder=_,n.OllamaModel=A,n.Parameter=v,n.ParameterBuilder=E,n.Thinking=C,n.Tool=x,n.ToolCall=T,n.ToolCallBuilder=O,n.ToolDescription=F,n.ToolName=J,n.ToolOutput=Q,n.ToolParameter=L,n.ToolResult=d,n.ToolSchema=g,n.ToolSchemaBuilder=R,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}));
1
+ (function(n,m){typeof exports=="object"&&typeof module<"u"?m(exports):typeof define=="function"&&define.amd?define(["exports"],m):(n=typeof globalThis<"u"?globalThis:n||self,m(n.Tapeworm={}))})(this,(function(n){"use strict";class m{messages;manager;constructor(){this.messages=[],this.manager=new f}append(e){this.messages.push(e),this.messages=this.manager.compact(this.messages)}}class w{compact(e){throw new M("No implementation for conversation manager!")}configure(e){throw new M("No implementation for conversation manager!")}}class f extends w{compact(e){return e}configure(e){}}class M extends Error{constructor(e){super(e),this.name="ConversationManagerNotImplemented"}}class h{role;content;constructor(e,s){this.role=e,this.content=s}static builder(){return new b}filter(e){return this.content.filter(s=>s.getMessageComponentType()==e)}}class b{_role;_content;role(e){return this._role=e,this}init(){this._content==null&&(this._content=[])}toolCall(e){return e==null?this:(this.init(),this._content.push(e),this)}toolCalls(e){if(e==null)return this;this.init();for(const s of e)this._content.push(s);return this}toolResult(e){return e==null?this:(this.init(),this._content.push(e),this)}thinking(e){return e==null?this:(this.init(),this._content.push(N.of(e)),this)}content(e){return e==null?this:(this.init(),this._content.push(C.of(e)),this)}build(){if(this._content==null||this._content.length==0)throw new Error("Role-only messages are not supported by Tapeworm.");return new h(this._role,this._content)}}const u={Content:"content",Thinking:"thinking",ToolCall:"toolcall",ToolResult:"toolresult"};class p{getMessageComponentType(){throw new Error("Message components that do not have a message component type are not allowed.")}}class C extends p{text;constructor(e){super(),this.text=e}getMessageComponentType(){return u.Content}get(){return this.text}static of(e){return new this(e)}}class N extends p{thought;constructor(e){super(),this.thought=e}getMessageComponentType(){return u.Thinking}get(){return this.thought}static of(e){return new this(e)}}class d extends p{id;toolName;toolResult;constructor(e,s,o){super(),this.id=e,this.toolName=s,this.toolResult=o}getMessageComponentType(){return u.ToolResult}static of(e,s){return new this(e.id,e.name,s)}}class P{async invoke(e){throw new k("The invoke function for this model was not correctly implemented.")}tokenLimit(){throw new k("The tokenLimit function for this model was not correctly implemented.")}}class q{messages;tools;constructor(e,s){this.messages=e,this.tools=s}static builder(){return new _}}class _{_messages;_tools;messages(e){return this._messages=e,this}tools(e){return this._tools=e,this}build(){if(this._tools==null&&(this._tools=[]),this._messages==null)throw new B("Requests to the model should include content.");return new q(this._messages,this._tools)}}class k extends Error{constructor(e){super(e),this.name="ModelNotImplementedError"}}class B extends Error{constructor(e){super(e),this.name="MessagesNotDefinedError"}}class T extends p{sequence;name;parameters;type;id;getMessageComponentType(){return u.ToolCall}constructor(e,s,o,r,i){super(),this.sequence=e,this.name=s,this.parameters=o,this.type=r,this.id=i}static builder(){return new O}}class O{_sequence;_name;_parameters;_type;_id;sequence(e){return this._sequence=e,this}name(e){return this._name=e,this}parameters(e){return this._parameters=e,this}type(e){return this._type=e,this}id(e){return e!=null&&(this._id=e),this}build(){return this._sequence==null&&(this._sequence=0),this._id==null&&(this._id=(Math.random()+1).toString(36).slice(2,7)),new T(this._sequence,this._name,this._parameters,this._type,this._id)}}class j extends Error{constructor(e){super(e),this.name="ToolNotFoundError"}}class R{name;systemPrompt;tools;model;conversation;conversationManager;toolNameToIndexMap;callback;constructor(e,s,o,r,i){this.name=e,this.model=o,this.conversationManager=r,this.tools=s,this.callback=i,this.conversationManager.configure(o)}async invoke(e,s=this.callback){this.conversation==null&&(this.conversation=new m,this.conversationManager!=null&&(this.conversation.manager=this.conversationManager),this.systemPrompt!=null&&this.conversation.append(h.builder().role("system").content(this.systemPrompt).build())),this.conversation.append(h.builder().role("user").content(e).build());let o=!1;for(;!o;){let r=await this._runQuery();s(r),this.conversation.append(r),o=!0;const i=r.filter(u.ToolCall);if(i!=null&&i.length!=0){o=!1,i.sort((l,a)=>(l.sequence??0)<(a.sequence??0)?-1:1);for(let l of i)await this._runTool(l)}}}async _runQuery(){return await this.model.invoke(new _().messages(this.conversation?.messages).tools(this.tools).build())}async _runTool(e){if(this.generateToolNameToIndexMap(),!(e.name in this.toolNameToIndexMap)){this.conversation.append(h.builder().role("tool").toolResult(d.of(e,new j("Agent does not have a tool with this name."))).build());return}let s=this.tools[this.toolNameToIndexMap[e.name]];try{let o=await s.execute(e.parameters);this.conversation.append(h.builder().role("tool").toolResult(d.of(e,o)).build())}catch(o){this.conversation.append(h.builder().role("tool").toolResult(d.of(e,JSON.stringify(o))).build())}}generateToolNameToIndexMap(){if(this.toolNameToIndexMap==null){this.toolNameToIndexMap={};for(let e=0;e<this.tools.length;e++)this.toolNameToIndexMap[this.tools[e].getName()]=e}}static builder(){return new I}}class I{_name;_systemPrompt;_tools;_model;_conversation;_conversationManager=new f;_toolNameToIndexMap;_callback=e=>D(e);name(e){return this._name=e,this}systemPrompt(e){return this._systemPrompt=e,this}tools(e){return this._tools=e,this}addTool(e){return this._tools==null&&(this._tools=[]),this._tools.push(e),this}model(e){return this._model=e,this}conversationManager(e){return this._conversationManager=e,this}callback(e){return this._callback=e,this}build(){let e=new R(this._name,this._tools,this._model,this._conversationManager,this._callback);return this._conversation!=null&&(e.conversation=this._conversation),this._systemPrompt!=null&&(e.systemPrompt=this._systemPrompt),e}}function D(t){for(const e of t.filter(u.Thinking))console.log("\x1B[90m"+e.get()+"\x1B[0m");for(const e of t.filter(u.Content))console.log(e.get());for(const e of t.filter(u.ToolCall))console.log("\x1B[32mCalling Tool: "+e.name+"\x1B[0m")}class y extends Error{constructor(e){super(e),this.name="ToolNotDefinedError"}}class x{getName(){throw new y("Tool name not defined.")}getDescription(){throw new y("Tool description not defined.")}getToolSchema(){throw new y("Tool parameter schema not defined.")}execute(e){return null}}class g{parameters;output;constructor(e,s){this.parameters=e,this.output=s}static builder(){return new S}}class S{_parameters;_output;addParameter(e){return this._parameters==null&&(this._parameters=[]),this._parameters.push(e),this}output(e){return this._output=e,this}build(){return this._parameters==null&&(this._parameters=[]),new g(this._parameters,this._output)}}class v{name;description;type;required;constructor(e,s,o,r){this.name=e,this.description=s,this.type=o,this.required=r,this.assertValidType()}assertValidType(){}static builder(){return new E}}class E{_name;_description;_type;_required;name(e){return this._name=e,this}description(e){return this._description=e,this}type(e){return this._type=e,this}required(e){return this._required=e,this}build(){return this._required==null&&(this._required=!1),new v(this._name,this._description,this._type,this._required)}}class A extends P{endpoint;model;options;constructor(e,s,o){super(),this.endpoint=e,this.model=s,this.options=o}async invoke(e){let s={model:this.model,messages:this._formatMessages(e),tools:this._formatTools(e),...this.options},o=await fetch(this.endpoint+"/api/chat",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(s)});if(!o.ok)throw new Error(`HTTP error! status: ${o.status}`);let r=await o.json(),i=[];if(r.message.tool_calls)for(let l in r.message.tool_calls){const a=r.message.tool_calls[l];let c="function",V=a[c]?.name,H=a[c]?.index,K=a.id??void 0,W=typeof a[c]?.arguments=="string"?JSON.parse(a[c]?.arguments):a[c]?.arguments;i.push(T.builder().name(V).type(c).parameters(W).sequence(H).id(K).build())}return h.builder().toolCalls(i).role(r.message.role).content(r.message.content).thinking(r.message.thinking).build()}_formatTools(e){let s=[];for(let o of e.tools){let r={},i=[];for(let a of o.getToolSchema().parameters)r[a.name]={},r[a.name].type=a.type,r[a.name].description=a.description,a.required&&i.push(a.name);let l={type:"function",function:{name:o.getName(),description:o.getDescription(),parameters:{type:"object",properties:r,required:i}}};s.push(l)}return s}_formatMessages(e){let s=[];for(let o of e.messages){if(o.role=="assistant"||o.role=="system"||o.role=="user"){s.push(this._formatSingleMessage(o));continue}if(o.role=="tool"){for(const r of o.content)if(r.getMessageComponentType()==u.ToolResult){const i=r;s.push({role:o.role,name:i.toolName,content:JSON.stringify(i.toolResult)})}}}return s}_formatSingleMessage(e){let s={role:e.role},o,r,i;for(const l of e.content){if(l.getMessageComponentType()==u.Content){const a=l;o==null&&(o=""),o+=a.get()}if(l.getMessageComponentType()==u.Thinking){const a=l;i==null&&(i=""),i+=a.get()}if(l.getMessageComponentType()==u.ToolCall){const a=l;r==null&&(r=[]),r.push(this._formatToolCall(a))}}return o!=null&&(s.content=o),r!=null&&(s.tool_calls=r),i!=null&&(s.thinking=i),s}_formatToolCall(e){return{function:{name:e.name,arguments:e.parameters}}}}function J(t){return e=>{e.prototype.getName=()=>t}}function F(t){return e=>{Object.defineProperty(e.prototype,"getDescription",{value:function(){return t},enumerable:!0,configurable:!0,writable:!0})}}function L(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParams.push(v.builder().name(t.name).description(t.description).required(t.required).type(t.type).build()),e.prototype.getToolSchema=()=>new g(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}function Q(t){return e=>{e.prototype.tapewormParams==null&&(e.prototype.tapewormParams=[]),e.prototype.tapewormParamsOutput==null&&(e.prototype.tapewormParamsOutput=""),e.prototype.tapewormParamsOutput=t,e.prototype.getToolSchema=()=>new g(e.prototype.tapewormParams,e.prototype.tapewormParamsOutput)}}n.Agent=R,n.Content=C,n.Conversation=m,n.ConversationManager=w,n.DefaultConversationManager=f,n.Message=h,n.MessageBuilder=b,n.MessageComponent=p,n.MessageComponentType=u,n.Model=P,n.ModelRequest=q,n.ModelRequestBuilder=_,n.OllamaModel=A,n.Parameter=v,n.ParameterBuilder=E,n.Thinking=N,n.Tool=x,n.ToolCall=T,n.ToolCallBuilder=O,n.ToolDescription=F,n.ToolName=J,n.ToolOutput=Q,n.ToolParameter=L,n.ToolResult=d,n.ToolSchema=g,n.ToolSchemaBuilder=S,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}));
@@ -1,16 +1,13 @@
1
+ /**
2
+ * The Tool module contains the Tool class, which shows
3
+ * what properties are required by a class to be invocable by Tapeworm.
4
+ */
1
5
  import type ToolSchema from "./toolschema";
2
6
  /**
3
7
  * The Tool class represents a tool that a Tapeworm agent can use.
4
8
  *
5
9
  */
6
10
  export default class Tool {
7
- private name;
8
- private description;
9
- private tool_schema;
10
- /**
11
- * Initialize tool metadata from subclass implementations.
12
- */
13
- constructor();
14
11
  /**
15
12
  * Name that uniquely identifies this tool.
16
13
  * @returns A short, stable identifier string.
@@ -1,3 +1,11 @@
1
+ /**
2
+ * This module is dedicated to just the ToolCall MessageComponent.
3
+ *
4
+ * The reason is that it's the most complicated MessageComponent and deserves to have its own file,
5
+ * as this class contains more ways to instantiate than normal MessageComponents.
6
+ *
7
+ * @module
8
+ */
1
9
  import { MessageComponent, MessageComponentType } from "../conversation/message";
2
10
  /**
3
11
  * Represents a single tool invocation returned by a model, including the target
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * They are different from the Babel decorators in @atgs/babel-plugin-tapeworm-decorator, but they achieve the same functionality.
5
5
  *
6
- *
6
+ * @module
7
7
  */
8
8
  export declare function ToolName(name: String): (toolClass: Function) => void;
9
9
  export declare function ToolDescription(description: String): (toolClass: Function) => void;
@@ -1,5 +1,17 @@
1
1
  /**
2
- * Tool schemas specify the input and output of a tool.
2
+ * This module contains everything related to tool schemas.
3
+ *
4
+ * Enclosed are the ToolSchema (and builder) and Parameter (and builder) classes.
5
+ *
6
+ * @module
7
+ */
8
+ /**
9
+ * ToolSchemas define the input and output of a tool.
10
+ *
11
+ * They consist of a list of parameters and a description of the output of the tool.
12
+ *
13
+ * You can build these using ToolSchemaBuilder, but it can be more pragmatic to use
14
+ * the Typescript or Babel decorators instead, as they will automatically generate a ToolSchema for you.
3
15
  */
4
16
  export default class ToolSchema {
5
17
  parameters: Parameter[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atgs/tapeworm",
3
- "version": "0.1.6",
3
+ "version": "0.1.8-canary.5.d0bf7ab",
4
4
  "type": "module",
5
5
  "main": "dist/tapeworm.cjs.js",
6
6
  "module": "dist/tapeworm.es.js",
@@ -15,7 +15,8 @@
15
15
  "README.md"
16
16
  ],
17
17
  "scripts": {
18
- "build": "npm run format && npm run test && vite build && npm run build:types",
18
+ "build": "npm run format && npm run test && vite build && npm run build:types && npm run docs",
19
+ "docs": "typedoc --options typedoc.json",
19
20
  "build:types": "tsc -p tsconfig.types.json",
20
21
  "test": "jest",
21
22
  "format": "prettier --write \"**/*.{ts,tsx,js,jsx,json,css,md}\""
@@ -27,6 +28,8 @@
27
28
  "jest": "^30.2.0",
28
29
  "prettier": "^3.7.4",
29
30
  "ts-node": "^10.9.2",
31
+ "typedoc": "^0.28.15",
32
+ "typedoc-plugin-rename-defaults": "^0.7.3",
30
33
  "typescript": "^5.9.3",
31
34
  "vite": "^7.2.7"
32
35
  }