Skip to content

Commit b3242e4

Browse files
committed
Require permissions for Plot access
1 parent 28a3102 commit b3242e4

6 files changed

Lines changed: 212 additions & 170 deletions

File tree

.changeset/full-queens-ask.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
---
2+
"@plotday/tool-outlook-calendar": minor
3+
"@plotday/tool-google-calendar": minor
4+
"@plotday/tool-google-contacts": minor
5+
"@plotday/sdk": minor
6+
---
7+
8+
Changed: BREAKING: Creating and updating Activity using the Plot tool now requires requesting permission in options

agents/chat/src/index.ts

Lines changed: 87 additions & 96 deletions
Original file line numberDiff line numberDiff line change
@@ -9,124 +9,115 @@ import {
99
type ToolBuilder,
1010
} from "@plotday/sdk";
1111
import { AI, type AIMessage } from "@plotday/sdk/tools/ai";
12-
import { Plot } from "@plotday/sdk/tools/plot";
12+
import { ActivityAccess, Plot } from "@plotday/sdk/tools/plot";
1313

1414
export default class ChatAgent extends Agent<ChatAgent> {
1515
build(build: ToolBuilder) {
1616
return {
1717
ai: build(AI),
18-
plot: build(Plot),
18+
plot: build(Plot, {
19+
activity: {
20+
access: ActivityAccess.Respond,
21+
intents: {
22+
"Respond to general questions and requests": this.responsd,
23+
},
24+
},
25+
}),
1926
};
2027
}
2128

22-
async activity(
23-
activity: Activity,
24-
changes?: {
25-
previous: Activity;
26-
tagsAdded: Record<number, string[]>;
27-
tagsRemoved: Record<number, string[]>;
28-
}
29-
) {
30-
if (changes) return;
31-
29+
async responsd(activity: Activity) {
3230
const previousActivities = await this.tools.plot.getThread(activity);
3331

34-
if (
35-
activity.note?.includes("@chat") ||
36-
previousActivities.some((activity: any) =>
37-
activity.note.includes("@chat")
38-
)
39-
) {
40-
// Add Thinking tag to indicate processing has started
41-
await this.tools.plot.updateActivity({
42-
id: activity.id,
43-
tags: {
44-
[Tag.Agent]: true,
45-
},
46-
});
32+
// Add Thinking tag to indicate processing has started
33+
await this.tools.plot.updateActivity({
34+
id: activity.id,
35+
tags: {
36+
[Tag.Agent]: true,
37+
},
38+
});
4739

48-
const messages: AIMessage[] = [
49-
{
50-
role: "system",
51-
content: `You are an AI assistant inside of a productivity app.
40+
const messages: AIMessage[] = [
41+
{
42+
role: "system",
43+
content: `You are an AI assistant inside of a productivity app.
5244
You respond helpfully to user requests.
5345
You can also create tasks, but should only do so when the user explicitly asks you to.`,
54-
},
55-
...previousActivities
56-
.filter((a) => a.note ?? a.title)
57-
.map(
58-
(prevActivity) =>
59-
({
60-
role:
61-
prevActivity.author.type === AuthorType.Agent
62-
? "assistant"
63-
: "user",
64-
content: (prevActivity.note ?? prevActivity.title)!,
65-
} satisfies AIMessage)
66-
),
67-
];
46+
},
47+
...previousActivities
48+
.filter((a) => a.note ?? a.title)
49+
.map(
50+
(prevActivity) =>
51+
({
52+
role:
53+
prevActivity.author.type === AuthorType.Agent
54+
? "assistant"
55+
: "user",
56+
content: (prevActivity.note ?? prevActivity.title)!,
57+
} satisfies AIMessage)
58+
),
59+
];
6860

69-
const schema = Type.Object({
70-
message: Type.Object({
71-
note: Type.String({ description: "Response to the user's prompt" }),
72-
title: Type.String({
73-
description: "Short title for the response notee",
74-
}),
61+
const schema = Type.Object({
62+
message: Type.Object({
63+
note: Type.String({ description: "Response to the user's prompt" }),
64+
title: Type.String({
65+
description: "Short title for the response notee",
7566
}),
76-
action_items: Type.Optional(
77-
Type.Array(
78-
Type.Object({
79-
note: Type.Optional(
80-
Type.String({
81-
description:
82-
"Optional detailed description of the action item. Can include markdown. Only add when important details are needed beyond the title.",
83-
})
84-
),
85-
title: Type.String({
67+
}),
68+
action_items: Type.Optional(
69+
Type.Array(
70+
Type.Object({
71+
note: Type.Optional(
72+
Type.String({
8673
description:
87-
"Succinct description of the action item (no markdown)",
88-
}),
74+
"Optional detailed description of the action item. Can include markdown. Only add when important details are needed beyond the title.",
75+
})
76+
),
77+
title: Type.String({
78+
description:
79+
"Succinct description of the action item (no markdown)",
8980
}),
90-
{
91-
description: "Tasks to create in response to the user's request.",
92-
}
93-
)
94-
),
95-
});
81+
}),
82+
{
83+
description: "Tasks to create in response to the user's request.",
84+
}
85+
)
86+
),
87+
});
9688

97-
const response = await this.tools.ai.prompt({
98-
model: { speed: "balanced", cost: "low" },
99-
messages,
100-
outputSchema: schema,
101-
});
89+
const response = await this.tools.ai.prompt({
90+
model: { speed: "balanced", cost: "low" },
91+
messages,
92+
outputSchema: schema,
93+
});
10294

103-
await Promise.all([
95+
await Promise.all([
96+
this.tools.plot.createActivity({
97+
title: response.output!.message.title,
98+
note: response.output!.message.note,
99+
parent: activity,
100+
priority: activity.priority,
101+
type: activity.type,
102+
}),
103+
...(response.output!.action_items?.map((item: any) =>
104104
this.tools.plot.createActivity({
105-
title: response.output!.message.title,
106-
note: response.output!.message.note,
105+
title: item.title,
106+
note: item.note,
107107
parent: activity,
108108
priority: activity.priority,
109-
type: activity.type,
110-
}),
111-
...(response.output!.action_items?.map((item: any) =>
112-
this.tools.plot.createActivity({
113-
title: item.title,
114-
note: item.note,
115-
parent: activity,
116-
priority: activity.priority,
117-
type: ActivityType.Task,
118-
start: new Date(),
119-
})
120-
) ?? []),
121-
]);
109+
type: ActivityType.Task,
110+
start: new Date(),
111+
})
112+
) ?? []),
113+
]);
122114

123-
// Remove Thinking tag after response is created
124-
await this.tools.plot.updateActivity({
125-
id: activity.id,
126-
tags: {
127-
[Tag.Agent]: false,
128-
},
129-
});
130-
}
115+
// Remove Thinking tag after response is created
116+
await this.tools.plot.updateActivity({
117+
id: activity.id,
118+
tags: {
119+
[Tag.Agent]: false,
120+
},
121+
});
131122
}
132123
}

agents/events/src/index.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import type {
1313
CalendarTool,
1414
SyncOptions,
1515
} from "@plotday/sdk/common/calendar";
16-
import { Plot } from "@plotday/sdk/tools/plot";
16+
import { ActivityAccess, Plot } from "@plotday/sdk/tools/plot";
1717
import { GoogleCalendar } from "@plotday/tool-google-calendar";
1818
import { OutlookCalendar } from "@plotday/tool-outlook-calendar";
1919

@@ -29,7 +29,11 @@ export default class EventsAgent extends Agent<EventsAgent> {
2929
return {
3030
googleCalendar: build(GoogleCalendar),
3131
outlookCalendar: build(OutlookCalendar),
32-
plot: build(Plot),
32+
plot: build(Plot, {
33+
activity: {
34+
access: ActivityAccess.Create,
35+
},
36+
}),
3337
};
3438
}
3539

sdk/src/tools/agents.ts

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -30,17 +30,28 @@ export type Log = {
3030

3131
/**
3232
* Agent permissions returned after deployment.
33-
* Maps tool names to their respective permission configurations.
33+
* Nested structure mapping domains to entities to permission flags.
34+
*
35+
* Format: { domain: { entity: flags[] } }
36+
* - domain: Tool name (e.g., "network", "plot")
37+
* - entity: Domain-specific identifier (e.g., URL pattern, resource type)
38+
* - flags: Array of permission flags ("read", "write", "update", "use")
3439
*
3540
* @example
3641
* ```typescript
3742
* {
38-
* "Network": { urls: ["https://api.example.com"] },
39-
* "Integrations": { provider: "google" }
43+
* "network": {
44+
* "https://api.example.com/*": ["use"],
45+
* "https://googleapis.com/*": ["use"]
46+
* },
47+
* "plot": {
48+
* "activity:mentioned": ["read", "write", "update"],
49+
* "priority": ["read", "write", "update"]
50+
* }
4051
* }
4152
* ```
4253
*/
43-
export type AgentPermissions = Record<string, object>;
54+
export type AgentPermissions = Record<string, Record<string, string[]>>;
4455

4556
/**
4657
* Built-in tool for managing agents and deployments.

0 commit comments

Comments
 (0)