Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .changeset/full-queens-ask.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@plotday/tool-outlook-calendar": minor
"@plotday/tool-google-calendar": minor
"@plotday/tool-google-contacts": minor
"@plotday/sdk": minor
---

Changed: BREAKING: Creating and updating Activity using the Plot tool now requires requesting permission in options
12 changes: 12 additions & 0 deletions .changeset/fuzzy-beans-thank.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
"@plotday/tool-outlook-calendar": minor
"@plotday/tool-google-calendar": minor
"@plotday/tool-google-contacts": minor
"@plotday/sdk": minor
---

Changed: BREAKING: Agents and Tools now define a build() method to gain access to tools, which are then available via this.tools.
Changed: BREAKING: Webhook functionality has been moved into the Network tool.
Changed: BREAKING: CallbackTool renamed Callbacks.
Changed: BREAKING: Auth renamed Integrations.
Changed: BREAKING: Run renamed Tasks.
5 changes: 5 additions & 0 deletions .changeset/lazy-snakes-refuse.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@plotday/sdk": minor
---

Added: Improved stack traces
7 changes: 7 additions & 0 deletions .changeset/sparkly-candles-camp.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@plotday/tool-outlook-calendar": patch
"@plotday/tool-google-calendar": patch
"@plotday/tool-google-contacts": patch
---

Changed: Update for new callback function names
5 changes: 5 additions & 0 deletions .changeset/sweet-clouds-dance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@plotday/sdk": minor
---

Changed: BREAKING: Renamed callCallback, run, cancel, and cancelAll Agent/Tool functions
8 changes: 8 additions & 0 deletions .changeset/warm-beds-jump.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@plotday/tool-outlook-calendar": minor
"@plotday/tool-google-calendar": minor
"@plotday/tool-google-contacts": minor
"@plotday/sdk": minor
---

Changed: BREAKING: Improved callback ergonomics and types to use functions instead of strings
201 changes: 95 additions & 106 deletions agents/chat/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,129 +6,118 @@ import {
Agent,
AuthorType,
Tag,
type Tools,
type ToolBuilder,
} from "@plotday/sdk";
import { AI, type AIMessage } from "@plotday/sdk/tools/ai";
import { Plot } from "@plotday/sdk/tools/plot";
import { ActivityAccess, Plot } from "@plotday/sdk/tools/plot";

export default class extends Agent {
private ai: AI;
private plot: Plot;

constructor(id: string, protected tools: Tools) {
super(id, tools);
this.ai = tools.get(AI);
this.plot = tools.get(Plot);
export default class ChatAgent extends Agent<ChatAgent> {
build(build: ToolBuilder) {
return {
ai: build(AI),
plot: build(Plot, {
activity: {
access: ActivityAccess.Respond,
intents: {
"Respond to general questions and requests": this.responsd,
},
},
}),
};
}

async activity(
activity: Activity,
changes?: {
previous: Activity;
tagsAdded: Record<number, string[]>;
tagsRemoved: Record<number, string[]>;
}
) {
if (changes) return;

const previousActivities = await this.plot.getThread(activity);
async responsd(activity: Activity) {
const previousActivities = await this.tools.plot.getThread(activity);

if (
activity.note?.includes("@chat") ||
previousActivities.some((activity: any) =>
activity.note.includes("@chat")
)
) {
// Add Thinking tag to indicate processing has started
await this.plot.updateActivity({
id: activity.id,
tags: {
[Tag.Agent]: true,
},
});
// Add Thinking tag to indicate processing has started
await this.tools.plot.updateActivity({
id: activity.id,
tags: {
[Tag.Agent]: true,
},
});

const messages: AIMessage[] = [
{
role: "system",
content: `You are an AI assistant inside of a productivity app.
const messages: AIMessage[] = [
{
role: "system",
content: `You are an AI assistant inside of a productivity app.
You respond helpfully to user requests.
You can also create tasks, but should only do so when the user explicitly asks you to.`,
},
...previousActivities
.filter((a) => a.note ?? a.title)
.map(
(prevActivity) =>
({
role:
prevActivity.author.type === AuthorType.Agent
? "assistant"
: "user",
content: (prevActivity.note ?? prevActivity.title)!,
} satisfies AIMessage)
),
];
},
...previousActivities
.filter((a) => a.note ?? a.title)
.map(
(prevActivity) =>
({
role:
prevActivity.author.type === AuthorType.Agent
? "assistant"
: "user",
content: (prevActivity.note ?? prevActivity.title)!,
} satisfies AIMessage)
),
];

const schema = Type.Object({
message: Type.Object({
note: Type.String({ description: "Response to the user's prompt" }),
title: Type.String({
description: "Short title for the response notee",
}),
const schema = Type.Object({
message: Type.Object({
note: Type.String({ description: "Response to the user's prompt" }),
title: Type.String({
description: "Short title for the response notee",
}),
action_items: Type.Optional(
Type.Array(
Type.Object({
note: Type.Optional(
Type.String({
description:
"Optional detailed description of the action item. Can include markdown. Only add when important details are needed beyond the title.",
})
),
title: Type.String({
}),
action_items: Type.Optional(
Type.Array(
Type.Object({
note: Type.Optional(
Type.String({
description:
"Succinct description of the action item (no markdown)",
}),
"Optional detailed description of the action item. Can include markdown. Only add when important details are needed beyond the title.",
})
),
title: Type.String({
description:
"Succinct description of the action item (no markdown)",
}),
{
description: "Tasks to create in response to the user's request.",
}
)
),
});
}),
{
description: "Tasks to create in response to the user's request.",
}
)
),
});

const response = await this.ai.prompt({
model: { speed: "balanced", cost: "low" },
messages,
outputSchema: schema,
});
const response = await this.tools.ai.prompt({
model: { speed: "balanced", cost: "low" },
messages,
outputSchema: schema,
});

await Promise.all([
this.plot.createActivity({
title: response.output!.message.title,
note: response.output!.message.note,
await Promise.all([
this.tools.plot.createActivity({
title: response.output!.message.title,
note: response.output!.message.note,
parent: activity,
priority: activity.priority,
type: activity.type,
}),
...(response.output!.action_items?.map((item: any) =>
this.tools.plot.createActivity({
title: item.title,
note: item.note,
parent: activity,
priority: activity.priority,
type: activity.type,
}),
...(response.output!.action_items?.map((item: any) =>
this.plot.createActivity({
title: item.title,
note: item.note,
parent: activity,
priority: activity.priority,
type: ActivityType.Task,
start: new Date(),
})
) ?? []),
]);
type: ActivityType.Task,
start: new Date(),
})
) ?? []),
]);

// Remove Thinking tag after response is created
await this.plot.updateActivity({
id: activity.id,
tags: {
[Tag.Agent]: false,
},
});
}
// Remove Thinking tag after response is created
await this.tools.plot.updateActivity({
id: activity.id,
tags: {
[Tag.Agent]: false,
},
});
}
}
Loading