@slashfi/agents-sdk 0.5.0 → 0.6.0

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.
Files changed (53) hide show
  1. package/dist/agent-definitions/auth.d.ts.map +1 -1
  2. package/dist/agent-definitions/auth.js +16 -3
  3. package/dist/agent-definitions/auth.js.map +1 -1
  4. package/dist/agent-definitions/integrations.d.ts +162 -0
  5. package/dist/agent-definitions/integrations.d.ts.map +1 -0
  6. package/dist/agent-definitions/integrations.js +861 -0
  7. package/dist/agent-definitions/integrations.js.map +1 -0
  8. package/dist/agent-definitions/secrets.d.ts.map +1 -1
  9. package/dist/agent-definitions/secrets.js +8 -25
  10. package/dist/agent-definitions/secrets.js.map +1 -1
  11. package/dist/agent-definitions/users.d.ts +80 -0
  12. package/dist/agent-definitions/users.d.ts.map +1 -0
  13. package/dist/agent-definitions/users.js +397 -0
  14. package/dist/agent-definitions/users.js.map +1 -0
  15. package/dist/crypto.d.ts.map +1 -1
  16. package/dist/crypto.js.map +1 -1
  17. package/dist/define.d.ts +6 -1
  18. package/dist/define.d.ts.map +1 -1
  19. package/dist/define.js +1 -0
  20. package/dist/define.js.map +1 -1
  21. package/dist/index.d.ts +8 -4
  22. package/dist/index.d.ts.map +1 -1
  23. package/dist/index.js +6 -2
  24. package/dist/index.js.map +1 -1
  25. package/dist/jwt.d.ts.map +1 -1
  26. package/dist/jwt.js.map +1 -1
  27. package/dist/server.d.ts +28 -1
  28. package/dist/server.d.ts.map +1 -1
  29. package/dist/server.js +477 -26
  30. package/dist/server.js.map +1 -1
  31. package/dist/slack-oauth.d.ts +27 -0
  32. package/dist/slack-oauth.d.ts.map +1 -0
  33. package/dist/slack-oauth.js +48 -0
  34. package/dist/slack-oauth.js.map +1 -0
  35. package/dist/types.d.ts +66 -0
  36. package/dist/types.d.ts.map +1 -1
  37. package/dist/web-pages.d.ts +8 -0
  38. package/dist/web-pages.d.ts.map +1 -0
  39. package/dist/web-pages.js +169 -0
  40. package/dist/web-pages.js.map +1 -0
  41. package/package.json +2 -1
  42. package/src/agent-definitions/auth.ts +37 -14
  43. package/src/agent-definitions/integrations.ts +1209 -0
  44. package/src/agent-definitions/secrets.ts +24 -30
  45. package/src/agent-definitions/users.ts +533 -0
  46. package/src/crypto.ts +3 -1
  47. package/src/define.ts +8 -0
  48. package/src/index.ts +56 -3
  49. package/src/jwt.ts +7 -5
  50. package/src/server.ts +565 -33
  51. package/src/slack-oauth.ts +66 -0
  52. package/src/types.ts +83 -0
  53. package/src/web-pages.ts +178 -0
@@ -8,7 +8,7 @@
8
8
  * - AES-256-GCM encryption via crypto.ts
9
9
  */
10
10
 
11
- import { encryptSecret, decryptSecret } from "../crypto.js";
11
+ import { decryptSecret, encryptSecret } from "../crypto.js";
12
12
  import { defineAgent, defineTool } from "../define.js";
13
13
  import type { AgentDefinition, ToolContext, ToolDefinition } from "../types.js";
14
14
 
@@ -50,7 +50,8 @@ export function makeSecretRef(id: string): string {
50
50
  function randomSecretId(): string {
51
51
  const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
52
52
  let id = "";
53
- for (let i = 0; i < 24; i++) id += chars[Math.floor(Math.random() * chars.length)];
53
+ for (let i = 0; i < 24; i++)
54
+ id += chars[Math.floor(Math.random() * chars.length)];
54
55
  return id;
55
56
  }
56
57
 
@@ -104,7 +105,8 @@ export function createSecretsAgent(
104
105
 
105
106
  const storeSecretTool = defineTool({
106
107
  name: "store",
107
- description: "Store secret values. Returns secret:<id> refs for each value.",
108
+ description:
109
+ "Store secret values. Returns secret:<id> refs for each value.",
108
110
  visibility: "internal" as const,
109
111
  inputSchema: {
110
112
  type: "object" as const,
@@ -117,7 +119,10 @@ export function createSecretsAgent(
117
119
  },
118
120
  required: ["secrets"],
119
121
  },
120
- execute: async (input: { secrets: Record<string, string> }, ctx: ToolContext) => {
122
+ execute: async (
123
+ input: { secrets: Record<string, string> },
124
+ ctx: ToolContext,
125
+ ) => {
121
126
  const ownerId = ctx.callerId ?? "anonymous";
122
127
  const refs: Record<string, string> = {};
123
128
  for (const [key, value] of Object.entries(input.secrets)) {
@@ -130,27 +135,6 @@ export function createSecretsAgent(
130
135
  },
131
136
  });
132
137
 
133
- const resolveSecretTool = defineTool({
134
- name: "resolve",
135
- description: "Resolve a secret ref to its value. Only accessible to the owner.",
136
- visibility: "internal" as const,
137
- inputSchema: {
138
- type: "object" as const,
139
- properties: {
140
- ref: { type: "string" as const, description: "Secret ref (secret:xxx)" },
141
- },
142
- required: ["ref"],
143
- },
144
- execute: async (input: { ref: string }, ctx: ToolContext) => {
145
- const ownerId = ctx.callerId ?? "anonymous";
146
- const id = getSecretId(input.ref);
147
- const value = await store.resolve(id, ownerId);
148
- if (!value) throw new Error("Secret not found or unauthorized");
149
- // Return wrapped so actor can handle it
150
- return { value: { $agent_type: "secret", value } };
151
- },
152
- });
153
-
154
138
  const revokeSecretTool = defineTool({
155
139
  name: "revoke",
156
140
  description: "Delete a stored secret.",
@@ -172,13 +156,17 @@ export function createSecretsAgent(
172
156
 
173
157
  return defineAgent({
174
158
  path: "@secrets",
175
- entrypoint: "Secret storage agent. Stores, resolves, and manages encrypted secrets.",
159
+ entrypoint:
160
+ "Secret storage agent. Stores, resolves, and manages encrypted secrets.",
176
161
  config: {
177
162
  name: "Secrets",
178
163
  description: "Encrypted secret storage and management",
179
164
  visibility: "internal",
180
165
  },
181
- tools: [storeSecretTool, resolveSecretTool, revokeSecretTool] as ToolDefinition<ToolContext>[],
166
+ tools: [
167
+ storeSecretTool,
168
+ revokeSecretTool,
169
+ ] as ToolDefinition<ToolContext>[],
182
170
  });
183
171
  }
184
172
 
@@ -200,7 +188,10 @@ export async function processSecretParams(
200
188
  schema: { properties?: Record<string, SchemaProperty> } | undefined,
201
189
  secretStore: SecretStore,
202
190
  ownerId: string,
203
- ): Promise<{ resolved: Record<string, unknown>; redacted: Record<string, unknown> }> {
191
+ ): Promise<{
192
+ resolved: Record<string, unknown>;
193
+ redacted: Record<string, unknown>;
194
+ }> {
204
195
  const resolved: Record<string, unknown> = { ...params };
205
196
  const redacted: Record<string, unknown> = { ...params };
206
197
 
@@ -210,7 +201,11 @@ export async function processSecretParams(
210
201
  const value = params[key];
211
202
  if (value === undefined || value === null) continue;
212
203
 
213
- if (schemaProp.type === "object" && typeof value === "object" && !Array.isArray(value)) {
204
+ if (
205
+ schemaProp.type === "object" &&
206
+ typeof value === "object" &&
207
+ !Array.isArray(value)
208
+ ) {
214
209
  const nested = await processSecretParams(
215
210
  value as Record<string, unknown>,
216
211
  schemaProp,
@@ -239,7 +234,6 @@ export async function processSecretParams(
239
234
  const id = await secretStore.store(value, ownerId);
240
235
  resolved[key] = value;
241
236
  redacted[key] = makeSecretRef(id);
242
- continue;
243
237
  }
244
238
  }
245
239
 
@@ -0,0 +1,533 @@
1
+ /**
2
+ * Users Agent (@users)
3
+ *
4
+ * Built-in agent for user and user identity management.
5
+ * Provides user CRUD and identity linking (OAuth providers, SSO, etc.).
6
+ *
7
+ * A User is a human entity. A UserIdentity links a user to an external
8
+ * identity provider (e.g. Google, Slack, GitHub) — one user can have
9
+ * many identities.
10
+ *
11
+ * @example
12
+ * ```typescript
13
+ * import { createAgentRegistry, createUsersAgent } from '@slashfi/agents-sdk';
14
+ *
15
+ * const registry = createAgentRegistry();
16
+ * registry.register(createUsersAgent({
17
+ * store: myUserStore,
18
+ * }));
19
+ * ```
20
+ */
21
+
22
+ import { defineAgent, defineTool } from "../define.js";
23
+ import type { AgentDefinition, ToolContext, ToolDefinition } from "../types.js";
24
+
25
+ // ============================================
26
+ // User Types
27
+ // ============================================
28
+
29
+ export interface User {
30
+ id: string;
31
+ tenantId: string;
32
+ email?: string;
33
+ name?: string;
34
+ avatarUrl?: string;
35
+ metadata?: Record<string, unknown>;
36
+ createdAt: number;
37
+ updatedAt: number;
38
+ }
39
+
40
+ /**
41
+ * A link between a User and an external identity provider.
42
+ * One user can have many identities (e.g. Google + Slack + GitHub).
43
+ */
44
+ export interface UserIdentity {
45
+ id: string;
46
+ userId: string;
47
+ provider: string;
48
+ /** External provider's user ID */
49
+ providerUserId: string;
50
+ /** Display info from the provider */
51
+ email?: string;
52
+ name?: string;
53
+ avatarUrl?: string;
54
+ /** OAuth tokens (encrypted at rest in the store) */
55
+ accessToken?: string;
56
+ refreshToken?: string;
57
+ expiresAt?: number;
58
+ tokenType?: string;
59
+ scopes?: string[];
60
+ metadata?: Record<string, unknown>;
61
+ connectedAt: number;
62
+ updatedAt: number;
63
+ }
64
+
65
+ // ============================================
66
+ // User Store Interface
67
+ // ============================================
68
+
69
+ /**
70
+ * Pluggable storage backend for users and identities.
71
+ */
72
+ export interface UserStore {
73
+ // Users
74
+ createUser(user: Omit<User, "createdAt" | "updatedAt">): Promise<User>;
75
+ getUser(userId: string): Promise<User | null>;
76
+ getUserByEmail(tenantId: string, email: string): Promise<User | null>;
77
+ listUsers(tenantId: string): Promise<User[]>;
78
+ updateUser(
79
+ userId: string,
80
+ updates: Partial<Pick<User, "email" | "name" | "avatarUrl" | "metadata">>,
81
+ ): Promise<User | null>;
82
+ deleteUser(userId: string): Promise<boolean>;
83
+
84
+ // Identities
85
+ createIdentity(
86
+ identity: Omit<UserIdentity, "connectedAt" | "updatedAt">,
87
+ ): Promise<UserIdentity>;
88
+ getIdentity(identityId: string): Promise<UserIdentity | null>;
89
+ getIdentityByProvider(
90
+ userId: string,
91
+ provider: string,
92
+ ): Promise<UserIdentity | null>;
93
+ findIdentityByProviderUserId(
94
+ provider: string,
95
+ providerUserId: string,
96
+ ): Promise<UserIdentity | null>;
97
+ listIdentities(userId: string): Promise<UserIdentity[]>;
98
+ updateIdentity(
99
+ identityId: string,
100
+ updates: Partial<
101
+ Pick<
102
+ UserIdentity,
103
+ | "accessToken"
104
+ | "refreshToken"
105
+ | "expiresAt"
106
+ | "email"
107
+ | "name"
108
+ | "avatarUrl"
109
+ | "metadata"
110
+ >
111
+ >,
112
+ ): Promise<UserIdentity | null>;
113
+ deleteIdentity(identityId: string): Promise<boolean>;
114
+ }
115
+
116
+ // ============================================
117
+ // In-Memory User Store
118
+ // ============================================
119
+
120
+ function generateId(prefix: string): string {
121
+ const chars = "abcdefghijklmnopqrstuvwxyz0123456789";
122
+ let id = prefix;
123
+ for (let i = 0; i < 20; i++) {
124
+ id += chars[Math.floor(Math.random() * chars.length)];
125
+ }
126
+ return id;
127
+ }
128
+
129
+ export function createInMemoryUserStore(): UserStore {
130
+ const users = new Map<string, User>();
131
+ const identities = new Map<string, UserIdentity>();
132
+
133
+ return {
134
+ async createUser(input) {
135
+ const now = Date.now();
136
+ const user: User = { ...input, createdAt: now, updatedAt: now };
137
+ users.set(user.id, user);
138
+ return user;
139
+ },
140
+
141
+ async getUser(userId) {
142
+ return users.get(userId) ?? null;
143
+ },
144
+
145
+ async getUserByEmail(tenantId, email) {
146
+ for (const u of users.values()) {
147
+ if (u.tenantId === tenantId && u.email === email) return u;
148
+ }
149
+ return null;
150
+ },
151
+
152
+ async listUsers(tenantId) {
153
+ return Array.from(users.values()).filter((u) => u.tenantId === tenantId);
154
+ },
155
+
156
+ async updateUser(userId, updates) {
157
+ const user = users.get(userId);
158
+ if (!user) return null;
159
+ const updated = { ...user, ...updates, updatedAt: Date.now() };
160
+ users.set(userId, updated);
161
+ return updated;
162
+ },
163
+
164
+ async deleteUser(userId) {
165
+ // Delete identities too
166
+ for (const [id, identity] of identities) {
167
+ if (identity.userId === userId) identities.delete(id);
168
+ }
169
+ return users.delete(userId);
170
+ },
171
+
172
+ async createIdentity(input) {
173
+ const now = Date.now();
174
+ const identity: UserIdentity = {
175
+ ...input,
176
+ connectedAt: now,
177
+ updatedAt: now,
178
+ };
179
+ identities.set(identity.id, identity);
180
+ return identity;
181
+ },
182
+
183
+ async getIdentity(identityId) {
184
+ return identities.get(identityId) ?? null;
185
+ },
186
+
187
+ async getIdentityByProvider(userId, provider) {
188
+ for (const identity of identities.values()) {
189
+ if (identity.userId === userId && identity.provider === provider)
190
+ return identity;
191
+ }
192
+ return null;
193
+ },
194
+
195
+ async findIdentityByProviderUserId(provider, providerUserId) {
196
+ for (const identity of identities.values()) {
197
+ if (
198
+ identity.provider === provider &&
199
+ identity.providerUserId === providerUserId
200
+ )
201
+ return identity;
202
+ }
203
+ return null;
204
+ },
205
+
206
+ async listIdentities(userId) {
207
+ return Array.from(identities.values()).filter((i) => i.userId === userId);
208
+ },
209
+
210
+ async updateIdentity(identityId, updates) {
211
+ const identity = identities.get(identityId);
212
+ if (!identity) return null;
213
+ const updated = { ...identity, ...updates, updatedAt: Date.now() };
214
+ identities.set(identityId, updated);
215
+ return updated;
216
+ },
217
+
218
+ async deleteIdentity(identityId) {
219
+ return identities.delete(identityId);
220
+ },
221
+ };
222
+ }
223
+
224
+ // ============================================
225
+ // Create Users Agent
226
+ // ============================================
227
+
228
+ export interface UsersAgentOptions {
229
+ /** User store backend */
230
+ store: UserStore;
231
+ }
232
+
233
+ export function createUsersAgent(options: UsersAgentOptions): AgentDefinition {
234
+ const { store } = options;
235
+
236
+ // ---- create_user ----
237
+ const createUserTool = defineTool({
238
+ name: "create_user",
239
+ description: "Create a new user.",
240
+ visibility: "public" as const,
241
+ inputSchema: {
242
+ type: "object" as const,
243
+ properties: {
244
+ id: {
245
+ type: "string",
246
+ description: "User ID (optional, auto-generated if omitted)",
247
+ },
248
+ tenantId: { type: "string", description: "Tenant ID" },
249
+ email: { type: "string", description: "Email address" },
250
+ name: { type: "string", description: "Display name" },
251
+ avatarUrl: { type: "string", description: "Avatar URL" },
252
+ metadata: { type: "object", description: "Additional metadata" },
253
+ },
254
+ required: ["tenantId"],
255
+ },
256
+ execute: async (input: any, __ctx: ToolContext) => {
257
+ const user = await store.createUser({
258
+ id: input.id ?? generateId("user_"),
259
+ tenantId: input.tenantId,
260
+ email: input.email,
261
+ name: input.name,
262
+ avatarUrl: input.avatarUrl,
263
+ metadata: input.metadata,
264
+ });
265
+ return { success: true, user };
266
+ },
267
+ });
268
+
269
+ // ---- get_user ----
270
+ const getUserTool = defineTool({
271
+ name: "get_user",
272
+ description: "Get a user by ID.",
273
+ visibility: "public" as const,
274
+ inputSchema: {
275
+ type: "object" as const,
276
+ properties: {
277
+ userId: { type: "string", description: "User ID" },
278
+ },
279
+ required: ["userId"],
280
+ },
281
+ execute: async (input: { userId: string }, __ctx: ToolContext) => {
282
+ const user = await store.getUser(input.userId);
283
+ if (!user) return { error: `User '${input.userId}' not found` };
284
+ return { user };
285
+ },
286
+ });
287
+
288
+ // ---- list_users ----
289
+ const listUsersTool = defineTool({
290
+ name: "list_users",
291
+ description: "List users in a tenant.",
292
+ visibility: "public" as const,
293
+ inputSchema: {
294
+ type: "object" as const,
295
+ properties: {
296
+ tenantId: { type: "string", description: "Tenant ID" },
297
+ },
298
+ required: ["tenantId"],
299
+ },
300
+ execute: async (input: { tenantId: string }, __ctx: ToolContext) => {
301
+ const users = await store.listUsers(input.tenantId);
302
+ return { users };
303
+ },
304
+ });
305
+
306
+ // ---- update_user ----
307
+ const updateUserTool = defineTool({
308
+ name: "update_user",
309
+ description: "Update a user's profile.",
310
+ visibility: "public" as const,
311
+ inputSchema: {
312
+ type: "object" as const,
313
+ properties: {
314
+ userId: { type: "string", description: "User ID" },
315
+ email: { type: "string", description: "New email" },
316
+ name: { type: "string", description: "New name" },
317
+ avatarUrl: { type: "string", description: "New avatar URL" },
318
+ metadata: { type: "object", description: "New metadata (merged)" },
319
+ },
320
+ required: ["userId"],
321
+ },
322
+ execute: async (input: any, __ctx: ToolContext) => {
323
+ const { userId, ...updates } = input;
324
+ const user = await store.updateUser(userId, updates);
325
+ if (!user) return { error: `User '${userId}' not found` };
326
+ return { success: true, user };
327
+ },
328
+ });
329
+
330
+ // ---- link_identity ----
331
+ const linkIdentityTool = defineTool({
332
+ name: "link_identity",
333
+ description:
334
+ "Link an external identity (OAuth provider) to a user. " +
335
+ "Creates a UserIdentity record associating the user with a provider account.",
336
+ visibility: "public" as const,
337
+ inputSchema: {
338
+ type: "object" as const,
339
+ properties: {
340
+ userId: { type: "string", description: "User ID to link to" },
341
+ provider: {
342
+ type: "string",
343
+ description: "Provider name (e.g. 'google', 'slack', 'github')",
344
+ },
345
+ providerUserId: {
346
+ type: "string",
347
+ description: "The user's ID in the external provider",
348
+ },
349
+ email: { type: "string", description: "Email from the provider" },
350
+ name: { type: "string", description: "Name from the provider" },
351
+ avatarUrl: {
352
+ type: "string",
353
+ description: "Avatar URL from the provider",
354
+ },
355
+ accessToken: { type: "string", description: "OAuth access token" },
356
+ refreshToken: { type: "string", description: "OAuth refresh token" },
357
+ expiresAt: {
358
+ type: "number",
359
+ description: "Token expiry timestamp (ms)",
360
+ },
361
+ scopes: {
362
+ type: "array",
363
+ items: { type: "string" },
364
+ description: "Granted scopes",
365
+ },
366
+ metadata: {
367
+ type: "object",
368
+ description: "Additional provider-specific data",
369
+ },
370
+ },
371
+ required: ["userId", "provider", "providerUserId"],
372
+ },
373
+ execute: async (input: any, __ctx: ToolContext) => {
374
+ // Check if identity already exists
375
+ const existing = await store.getIdentityByProvider(
376
+ input.userId,
377
+ input.provider,
378
+ );
379
+ if (existing) {
380
+ // Update existing
381
+ const updated = await store.updateIdentity(existing.id, {
382
+ accessToken: input.accessToken,
383
+ refreshToken: input.refreshToken,
384
+ expiresAt: input.expiresAt,
385
+ email: input.email,
386
+ name: input.name,
387
+ avatarUrl: input.avatarUrl,
388
+ metadata: input.metadata,
389
+ });
390
+ return { success: true, identity: updated, updated: true };
391
+ }
392
+
393
+ const identity = await store.createIdentity({
394
+ id: generateId("ident_"),
395
+ userId: input.userId,
396
+ provider: input.provider,
397
+ providerUserId: input.providerUserId,
398
+ email: input.email,
399
+ name: input.name,
400
+ avatarUrl: input.avatarUrl,
401
+ accessToken: input.accessToken,
402
+ refreshToken: input.refreshToken,
403
+ expiresAt: input.expiresAt,
404
+ tokenType: input.tokenType,
405
+ scopes: input.scopes,
406
+ metadata: input.metadata,
407
+ });
408
+ return { success: true, identity, created: true };
409
+ },
410
+ });
411
+
412
+ // ---- list_identities ----
413
+ const listIdentitiesTool = defineTool({
414
+ name: "list_identities",
415
+ description: "List all linked identities for a user.",
416
+ visibility: "public" as const,
417
+ inputSchema: {
418
+ type: "object" as const,
419
+ properties: {
420
+ userId: { type: "string", description: "User ID" },
421
+ },
422
+ required: ["userId"],
423
+ },
424
+ execute: async (input: { userId: string }, __ctx: ToolContext) => {
425
+ const identities = await store.listIdentities(input.userId);
426
+ return {
427
+ identities: identities.map((i) => ({
428
+ id: i.id,
429
+ provider: i.provider,
430
+ providerUserId: i.providerUserId,
431
+ email: i.email,
432
+ name: i.name,
433
+ connectedAt: i.connectedAt,
434
+ hasAccessToken: !!i.accessToken,
435
+ expiresAt: i.expiresAt,
436
+ })),
437
+ };
438
+ },
439
+ });
440
+
441
+ // ---- unlink_identity ----
442
+ const unlinkIdentityTool = defineTool({
443
+ name: "unlink_identity",
444
+ description: "Remove a linked identity from a user.",
445
+ visibility: "public" as const,
446
+ inputSchema: {
447
+ type: "object" as const,
448
+ properties: {
449
+ identityId: { type: "string", description: "Identity ID to unlink" },
450
+ },
451
+ required: ["identityId"],
452
+ },
453
+ execute: async (input: { identityId: string }, __ctx: ToolContext) => {
454
+ const deleted = await store.deleteIdentity(input.identityId);
455
+ return { success: deleted };
456
+ },
457
+ });
458
+
459
+ // ---- resolve_identity ----
460
+ const resolveIdentityTool = defineTool({
461
+ name: "resolve_identity",
462
+ description:
463
+ "Find a user by their external provider identity. " +
464
+ "Useful for login flows — given a provider + providerUserId, find the linked user.",
465
+ visibility: "public" as const,
466
+ inputSchema: {
467
+ type: "object" as const,
468
+ properties: {
469
+ provider: {
470
+ type: "string",
471
+ description: "Provider name (e.g. 'google')",
472
+ },
473
+ providerUserId: {
474
+ type: "string",
475
+ description: "External user ID from the provider",
476
+ },
477
+ },
478
+ required: ["provider", "providerUserId"],
479
+ },
480
+ execute: async (
481
+ input: { provider: string; providerUserId: string },
482
+ __ctx: ToolContext,
483
+ ) => {
484
+ const identity = await store.findIdentityByProviderUserId(
485
+ input.provider,
486
+ input.providerUserId,
487
+ );
488
+ if (!identity) return { found: false };
489
+
490
+ const user = await store.getUser(identity.userId);
491
+ return {
492
+ found: true,
493
+ user: user
494
+ ? {
495
+ id: user.id,
496
+ email: user.email,
497
+ name: user.name,
498
+ tenantId: user.tenantId,
499
+ }
500
+ : null,
501
+ identity: {
502
+ id: identity.id,
503
+ provider: identity.provider,
504
+ providerUserId: identity.providerUserId,
505
+ email: identity.email,
506
+ },
507
+ };
508
+ },
509
+ });
510
+
511
+ return defineAgent({
512
+ path: "@users",
513
+ entrypoint:
514
+ "You are the users agent. You manage user accounts and their linked external identities " +
515
+ "(OAuth providers like Google, Slack, GitHub, etc.).",
516
+ config: {
517
+ name: "Users",
518
+ description: "User and identity management",
519
+ supportedActions: ["execute_tool", "describe_tools", "load"],
520
+ },
521
+ visibility: "public",
522
+ tools: [
523
+ createUserTool,
524
+ getUserTool,
525
+ listUsersTool,
526
+ updateUserTool,
527
+ linkIdentityTool,
528
+ listIdentitiesTool,
529
+ unlinkIdentityTool,
530
+ resolveIdentityTool,
531
+ ] as ToolDefinition[],
532
+ });
533
+ }
package/src/crypto.ts CHANGED
@@ -43,7 +43,9 @@ export async function encryptSecret(
43
43
  key,
44
44
  encoder.encode(plaintext),
45
45
  );
46
- const combined = new Uint8Array(iv.length + new Uint8Array(ciphertext).length);
46
+ const combined = new Uint8Array(
47
+ iv.length + new Uint8Array(ciphertext).length,
48
+ );
47
49
  combined.set(iv);
48
50
  combined.set(new Uint8Array(ciphertext), iv.length);
49
51
  return btoa(String.fromCharCode(...combined));
package/src/define.ts CHANGED
@@ -8,6 +8,7 @@ import type {
8
8
  AgentConfig,
9
9
  AgentDefinition,
10
10
  AgentRuntime,
11
+ IntegrationMethods,
11
12
  JsonSchema,
12
13
  ToolContext,
13
14
  ToolDefinition,
@@ -112,6 +113,12 @@ export interface DefineAgentOptions<
112
113
 
113
114
  /** Explicit allowed callers */
114
115
  allowedCallers?: string[];
116
+
117
+ /**
118
+ * Integration method callbacks.
119
+ * Implement these when this agent acts as an integration.
120
+ */
121
+ integrationMethods?: IntegrationMethods;
115
122
  }
116
123
 
117
124
  /**
@@ -149,5 +156,6 @@ export function defineAgent<TContext extends ToolContext = ToolContext>(
149
156
  runtime: options.runtime,
150
157
  visibility: options.visibility,
151
158
  allowedCallers: options.allowedCallers,
159
+ integrationMethods: options.integrationMethods,
152
160
  };
153
161
  }