@statelyai/agent 0.0.4 → 0.0.5

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.
@@ -1,17 +1,17 @@
1
1
  {
2
- // Use IntelliSense to learn about possible attributes.
3
- // Hover to view descriptions of existing attributes.
4
2
  // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
5
3
  "version": "0.2.0",
6
4
  "configurations": [
7
5
  {
8
6
  "type": "node",
9
7
  "request": "launch",
10
- "name": "Launch Program",
11
- "skipFiles": ["<node_internals>/**"],
12
- "program": "${file}",
13
- "preLaunchTask": "tsc: build - tsconfig.json",
14
- "outFiles": ["${workspaceFolder}/**/*.js"]
8
+ "name": "Debug Current Test File",
9
+ "autoAttachChildProcesses": true,
10
+ "skipFiles": ["<node_internals>/**", "**/node_modules/**"],
11
+ "program": "${workspaceRoot}/node_modules/vitest/vitest.mjs",
12
+ "args": ["run", "${relativeFile}"],
13
+ "smartStep": true,
14
+ "console": "integratedTerminal"
15
15
  }
16
16
  ]
17
17
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,37 @@
1
1
  # @statelyai/agent
2
2
 
3
+ ## 0.0.5
4
+
5
+ ### Patch Changes
6
+
7
+ - [#9](https://github.com/statelyai/agent/pull/9) [`d8e7b67`](https://github.com/statelyai/agent/commit/d8e7b673f6d265f37b2096b25d75310845860271) Thanks [@davidkpiano](https://github.com/davidkpiano)! - Add `adapter.fromTool(…)`, which creates an actor that chooses agent logic based on a input.
8
+
9
+ ```ts
10
+ const actor = adapter.fromTool(() => "Draw me a picture of a donut", {
11
+ // tools
12
+ makeIllustration: {
13
+ description: "Makes an illustration",
14
+ run: async (input) => {
15
+ /* ... */
16
+ },
17
+ inputSchema: {
18
+ /* ... */
19
+ },
20
+ },
21
+ getWeather: {
22
+ description: "Gets the weather",
23
+ run: async (input) => {
24
+ /* ... */
25
+ },
26
+ inputSchema: {
27
+ /* ... */
28
+ },
29
+ },
30
+ });
31
+
32
+ //...
33
+ ```
34
+
3
35
  ## 0.0.4
4
36
 
5
37
  ### Patch Changes
package/dist/index.d.ts CHANGED
@@ -3,8 +3,8 @@ import { Prop, Values, AnyStateMachine, createActor, PromiseActorLogic, AnyEvent
3
3
  import { JSONSchema7 } from 'json-schema-to-ts/lib/types/definitions';
4
4
  import { FromSchema } from 'json-schema-to-ts';
5
5
  import OpenAI from 'openai';
6
- import { ChatCompletionCreateParamsNonStreaming } from 'openai/resources';
7
- import { ChatCompletionCreateParamsBase, ChatCompletionCreateParamsStreaming } from 'openai/resources/chat/completions';
6
+ import { ChatCompletionCreateParamsBase } from 'openai/resources/chat/completions';
7
+ import { ChatCompletionCreateParamsNonStreaming, ChatCompletionCreateParamsStreaming } from 'openai/resources';
8
8
 
9
9
  type EventSchemas = {
10
10
  [key: string]: {
@@ -50,14 +50,9 @@ declare function createSchemas<TContextSchema extends ContextSchema, TEventSchem
50
50
 
51
51
  declare function createAgent<T extends AnyStateMachine>(...args: Parameters<typeof createActor<T>>): xstate.Actor<T>;
52
52
 
53
- interface OpenAIAdapterOutput<T extends {
54
- model: ChatCompletionCreateParamsBase['model'];
55
- }> {
56
- model: T['model'];
57
- /**
58
- * Determines which event to send to the parent state machine actor based on the prompt.
59
- */
60
- fromEventChoice: <TInput>(inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming, options?: {
53
+ interface StatelyAgentAdapter {
54
+ model: string;
55
+ fromEvent: <TInput>(inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming, options?: {
61
56
  /**
62
57
  * Immediately execute sending the event to the parent actor.
63
58
  * @default true
@@ -72,9 +67,28 @@ interface OpenAIAdapterOutput<T extends {
72
67
  * Creates observable actor logic that emits a chat completion stream.
73
68
  */
74
69
  fromChatStream: <TInput>(inputFn: (input: TInput) => string | ChatCompletionCreateParamsStreaming) => ObservableActorLogic<OpenAI.Chat.Completions.ChatCompletionChunk, TInput>;
70
+ fromTool: <TInput>(inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming, tools: {
71
+ [key: string]: Tool<any, any>;
72
+ }, options?: {
73
+ /**
74
+ * Immediately execute sending the event to the parent actor.
75
+ * @default true
76
+ */
77
+ execute?: boolean;
78
+ }) => PromiseActorLogic<{
79
+ result: any;
80
+ tool: string;
81
+ toolCall: OpenAI.Chat.Completions.ChatCompletionMessageToolCall;
82
+ } | undefined, TInput>;
75
83
  }
84
+ interface Tool<TInput, TOutput> {
85
+ description: string;
86
+ inputSchema: any;
87
+ run: (input: TInput) => TOutput;
88
+ }
89
+
76
90
  declare function createOpenAIAdapter<T extends {
77
91
  model: ChatCompletionCreateParamsBase['model'];
78
- }>(openai: OpenAI, settings: T): OpenAIAdapterOutput<T>;
92
+ }>(openai: OpenAI, settings: T): StatelyAgentAdapter;
79
93
 
80
94
  export { createAgent, createOpenAIAdapter, createSchemas };
package/dist/index.js CHANGED
@@ -134,7 +134,7 @@ function fromChatStream(openai, agentSettings, inputFn) {
134
134
  }
135
135
  );
136
136
  }
137
- function fromEventChoice(openai, agentSettings, inputFn, options) {
137
+ function fromEvent(openai, agentSettings, inputFn, options) {
138
138
  return (0, import_xstate2.fromPromise)(
139
139
  async ({ input, self, system }) => {
140
140
  const parentSnapshot = self._parent?.getSnapshot();
@@ -194,15 +194,60 @@ function fromEventChoice(openai, agentSettings, inputFn, options) {
194
194
  }
195
195
  );
196
196
  }
197
+ function fromTool(openai, agentSettings, tools, inputFn) {
198
+ return (0, import_xstate2.fromPromise)(async ({ input, self, system }) => {
199
+ const functionNameMapping = {};
200
+ const resolvedTools = Object.entries(tools).map(([key, value]) => {
201
+ return {
202
+ type: "function",
203
+ function: {
204
+ name: key,
205
+ description: value.description,
206
+ parameters: value.inputSchema
207
+ }
208
+ };
209
+ });
210
+ const openAiInput = inputFn(input);
211
+ const completionParams = typeof openAiInput === "string" ? {
212
+ model: agentSettings.model,
213
+ messages: [
214
+ {
215
+ role: "user",
216
+ content: openAiInput
217
+ }
218
+ ]
219
+ } : openAiInput;
220
+ const completion = await openai.chat.completions.create({
221
+ ...completionParams,
222
+ tools: resolvedTools
223
+ });
224
+ const toolCalls = completion.choices[0]?.message.tool_calls;
225
+ if (toolCalls?.length) {
226
+ const toolCall = toolCalls[0];
227
+ const tool = tools[toolCall.function.name];
228
+ const args = JSON.parse(toolCall.function.arguments);
229
+ if (tool) {
230
+ const result = await tool.run(args);
231
+ return {
232
+ toolCall,
233
+ tool: toolCall.function.name,
234
+ result
235
+ };
236
+ }
237
+ }
238
+ return void 0;
239
+ });
240
+ }
197
241
  function createOpenAIAdapter(openai, settings) {
198
242
  const agentSettings = {
199
243
  model: settings.model,
200
- fromEventChoice: (input) => (
244
+ fromEvent: (input) => (
201
245
  // @ts-ignore infinitely deep
202
- fromEventChoice(openai, agentSettings, input, { execute: true })
246
+ fromEvent(openai, agentSettings, input, { execute: true })
203
247
  ),
204
248
  fromChat: (input) => fromChatCompletion(openai, agentSettings, input),
205
- fromChatStream: (input) => fromChatStream(openai, agentSettings, input)
249
+ fromChatStream: (input) => fromChatStream(openai, agentSettings, input),
250
+ fromTool: (input, tools) => fromTool(openai, agentSettings, tools, input)
206
251
  };
207
252
  return agentSettings;
208
253
  }
package/examples/joke.ts CHANGED
@@ -61,7 +61,7 @@ const getTopic = fromPromise(async () => {
61
61
  return topic;
62
62
  });
63
63
 
64
- const decide = adapter.fromEventChoice(
64
+ const decide = adapter.fromEvent(
65
65
  (lastRating: string) =>
66
66
  `Choose what to do next, given the previous rating of the joke: ${lastRating}`
67
67
  );
@@ -80,7 +80,7 @@ const initialContext = {
80
80
  events: [],
81
81
  } satisfies typeof schemas.types.context;
82
82
 
83
- const bot = adapter.fromEventChoice(
83
+ const bot = adapter.fromEvent(
84
84
  ({ context }: { context: typeof schemas.types.context }) => `
85
85
  You are playing a game of tic tac toe. This is the current game state. The 3x3 board is represented by a 9-element array. The first element is the top-left cell, the second element is the top-middle cell, the third element is the top-right cell, the fourth element is the middle-left cell, and so on. The value of each cell is either null, x, or o. The value of null means that the cell is empty. The value of x means that the cell is occupied by an x. The value of o means that the cell is occupied by an o.
86
86
 
@@ -84,7 +84,7 @@ const machine = setup({
84
84
  types: schemas.types,
85
85
  actors: {
86
86
  getWeather,
87
- decide: adapter.fromEventChoice(
87
+ decide: adapter.fromEvent(
88
88
  (input: string) =>
89
89
  `Decide what to do based on the given input, which may or may not be a location: ${input}`
90
90
  ),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@statelyai/agent",
3
- "version": "0.0.4",
3
+ "version": "0.0.5",
4
4
  "description": "",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
@@ -17,7 +17,8 @@
17
17
  "openai": "^4.24.1",
18
18
  "ts-node": "^10.9.2",
19
19
  "tsup": "^8.0.1",
20
- "typescript": "^5.3.3"
20
+ "typescript": "^5.3.3",
21
+ "vitest": "^1.2.2"
21
22
  },
22
23
  "publishConfig": {
23
24
  "access": "public"
@@ -0,0 +1,217 @@
1
+ import { test, expect } from 'vitest';
2
+ import { createOpenAIAdapter, createTool } from './adapters/openai';
3
+ import OpenAI from 'openai';
4
+ import { createActor, toPromise } from 'xstate';
5
+
6
+ test('fromTool - weather or illustration', async () => {
7
+ const openAi = new OpenAI({
8
+ apiKey: process.env.OPENAI_API_KEY,
9
+ });
10
+
11
+ const adapter = createOpenAIAdapter(openAi, {
12
+ model: 'gpt-3.5-turbo',
13
+ });
14
+
15
+ const toolChoice = adapter.fromTool(() => 'Create an image of a donut', {
16
+ makeIllustration: {
17
+ description: 'Make an illustration',
18
+ run: async () => 'Illustration',
19
+ inputSchema: {
20
+ type: 'object',
21
+ properties: {
22
+ name: {
23
+ type: 'string',
24
+ description: 'The name of the illustration',
25
+ },
26
+ },
27
+ required: ['name'],
28
+ },
29
+ },
30
+ getWeather: {
31
+ description: 'Get the weather for a location',
32
+ run: async () => 'Weather',
33
+ inputSchema: {
34
+ type: 'object',
35
+ properties: {
36
+ location: {
37
+ type: 'object',
38
+ properties: {
39
+ city: {
40
+ type: 'string',
41
+ description: 'The name of the city',
42
+ },
43
+ state: {
44
+ type: 'string',
45
+ description: 'The name of the state',
46
+ },
47
+ },
48
+ required: ['city', 'state'],
49
+ },
50
+ },
51
+ required: ['location'],
52
+ },
53
+ },
54
+ });
55
+
56
+ const actor = createActor(toolChoice);
57
+
58
+ actor.start();
59
+
60
+ const res = await toPromise(actor);
61
+
62
+ expect(res?.result).toBe('Illustration');
63
+ });
64
+
65
+ test('fromTool - GitHub PR description inserter', async () => {
66
+ const openAi = new OpenAI({
67
+ apiKey: process.env.OPENAI_API_KEY,
68
+ });
69
+
70
+ const adapter = createOpenAIAdapter(openAi, {
71
+ model: 'gpt-3.5-turbo-16k-0613',
72
+ });
73
+
74
+ const toolChoice = adapter.fromTool(
75
+ (input: string) =>
76
+ `Create a GitHub PR description for the following: ${input}`,
77
+ {
78
+ fetchGitHubPR: {
79
+ description: 'Fetch a GitHub PR',
80
+ run: async (input: string) => {
81
+ return {
82
+ title: 'Title',
83
+ body: input,
84
+ };
85
+ },
86
+ inputSchema: {
87
+ type: 'object',
88
+ properties: {
89
+ repo: {
90
+ type: 'string',
91
+ description: 'The name of the repo',
92
+ },
93
+ number: {
94
+ type: 'number',
95
+ description: 'The number of the PR',
96
+ },
97
+ },
98
+ required: ['repo', 'number'],
99
+ },
100
+ },
101
+ createPullRequestDescription: {
102
+ description: 'Create a GitHub PR description',
103
+ run: () => 'Description',
104
+ inputSchema: {
105
+ type: 'object',
106
+ properties: {
107
+ title: {
108
+ type: 'string',
109
+ description: 'The title of the PR',
110
+ },
111
+ body: {
112
+ type: 'string',
113
+ description: 'The body of the PR',
114
+ },
115
+ },
116
+ required: ['title', 'body'],
117
+ },
118
+ },
119
+ }
120
+ );
121
+
122
+ const actor = createActor(toolChoice, {
123
+ input:
124
+ // 'Get the details from this: https://github.com/microsoft/TypeScript/pull/47198',
125
+ 'Make a summary of this PR: (some code here)',
126
+ });
127
+
128
+ actor.start();
129
+
130
+ const res = await toPromise(actor);
131
+
132
+ expect(res?.tool).toEqual('createPullRequestDescription');
133
+ expect(res?.result).toEqual('Description');
134
+ });
135
+
136
+ test('fromTool - joke creator or rater', async () => {
137
+ const openAi = new OpenAI({
138
+ apiKey: process.env.OPENAI_API_KEY,
139
+ });
140
+
141
+ const adapter = createOpenAIAdapter(openAi, {
142
+ model: 'gpt-4-1106-preview',
143
+ });
144
+
145
+ const rateJoke = createTool({
146
+ description: 'Rate a joke',
147
+ inputSchema: {
148
+ type: 'object',
149
+ properties: {
150
+ joke: {
151
+ type: 'string',
152
+ description: 'The joke to rate',
153
+ },
154
+ },
155
+ },
156
+ run: async ({ topic }: { topic: string }) => {
157
+ return `Here is a joke about ${topic}`;
158
+ },
159
+ });
160
+
161
+ const createJoke = createTool({
162
+ description: 'Create a joke',
163
+ inputSchema: {
164
+ type: 'object',
165
+ properties: {
166
+ category: {
167
+ type: 'string',
168
+ description: 'The category of the joke',
169
+ },
170
+ },
171
+ required: ['category'],
172
+ },
173
+ run: async () => {
174
+ return 'Some joke';
175
+ },
176
+ });
177
+
178
+ const toolChoice = adapter.fromTool(
179
+ (input: string) => `
180
+ The user provided this input:
181
+
182
+ <input>
183
+ ${input}
184
+ </input>
185
+
186
+ Determine what to do:
187
+ - If the input is asking for a joke, create a joke,
188
+ - But if the input is providing a joke, then rate the joke.
189
+ `,
190
+ {
191
+ rateJoke,
192
+ createJoke,
193
+ }
194
+ );
195
+
196
+ const actor = createActor(toolChoice, {
197
+ // input: 'Why did the chicken cross the road? To get to the other side!',
198
+ input: 'Tell me a joke about chickens',
199
+ });
200
+
201
+ actor.start();
202
+
203
+ const res = await toPromise(actor);
204
+
205
+ expect(res?.tool).toEqual('createJoke');
206
+ expect(res?.result).toEqual('Some joke');
207
+
208
+ const actor2 = createActor(toolChoice, {
209
+ input:
210
+ 'Check this joke out: Why did the chicken cross the road? To get to the other side!',
211
+ });
212
+
213
+ actor2.start();
214
+
215
+ const res2 = await toPromise(actor2);
216
+ expect(res2?.tool).toEqual('rateJoke');
217
+ });
@@ -15,6 +15,7 @@ import {
15
15
  ChatCompletionCreateParamsBase,
16
16
  ChatCompletionCreateParamsStreaming,
17
17
  } from 'openai/resources/chat/completions';
18
+ import { StatelyAgentAdapter, Tool } from '../types';
18
19
 
19
20
  /**
20
21
  * Creates [promise actor logic](https://stately.ai/docs/promise-actors) that uses the OpenAI API to generate a completion.
@@ -117,7 +118,7 @@ export function fromChatStream<TInput>(
117
118
  * @param openai The OpenAI instance to use.
118
119
  * @param inputFn A function that maps arbitrary input to OpenAI chat completion input.
119
120
  */
120
- export function fromEventChoice<TInput>(
121
+ export function fromEvent<TInput>(
121
122
  openai: OpenAI,
122
123
  agentSettings: OpenAIAdapterOutput<any>,
123
124
  inputFn: (
@@ -206,6 +207,95 @@ export function fromEventChoice<TInput>(
206
207
  );
207
208
  }
208
209
 
210
+ export function createTool<TInput, T>({
211
+ description,
212
+ inputSchema,
213
+ run,
214
+ }: Tool<TInput, T>): Tool<TInput, T> {
215
+ return {
216
+ description,
217
+ inputSchema,
218
+ run,
219
+ };
220
+ }
221
+
222
+ /**
223
+ * Creates [promise actor logic](https://stately.ai/docs/promise-actors) that passes the next possible transitions as functions to [OpenAI tool calls](https://platform.openai.com/docs/guides/function-calling) and returns an array of potential next events.
224
+ *
225
+ * @param openai The OpenAI instance to use.
226
+ * @param inputFn A function that maps arbitrary input to OpenAI chat completion input.
227
+ */
228
+ export function fromTool<TInput>(
229
+ openai: OpenAI,
230
+ agentSettings: StatelyAgentAdapter,
231
+ tools: {
232
+ [key: string]: Tool<any, any>;
233
+ },
234
+ inputFn: (
235
+ input: TInput
236
+ ) => string | OpenAI.Chat.Completions.ChatCompletionCreateParamsNonStreaming
237
+ ) {
238
+ return fromPromise<
239
+ | {
240
+ result: any;
241
+ tool: string;
242
+ toolCall: OpenAI.Chat.Completions.ChatCompletionMessageToolCall;
243
+ }
244
+ | undefined,
245
+ TInput
246
+ >(async ({ input, self, system }) => {
247
+ const functionNameMapping: Record<string, string> = {};
248
+ const resolvedTools = Object.entries(tools).map(([key, value]) => {
249
+ return {
250
+ type: 'function',
251
+ function: {
252
+ name: key,
253
+ description: value.description,
254
+ parameters: value.inputSchema,
255
+ },
256
+ } as const;
257
+ });
258
+
259
+ const openAiInput = inputFn(input);
260
+ const completionParams: ChatCompletionCreateParamsNonStreaming =
261
+ typeof openAiInput === 'string'
262
+ ? {
263
+ model: agentSettings.model,
264
+ messages: [
265
+ {
266
+ role: 'user',
267
+ content: openAiInput,
268
+ },
269
+ ],
270
+ }
271
+ : openAiInput;
272
+ const completion = await openai.chat.completions.create({
273
+ ...completionParams,
274
+ tools: resolvedTools,
275
+ });
276
+
277
+ const toolCalls = completion.choices[0]?.message.tool_calls;
278
+
279
+ if (toolCalls?.length) {
280
+ const toolCall = toolCalls[0]!;
281
+ const tool = tools[toolCall.function.name];
282
+ const args = JSON.parse(toolCall.function.arguments);
283
+
284
+ if (tool) {
285
+ const result = await tool.run(args);
286
+
287
+ return {
288
+ toolCall,
289
+ tool: toolCall.function.name,
290
+ result,
291
+ };
292
+ }
293
+ }
294
+
295
+ return undefined;
296
+ });
297
+ }
298
+
209
299
  interface OpenAIAdapterOutput<
210
300
  T extends {
211
301
  model: ChatCompletionCreateParamsBase['model'];
@@ -215,7 +305,7 @@ interface OpenAIAdapterOutput<
215
305
  /**
216
306
  * Determines which event to send to the parent state machine actor based on the prompt.
217
307
  */
218
- fromEventChoice: <TInput>(
308
+ fromEvent: <TInput>(
219
309
  inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming,
220
310
  options?: {
221
311
  /**
@@ -246,14 +336,15 @@ export function createOpenAIAdapter<
246
336
  T extends {
247
337
  model: ChatCompletionCreateParamsBase['model'];
248
338
  }
249
- >(openai: OpenAI, settings: T): OpenAIAdapterOutput<T> {
250
- const agentSettings: OpenAIAdapterOutput<T> = {
339
+ >(openai: OpenAI, settings: T): StatelyAgentAdapter {
340
+ const agentSettings: StatelyAgentAdapter = {
251
341
  model: settings.model,
252
- fromEventChoice: (input) =>
342
+ fromEvent: (input) =>
253
343
  // @ts-ignore infinitely deep
254
- fromEventChoice(openai, agentSettings, input, { execute: true }) as any,
344
+ fromEvent(openai, agentSettings, input, { execute: true }) as any,
255
345
  fromChat: (input) => fromChatCompletion(openai, agentSettings, input),
256
346
  fromChatStream: (input) => fromChatStream(openai, agentSettings, input),
347
+ fromTool: (input, tools) => fromTool(openai, agentSettings, tools, input),
257
348
  };
258
349
 
259
350
  return agentSettings;
package/src/types.ts ADDED
@@ -0,0 +1,69 @@
1
+ import OpenAI from 'openai';
2
+ import {
3
+ ChatCompletionCreateParamsNonStreaming,
4
+ ChatCompletionCreateParamsStreaming,
5
+ } from 'openai/resources';
6
+ import {
7
+ AnyActorLogic,
8
+ AnyActorRef,
9
+ AnyEventObject,
10
+ ObservableActorLogic,
11
+ PromiseActorLogic,
12
+ } from 'xstate';
13
+
14
+ export interface StatelyAgentAdapter {
15
+ model: string;
16
+ fromEvent: <TInput>(
17
+ inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming,
18
+ options?: {
19
+ /**
20
+ * Immediately execute sending the event to the parent actor.
21
+ * @default true
22
+ */
23
+ execute?: boolean;
24
+ }
25
+ ) => PromiseActorLogic<AnyEventObject[] | undefined, TInput>;
26
+ /**
27
+ * Creates promise actor logic that resolves with a chat completion.
28
+ */
29
+ fromChat: <TInput>(
30
+ inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming
31
+ ) => PromiseActorLogic<OpenAI.Chat.Completions.ChatCompletion, TInput>;
32
+ /**
33
+ * Creates observable actor logic that emits a chat completion stream.
34
+ */
35
+ fromChatStream: <TInput>(
36
+ inputFn: (input: TInput) => string | ChatCompletionCreateParamsStreaming
37
+ ) => ObservableActorLogic<
38
+ OpenAI.Chat.Completions.ChatCompletionChunk,
39
+ TInput
40
+ >;
41
+
42
+ fromTool: <TInput>(
43
+ inputFn: (input: TInput) => string | ChatCompletionCreateParamsNonStreaming,
44
+ tools: {
45
+ [key: string]: Tool<any, any>;
46
+ },
47
+ options?: {
48
+ /**
49
+ * Immediately execute sending the event to the parent actor.
50
+ * @default true
51
+ */
52
+ execute?: boolean;
53
+ }
54
+ ) => PromiseActorLogic<
55
+ | {
56
+ result: any;
57
+ tool: string;
58
+ toolCall: OpenAI.Chat.Completions.ChatCompletionMessageToolCall;
59
+ }
60
+ | undefined,
61
+ TInput
62
+ >;
63
+ }
64
+
65
+ export interface Tool<TInput, TOutput> {
66
+ description: string;
67
+ inputSchema: any;
68
+ run: (input: TInput) => TOutput;
69
+ }