Skip to content

Commit

Permalink
Merge pull request #51 from statelyai/davidkpiano/middleware
Browse files Browse the repository at this point in the history
Middleware
  • Loading branch information
davidkpiano authored Oct 6, 2024
2 parents 05fba0d + c026378 commit 78f4067
Show file tree
Hide file tree
Showing 36 changed files with 1,808 additions and 1,496 deletions.
9 changes: 9 additions & 0 deletions .changeset/light-hats-drive.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
---
'@statelyai/agent': major
---

- `agent.generateText(…)` is removed in favor of using the AI SDK's `generateText(…)` function with a wrapped model.
- `agent.streamText(…)` is removed in favor of using the AI SDK's `streamText(…)` function with a wrapped model.
- Custom adapters are removed for now, but may be re-added in future releases. Using the AI SDK is recommended for now.
- Correlation IDs are removed in favor of using [OpenTelemetry with the AI SDK](https://sdk.vercel.ai/docs/ai-sdk-core/telemetry#telemetry).
- The `createAgentMiddleware(…)` function was introduced to facilitate agent message history. You can also use `agent.wrap(model)` to wrap a model with Stately Agent middleware.
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
57 changes: 57 additions & 0 deletions examples/chatbot-alt.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
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.');
process.exit();
}

main().catch(console.error);
12 changes: 6 additions & 6 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 All @@ -33,7 +33,7 @@ const machine = setup({
input: 'User:',
onDone: {
actions: assign({
userMessage: (x) => x.event.output,
userMessage: ({ event }) => event.output,
}),
target: 'responding',
},
Expand All @@ -42,17 +42,17 @@ const machine = setup({
responding: {
invoke: {
src: 'agent',
input: (x) => ({
input: ({ context }) => ({
context: {
userMessage: 'User says: ' + x.context.userMessage,
userMessage: 'User says: ' + context.userMessage,
},
messages: agent.getMessages(),
goal: 'Respond to the user, unless they want to end the conversation.',
}),
},
on: {
'agent.respond': {
actions: [log((x) => `Agent: ${x.event.response}`)],
actions: log(({ event }) => `Agent: ${event.response}`),
target: 'listening',
},
'agent.endConversation': 'finished',
Expand Down
20 changes: 10 additions & 10 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 All @@ -39,7 +39,7 @@ const machine = setup({
input: 'What would you like to ask?',
onDone: {
actions: assign({
question: (x) => x.event.output,
question: ({ event }) => event.output,
}),
target: 'thinking',
},
Expand All @@ -48,17 +48,17 @@ const machine = setup({
thinking: {
invoke: {
src: 'agent',
input: (x) => ({
context: x.context,
input: ({ context }) => ({
context,
goal: 'Answer the question. Think step-by-step.',
}),
},
on: {
'agent.think': {
actions: [
log((x) => x.event.thought),
log(({ event }) => event.thought),
assign({
thought: (x) => x.event.thought,
thought: ({ event }) => event.thought,
}),
],
target: 'answering',
Expand All @@ -68,14 +68,14 @@ const machine = setup({
answering: {
invoke: {
src: 'agent',
input: (x) => ({
context: x.context,
input: ({ context }) => ({
context,
goal: 'Answer the question',
}),
},
on: {
'agent.answer': {
actions: [log((x) => x.event.answer)],
actions: [log(({ event }) => event.answer)],
target: 'answered',
},
},
Expand Down
26 changes: 13 additions & 13 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,32 +31,32 @@ const machine = setup({
replyEmail: string | null;
},
},
actors: { agent: fromDecision(agent), getFromTerminal },
actors: { agent: fromDecision(agent), getFromTerminal: fromTerminal },
}).createMachine({
initial: 'checking',
context: (x) => ({
email: x.input.email,
instructions: x.input.instructions,
context: ({ input }) => ({
email: input.email,
instructions: input.instructions,
clarifications: [],
replyEmail: null,
}),
states: {
checking: {
invoke: {
src: 'agent',
input: (x) => ({
input: ({ context }) => ({
context: {
email: x.context.email,
instructions: x.context.instructions,
clarifications: x.context.clarifications,
email: context.email,
instructions: context.instructions,
clarifications: context.clarifications,
},
messages: agent.getMessages(),
goal: 'Respond to the email given the instructions and the provided clarifications. If not enough information is provided, ask for clarification. Otherwise, if you are absolutely sure that there is no ambiguous or missing information, create and submit a response email.',
}),
},
on: {
askForClarification: {
actions: (x) => console.log(x.event.questions.join('\n')),
actions: ({ event }) => console.log(event.questions.join('\n')),
target: 'clarifying',
},
submitEmail: {
Expand All @@ -70,8 +70,8 @@ const machine = setup({
input: `Please provide answers to the questions above`,
onDone: {
actions: assign({
clarifications: (x) =>
x.context.clarifications.concat(x.event.output),
clarifications: ({ context, event }) =>
context.clarifications.concat(event.output),
}),
target: 'checking',
},
Expand Down Expand Up @@ -100,7 +100,7 @@ const machine = setup({
},
done: {
type: 'final',
entry: (x) => console.log(x.context.replyEmail),
entry: ({ context }) => console.log(context.replyEmail),
},
},
exit: () => {
Expand Down
8 changes: 4 additions & 4 deletions examples/example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ const machine = setup({
invoke: [
{
src: 'summarizer',
input: (x) => ({
context: x.context,
input: ({ context }) => ({
context,
prompt:
'Summarize the patient visit in a single sentence. The summary should be in English.',
}),
Expand All @@ -45,8 +45,8 @@ const machine = setup({
},
{
src: 'summarizer',
input: (x) => ({
context: x.context,
input: ({ context }) => ({
context,
prompt:
'Summarize the patient visit in a single sentence. The summary should be in Spanish.',
}),
Expand Down
66 changes: 66 additions & 0 deletions examples/executor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
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: ({ event }) => 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(
'You want me to do something else. I can only tell the time.'
),
after: {
1000: 'start',
},
},
},
});

createActor(machine).start();
6 changes: 3 additions & 3 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 Expand Up @@ -62,7 +62,7 @@ const machine = setup({
assign({
goal: ({ event }) => event.goal,
}),
log((x) => x.event),
log(({ event }) => event),
],
target: 'responding',
},
Expand Down
Loading

0 comments on commit 78f4067

Please sign in to comment.