Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Middleware #51

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
6 changes: 6 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,14 @@
"program": "${file}",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/ts-node",
"runtimeArgs": ["--transpile-only"],
"outFiles": ["${workspaceFolder}/dist/**/*.js"],
"sourceMaps": true,
"smartStep": true,
"resolveSourceMapLocations": [
"${workspaceFolder}/**",
"!**/node_modules/**"
],
"console": "integratedTerminal"
}
]
Expand Down
56 changes: 56 additions & 0 deletions examples/chatbot-alt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { z } from 'zod';
import { createAgent } from '../src';
import { openai } from '@ai-sdk/openai';
import { getFromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'chatbot',
model: openai('gpt-4-turbo'),
events: {
'agent.respond': z.object({
response: z.string().describe('The response from the agent'),
}),
'agent.endConversation': z.object({}).describe('Stop the conversation'),
},
context: {
userMessage: z.string(),
},
});

async function main() {
let status = 'listening';
let userMessage = '';

while (status !== 'finished') {
switch (status) {
case 'listening':
userMessage = await getFromTerminal('User:');
status = 'responding';
break;

case 'responding':
const decision = await agent.decide({
messages: agent.getMessages(),
goal: 'Respond to the user, unless they want to end the conversation.',
state: {
value: status,
context: {
userMessage: 'User says: ' + userMessage,
},
},
});

if (decision?.nextEvent?.type === 'agent.respond') {
console.log(`Agent: ${decision.nextEvent.response}`);
status = 'listening';
} else if (decision?.nextEvent?.type === 'agent.endConversation') {
status = 'finished';
}
break;
}
}

console.log('End of conversation.');
}

main().catch(console.error);
4 changes: 2 additions & 2 deletions examples/chatbot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { createAgent, fromDecision } from '../src';
import { openai } from '@ai-sdk/openai';
import { assign, createActor, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'chatbot',
Expand All @@ -20,7 +20,7 @@ const agent = createAgent({

const machine = setup({
types: agent.types,
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
initial: 'listening',
context: {
Expand Down
4 changes: 2 additions & 2 deletions examples/cot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { createAgent, fromDecision } from '../src';
import { openai } from '@ai-sdk/openai';
import { assign, createActor, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'chain-of-thought',
Expand All @@ -25,7 +25,7 @@ const agent = createAgent({

const machine = setup({
types: agent.types,
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
initial: 'asking',
context: {
Expand Down
4 changes: 2 additions & 2 deletions examples/email.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { createAgent, fromDecision } from '../src';
import { openai } from '@ai-sdk/openai';
import { assign, createActor, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'email',
Expand Down Expand Up @@ -31,7 +31,7 @@ const machine = setup({
replyEmail: string | null;
},
},
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
initial: 'checking',
context: (x) => ({
Expand Down
61 changes: 61 additions & 0 deletions examples/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
import { openai } from '@ai-sdk/openai';
import { createAgent, fromDecision } from '../src';
import { assign, createActor, createMachine, fromPromise } from 'xstate';
import { z } from 'zod';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
model: openai('gpt-4o-mini'),
events: {
getTime: z.object({}).describe('Get the current time'),
other: z.object({}).describe('Do something else'),
},
});

const machine = createMachine({
initial: 'start',
context: {
question: null,
},
states: {
start: {
invoke: {
src: fromTerminal,
input: 'What do you want to do?',
onDone: {
actions: assign({
question: (x) => x.event.output,
}),
target: 'deciding',
},
},
},
deciding: {
invoke: {
src: fromDecision(agent),
input: {
goal: 'Satisfy the user question',
context: true,
},
},
on: {
getTime: 'gettingTime',
other: 'other',
},
},
gettingTime: {
invoke: {
src: fromPromise(async () => {
console.log('Time:', new Date().toLocaleTimeString());
}),
onDone: 'start',
},
},
other: {
entry: () => console.log('Nothing to do!'),
type: 'final',
},
},
});

createActor(machine).start();
4 changes: 2 additions & 2 deletions examples/goal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { createAgent, fromDecision } from '../src';
import { openai } from '@ai-sdk/openai';
import { assign, createActor, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'goal',
Expand All @@ -27,7 +27,7 @@ const machine = setup({
},
events: agent.types.events,
},
actors: { decider, getFromTerminal },
actors: { decider, getFromTerminal: fromTerminal },
}).createMachine({
initial: 'gettingQuestion',
context: {
Expand Down
40 changes: 26 additions & 14 deletions examples/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,29 @@
import { fromPromise } from 'xstate';

export const getFromTerminal = fromPromise<string, string>(
async ({ input }) => {
const topic = await new Promise<string>((res) => {
console.log(input + '\n');
const listener = (data: Buffer) => {
const result = data.toString().trim();
process.stdin.off('data', listener);
res(result);
};
process.stdin.on('data', listener);
});
export const fromTerminal = fromPromise<string, string>(async ({ input }) => {
const topic = await new Promise<string>((res) => {
console.log(input + '\n');
const listener = (data: Buffer) => {
const result = data.toString().trim();
process.stdin.off('data', listener);
res(result);
};
process.stdin.on('data', listener);
});

return topic;
}
);
return topic;
});

export async function getFromTerminal(msg: string) {
const topic = await new Promise<string>((res) => {
console.log(msg + '\n');
const listener = (data: Buffer) => {
const result = data.toString().trim();
process.stdin.off('data', listener);
res(result);
};
process.stdin.on('data', listener);
});

return topic;
}
4 changes: 2 additions & 2 deletions examples/joke.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { createAgent, fromDecision } from '../src';
import { loadingAnimation } from './helpers/loader';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

export function getRandomFunnyPhrase() {
const funnyPhrases = [
Expand Down Expand Up @@ -81,7 +81,7 @@ const jokeMachine = setup({
actors: {
agent: fromDecision(agent),
loader,
getFromTerminal,
getFromTerminal: fromTerminal,
},
}).createMachine({
id: 'joke',
Expand Down
4 changes: 2 additions & 2 deletions examples/multi.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { createAgent, fromDecision } from '../src';
import { z } from 'zod';
import { assign, createActor, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';
import { openai } from '@ai-sdk/openai';

const agent = createAgent({
Expand All @@ -22,7 +22,7 @@ const machine = setup({
},
},
actors: {
getFromTerminal,
getFromTerminal: fromTerminal,
agent: fromDecision(agent),
},
}).createMachine({
Expand Down
4 changes: 2 additions & 2 deletions examples/number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { createAgent, fromDecision } from '../src';
import { assign, createActor, log, setup } from 'xstate';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'number-guesser',
Expand All @@ -24,7 +24,7 @@ const machine = setup({
},
actors: {
agent: fromDecision(agent),
getFromTerminal,
getFromTerminal: fromTerminal,
},
}).createMachine({
context: {
Expand Down
5 changes: 2 additions & 3 deletions examples/raffle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { z } from 'zod';
import { createAgent, fromDecision } from '../src';
import { openai } from '@ai-sdk/openai';
import { assign, createActor, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'raffle-chooser',
Expand All @@ -29,9 +29,8 @@ const machine = setup({
},
events: {} as typeof agent.types.events | { type: 'draw' },
},
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
/** @xstate-layout N4IgpgJg5mDOIC5QAoC2BDAxgCwJYDswBKAOjHwBcwAnAqAYggHtCSCA3JgazBLSzyFS5KrXxQEHJpnQVcLANoAGALrKViUAAcmsXHJaaQAD0QAmAOwBmEmYCsADgCMZgJxmALE4ceHSuwA0IACe5gBsZiR29q5KPnaOrmEOAL4pQfw4BMQkEGCiqAR09OgwlCSYTAA2VWCYFACilLRw6kY6egb4RqYIZg52JB52Ya5jSq5+To4eQaEILhYkA0qjVlYeSlsOYWFpGRhZQrn5NIX4xaUiudToAO5tSCAd+vLdT727SiRKHsl2FjCwxcrlmIUQTl2ticHk26ycMPsqXSIEyghyEFud0uZQoJGoYB01AoAHUCIRqI9tLpXoYPohXBYnCQnP4HK4nFYLF5vK45hCPDYmVtdk5uYzuWkUfgmHl4E80dkiO0aV0eogALRhfkIDWDMZjJn9MxhKwjSb7VGHdHCSg0OgqzpvdUIDxmHWc5l2caeKxhVYDFyWxXHPIFIriR2096gXoeVw2VmgiIOBzWJRiqwe2FRdzcpRWE0JPPB61Km73B1PF5q+kIPweEhWMWjCz+BJKJketwkQEWCyuOywv0WaJ2UsCcvY-AUqO12MQls-Ue+Px2KzspweoHLXxsjO-eNmMxSlJAA */
context: {
lastInput: null,
entries: [],
Expand Down
4 changes: 2 additions & 2 deletions examples/todo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { assign, setup, assertEvent, createActor, createMachine } from 'xstate';
import { z } from 'zod';
import { createAgent, fromDecision } from '../src';
import { openai } from '@ai-sdk/openai';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';

const agent = createAgent({
name: 'todo',
Expand Down Expand Up @@ -40,7 +40,7 @@ const machine = setup({
| typeof agent.types.events
| { type: 'assist'; command: string },
},
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
context: {
command: null,
Expand Down
4 changes: 2 additions & 2 deletions examples/tutor.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assign, createActor, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';
import { createAgent, fromDecision } from '../src';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';
Expand Down Expand Up @@ -30,7 +30,7 @@ const machine = setup({
},
events: agent.types.events,
},
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
initial: 'human',
context: {
Expand Down
4 changes: 2 additions & 2 deletions examples/verify.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { assign, createActor, setup, log } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';
import { createAgent, fromDecision } from '../src';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';
Expand Down Expand Up @@ -38,7 +38,7 @@ const machine = setup({
events: agent.types.events,
},
actors: {
getFromTerminal,
getFromTerminal: fromTerminal,
agent: fromDecision(agent),
},
}).createMachine({
Expand Down
4 changes: 2 additions & 2 deletions examples/weather.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { createAgent, fromDecision } from '../src';
import { assign, createActor, fromPromise, log, setup } from 'xstate';
import { getFromTerminal } from './helpers/helpers';
import { fromTerminal } from './helpers/helpers';
import { z } from 'zod';
import { openai } from '@ai-sdk/openai';

Expand Down Expand Up @@ -83,7 +83,7 @@ const machine = setup({
actors: {
agent: fromDecision(agent),
getWeather,
getFromTerminal,
getFromTerminal: fromTerminal,
},
}).createMachine({
initial: 'getLocation',
Expand Down
Loading