@slates-integrations/anthropic 0.2.0-rc.5
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.
- package/README.md +53 -0
- package/docs/SPEC.md +113 -0
- package/logo.png +0 -0
- package/package.json +19 -0
- package/slate.json +22 -0
- package/src/auth.ts +24 -0
- package/src/config.ts +8 -0
- package/src/index.ts +33 -0
- package/src/lib/client.ts +632 -0
- package/src/lib/errors.ts +74 -0
- package/src/spec.ts +13 -0
- package/src/tools/count-tokens.ts +74 -0
- package/src/tools/get-organization.ts +36 -0
- package/src/tools/get-usage-report.ts +141 -0
- package/src/tools/index.ts +10 -0
- package/src/tools/list-models.ts +84 -0
- package/src/tools/manage-api-keys.ts +94 -0
- package/src/tools/manage-files.ts +149 -0
- package/src/tools/manage-message-batch.ts +132 -0
- package/src/tools/manage-organization-members.ts +149 -0
- package/src/tools/manage-workspaces.ts +219 -0
- package/src/tools/send-message.ts +196 -0
- package/src/triggers/inbound-webhook.ts +67 -0
- package/src/triggers/index.ts +3 -0
- package/tsconfig.json +23 -0
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { SlateTool } from 'slates';
|
|
2
|
+
import { AnthropicClient } from '../lib/client';
|
|
3
|
+
import { anthropicServiceError } from '../lib/errors';
|
|
4
|
+
import { spec } from '../spec';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
let batchRequestSchema = z.object({
|
|
8
|
+
customId: z.string().describe('Unique identifier for matching results to this request'),
|
|
9
|
+
params: z
|
|
10
|
+
.record(z.string(), z.unknown())
|
|
11
|
+
.describe('Standard Messages API parameters (model, max_tokens, messages, etc.)')
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
let requestCountsSchema = z
|
|
15
|
+
.object({
|
|
16
|
+
processing: z.number(),
|
|
17
|
+
succeeded: z.number(),
|
|
18
|
+
errored: z.number(),
|
|
19
|
+
canceled: z.number(),
|
|
20
|
+
expired: z.number()
|
|
21
|
+
})
|
|
22
|
+
.optional();
|
|
23
|
+
|
|
24
|
+
let batchOutputSchema = z.object({
|
|
25
|
+
batchId: z.string().describe('Batch ID'),
|
|
26
|
+
type: z.string().optional(),
|
|
27
|
+
processingStatus: z
|
|
28
|
+
.string()
|
|
29
|
+
.optional()
|
|
30
|
+
.describe('Current status: queued, in_progress, succeeded, failed, expired, canceled'),
|
|
31
|
+
requestCounts: requestCountsSchema.describe('Counts of requests by status'),
|
|
32
|
+
createdAt: z.string().optional().describe('ISO 8601 creation timestamp'),
|
|
33
|
+
updatedAt: z.string().optional().describe('ISO 8601 last update timestamp'),
|
|
34
|
+
expiresAt: z.string().optional().describe('ISO 8601 expiration timestamp'),
|
|
35
|
+
resultsUrl: z.string().optional().describe('URL to download batch results when complete')
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
export let manageMessageBatch = SlateTool.create(spec, {
|
|
39
|
+
name: 'Manage Message Batch',
|
|
40
|
+
key: 'manage_message_batch',
|
|
41
|
+
description: `Create, retrieve, list, or cancel message batches for asynchronous processing. Batches allow processing large volumes of messages at reduced cost (up to 24 hours).
|
|
42
|
+
Use **action** to specify the operation: "create", "get", "list", or "cancel".`,
|
|
43
|
+
instructions: [
|
|
44
|
+
'For "create": provide requests array with customId and params for each message.',
|
|
45
|
+
'For "get": provide batchId to check status and retrieve the results URL.',
|
|
46
|
+
'For "cancel": provide batchId to cancel an in-progress batch.',
|
|
47
|
+
'For "list": optionally provide limit and afterId for pagination.'
|
|
48
|
+
],
|
|
49
|
+
tags: {
|
|
50
|
+
destructive: false,
|
|
51
|
+
readOnly: false
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
.input(
|
|
55
|
+
z.object({
|
|
56
|
+
action: z.enum(['create', 'get', 'list', 'cancel']).describe('Operation to perform'),
|
|
57
|
+
batchId: z.string().optional().describe('Batch ID (required for "get" and "cancel")'),
|
|
58
|
+
requests: z
|
|
59
|
+
.array(batchRequestSchema)
|
|
60
|
+
.optional()
|
|
61
|
+
.describe('Batch requests (required for "create")'),
|
|
62
|
+
limit: z.number().optional().describe('Max results to return (for "list")'),
|
|
63
|
+
afterId: z.string().optional().describe('Pagination cursor after this batch ID'),
|
|
64
|
+
beforeId: z.string().optional().describe('Pagination cursor before this batch ID'),
|
|
65
|
+
betaHeaders: z
|
|
66
|
+
.array(z.string())
|
|
67
|
+
.optional()
|
|
68
|
+
.describe('Anthropic beta headers to send when creating the batch')
|
|
69
|
+
})
|
|
70
|
+
)
|
|
71
|
+
.output(
|
|
72
|
+
z.object({
|
|
73
|
+
batch: batchOutputSchema
|
|
74
|
+
.optional()
|
|
75
|
+
.describe('Single batch result (for create, get, cancel)'),
|
|
76
|
+
batches: z.array(batchOutputSchema).optional().describe('List of batches (for list)'),
|
|
77
|
+
hasMore: z.boolean().optional().describe('Whether more results are available')
|
|
78
|
+
})
|
|
79
|
+
)
|
|
80
|
+
.handleInvocation(async ctx => {
|
|
81
|
+
let client = new AnthropicClient({
|
|
82
|
+
token: ctx.auth.token,
|
|
83
|
+
apiVersion: ctx.config.apiVersion
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
let { action } = ctx.input;
|
|
87
|
+
|
|
88
|
+
if (action === 'create') {
|
|
89
|
+
if (!ctx.input.requests || ctx.input.requests.length === 0) {
|
|
90
|
+
throw anthropicServiceError('requests array is required for "create" action');
|
|
91
|
+
}
|
|
92
|
+
let batch = await client.createMessageBatch(ctx.input.requests, ctx.input.betaHeaders);
|
|
93
|
+
return {
|
|
94
|
+
output: { batch, batches: undefined, hasMore: undefined },
|
|
95
|
+
message: `Created message batch **${batch.batchId}** with **${ctx.input.requests.length}** request(s).`
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
if (action === 'get') {
|
|
100
|
+
if (!ctx.input.batchId) {
|
|
101
|
+
throw anthropicServiceError('batchId is required for "get" action');
|
|
102
|
+
}
|
|
103
|
+
let batch = await client.getMessageBatch(ctx.input.batchId);
|
|
104
|
+
return {
|
|
105
|
+
output: { batch, batches: undefined, hasMore: undefined },
|
|
106
|
+
message: `Batch **${batch.batchId}** status: **${batch.processingStatus}**.`
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
if (action === 'list') {
|
|
111
|
+
let result = await client.listMessageBatches({
|
|
112
|
+
limit: ctx.input.limit,
|
|
113
|
+
afterId: ctx.input.afterId,
|
|
114
|
+
beforeId: ctx.input.beforeId
|
|
115
|
+
});
|
|
116
|
+
return {
|
|
117
|
+
output: { batch: undefined, batches: result.batches, hasMore: result.hasMore },
|
|
118
|
+
message: `Found **${result.batches.length}** batch(es).${result.hasMore ? ' More available with pagination.' : ''}`
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// cancel
|
|
123
|
+
if (!ctx.input.batchId) {
|
|
124
|
+
throw anthropicServiceError('batchId is required for "cancel" action');
|
|
125
|
+
}
|
|
126
|
+
let batch = await client.cancelMessageBatch(ctx.input.batchId);
|
|
127
|
+
return {
|
|
128
|
+
output: { batch, batches: undefined, hasMore: undefined },
|
|
129
|
+
message: `Cancelled batch **${batch.batchId}**.`
|
|
130
|
+
};
|
|
131
|
+
})
|
|
132
|
+
.build();
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { SlateTool } from 'slates';
|
|
2
|
+
import { AnthropicClient } from '../lib/client';
|
|
3
|
+
import { anthropicServiceError } from '../lib/errors';
|
|
4
|
+
import { spec } from '../spec';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
export let manageOrganizationMembers = SlateTool.create(spec, {
|
|
8
|
+
name: 'Manage Organization Members',
|
|
9
|
+
key: 'manage_organization_members',
|
|
10
|
+
description: `Manage organization members and invites via the Admin API. List members, update roles, remove members, or manage invitations.
|
|
11
|
+
Use **action** to specify the operation. Requires an Admin API key (sk-ant-admin...).`,
|
|
12
|
+
instructions: [
|
|
13
|
+
'For "list_members": optionally pass limit and afterId for pagination.',
|
|
14
|
+
'For "update_member": provide userId and role.',
|
|
15
|
+
'For "remove_member": provide userId.',
|
|
16
|
+
'For "invite": provide email and role.',
|
|
17
|
+
'For "list_invites": optionally pass limit and afterId for pagination.',
|
|
18
|
+
'For "get_invite": provide inviteId.',
|
|
19
|
+
'For "delete_invite": provide inviteId.'
|
|
20
|
+
],
|
|
21
|
+
constraints: [
|
|
22
|
+
'Requires an Admin API key (sk-ant-admin...).',
|
|
23
|
+
'Only organization admins can use this tool.'
|
|
24
|
+
],
|
|
25
|
+
tags: {
|
|
26
|
+
destructive: true,
|
|
27
|
+
readOnly: false
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
.input(
|
|
31
|
+
z.object({
|
|
32
|
+
action: z
|
|
33
|
+
.enum([
|
|
34
|
+
'list_members',
|
|
35
|
+
'update_member',
|
|
36
|
+
'remove_member',
|
|
37
|
+
'invite',
|
|
38
|
+
'list_invites',
|
|
39
|
+
'get_invite',
|
|
40
|
+
'delete_invite'
|
|
41
|
+
])
|
|
42
|
+
.describe('Operation to perform'),
|
|
43
|
+
userId: z.string().optional().describe('User ID (for update_member, remove_member)'),
|
|
44
|
+
inviteId: z.string().optional().describe('Invite ID (for delete_invite)'),
|
|
45
|
+
email: z.string().optional().describe('Email address (for invite)'),
|
|
46
|
+
role: z.string().optional().describe('Organization role (for update_member, invite)'),
|
|
47
|
+
limit: z.number().optional().describe('Max results (for list operations)'),
|
|
48
|
+
afterId: z.string().optional().describe('Pagination cursor (for list operations)')
|
|
49
|
+
})
|
|
50
|
+
)
|
|
51
|
+
.output(
|
|
52
|
+
z.object({
|
|
53
|
+
members: z
|
|
54
|
+
.array(z.record(z.string(), z.unknown()))
|
|
55
|
+
.optional()
|
|
56
|
+
.describe('List of organization members'),
|
|
57
|
+
invites: z
|
|
58
|
+
.array(z.record(z.string(), z.unknown()))
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('List of invitations'),
|
|
61
|
+
invite: z.record(z.string(), z.unknown()).optional().describe('Invitation details'),
|
|
62
|
+
member: z
|
|
63
|
+
.record(z.string(), z.unknown())
|
|
64
|
+
.optional()
|
|
65
|
+
.describe('Updated or invited member details'),
|
|
66
|
+
hasMore: z.boolean().optional().describe('Whether more results are available'),
|
|
67
|
+
success: z.boolean().optional().describe('Whether a delete/remove operation succeeded')
|
|
68
|
+
})
|
|
69
|
+
)
|
|
70
|
+
.handleInvocation(async ctx => {
|
|
71
|
+
let client = new AnthropicClient({
|
|
72
|
+
token: ctx.auth.token,
|
|
73
|
+
apiVersion: ctx.config.apiVersion
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
switch (ctx.input.action) {
|
|
77
|
+
case 'list_members': {
|
|
78
|
+
let result = await client.listMembers({
|
|
79
|
+
limit: ctx.input.limit,
|
|
80
|
+
afterId: ctx.input.afterId
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
output: { members: result.members, hasMore: result.hasMore },
|
|
84
|
+
message: `Found **${result.members.length}** organization member(s).`
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
case 'update_member': {
|
|
88
|
+
if (!ctx.input.userId || !ctx.input.role) {
|
|
89
|
+
throw anthropicServiceError('userId and role are required for "update_member"');
|
|
90
|
+
}
|
|
91
|
+
let member = await client.updateMember(ctx.input.userId, ctx.input.role);
|
|
92
|
+
return {
|
|
93
|
+
output: { member },
|
|
94
|
+
message: `Updated member **${ctx.input.userId}** to role **${ctx.input.role}**.`
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
case 'remove_member': {
|
|
98
|
+
if (!ctx.input.userId) {
|
|
99
|
+
throw anthropicServiceError('userId is required for "remove_member"');
|
|
100
|
+
}
|
|
101
|
+
await client.removeMember(ctx.input.userId);
|
|
102
|
+
return {
|
|
103
|
+
output: { success: true },
|
|
104
|
+
message: `Removed member **${ctx.input.userId}** from the organization.`
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
case 'invite': {
|
|
108
|
+
if (!ctx.input.email || !ctx.input.role) {
|
|
109
|
+
throw anthropicServiceError('email and role are required for "invite"');
|
|
110
|
+
}
|
|
111
|
+
let member = await client.createInvite(ctx.input.email, ctx.input.role);
|
|
112
|
+
return {
|
|
113
|
+
output: { member },
|
|
114
|
+
message: `Invited **${ctx.input.email}** with role **${ctx.input.role}**.`
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
case 'list_invites': {
|
|
118
|
+
let result = await client.listInvites({
|
|
119
|
+
limit: ctx.input.limit,
|
|
120
|
+
afterId: ctx.input.afterId
|
|
121
|
+
});
|
|
122
|
+
return {
|
|
123
|
+
output: { invites: result.invites, hasMore: result.hasMore },
|
|
124
|
+
message: `Found **${result.invites.length}** invitation(s).`
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
case 'get_invite': {
|
|
128
|
+
if (!ctx.input.inviteId) {
|
|
129
|
+
throw anthropicServiceError('inviteId is required for "get_invite"');
|
|
130
|
+
}
|
|
131
|
+
let invite = await client.getInvite(ctx.input.inviteId);
|
|
132
|
+
return {
|
|
133
|
+
output: { invite },
|
|
134
|
+
message: `Retrieved invite **${ctx.input.inviteId}**.`
|
|
135
|
+
};
|
|
136
|
+
}
|
|
137
|
+
case 'delete_invite': {
|
|
138
|
+
if (!ctx.input.inviteId) {
|
|
139
|
+
throw anthropicServiceError('inviteId is required for "delete_invite"');
|
|
140
|
+
}
|
|
141
|
+
await client.deleteInvite(ctx.input.inviteId);
|
|
142
|
+
return {
|
|
143
|
+
output: { success: true },
|
|
144
|
+
message: `Deleted invite **${ctx.input.inviteId}**.`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
})
|
|
149
|
+
.build();
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
import { SlateTool } from 'slates';
|
|
2
|
+
import { AnthropicClient } from '../lib/client';
|
|
3
|
+
import { anthropicServiceError } from '../lib/errors';
|
|
4
|
+
import { spec } from '../spec';
|
|
5
|
+
import { z } from 'zod';
|
|
6
|
+
|
|
7
|
+
export let manageWorkspaces = SlateTool.create(spec, {
|
|
8
|
+
name: 'Manage Workspaces',
|
|
9
|
+
key: 'manage_workspaces',
|
|
10
|
+
description: `Manage organization workspaces and their members via the Admin API. Create, list, update, archive workspaces, and manage workspace membership.
|
|
11
|
+
Use **action** to specify the operation. Requires an Admin API key (sk-ant-admin...).`,
|
|
12
|
+
instructions: [
|
|
13
|
+
'For "create": provide workspaceName.',
|
|
14
|
+
'For "list": optionally provide limit, afterId, and includeArchived.',
|
|
15
|
+
'For "get": provide workspaceId.',
|
|
16
|
+
'For "update": provide workspaceId and workspaceName.',
|
|
17
|
+
'For "archive": provide workspaceId.',
|
|
18
|
+
'For "add_member": provide workspaceId, userId, and workspaceRole.',
|
|
19
|
+
'For "list_members": provide workspaceId.',
|
|
20
|
+
'For "get_member": provide workspaceId and userId.',
|
|
21
|
+
'For "update_member": provide workspaceId, userId, and workspaceRole.',
|
|
22
|
+
'For "remove_member": provide workspaceId and userId.'
|
|
23
|
+
],
|
|
24
|
+
constraints: ['Requires an Admin API key (sk-ant-admin...).'],
|
|
25
|
+
tags: {
|
|
26
|
+
destructive: true,
|
|
27
|
+
readOnly: false
|
|
28
|
+
}
|
|
29
|
+
})
|
|
30
|
+
.input(
|
|
31
|
+
z.object({
|
|
32
|
+
action: z
|
|
33
|
+
.enum([
|
|
34
|
+
'create',
|
|
35
|
+
'list',
|
|
36
|
+
'get',
|
|
37
|
+
'update',
|
|
38
|
+
'archive',
|
|
39
|
+
'add_member',
|
|
40
|
+
'list_members',
|
|
41
|
+
'get_member',
|
|
42
|
+
'update_member',
|
|
43
|
+
'remove_member'
|
|
44
|
+
])
|
|
45
|
+
.describe('Operation to perform'),
|
|
46
|
+
workspaceId: z
|
|
47
|
+
.string()
|
|
48
|
+
.optional()
|
|
49
|
+
.describe('Workspace ID (required for most operations except create and list)'),
|
|
50
|
+
workspaceName: z.string().optional().describe('Workspace name (for create, update)'),
|
|
51
|
+
userId: z.string().optional().describe('User ID (for member operations)'),
|
|
52
|
+
workspaceRole: z
|
|
53
|
+
.enum([
|
|
54
|
+
'workspace_user',
|
|
55
|
+
'workspace_developer',
|
|
56
|
+
'workspace_admin',
|
|
57
|
+
'workspace_billing'
|
|
58
|
+
])
|
|
59
|
+
.optional()
|
|
60
|
+
.describe('Workspace role (for add_member, update_member)'),
|
|
61
|
+
includeArchived: z
|
|
62
|
+
.boolean()
|
|
63
|
+
.optional()
|
|
64
|
+
.describe('Include archived workspaces in list results'),
|
|
65
|
+
limit: z.number().optional().describe('Max results for list operations'),
|
|
66
|
+
afterId: z.string().optional().describe('Pagination cursor for list operations')
|
|
67
|
+
})
|
|
68
|
+
)
|
|
69
|
+
.output(
|
|
70
|
+
z.object({
|
|
71
|
+
workspace: z.record(z.string(), z.unknown()).optional().describe('Workspace details'),
|
|
72
|
+
workspaces: z
|
|
73
|
+
.array(z.record(z.string(), z.unknown()))
|
|
74
|
+
.optional()
|
|
75
|
+
.describe('List of workspaces'),
|
|
76
|
+
member: z
|
|
77
|
+
.record(z.string(), z.unknown())
|
|
78
|
+
.optional()
|
|
79
|
+
.describe('Workspace member details'),
|
|
80
|
+
members: z
|
|
81
|
+
.array(z.record(z.string(), z.unknown()))
|
|
82
|
+
.optional()
|
|
83
|
+
.describe('List of workspace members'),
|
|
84
|
+
hasMore: z.boolean().optional().describe('Whether more results are available'),
|
|
85
|
+
success: z.boolean().optional().describe('Whether a remove/archive operation succeeded')
|
|
86
|
+
})
|
|
87
|
+
)
|
|
88
|
+
.handleInvocation(async ctx => {
|
|
89
|
+
let client = new AnthropicClient({
|
|
90
|
+
token: ctx.auth.token,
|
|
91
|
+
apiVersion: ctx.config.apiVersion
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
switch (ctx.input.action) {
|
|
95
|
+
case 'create': {
|
|
96
|
+
if (!ctx.input.workspaceName) {
|
|
97
|
+
throw anthropicServiceError('workspaceName is required for "create"');
|
|
98
|
+
}
|
|
99
|
+
let workspace = await client.createWorkspace(ctx.input.workspaceName);
|
|
100
|
+
return {
|
|
101
|
+
output: { workspace },
|
|
102
|
+
message: `Created workspace **${ctx.input.workspaceName}**.`
|
|
103
|
+
};
|
|
104
|
+
}
|
|
105
|
+
case 'list': {
|
|
106
|
+
let result = await client.listWorkspaces({
|
|
107
|
+
limit: ctx.input.limit,
|
|
108
|
+
afterId: ctx.input.afterId,
|
|
109
|
+
includeArchived: ctx.input.includeArchived
|
|
110
|
+
});
|
|
111
|
+
return {
|
|
112
|
+
output: { workspaces: result.workspaces, hasMore: result.hasMore },
|
|
113
|
+
message: `Found **${result.workspaces.length}** workspace(s).`
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
case 'get': {
|
|
117
|
+
if (!ctx.input.workspaceId) {
|
|
118
|
+
throw anthropicServiceError('workspaceId is required for "get"');
|
|
119
|
+
}
|
|
120
|
+
let workspace = await client.getWorkspace(ctx.input.workspaceId);
|
|
121
|
+
return {
|
|
122
|
+
output: { workspace },
|
|
123
|
+
message: `Retrieved workspace **${ctx.input.workspaceId}**.`
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
case 'update': {
|
|
127
|
+
if (!ctx.input.workspaceId || !ctx.input.workspaceName) {
|
|
128
|
+
throw anthropicServiceError(
|
|
129
|
+
'workspaceId and workspaceName are required for "update"'
|
|
130
|
+
);
|
|
131
|
+
}
|
|
132
|
+
let workspace = await client.updateWorkspace(ctx.input.workspaceId, {
|
|
133
|
+
name: ctx.input.workspaceName
|
|
134
|
+
});
|
|
135
|
+
return {
|
|
136
|
+
output: { workspace },
|
|
137
|
+
message: `Updated workspace **${ctx.input.workspaceId}** name to **${ctx.input.workspaceName}**.`
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
case 'archive': {
|
|
141
|
+
if (!ctx.input.workspaceId) {
|
|
142
|
+
throw anthropicServiceError('workspaceId is required for "archive"');
|
|
143
|
+
}
|
|
144
|
+
await client.archiveWorkspace(ctx.input.workspaceId);
|
|
145
|
+
return {
|
|
146
|
+
output: { success: true },
|
|
147
|
+
message: `Archived workspace **${ctx.input.workspaceId}**.`
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
case 'add_member': {
|
|
151
|
+
if (!ctx.input.workspaceId || !ctx.input.userId || !ctx.input.workspaceRole) {
|
|
152
|
+
throw anthropicServiceError(
|
|
153
|
+
'workspaceId, userId, and workspaceRole are required for "add_member"'
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
let member = await client.addWorkspaceMember(
|
|
157
|
+
ctx.input.workspaceId,
|
|
158
|
+
ctx.input.userId,
|
|
159
|
+
ctx.input.workspaceRole
|
|
160
|
+
);
|
|
161
|
+
return {
|
|
162
|
+
output: { member },
|
|
163
|
+
message: `Added **${ctx.input.userId}** to workspace **${ctx.input.workspaceId}** as **${ctx.input.workspaceRole}**.`
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
case 'list_members': {
|
|
167
|
+
if (!ctx.input.workspaceId) {
|
|
168
|
+
throw anthropicServiceError('workspaceId is required for "list_members"');
|
|
169
|
+
}
|
|
170
|
+
let result = await client.listWorkspaceMembers(ctx.input.workspaceId, {
|
|
171
|
+
limit: ctx.input.limit,
|
|
172
|
+
afterId: ctx.input.afterId
|
|
173
|
+
});
|
|
174
|
+
return {
|
|
175
|
+
output: { members: result.members, hasMore: result.hasMore },
|
|
176
|
+
message: `Found **${result.members.length}** member(s) in workspace **${ctx.input.workspaceId}**.`
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
case 'get_member': {
|
|
180
|
+
if (!ctx.input.workspaceId || !ctx.input.userId) {
|
|
181
|
+
throw anthropicServiceError('workspaceId and userId are required for "get_member"');
|
|
182
|
+
}
|
|
183
|
+
let member = await client.getWorkspaceMember(ctx.input.workspaceId, ctx.input.userId);
|
|
184
|
+
return {
|
|
185
|
+
output: { member },
|
|
186
|
+
message: `Retrieved **${ctx.input.userId}** membership in workspace **${ctx.input.workspaceId}**.`
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
case 'update_member': {
|
|
190
|
+
if (!ctx.input.workspaceId || !ctx.input.userId || !ctx.input.workspaceRole) {
|
|
191
|
+
throw anthropicServiceError(
|
|
192
|
+
'workspaceId, userId, and workspaceRole are required for "update_member"'
|
|
193
|
+
);
|
|
194
|
+
}
|
|
195
|
+
let member = await client.updateWorkspaceMember(
|
|
196
|
+
ctx.input.workspaceId,
|
|
197
|
+
ctx.input.userId,
|
|
198
|
+
ctx.input.workspaceRole
|
|
199
|
+
);
|
|
200
|
+
return {
|
|
201
|
+
output: { member },
|
|
202
|
+
message: `Updated **${ctx.input.userId}** role to **${ctx.input.workspaceRole}** in workspace **${ctx.input.workspaceId}**.`
|
|
203
|
+
};
|
|
204
|
+
}
|
|
205
|
+
case 'remove_member': {
|
|
206
|
+
if (!ctx.input.workspaceId || !ctx.input.userId) {
|
|
207
|
+
throw anthropicServiceError(
|
|
208
|
+
'workspaceId and userId are required for "remove_member"'
|
|
209
|
+
);
|
|
210
|
+
}
|
|
211
|
+
await client.removeWorkspaceMember(ctx.input.workspaceId, ctx.input.userId);
|
|
212
|
+
return {
|
|
213
|
+
output: { success: true },
|
|
214
|
+
message: `Removed **${ctx.input.userId}** from workspace **${ctx.input.workspaceId}**.`
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
})
|
|
219
|
+
.build();
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
import { SlateTool } from 'slates';
|
|
2
|
+
import { AnthropicClient } from '../lib/client';
|
|
3
|
+
import { spec } from '../spec';
|
|
4
|
+
import { z } from 'zod';
|
|
5
|
+
|
|
6
|
+
let contentBlockSchema: z.ZodType<Record<string, unknown>> = z
|
|
7
|
+
.record(z.string(), z.unknown())
|
|
8
|
+
.describe('Content block (text, image, tool_use, tool_result, etc.)');
|
|
9
|
+
|
|
10
|
+
let messageSchema = z.object({
|
|
11
|
+
role: z.enum(['user', 'assistant']).describe('Role of the message sender'),
|
|
12
|
+
content: z
|
|
13
|
+
.union([
|
|
14
|
+
z.string().describe('Simple text content'),
|
|
15
|
+
z.array(contentBlockSchema).describe('Array of content blocks for multi-modal input')
|
|
16
|
+
])
|
|
17
|
+
.describe('Message content')
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
let clientToolDefinitionSchema = z
|
|
21
|
+
.object({
|
|
22
|
+
name: z.string().describe('Tool name'),
|
|
23
|
+
description: z.string().optional().describe('Tool description'),
|
|
24
|
+
inputSchema: z.record(z.string(), z.unknown()).describe('JSON Schema for tool input')
|
|
25
|
+
})
|
|
26
|
+
.passthrough()
|
|
27
|
+
.describe('Client tool definition using inputSchema');
|
|
28
|
+
|
|
29
|
+
let rawToolDefinitionSchema = z
|
|
30
|
+
.record(z.string(), z.unknown())
|
|
31
|
+
.describe(
|
|
32
|
+
'Raw Anthropic tool definition, such as { name, input_schema } or server tools like web_search/code_execution'
|
|
33
|
+
);
|
|
34
|
+
|
|
35
|
+
let toolDefinitionSchema = z.union([clientToolDefinitionSchema, rawToolDefinitionSchema]);
|
|
36
|
+
|
|
37
|
+
let toolChoiceSchema = z
|
|
38
|
+
.record(z.string(), z.unknown())
|
|
39
|
+
.optional()
|
|
40
|
+
.describe(
|
|
41
|
+
'Tool choice configuration: { type: "auto" }, { type: "any" }, { type: "tool", name: "..." }, or { type: "none" }'
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
let thinkingSchema = z
|
|
45
|
+
.record(z.string(), z.unknown())
|
|
46
|
+
.optional()
|
|
47
|
+
.describe(
|
|
48
|
+
'Extended thinking config: { type: "enabled", budget_tokens: 1024 }, { type: "disabled" }, or { type: "adaptive" }'
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
export let sendMessage = SlateTool.create(spec, {
|
|
52
|
+
name: 'Send Message',
|
|
53
|
+
key: 'send_message',
|
|
54
|
+
description: `Send a message to Claude and receive a generated response. Supports multi-turn conversations, system prompts, tool use (function calling), extended thinking, and vision (images).
|
|
55
|
+
Provide a conversation history as messages and configure model parameters to control the response.`,
|
|
56
|
+
instructions: [
|
|
57
|
+
'The messages array must alternate between user and assistant roles.',
|
|
58
|
+
'Use content blocks (arrays) for multi-modal input like images or tool results.',
|
|
59
|
+
'Set tools and toolChoice to enable function calling.',
|
|
60
|
+
'Enable extended thinking with the thinking parameter for complex reasoning tasks (minimum 1024 budget tokens).'
|
|
61
|
+
],
|
|
62
|
+
tags: {
|
|
63
|
+
destructive: false,
|
|
64
|
+
readOnly: false
|
|
65
|
+
}
|
|
66
|
+
})
|
|
67
|
+
.input(
|
|
68
|
+
z.object({
|
|
69
|
+
model: z
|
|
70
|
+
.string()
|
|
71
|
+
.describe('Claude model ID, e.g. "claude-sonnet-4-5-20250929", "claude-haiku-4-5"'),
|
|
72
|
+
maxTokens: z.number().describe('Maximum number of tokens to generate'),
|
|
73
|
+
messages: z.array(messageSchema).describe('Conversation messages'),
|
|
74
|
+
system: z
|
|
75
|
+
.string()
|
|
76
|
+
.optional()
|
|
77
|
+
.describe('System prompt to set context and instructions for Claude'),
|
|
78
|
+
temperature: z
|
|
79
|
+
.number()
|
|
80
|
+
.min(0)
|
|
81
|
+
.max(1)
|
|
82
|
+
.optional()
|
|
83
|
+
.describe('Sampling temperature (0-1). Lower values are more deterministic'),
|
|
84
|
+
topK: z.number().optional().describe('Top-K sampling parameter'),
|
|
85
|
+
topP: z.number().optional().describe('Nucleus sampling parameter'),
|
|
86
|
+
stopSequences: z.array(z.string()).optional().describe('Custom stop sequences'),
|
|
87
|
+
tools: z
|
|
88
|
+
.array(toolDefinitionSchema)
|
|
89
|
+
.optional()
|
|
90
|
+
.describe('Client tool or raw Anthropic tool definitions for function calling'),
|
|
91
|
+
toolChoice: toolChoiceSchema,
|
|
92
|
+
thinking: thinkingSchema,
|
|
93
|
+
metadata: z
|
|
94
|
+
.record(z.string(), z.unknown())
|
|
95
|
+
.optional()
|
|
96
|
+
.describe('Request metadata object passed to Anthropic'),
|
|
97
|
+
mcpServers: z
|
|
98
|
+
.array(z.record(z.string(), z.unknown()))
|
|
99
|
+
.optional()
|
|
100
|
+
.describe('Remote MCP server definitions for the Messages API'),
|
|
101
|
+
serviceTier: z.string().optional().describe('Anthropic service_tier request option'),
|
|
102
|
+
betaHeaders: z
|
|
103
|
+
.array(z.string())
|
|
104
|
+
.optional()
|
|
105
|
+
.describe('Anthropic beta headers to send with this request')
|
|
106
|
+
})
|
|
107
|
+
)
|
|
108
|
+
.output(
|
|
109
|
+
z.object({
|
|
110
|
+
messageId: z.string().describe('Unique message ID'),
|
|
111
|
+
role: z.string().describe('Response role (always "assistant")'),
|
|
112
|
+
content: z
|
|
113
|
+
.array(z.record(z.string(), z.unknown()))
|
|
114
|
+
.describe('Response content blocks (text, tool_use, thinking, etc.)'),
|
|
115
|
+
model: z.string().describe('Model that generated the response'),
|
|
116
|
+
stopReason: z
|
|
117
|
+
.string()
|
|
118
|
+
.describe(
|
|
119
|
+
'Reason the model stopped: "end_turn", "max_tokens", "stop_sequence", or "tool_use"'
|
|
120
|
+
),
|
|
121
|
+
stopSequence: z
|
|
122
|
+
.string()
|
|
123
|
+
.optional()
|
|
124
|
+
.describe('The stop sequence that caused the model to stop, if applicable'),
|
|
125
|
+
inputTokens: z.number().describe('Number of input tokens consumed'),
|
|
126
|
+
outputTokens: z.number().describe('Number of output tokens generated')
|
|
127
|
+
})
|
|
128
|
+
)
|
|
129
|
+
.handleInvocation(async ctx => {
|
|
130
|
+
let client = new AnthropicClient({
|
|
131
|
+
token: ctx.auth.token,
|
|
132
|
+
apiVersion: ctx.config.apiVersion
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
let tools = ctx.input.tools?.map(tool => {
|
|
136
|
+
let rawTool = tool as Record<string, unknown>;
|
|
137
|
+
if (rawTool.inputSchema !== undefined) {
|
|
138
|
+
let { inputSchema, ...rest } = rawTool;
|
|
139
|
+
return {
|
|
140
|
+
...rest,
|
|
141
|
+
input_schema: inputSchema
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return rawTool;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
let messages = ctx.input.messages as Array<{
|
|
148
|
+
role: 'user' | 'assistant';
|
|
149
|
+
content: string | Array<Record<string, unknown>>;
|
|
150
|
+
}>;
|
|
151
|
+
let result = await client.createMessage({
|
|
152
|
+
model: ctx.input.model,
|
|
153
|
+
maxTokens: ctx.input.maxTokens,
|
|
154
|
+
messages,
|
|
155
|
+
system: ctx.input.system,
|
|
156
|
+
temperature: ctx.input.temperature,
|
|
157
|
+
topK: ctx.input.topK,
|
|
158
|
+
topP: ctx.input.topP,
|
|
159
|
+
stopSequences: ctx.input.stopSequences,
|
|
160
|
+
tools,
|
|
161
|
+
toolChoice: ctx.input.toolChoice,
|
|
162
|
+
thinking: ctx.input.thinking,
|
|
163
|
+
metadata: ctx.input.metadata,
|
|
164
|
+
mcpServers: ctx.input.mcpServers,
|
|
165
|
+
serviceTier: ctx.input.serviceTier,
|
|
166
|
+
betaHeaders: ctx.input.betaHeaders
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
let usage = result.usage as Record<string, number> | undefined;
|
|
170
|
+
let content = result.content as Array<Record<string, unknown>>;
|
|
171
|
+
|
|
172
|
+
let textContent = content
|
|
173
|
+
.filter(b => b.type === 'text')
|
|
174
|
+
.map(b => b.text as string)
|
|
175
|
+
.join('\n');
|
|
176
|
+
|
|
177
|
+
let summary =
|
|
178
|
+
textContent.length > 200 ? textContent.substring(0, 200) + '...' : textContent;
|
|
179
|
+
let stopSequence =
|
|
180
|
+
typeof result.stop_sequence === 'string' ? result.stop_sequence : undefined;
|
|
181
|
+
|
|
182
|
+
return {
|
|
183
|
+
output: {
|
|
184
|
+
messageId: result.id as string,
|
|
185
|
+
role: result.role as string,
|
|
186
|
+
content,
|
|
187
|
+
model: result.model as string,
|
|
188
|
+
stopReason: result.stop_reason as string,
|
|
189
|
+
stopSequence,
|
|
190
|
+
inputTokens: usage?.input_tokens ?? 0,
|
|
191
|
+
outputTokens: usage?.output_tokens ?? 0
|
|
192
|
+
},
|
|
193
|
+
message: `Claude responded with **${content.length}** content block(s) using **${result.model}**. Stop reason: **${result.stop_reason}**.\n\n${summary ? `> ${summary}` : ''}`
|
|
194
|
+
};
|
|
195
|
+
})
|
|
196
|
+
.build();
|