@effect/ai-anthropic 0.16.1 → 0.17.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.
- package/AnthropicTool/package.json +6 -0
- package/dist/cjs/AnthropicClient.js +286 -190
- package/dist/cjs/AnthropicClient.js.map +1 -1
- package/dist/cjs/AnthropicLanguageModel.js +1026 -311
- package/dist/cjs/AnthropicLanguageModel.js.map +1 -1
- package/dist/cjs/AnthropicTokenizer.js +8 -6
- package/dist/cjs/AnthropicTokenizer.js.map +1 -1
- package/dist/cjs/AnthropicTool.js +461 -0
- package/dist/cjs/AnthropicTool.js.map +1 -0
- package/dist/cjs/Generated.js +3507 -1230
- package/dist/cjs/Generated.js.map +1 -1
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internal/utilities.js +13 -3
- package/dist/cjs/internal/utilities.js.map +1 -1
- package/dist/dts/AnthropicClient.d.ts +673 -17
- package/dist/dts/AnthropicClient.d.ts.map +1 -1
- package/dist/dts/AnthropicLanguageModel.d.ts +217 -26
- package/dist/dts/AnthropicLanguageModel.d.ts.map +1 -1
- package/dist/dts/AnthropicTokenizer.d.ts +1 -1
- package/dist/dts/AnthropicTokenizer.d.ts.map +1 -1
- package/dist/dts/AnthropicTool.d.ts +523 -0
- package/dist/dts/AnthropicTool.d.ts.map +1 -0
- package/dist/dts/Generated.d.ts +7863 -3496
- package/dist/dts/Generated.d.ts.map +1 -1
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/AnthropicClient.js +269 -188
- package/dist/esm/AnthropicClient.js.map +1 -1
- package/dist/esm/AnthropicLanguageModel.js +1022 -306
- package/dist/esm/AnthropicLanguageModel.js.map +1 -1
- package/dist/esm/AnthropicTokenizer.js +8 -6
- package/dist/esm/AnthropicTokenizer.js.map +1 -1
- package/dist/esm/AnthropicTool.js +452 -0
- package/dist/esm/AnthropicTool.js.map +1 -0
- package/dist/esm/Generated.js +3492 -1063
- package/dist/esm/Generated.js.map +1 -1
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/utilities.js +12 -2
- package/dist/esm/internal/utilities.js.map +1 -1
- package/package.json +11 -3
- package/src/AnthropicClient.ts +713 -369
- package/src/AnthropicLanguageModel.ts +1404 -345
- package/src/AnthropicTokenizer.ts +14 -23
- package/src/AnthropicTool.ts +553 -0
- package/src/Generated.ts +4165 -1681
- package/src/index.ts +5 -0
- package/src/internal/utilities.ts +18 -4
|
@@ -1,26 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @since 1.0.0
|
|
3
3
|
*/
|
|
4
|
-
import
|
|
5
|
-
import * as
|
|
6
|
-
import * as
|
|
7
|
-
import * as
|
|
8
|
-
import { addGenAIAnnotations } from "@effect/ai/
|
|
4
|
+
import * as AiError from "@effect/ai/AiError";
|
|
5
|
+
import * as IdGenerator from "@effect/ai/IdGenerator";
|
|
6
|
+
import * as LanguageModel from "@effect/ai/LanguageModel";
|
|
7
|
+
import * as AiModel from "@effect/ai/Model";
|
|
8
|
+
import { addGenAIAnnotations } from "@effect/ai/Telemetry";
|
|
9
|
+
import * as Tool from "@effect/ai/Tool";
|
|
9
10
|
import * as Arr from "effect/Array";
|
|
10
11
|
import * as Context from "effect/Context";
|
|
12
|
+
import * as DateTime from "effect/DateTime";
|
|
11
13
|
import * as Effect from "effect/Effect";
|
|
12
14
|
import * as Encoding from "effect/Encoding";
|
|
13
15
|
import { dual } from "effect/Function";
|
|
14
16
|
import * as Layer from "effect/Layer";
|
|
15
|
-
import * as Option from "effect/Option";
|
|
16
17
|
import * as Predicate from "effect/Predicate";
|
|
17
18
|
import * as Stream from "effect/Stream";
|
|
18
19
|
import { AnthropicClient } from "./AnthropicClient.js";
|
|
19
20
|
import * as AnthropicTokenizer from "./AnthropicTokenizer.js";
|
|
21
|
+
import * as AnthropicTool from "./AnthropicTool.js";
|
|
20
22
|
import * as InternalUtilities from "./internal/utilities.js";
|
|
21
|
-
const constDisableValidation = {
|
|
22
|
-
disableValidation: true
|
|
23
|
-
};
|
|
24
23
|
// =============================================================================
|
|
25
24
|
// Configuration
|
|
26
25
|
// =============================================================================
|
|
@@ -35,29 +34,21 @@ export class Config extends /*#__PURE__*/Context.Tag("@effect/ai-anthropic/Anthr
|
|
|
35
34
|
static getOrUndefined = /*#__PURE__*/Effect.map(/*#__PURE__*/Effect.context(), context => context.unsafeMap.get(Config.key));
|
|
36
35
|
}
|
|
37
36
|
// =============================================================================
|
|
38
|
-
// Anthropic Provider Metadata
|
|
39
|
-
// =============================================================================
|
|
40
|
-
/**
|
|
41
|
-
* @since 1.0.0
|
|
42
|
-
* @category Context
|
|
43
|
-
*/
|
|
44
|
-
export class ProviderMetadata extends /*#__PURE__*/Context.Tag(InternalUtilities.ProviderMetadataKey)() {}
|
|
45
|
-
// =============================================================================
|
|
46
37
|
// Anthropic Language Model
|
|
47
38
|
// =============================================================================
|
|
48
39
|
/**
|
|
49
40
|
* @since 1.0.0
|
|
50
|
-
* @category
|
|
41
|
+
* @category Ai Models
|
|
51
42
|
*/
|
|
52
|
-
export const model = (model, config) => AiModel.make(layer({
|
|
43
|
+
export const model = (model, config) => AiModel.make("anthropic", layer({
|
|
53
44
|
model,
|
|
54
45
|
config
|
|
55
46
|
}));
|
|
56
47
|
/**
|
|
57
48
|
* @since 1.0.0
|
|
58
|
-
* @category
|
|
49
|
+
* @category Ai Models
|
|
59
50
|
*/
|
|
60
|
-
export const modelWithTokenizer = (model, config) => AiModel.make(layerWithTokenizer({
|
|
51
|
+
export const modelWithTokenizer = (model, config) => AiModel.make("anthropic", layerWithTokenizer({
|
|
61
52
|
model,
|
|
62
53
|
config
|
|
63
54
|
}));
|
|
@@ -67,88 +58,86 @@ export const modelWithTokenizer = (model, config) => AiModel.make(layerWithToken
|
|
|
67
58
|
*/
|
|
68
59
|
export const make = /*#__PURE__*/Effect.fnUntraced(function* (options) {
|
|
69
60
|
const client = yield* AnthropicClient;
|
|
70
|
-
const makeRequest = Effect.fnUntraced(function* (
|
|
71
|
-
prompt,
|
|
72
|
-
system,
|
|
73
|
-
toolChoice,
|
|
74
|
-
tools
|
|
75
|
-
}) {
|
|
61
|
+
const makeRequest = Effect.fnUntraced(function* (providerOptions) {
|
|
76
62
|
const context = yield* Effect.context();
|
|
77
|
-
const
|
|
78
|
-
let tool_choice = undefined;
|
|
79
|
-
if (useStructured) {
|
|
80
|
-
tool_choice = {
|
|
81
|
-
type: "tool",
|
|
82
|
-
name: tools[0].name
|
|
83
|
-
};
|
|
84
|
-
} else if (tools.length > 0) {
|
|
85
|
-
if (toolChoice === "required") {
|
|
86
|
-
tool_choice = {
|
|
87
|
-
type: "any"
|
|
88
|
-
};
|
|
89
|
-
} else if (typeof toolChoice === "object") {
|
|
90
|
-
tool_choice = {
|
|
91
|
-
type: "tool",
|
|
92
|
-
name: toolChoice.tool
|
|
93
|
-
};
|
|
94
|
-
} else {
|
|
95
|
-
tool_choice = {
|
|
96
|
-
type: toolChoice
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
const messages = yield* makeMessages(method, prompt);
|
|
101
|
-
return {
|
|
63
|
+
const config = {
|
|
102
64
|
model: options.model,
|
|
103
|
-
max_tokens: 4096,
|
|
104
65
|
...options.config,
|
|
105
|
-
...context.unsafeMap.get(Config.key)
|
|
106
|
-
|
|
107
|
-
|
|
66
|
+
...context.unsafeMap.get(Config.key)
|
|
67
|
+
};
|
|
68
|
+
const {
|
|
69
|
+
betas: messageBetas,
|
|
108
70
|
messages,
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
71
|
+
system
|
|
72
|
+
} = yield* prepareMessages(providerOptions);
|
|
73
|
+
const {
|
|
74
|
+
betas: toolBetas,
|
|
75
|
+
toolChoice,
|
|
76
|
+
tools
|
|
77
|
+
} = yield* prepareTools(providerOptions, config);
|
|
78
|
+
const responseFormat = providerOptions.responseFormat;
|
|
79
|
+
const request = {
|
|
80
|
+
max_tokens: 4096,
|
|
81
|
+
...config,
|
|
82
|
+
system,
|
|
83
|
+
messages,
|
|
84
|
+
tools: responseFormat.type === "text" ? tools : [{
|
|
85
|
+
name: responseFormat.objectName,
|
|
86
|
+
description: Tool.getDescriptionFromSchemaAst(responseFormat.schema.ast) ?? "Respond with a JSON object",
|
|
87
|
+
input_schema: Tool.getJsonSchemaFromSchemaAst(responseFormat.schema.ast)
|
|
88
|
+
}],
|
|
89
|
+
tool_choice: responseFormat.type === "text" ? toolChoice : {
|
|
90
|
+
type: "tool",
|
|
91
|
+
name: responseFormat.objectName,
|
|
92
|
+
disable_parallel_tool_use: true
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
return {
|
|
96
|
+
betas: new Set([...messageBetas, ...toolBetas]),
|
|
97
|
+
request
|
|
115
98
|
};
|
|
116
99
|
});
|
|
117
|
-
return yield*
|
|
100
|
+
return yield* LanguageModel.make({
|
|
118
101
|
generateText: Effect.fnUntraced(function* (options) {
|
|
119
|
-
const
|
|
102
|
+
const {
|
|
103
|
+
betas,
|
|
104
|
+
request
|
|
105
|
+
} = yield* makeRequest(options);
|
|
120
106
|
annotateRequest(options.span, request);
|
|
121
|
-
const
|
|
122
|
-
|
|
107
|
+
const anthropicBeta = betas.size > 0 ? Array.from(betas).join(",") : undefined;
|
|
108
|
+
const rawResponse = yield* client.createMessage({
|
|
109
|
+
params: {
|
|
110
|
+
"anthropic-beta": anthropicBeta
|
|
111
|
+
},
|
|
123
112
|
payload: request
|
|
124
113
|
});
|
|
125
|
-
|
|
126
|
-
|
|
114
|
+
annotateResponse(options.span, rawResponse);
|
|
115
|
+
return yield* makeResponse(rawResponse, options);
|
|
116
|
+
}),
|
|
117
|
+
streamText: Effect.fnUntraced(function* (options) {
|
|
118
|
+
const {
|
|
119
|
+
betas,
|
|
120
|
+
request
|
|
121
|
+
} = yield* makeRequest(options);
|
|
122
|
+
annotateRequest(options.span, request);
|
|
123
|
+
const anthropicBeta = betas.size > 0 ? Array.from(betas).join(",") : undefined;
|
|
124
|
+
return client.createMessageStream({
|
|
125
|
+
params: {
|
|
126
|
+
"anthropic-beta": anthropicBeta
|
|
127
|
+
},
|
|
128
|
+
payload: request
|
|
129
|
+
});
|
|
130
|
+
}, (effect, options) => effect.pipe(Effect.flatMap(stream => makeStreamResponse(stream, options)), Stream.unwrap, Stream.map(response => {
|
|
131
|
+
annotateStreamResponse(options.span, response);
|
|
127
132
|
return response;
|
|
128
|
-
}
|
|
129
|
-
module: "AnthropicLanguageModel",
|
|
130
|
-
method: "generateText",
|
|
131
|
-
description: "An error occurred",
|
|
132
|
-
cause
|
|
133
|
-
}))),
|
|
134
|
-
streamText(options) {
|
|
135
|
-
return makeRequest("streamText", options).pipe(Effect.tap(request => annotateRequest(options.span, request)), Effect.map(client.stream), Stream.unwrap, Stream.map(response => {
|
|
136
|
-
annotateStreamResponse(options.span, response);
|
|
137
|
-
return response;
|
|
138
|
-
}), Stream.catchAll(cause => AiError.is(cause) ? Effect.fail(cause) : Effect.fail(new AiError({
|
|
139
|
-
module: "AnthropicLanguageModel",
|
|
140
|
-
method: "streamText",
|
|
141
|
-
description: "An error occurred",
|
|
142
|
-
cause
|
|
143
|
-
}))));
|
|
144
|
-
}
|
|
133
|
+
})))
|
|
145
134
|
});
|
|
146
135
|
});
|
|
147
136
|
/**
|
|
148
137
|
* @since 1.0.0
|
|
149
138
|
* @category Layers
|
|
150
139
|
*/
|
|
151
|
-
export const layer = options => Layer.effect(
|
|
140
|
+
export const layer = options => Layer.effect(LanguageModel.LanguageModel, make({
|
|
152
141
|
model: options.model,
|
|
153
142
|
config: options.config
|
|
154
143
|
}));
|
|
@@ -165,193 +154,125 @@ export const withConfigOverride = /*#__PURE__*/dual(2, (self, overrides) => Effe
|
|
|
165
154
|
...config,
|
|
166
155
|
...overrides
|
|
167
156
|
})));
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
if (current?.type !== "assistant") {
|
|
176
|
-
current = {
|
|
177
|
-
type: "assistant",
|
|
178
|
-
messages: []
|
|
179
|
-
};
|
|
180
|
-
messages.push(current);
|
|
181
|
-
}
|
|
182
|
-
current.messages.push(message);
|
|
183
|
-
break;
|
|
184
|
-
}
|
|
185
|
-
case "ToolMessage":
|
|
186
|
-
case "UserMessage":
|
|
187
|
-
{
|
|
188
|
-
if (current?.type !== "user") {
|
|
189
|
-
current = {
|
|
190
|
-
type: "user",
|
|
191
|
-
messages: []
|
|
192
|
-
};
|
|
193
|
-
messages.push(current);
|
|
194
|
-
}
|
|
195
|
-
current.messages.push(message);
|
|
196
|
-
break;
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
return messages;
|
|
201
|
-
};
|
|
202
|
-
const makeMessages = /*#__PURE__*/Effect.fnUntraced(function* (method, prompt) {
|
|
157
|
+
// =============================================================================
|
|
158
|
+
// Prompt Conversion
|
|
159
|
+
// =============================================================================
|
|
160
|
+
const prepareMessages = /*#__PURE__*/Effect.fnUntraced(function* (options) {
|
|
161
|
+
const betas = new Set();
|
|
162
|
+
const groups = groupMessages(options.prompt);
|
|
163
|
+
let system = undefined;
|
|
203
164
|
const messages = [];
|
|
204
|
-
const groups = groupMessages(prompt);
|
|
205
165
|
for (let i = 0; i < groups.length; i++) {
|
|
206
166
|
const group = groups[i];
|
|
207
167
|
const isLastGroup = i === groups.length - 1;
|
|
208
168
|
switch (group.type) {
|
|
209
|
-
case "
|
|
169
|
+
case "system":
|
|
210
170
|
{
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
const part = message.parts[k];
|
|
217
|
-
const isLastPart = k === message.parts.length - 1;
|
|
218
|
-
switch (part._tag) {
|
|
219
|
-
case "ReasoningPart":
|
|
220
|
-
{
|
|
221
|
-
content.push({
|
|
222
|
-
type: "thinking",
|
|
223
|
-
thinking: part.reasoningText,
|
|
224
|
-
signature: part.signature
|
|
225
|
-
});
|
|
226
|
-
break;
|
|
227
|
-
}
|
|
228
|
-
case "RedactedReasoningPart":
|
|
229
|
-
{
|
|
230
|
-
content.push({
|
|
231
|
-
type: "redacted_thinking",
|
|
232
|
-
data: part.redactedText
|
|
233
|
-
});
|
|
234
|
-
break;
|
|
235
|
-
}
|
|
236
|
-
case "TextPart":
|
|
237
|
-
{
|
|
238
|
-
content.push({
|
|
239
|
-
type: "text",
|
|
240
|
-
text:
|
|
241
|
-
// Anthropic does not allow trailing whitespace in assistant
|
|
242
|
-
// content blocks
|
|
243
|
-
isLastGroup && isLastMessage && isLastPart ? part.text.trim() : part.text
|
|
244
|
-
});
|
|
245
|
-
break;
|
|
246
|
-
}
|
|
247
|
-
case "ToolCallPart":
|
|
248
|
-
{
|
|
249
|
-
content.push({
|
|
250
|
-
type: "tool_use",
|
|
251
|
-
id: part.id,
|
|
252
|
-
name: part.name,
|
|
253
|
-
input: part.params
|
|
254
|
-
});
|
|
255
|
-
break;
|
|
256
|
-
}
|
|
257
|
-
}
|
|
258
|
-
}
|
|
259
|
-
}
|
|
260
|
-
messages.push({
|
|
261
|
-
role: "assistant",
|
|
262
|
-
content
|
|
263
|
-
});
|
|
171
|
+
system = group.messages.map(message => ({
|
|
172
|
+
type: "text",
|
|
173
|
+
text: message.content,
|
|
174
|
+
cache_control: getCacheControl(message)
|
|
175
|
+
}));
|
|
264
176
|
break;
|
|
265
177
|
}
|
|
266
178
|
case "user":
|
|
267
179
|
{
|
|
268
180
|
const content = [];
|
|
269
|
-
for (
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
case "ToolMessage":
|
|
181
|
+
for (const message of group.messages) {
|
|
182
|
+
switch (message.role) {
|
|
183
|
+
case "user":
|
|
273
184
|
{
|
|
274
|
-
for (let
|
|
275
|
-
const part = message.
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
}
|
|
285
|
-
case "UserMessage":
|
|
286
|
-
{
|
|
287
|
-
for (let k = 0; k < message.parts.length; k++) {
|
|
288
|
-
const part = message.parts[k];
|
|
289
|
-
switch (part._tag) {
|
|
290
|
-
case "FilePart":
|
|
291
|
-
{
|
|
292
|
-
if (Predicate.isUndefined(part.mediaType) || part.mediaType !== "application/pdf") {
|
|
293
|
-
return yield* new AiError({
|
|
294
|
-
module: "AnthropicLanguageModel",
|
|
295
|
-
method,
|
|
296
|
-
description: "AnthropicLanguageModel only supports PDF file inputs"
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
content.push({
|
|
300
|
-
type: "document",
|
|
301
|
-
source: {
|
|
302
|
-
type: "base64",
|
|
303
|
-
media_type: "application/pdf",
|
|
304
|
-
data: Encoding.encodeBase64(part.data)
|
|
305
|
-
}
|
|
306
|
-
});
|
|
307
|
-
break;
|
|
308
|
-
}
|
|
309
|
-
case "FileUrlPart":
|
|
310
|
-
{
|
|
311
|
-
content.push({
|
|
312
|
-
type: "document",
|
|
313
|
-
source: {
|
|
314
|
-
type: "url",
|
|
315
|
-
url: part.url.toString()
|
|
316
|
-
}
|
|
317
|
-
});
|
|
318
|
-
break;
|
|
319
|
-
}
|
|
320
|
-
case "TextPart":
|
|
185
|
+
for (let j = 0; j < message.content.length; j++) {
|
|
186
|
+
const part = message.content[j];
|
|
187
|
+
const isLastPart = j === message.content.length - 1;
|
|
188
|
+
// Attempt to get the cache control from the part first. If
|
|
189
|
+
// the part does not have cache control defined and we are
|
|
190
|
+
// evaluating the last part for this message, also check the
|
|
191
|
+
// message for cache control.
|
|
192
|
+
const cacheControl = getCacheControl(part) ?? (isLastPart ? getCacheControl(message) : undefined);
|
|
193
|
+
switch (part.type) {
|
|
194
|
+
case "text":
|
|
321
195
|
{
|
|
322
196
|
content.push({
|
|
323
197
|
type: "text",
|
|
324
|
-
text: part.text
|
|
198
|
+
text: part.text,
|
|
199
|
+
cache_control: cacheControl
|
|
325
200
|
});
|
|
326
201
|
break;
|
|
327
202
|
}
|
|
328
|
-
case "
|
|
203
|
+
case "file":
|
|
329
204
|
{
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
205
|
+
if (part.mediaType.startsWith("image/")) {
|
|
206
|
+
const source = part.data instanceof URL ? {
|
|
207
|
+
type: "url",
|
|
208
|
+
url: part.data.toString()
|
|
209
|
+
} : {
|
|
333
210
|
type: "base64",
|
|
334
|
-
media_type: part.mediaType
|
|
335
|
-
data: Encoding.encodeBase64(part.data)
|
|
211
|
+
media_type: part.mediaType === "image/*" ? "image/jpeg" : part.mediaType,
|
|
212
|
+
data: typeof part.data === "string" ? part.data : Encoding.encodeBase64(part.data)
|
|
213
|
+
};
|
|
214
|
+
content.push({
|
|
215
|
+
type: "image",
|
|
216
|
+
source,
|
|
217
|
+
cache_control: cacheControl
|
|
218
|
+
});
|
|
219
|
+
} else if (part.mediaType === "application/pdf" || part.mediaType === "text/plain") {
|
|
220
|
+
if (part.mediaType === "application/pdf") {
|
|
221
|
+
betas.add("pdfs-2024-09-25");
|
|
336
222
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
case "ImageUrlPart":
|
|
341
|
-
{
|
|
342
|
-
content.push({
|
|
343
|
-
type: "image",
|
|
344
|
-
source: {
|
|
223
|
+
const enableCitations = shouldEnableCitations(part);
|
|
224
|
+
const documentOptions = getDocumentMetadata(part);
|
|
225
|
+
const source = part.data instanceof URL ? {
|
|
345
226
|
type: "url",
|
|
346
|
-
url: part.
|
|
347
|
-
}
|
|
348
|
-
|
|
227
|
+
url: part.data.toString()
|
|
228
|
+
} : part.mediaType === "application/pdf" ? {
|
|
229
|
+
type: "base64",
|
|
230
|
+
media_type: "application/pdf",
|
|
231
|
+
data: typeof part.data === "string" ? part.data : Encoding.encodeBase64(part.data)
|
|
232
|
+
} : {
|
|
233
|
+
type: "text",
|
|
234
|
+
media_type: "text/plain",
|
|
235
|
+
data: typeof part.data === "string" ? part.data : Encoding.encodeBase64(part.data)
|
|
236
|
+
};
|
|
237
|
+
content.push({
|
|
238
|
+
type: "document",
|
|
239
|
+
source,
|
|
240
|
+
title: documentOptions?.title ?? part.fileName,
|
|
241
|
+
...(documentOptions?.context ? {
|
|
242
|
+
context: documentOptions.context
|
|
243
|
+
} : undefined),
|
|
244
|
+
...(enableCitations ? {
|
|
245
|
+
citations: {
|
|
246
|
+
enabled: true
|
|
247
|
+
}
|
|
248
|
+
} : undefined),
|
|
249
|
+
cache_control: cacheControl
|
|
250
|
+
});
|
|
251
|
+
} else {
|
|
252
|
+
return yield* new AiError.MalformedInput({
|
|
253
|
+
module: "AnthropicLanguageModel",
|
|
254
|
+
method: "prepareMessages",
|
|
255
|
+
description: `Detected unsupported media type for file: '${part.mediaType}'`
|
|
256
|
+
});
|
|
257
|
+
}
|
|
349
258
|
break;
|
|
350
259
|
}
|
|
351
260
|
}
|
|
352
261
|
}
|
|
353
262
|
break;
|
|
354
263
|
}
|
|
264
|
+
// TODO: advanced tool result content parts
|
|
265
|
+
case "tool":
|
|
266
|
+
{
|
|
267
|
+
for (const part of message.content) {
|
|
268
|
+
content.push({
|
|
269
|
+
type: "tool_result",
|
|
270
|
+
tool_use_id: part.id,
|
|
271
|
+
content: JSON.stringify(part.result)
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
break;
|
|
275
|
+
}
|
|
355
276
|
}
|
|
356
277
|
}
|
|
357
278
|
messages.push({
|
|
@@ -360,81 +281,559 @@ const makeMessages = /*#__PURE__*/Effect.fnUntraced(function* (method, prompt) {
|
|
|
360
281
|
});
|
|
361
282
|
break;
|
|
362
283
|
}
|
|
284
|
+
case "assistant":
|
|
285
|
+
{
|
|
286
|
+
const content = [];
|
|
287
|
+
for (let j = 0; j < group.messages.length; j++) {
|
|
288
|
+
const message = group.messages[j];
|
|
289
|
+
const isLastMessage = j === group.messages.length - 1;
|
|
290
|
+
for (let k = 0; k < message.content.length; k++) {
|
|
291
|
+
const part = message.content[k];
|
|
292
|
+
const isLastPart = k === message.content.length - 1;
|
|
293
|
+
// Attempt to get the cache control from the part first. If
|
|
294
|
+
// the part does not have cache control defined and we are
|
|
295
|
+
// evaluating the last part for this message, also check the
|
|
296
|
+
// message for cache control.
|
|
297
|
+
const cacheControl = getCacheControl(part) ?? (isLastPart ? getCacheControl(message) : undefined);
|
|
298
|
+
switch (part.type) {
|
|
299
|
+
case "text":
|
|
300
|
+
{
|
|
301
|
+
content.push({
|
|
302
|
+
type: "text",
|
|
303
|
+
// Anthropic does not allow trailing whitespace in assistant
|
|
304
|
+
// content blocks
|
|
305
|
+
text: isLastGroup && isLastMessage && isLastPart ? part.text.trim() : part.text
|
|
306
|
+
});
|
|
307
|
+
break;
|
|
308
|
+
}
|
|
309
|
+
case "reasoning":
|
|
310
|
+
{
|
|
311
|
+
const options = part.options.anthropic;
|
|
312
|
+
if (Predicate.isNotUndefined(options)) {
|
|
313
|
+
if (options.type === "thinking") {
|
|
314
|
+
content.push({
|
|
315
|
+
type: "thinking",
|
|
316
|
+
thinking: part.text,
|
|
317
|
+
signature: options.signature
|
|
318
|
+
});
|
|
319
|
+
} else {
|
|
320
|
+
content.push({
|
|
321
|
+
type: "redacted_thinking",
|
|
322
|
+
data: options.redactedData
|
|
323
|
+
});
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
case "tool-call":
|
|
329
|
+
{
|
|
330
|
+
if (part.providerExecuted) {
|
|
331
|
+
if (part.name === "AnthropicWebSearch") {
|
|
332
|
+
content.push({
|
|
333
|
+
type: "server_tool_use",
|
|
334
|
+
id: part.id,
|
|
335
|
+
name: "web_search",
|
|
336
|
+
input: part.params,
|
|
337
|
+
cache_control: cacheControl
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
if (part.name === "AnthropicCodeExecution") {
|
|
341
|
+
content.push({
|
|
342
|
+
type: "server_tool_use",
|
|
343
|
+
id: part.id,
|
|
344
|
+
name: "code_execution",
|
|
345
|
+
input: part.params,
|
|
346
|
+
cache_control: cacheControl
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
} else {
|
|
350
|
+
content.push({
|
|
351
|
+
type: "tool_use",
|
|
352
|
+
id: part.id,
|
|
353
|
+
name: part.name,
|
|
354
|
+
input: part.params,
|
|
355
|
+
cache_control: cacheControl
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
messages.push({
|
|
364
|
+
role: "assistant",
|
|
365
|
+
content
|
|
366
|
+
});
|
|
367
|
+
break;
|
|
368
|
+
}
|
|
363
369
|
}
|
|
364
370
|
}
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
method,
|
|
371
|
-
description: "Prompt contained no messages"
|
|
372
|
-
});
|
|
371
|
+
return {
|
|
372
|
+
system,
|
|
373
|
+
messages,
|
|
374
|
+
betas
|
|
375
|
+
};
|
|
373
376
|
});
|
|
374
|
-
|
|
377
|
+
// =============================================================================
|
|
378
|
+
// Response Conversion
|
|
379
|
+
// =============================================================================
|
|
380
|
+
const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* (response, options) {
|
|
381
|
+
const idGenerator = yield* IdGenerator.IdGenerator;
|
|
375
382
|
const parts = [];
|
|
376
|
-
|
|
383
|
+
const citableDocuments = extractCitableDocuments(options.prompt);
|
|
384
|
+
parts.push({
|
|
385
|
+
type: "response-metadata",
|
|
377
386
|
id: response.id,
|
|
378
|
-
|
|
379
|
-
|
|
387
|
+
modelId: response.model,
|
|
388
|
+
timestamp: DateTime.formatIso(yield* DateTime.now)
|
|
389
|
+
});
|
|
380
390
|
for (const part of response.content) {
|
|
381
391
|
switch (part.type) {
|
|
382
392
|
case "text":
|
|
383
393
|
{
|
|
384
|
-
parts
|
|
385
|
-
|
|
386
|
-
|
|
394
|
+
// The text parts should only be added to the response here if the
|
|
395
|
+
// response format is `"text"`. If the response format is `"json"`,
|
|
396
|
+
// then the text parts must instead be added to the response when a
|
|
397
|
+
// tool call is received.
|
|
398
|
+
if (options.responseFormat.type === "text") {
|
|
399
|
+
parts.push({
|
|
400
|
+
type: "text",
|
|
401
|
+
text: part.text
|
|
402
|
+
});
|
|
403
|
+
if (Predicate.isNotNullable(part.citations)) {
|
|
404
|
+
for (const citation of part.citations) {
|
|
405
|
+
const source = yield* processCitation(citation, citableDocuments, idGenerator);
|
|
406
|
+
if (Predicate.isNotUndefined(source)) {
|
|
407
|
+
parts.push(source);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
break;
|
|
413
|
+
}
|
|
414
|
+
case "thinking":
|
|
415
|
+
{
|
|
416
|
+
parts.push({
|
|
417
|
+
type: "reasoning",
|
|
418
|
+
text: part.thinking,
|
|
419
|
+
metadata: {
|
|
420
|
+
anthropic: {
|
|
421
|
+
type: "thinking",
|
|
422
|
+
signature: part.signature
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
break;
|
|
427
|
+
}
|
|
428
|
+
case "redacted_thinking":
|
|
429
|
+
{
|
|
430
|
+
parts.push({
|
|
431
|
+
type: "reasoning",
|
|
432
|
+
text: "",
|
|
433
|
+
metadata: {
|
|
434
|
+
anthropic: {
|
|
435
|
+
type: "redacted_thinking",
|
|
436
|
+
redactedData: part.data
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
});
|
|
387
440
|
break;
|
|
388
441
|
}
|
|
389
442
|
case "tool_use":
|
|
390
443
|
{
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
444
|
+
// When a `"json"` response format is requested, the JSON that we need
|
|
445
|
+
// will be returned by the tool call injected into the request
|
|
446
|
+
if (options.responseFormat.type === "json") {
|
|
447
|
+
parts.push({
|
|
448
|
+
type: "text",
|
|
449
|
+
text: JSON.stringify(part.input)
|
|
450
|
+
});
|
|
451
|
+
} else {
|
|
452
|
+
const providerTool = AnthropicTool.getProviderDefinedToolName(part.name);
|
|
453
|
+
const name = Predicate.isNotUndefined(providerTool) ? providerTool : part.name;
|
|
454
|
+
const providerName = Predicate.isNotUndefined(providerTool) ? part.name : undefined;
|
|
455
|
+
parts.push({
|
|
456
|
+
type: "tool-call",
|
|
457
|
+
id: part.id,
|
|
458
|
+
name,
|
|
459
|
+
params: part.input,
|
|
460
|
+
providerName,
|
|
461
|
+
providerExecuted: false
|
|
462
|
+
});
|
|
463
|
+
}
|
|
396
464
|
break;
|
|
397
465
|
}
|
|
398
|
-
case "
|
|
466
|
+
case "server_tool_use":
|
|
399
467
|
{
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
468
|
+
const providerTool = AnthropicTool.getProviderDefinedToolName(part.name);
|
|
469
|
+
if (Predicate.isNotUndefined(providerTool)) {
|
|
470
|
+
parts.push({
|
|
471
|
+
type: "tool-call",
|
|
472
|
+
id: part.id,
|
|
473
|
+
name: providerTool,
|
|
474
|
+
params: part.input,
|
|
475
|
+
providerName: part.name,
|
|
476
|
+
providerExecuted: true
|
|
477
|
+
});
|
|
478
|
+
}
|
|
404
479
|
break;
|
|
405
480
|
}
|
|
406
|
-
case "
|
|
481
|
+
case "code_execution_tool_result":
|
|
482
|
+
case "bash_code_execution_tool_result":
|
|
483
|
+
case "text_editor_code_execution_tool_result":
|
|
484
|
+
{
|
|
485
|
+
parts.push({
|
|
486
|
+
type: "tool-result",
|
|
487
|
+
id: part.tool_use_id,
|
|
488
|
+
name: "AnthropicCodeExecution",
|
|
489
|
+
result: part.content,
|
|
490
|
+
providerName: "code_execution",
|
|
491
|
+
providerExecuted: true
|
|
492
|
+
});
|
|
493
|
+
break;
|
|
494
|
+
}
|
|
495
|
+
case "web_search_tool_result":
|
|
407
496
|
{
|
|
408
|
-
parts.push(
|
|
409
|
-
|
|
410
|
-
|
|
497
|
+
parts.push({
|
|
498
|
+
type: "tool-result",
|
|
499
|
+
id: part.tool_use_id,
|
|
500
|
+
name: "AnthropicWebSearch",
|
|
501
|
+
result: part.content,
|
|
502
|
+
providerName: "web_search",
|
|
503
|
+
providerExecuted: true
|
|
504
|
+
});
|
|
411
505
|
break;
|
|
412
506
|
}
|
|
413
507
|
}
|
|
414
508
|
}
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
reason: InternalUtilities.resolveFinishReason(response.stop_reason),
|
|
422
|
-
usage: new AiResponse.Usage({
|
|
509
|
+
// Anthropic always returns a non-null `stop_reason` for non-streaming responses
|
|
510
|
+
const finishReason = InternalUtilities.resolveFinishReason(response.stop_reason, options.responseFormat.type === "json");
|
|
511
|
+
parts.push({
|
|
512
|
+
type: "finish",
|
|
513
|
+
reason: finishReason,
|
|
514
|
+
usage: {
|
|
423
515
|
inputTokens: response.usage.input_tokens,
|
|
424
516
|
outputTokens: response.usage.output_tokens,
|
|
425
517
|
totalTokens: response.usage.input_tokens + response.usage.output_tokens,
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
518
|
+
cachedInputTokens: response.usage.cache_read_input_tokens ?? undefined
|
|
519
|
+
},
|
|
520
|
+
metadata: {
|
|
521
|
+
anthropic: {
|
|
522
|
+
usage: response.usage,
|
|
523
|
+
stopSequence: response.stop_sequence ?? undefined
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
return parts;
|
|
528
|
+
});
|
|
529
|
+
const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* (stream, options) {
|
|
530
|
+
const idGenerator = yield* IdGenerator.IdGenerator;
|
|
531
|
+
const citableDocuments = extractCitableDocuments(options.prompt);
|
|
532
|
+
// Setup all requisite state for the streaming response
|
|
533
|
+
let finishReason = "unknown";
|
|
534
|
+
const contentBlocks = {};
|
|
535
|
+
let blockType = undefined;
|
|
536
|
+
const usage = {
|
|
537
|
+
inputTokens: undefined,
|
|
538
|
+
outputTokens: undefined,
|
|
539
|
+
totalTokens: undefined
|
|
540
|
+
};
|
|
541
|
+
let metaUsage = undefined;
|
|
542
|
+
let stopSequence = undefined;
|
|
543
|
+
return stream.pipe(Stream.mapEffect(Effect.fnUntraced(function* (event) {
|
|
544
|
+
const parts = [];
|
|
545
|
+
switch (event.type) {
|
|
546
|
+
case "ping":
|
|
547
|
+
{
|
|
548
|
+
break;
|
|
549
|
+
}
|
|
550
|
+
case "message_start":
|
|
551
|
+
{
|
|
552
|
+
// Track usage metadata
|
|
553
|
+
usage.inputTokens = event.message.usage.input_tokens;
|
|
554
|
+
metaUsage = event.message.usage;
|
|
555
|
+
// Track response metadata
|
|
556
|
+
parts.push({
|
|
557
|
+
type: "response-metadata",
|
|
558
|
+
id: event.message.id,
|
|
559
|
+
modelId: event.message.model,
|
|
560
|
+
timestamp: DateTime.formatIso(yield* DateTime.now)
|
|
561
|
+
});
|
|
562
|
+
break;
|
|
563
|
+
}
|
|
564
|
+
case "message_delta":
|
|
565
|
+
{
|
|
566
|
+
// Track usage metadata
|
|
567
|
+
if (Predicate.isNotNullable(event.usage.output_tokens)) {
|
|
568
|
+
usage.outputTokens = event.usage.output_tokens;
|
|
569
|
+
}
|
|
570
|
+
usage.totalTokens = (usage.inputTokens ?? 0) + (event.usage.output_tokens ?? 0);
|
|
571
|
+
// Track stop sequence metadata
|
|
572
|
+
if (Predicate.isNotNullable(event.delta.stop_sequence)) {
|
|
573
|
+
stopSequence = event.delta.stop_sequence;
|
|
574
|
+
}
|
|
575
|
+
// Track the response finish reason
|
|
576
|
+
if (Predicate.isNotNullable(event.delta.stop_reason)) {
|
|
577
|
+
finishReason = InternalUtilities.resolveFinishReason(event.delta.stop_reason);
|
|
578
|
+
}
|
|
579
|
+
break;
|
|
580
|
+
}
|
|
581
|
+
case "message_stop":
|
|
582
|
+
{
|
|
583
|
+
parts.push({
|
|
584
|
+
type: "finish",
|
|
585
|
+
reason: finishReason,
|
|
586
|
+
usage,
|
|
587
|
+
metadata: {
|
|
588
|
+
anthropic: {
|
|
589
|
+
usage: metaUsage,
|
|
590
|
+
stopSequence
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
});
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
case "content_block_start":
|
|
597
|
+
{
|
|
598
|
+
blockType = event.content_block.type;
|
|
599
|
+
switch (event.content_block.type) {
|
|
600
|
+
case "text":
|
|
601
|
+
{
|
|
602
|
+
contentBlocks[event.index] = {
|
|
603
|
+
type: "text"
|
|
604
|
+
};
|
|
605
|
+
parts.push({
|
|
606
|
+
type: "text-start",
|
|
607
|
+
id: event.index.toString()
|
|
608
|
+
});
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
case "thinking":
|
|
612
|
+
{
|
|
613
|
+
contentBlocks[event.index] = {
|
|
614
|
+
type: "reasoning"
|
|
615
|
+
};
|
|
616
|
+
parts.push({
|
|
617
|
+
type: "reasoning-start",
|
|
618
|
+
id: event.index.toString()
|
|
619
|
+
});
|
|
620
|
+
break;
|
|
621
|
+
}
|
|
622
|
+
case "redacted_thinking":
|
|
623
|
+
{
|
|
624
|
+
contentBlocks[event.index] = {
|
|
625
|
+
type: "reasoning"
|
|
626
|
+
};
|
|
627
|
+
parts.push({
|
|
628
|
+
type: "reasoning-start",
|
|
629
|
+
id: event.index.toString(),
|
|
630
|
+
metadata: {
|
|
631
|
+
anthropic: {
|
|
632
|
+
type: "redacted_thinking",
|
|
633
|
+
redactedData: event.content_block.data
|
|
634
|
+
}
|
|
635
|
+
}
|
|
636
|
+
});
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
case "tool_use":
|
|
640
|
+
{
|
|
641
|
+
const toolName = event.content_block.name;
|
|
642
|
+
const providerTool = AnthropicTool.getProviderDefinedToolName(toolName);
|
|
643
|
+
const name = Predicate.isNotUndefined(providerTool) ? providerTool : toolName;
|
|
644
|
+
const providerName = Predicate.isNotUndefined(providerTool) ? toolName : undefined;
|
|
645
|
+
contentBlocks[event.index] = {
|
|
646
|
+
type: "tool-call",
|
|
647
|
+
id: event.content_block.id,
|
|
648
|
+
name,
|
|
649
|
+
params: "",
|
|
650
|
+
providerName,
|
|
651
|
+
providerExecuted: false
|
|
652
|
+
};
|
|
653
|
+
parts.push({
|
|
654
|
+
type: "tool-params-start",
|
|
655
|
+
id: event.content_block.id,
|
|
656
|
+
name: toolName,
|
|
657
|
+
providerName,
|
|
658
|
+
providerExecuted: false
|
|
659
|
+
});
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
case "server_tool_use":
|
|
663
|
+
{
|
|
664
|
+
const toolName = event.content_block.name;
|
|
665
|
+
const providerTool = AnthropicTool.getProviderDefinedToolName(toolName);
|
|
666
|
+
if (Predicate.isNotUndefined(providerTool)) {
|
|
667
|
+
contentBlocks[event.index] = {
|
|
668
|
+
type: "tool-call",
|
|
669
|
+
id: event.content_block.id,
|
|
670
|
+
name: providerTool,
|
|
671
|
+
params: "",
|
|
672
|
+
providerName: toolName,
|
|
673
|
+
providerExecuted: true
|
|
674
|
+
};
|
|
675
|
+
parts.push({
|
|
676
|
+
type: "tool-params-start",
|
|
677
|
+
id: event.content_block.id,
|
|
678
|
+
name: providerTool,
|
|
679
|
+
providerName: toolName,
|
|
680
|
+
providerExecuted: true
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
break;
|
|
684
|
+
}
|
|
685
|
+
case "code_execution_tool_result":
|
|
686
|
+
case "bash_code_execution_tool_result":
|
|
687
|
+
case "text_editor_code_execution_tool_result":
|
|
688
|
+
{
|
|
689
|
+
parts.push({
|
|
690
|
+
type: "tool-result",
|
|
691
|
+
id: event.content_block.tool_use_id,
|
|
692
|
+
name: "AnthropicCodeExecution",
|
|
693
|
+
result: event.content_block.content,
|
|
694
|
+
providerName: "code_execution",
|
|
695
|
+
providerExecuted: true
|
|
696
|
+
});
|
|
697
|
+
break;
|
|
698
|
+
}
|
|
699
|
+
case "web_search_tool_result":
|
|
700
|
+
{
|
|
701
|
+
parts.push({
|
|
702
|
+
type: "tool-result",
|
|
703
|
+
id: event.content_block.tool_use_id,
|
|
704
|
+
name: "AnthropicWebSearch",
|
|
705
|
+
result: event.content_block.content,
|
|
706
|
+
providerName: "web_search",
|
|
707
|
+
providerExecuted: true
|
|
708
|
+
});
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
}
|
|
712
|
+
break;
|
|
713
|
+
}
|
|
714
|
+
case "content_block_delta":
|
|
715
|
+
{
|
|
716
|
+
switch (event.delta.type) {
|
|
717
|
+
case "text_delta":
|
|
718
|
+
{
|
|
719
|
+
parts.push({
|
|
720
|
+
type: "text-delta",
|
|
721
|
+
id: event.index.toString(),
|
|
722
|
+
delta: event.delta.text
|
|
723
|
+
});
|
|
724
|
+
break;
|
|
725
|
+
}
|
|
726
|
+
case "thinking_delta":
|
|
727
|
+
{
|
|
728
|
+
parts.push({
|
|
729
|
+
type: "reasoning-delta",
|
|
730
|
+
id: event.index.toString(),
|
|
731
|
+
delta: event.delta.thinking
|
|
732
|
+
});
|
|
733
|
+
break;
|
|
734
|
+
}
|
|
735
|
+
case "signature_delta":
|
|
736
|
+
{
|
|
737
|
+
if (blockType === "thinking") {
|
|
738
|
+
parts.push({
|
|
739
|
+
type: "reasoning-delta",
|
|
740
|
+
id: event.index.toString(),
|
|
741
|
+
delta: "",
|
|
742
|
+
metadata: {
|
|
743
|
+
anthropic: {
|
|
744
|
+
type: "thinking",
|
|
745
|
+
signature: event.delta.signature
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
});
|
|
749
|
+
}
|
|
750
|
+
break;
|
|
751
|
+
}
|
|
752
|
+
case "input_json_delta":
|
|
753
|
+
{
|
|
754
|
+
const contentBlock = contentBlocks[event.index];
|
|
755
|
+
const delta = event.delta.partial_json;
|
|
756
|
+
if (contentBlock.type === "tool-call") {
|
|
757
|
+
parts.push({
|
|
758
|
+
type: "tool-params-delta",
|
|
759
|
+
id: contentBlock.id,
|
|
760
|
+
delta
|
|
761
|
+
});
|
|
762
|
+
contentBlock.params += delta;
|
|
763
|
+
}
|
|
764
|
+
break;
|
|
765
|
+
}
|
|
766
|
+
case "citations_delta":
|
|
767
|
+
{
|
|
768
|
+
const citation = event.delta.citation;
|
|
769
|
+
const source = yield* processCitation(citation, citableDocuments, idGenerator);
|
|
770
|
+
if (Predicate.isNotUndefined(source)) {
|
|
771
|
+
parts.push(source);
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
break;
|
|
776
|
+
}
|
|
777
|
+
case "content_block_stop":
|
|
778
|
+
{
|
|
779
|
+
if (Predicate.isNotNullable(contentBlocks[event.index])) {
|
|
780
|
+
const contentBlock = contentBlocks[event.index];
|
|
781
|
+
switch (contentBlock.type) {
|
|
782
|
+
case "text":
|
|
783
|
+
{
|
|
784
|
+
parts.push({
|
|
785
|
+
type: "text-end",
|
|
786
|
+
id: event.index.toString()
|
|
787
|
+
});
|
|
788
|
+
break;
|
|
789
|
+
}
|
|
790
|
+
case "reasoning":
|
|
791
|
+
{
|
|
792
|
+
parts.push({
|
|
793
|
+
type: "reasoning-end",
|
|
794
|
+
id: event.index.toString()
|
|
795
|
+
});
|
|
796
|
+
break;
|
|
797
|
+
}
|
|
798
|
+
case "tool-call":
|
|
799
|
+
{
|
|
800
|
+
parts.push({
|
|
801
|
+
type: "tool-params-end",
|
|
802
|
+
id: contentBlock.id
|
|
803
|
+
});
|
|
804
|
+
// If the tool call has no parameters, an empty string is returned
|
|
805
|
+
const params = contentBlock.params.length === 0 ? "{}" : contentBlock.params;
|
|
806
|
+
parts.push({
|
|
807
|
+
type: "tool-call",
|
|
808
|
+
id: contentBlock.id,
|
|
809
|
+
name: contentBlock.name,
|
|
810
|
+
params: JSON.parse(params),
|
|
811
|
+
providerName: contentBlock.providerName,
|
|
812
|
+
providerExecuted: contentBlock.providerExecuted
|
|
813
|
+
});
|
|
814
|
+
break;
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
delete contentBlocks[event.index];
|
|
818
|
+
}
|
|
819
|
+
blockType = undefined;
|
|
820
|
+
break;
|
|
821
|
+
}
|
|
822
|
+
case "error":
|
|
823
|
+
{
|
|
824
|
+
parts.push({
|
|
825
|
+
type: "error",
|
|
826
|
+
error: event.error
|
|
827
|
+
});
|
|
828
|
+
break;
|
|
829
|
+
}
|
|
432
830
|
}
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
parts
|
|
436
|
-
}, constDisableValidation);
|
|
831
|
+
return parts;
|
|
832
|
+
})), Stream.flattenIterables);
|
|
437
833
|
});
|
|
834
|
+
// =============================================================================
|
|
835
|
+
// Telemetry
|
|
836
|
+
// =============================================================================
|
|
438
837
|
const annotateRequest = (span, request) => {
|
|
439
838
|
addGenAIAnnotations(span, {
|
|
440
839
|
system: "anthropic",
|
|
@@ -451,7 +850,7 @@ const annotateRequest = (span, request) => {
|
|
|
451
850
|
}
|
|
452
851
|
});
|
|
453
852
|
};
|
|
454
|
-
const
|
|
853
|
+
const annotateResponse = (span, response) => {
|
|
455
854
|
addGenAIAnnotations(span, {
|
|
456
855
|
response: {
|
|
457
856
|
id: response.id,
|
|
@@ -464,19 +863,336 @@ const annotateChatResponse = (span, response) => {
|
|
|
464
863
|
}
|
|
465
864
|
});
|
|
466
865
|
};
|
|
467
|
-
const annotateStreamResponse = (span,
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
866
|
+
const annotateStreamResponse = (span, part) => {
|
|
867
|
+
if (part.type === "response-metadata") {
|
|
868
|
+
addGenAIAnnotations(span, {
|
|
869
|
+
response: {
|
|
870
|
+
id: part.id,
|
|
871
|
+
model: part.modelId
|
|
872
|
+
}
|
|
873
|
+
});
|
|
874
|
+
}
|
|
875
|
+
if (part.type === "finish") {
|
|
876
|
+
addGenAIAnnotations(span, {
|
|
877
|
+
response: {
|
|
878
|
+
finishReasons: [part.reason]
|
|
879
|
+
},
|
|
880
|
+
usage: {
|
|
881
|
+
inputTokens: part.usage.inputTokens,
|
|
882
|
+
outputTokens: part.usage.outputTokens
|
|
883
|
+
}
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
};
|
|
887
|
+
/**
|
|
888
|
+
* A helper method which takes in large language model provider options from
|
|
889
|
+
* the base Effect AI SDK as well as Anthropic request configuration options
|
|
890
|
+
* and returns the prepared tools, tool choice, and Anthropic betas to include
|
|
891
|
+
* in a request.
|
|
892
|
+
*
|
|
893
|
+
* This method is primarily exposed for use by other Effect provider
|
|
894
|
+
* integrations which can utilize Anthropic models (i.e. Amazon Bedrock).
|
|
895
|
+
*
|
|
896
|
+
* @since 1.0.0
|
|
897
|
+
* @category Tool Calling
|
|
898
|
+
*/
|
|
899
|
+
export const prepareTools = /*#__PURE__*/Effect.fnUntraced(function* (options, config) {
|
|
900
|
+
// Return immediately if no tools are in the toolkit or a tool choice of
|
|
901
|
+
// "none" was specified
|
|
902
|
+
if (options.tools.length === 0 || options.toolChoice === "none") {
|
|
903
|
+
return {
|
|
904
|
+
betas: new Set(),
|
|
905
|
+
tools: undefined,
|
|
906
|
+
toolChoice: undefined
|
|
907
|
+
};
|
|
908
|
+
}
|
|
909
|
+
const betas = new Set();
|
|
910
|
+
let tools = [];
|
|
911
|
+
let toolChoice = undefined;
|
|
912
|
+
// Convert the tools in the toolkit to the provider-defined format
|
|
913
|
+
for (const tool of options.tools) {
|
|
914
|
+
if (Tool.isUserDefined(tool)) {
|
|
915
|
+
tools.push({
|
|
916
|
+
name: tool.name,
|
|
917
|
+
description: Tool.getDescription(tool),
|
|
918
|
+
input_schema: Tool.getJsonSchema(tool)
|
|
919
|
+
});
|
|
479
920
|
}
|
|
480
|
-
|
|
921
|
+
if (Tool.isProviderDefined(tool)) {
|
|
922
|
+
switch (tool.id) {
|
|
923
|
+
case "anthropic.bash_20241022":
|
|
924
|
+
{
|
|
925
|
+
betas.add("computer-use-2024-10-22");
|
|
926
|
+
tools.push({
|
|
927
|
+
name: "bash",
|
|
928
|
+
type: "bash_20241022"
|
|
929
|
+
});
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
case "anthropic.bash_20250124":
|
|
933
|
+
{
|
|
934
|
+
betas.add("computer-use-2025-01-24");
|
|
935
|
+
tools.push({
|
|
936
|
+
name: "bash",
|
|
937
|
+
type: "bash_20250124"
|
|
938
|
+
});
|
|
939
|
+
break;
|
|
940
|
+
}
|
|
941
|
+
case "anthropic.code_execution_20250522":
|
|
942
|
+
{
|
|
943
|
+
betas.add("code-execution-2025-05-22");
|
|
944
|
+
tools.push({
|
|
945
|
+
...tool.args,
|
|
946
|
+
name: "code_execution",
|
|
947
|
+
type: "code_execution_2025522"
|
|
948
|
+
});
|
|
949
|
+
break;
|
|
950
|
+
}
|
|
951
|
+
case "anthropic.code_execution_20250825":
|
|
952
|
+
{
|
|
953
|
+
betas.add("code-execution-2025-08-25");
|
|
954
|
+
tools.push({
|
|
955
|
+
...tool.args,
|
|
956
|
+
name: "code_execution",
|
|
957
|
+
type: "code_execution_20250825"
|
|
958
|
+
});
|
|
959
|
+
break;
|
|
960
|
+
}
|
|
961
|
+
case "anthropic.computer_use_20241022":
|
|
962
|
+
{
|
|
963
|
+
betas.add("computer-use-2025-10-22");
|
|
964
|
+
tools.push({
|
|
965
|
+
...tool.args,
|
|
966
|
+
name: "computer",
|
|
967
|
+
type: "computer_20241022"
|
|
968
|
+
});
|
|
969
|
+
break;
|
|
970
|
+
}
|
|
971
|
+
case "anthropic.computer_use_20250124":
|
|
972
|
+
{
|
|
973
|
+
betas.add("computer-use-2025-01-24");
|
|
974
|
+
tools.push({
|
|
975
|
+
...tool.args,
|
|
976
|
+
name: "computer",
|
|
977
|
+
type: "computer_20250124"
|
|
978
|
+
});
|
|
979
|
+
break;
|
|
980
|
+
}
|
|
981
|
+
case "anthropic.text_editor_20241022":
|
|
982
|
+
{
|
|
983
|
+
betas.add("computer-use-2024-10-22");
|
|
984
|
+
tools.push({
|
|
985
|
+
name: "str_replace_editor",
|
|
986
|
+
type: "text_editor_20241022"
|
|
987
|
+
});
|
|
988
|
+
break;
|
|
989
|
+
}
|
|
990
|
+
case "anthropic.text_editor_20250124":
|
|
991
|
+
{
|
|
992
|
+
betas.add("computer-use-2025-01-24");
|
|
993
|
+
tools.push({
|
|
994
|
+
name: "str_replace_editor",
|
|
995
|
+
type: "text_editor_20250124"
|
|
996
|
+
});
|
|
997
|
+
break;
|
|
998
|
+
}
|
|
999
|
+
case "anthropic.text_editor_20250429":
|
|
1000
|
+
{
|
|
1001
|
+
betas.add("computer-use-2025-01-24");
|
|
1002
|
+
tools.push({
|
|
1003
|
+
name: "str_replace_based_edit_tool",
|
|
1004
|
+
type: "text_editor_20250429"
|
|
1005
|
+
});
|
|
1006
|
+
break;
|
|
1007
|
+
}
|
|
1008
|
+
case "anthropic.text_editor_20250728":
|
|
1009
|
+
{
|
|
1010
|
+
tools.push({
|
|
1011
|
+
name: "str_replace_based_edit_tool",
|
|
1012
|
+
type: "text_editor_20250728"
|
|
1013
|
+
});
|
|
1014
|
+
break;
|
|
1015
|
+
}
|
|
1016
|
+
case "anthropic.web_search_20250305":
|
|
1017
|
+
{
|
|
1018
|
+
tools.push({
|
|
1019
|
+
...tool.args,
|
|
1020
|
+
name: "web_search",
|
|
1021
|
+
type: "web_search_20250305"
|
|
1022
|
+
});
|
|
1023
|
+
break;
|
|
1024
|
+
}
|
|
1025
|
+
default:
|
|
1026
|
+
{
|
|
1027
|
+
return yield* new AiError.MalformedInput({
|
|
1028
|
+
module: "AnthropicLanguageModel",
|
|
1029
|
+
method: "prepareTools",
|
|
1030
|
+
description: `Received request to call unknown provider-defined tool '${tool.name}'`
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
}
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
// Convert the tool choice to the provider-defined format
|
|
1037
|
+
if (options.toolChoice === "auto") {
|
|
1038
|
+
toolChoice = {
|
|
1039
|
+
type: "auto",
|
|
1040
|
+
disable_parallel_tool_use: config.disableParallelToolCalls
|
|
1041
|
+
};
|
|
1042
|
+
} else if (options.toolChoice === "required") {
|
|
1043
|
+
toolChoice = {
|
|
1044
|
+
type: "any",
|
|
1045
|
+
disable_parallel_tool_use: config.disableParallelToolCalls
|
|
1046
|
+
};
|
|
1047
|
+
} else if ("tool" in options.toolChoice) {
|
|
1048
|
+
toolChoice = {
|
|
1049
|
+
type: "tool",
|
|
1050
|
+
name: options.toolChoice.tool,
|
|
1051
|
+
disable_parallel_tool_use: config.disableParallelToolCalls
|
|
1052
|
+
};
|
|
1053
|
+
} else {
|
|
1054
|
+
const allowedTools = new Set(options.toolChoice.oneOf);
|
|
1055
|
+
tools = tools.filter(tool => allowedTools.has(tool.name));
|
|
1056
|
+
toolChoice = {
|
|
1057
|
+
type: options.toolChoice.mode === "required" ? "any" : "auto",
|
|
1058
|
+
disable_parallel_tool_use: config.disableParallelToolCalls
|
|
1059
|
+
};
|
|
1060
|
+
}
|
|
1061
|
+
return {
|
|
1062
|
+
betas,
|
|
1063
|
+
tools,
|
|
1064
|
+
toolChoice
|
|
1065
|
+
};
|
|
1066
|
+
});
|
|
1067
|
+
const groupMessages = prompt => {
|
|
1068
|
+
const messages = [];
|
|
1069
|
+
let current = undefined;
|
|
1070
|
+
for (const message of prompt.content) {
|
|
1071
|
+
switch (message.role) {
|
|
1072
|
+
case "system":
|
|
1073
|
+
{
|
|
1074
|
+
if (current?.type !== "system") {
|
|
1075
|
+
current = {
|
|
1076
|
+
type: "system",
|
|
1077
|
+
messages: []
|
|
1078
|
+
};
|
|
1079
|
+
messages.push(current);
|
|
1080
|
+
}
|
|
1081
|
+
current.messages.push(message);
|
|
1082
|
+
break;
|
|
1083
|
+
}
|
|
1084
|
+
case "assistant":
|
|
1085
|
+
{
|
|
1086
|
+
if (current?.type !== "assistant") {
|
|
1087
|
+
current = {
|
|
1088
|
+
type: "assistant",
|
|
1089
|
+
messages: []
|
|
1090
|
+
};
|
|
1091
|
+
messages.push(current);
|
|
1092
|
+
}
|
|
1093
|
+
current.messages.push(message);
|
|
1094
|
+
break;
|
|
1095
|
+
}
|
|
1096
|
+
case "tool":
|
|
1097
|
+
case "user":
|
|
1098
|
+
{
|
|
1099
|
+
if (current?.type !== "user") {
|
|
1100
|
+
current = {
|
|
1101
|
+
type: "user",
|
|
1102
|
+
messages: []
|
|
1103
|
+
};
|
|
1104
|
+
messages.push(current);
|
|
1105
|
+
}
|
|
1106
|
+
current.messages.push(message);
|
|
1107
|
+
break;
|
|
1108
|
+
}
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
return messages;
|
|
1112
|
+
};
|
|
1113
|
+
const isCitationPart = part => {
|
|
1114
|
+
if (part.type === "file" && (part.mediaType === "application/pdf" || part.mediaType === "text/plain")) {
|
|
1115
|
+
return part.options.anthropic?.citations?.enabled ?? false;
|
|
1116
|
+
}
|
|
1117
|
+
return false;
|
|
1118
|
+
};
|
|
1119
|
+
const extractCitableDocuments = prompt => {
|
|
1120
|
+
const citableDocuments = [];
|
|
1121
|
+
for (const message of prompt.content) {
|
|
1122
|
+
if (message.role === "user") {
|
|
1123
|
+
for (const part of message.content) {
|
|
1124
|
+
if (isCitationPart(part)) {
|
|
1125
|
+
citableDocuments.push({
|
|
1126
|
+
title: part.fileName ?? "Untitled Document",
|
|
1127
|
+
fileName: part.fileName,
|
|
1128
|
+
mediaType: part.mediaType
|
|
1129
|
+
});
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
return citableDocuments;
|
|
1135
|
+
};
|
|
1136
|
+
const getCacheControl = part => part.options.anthropic?.cacheControl;
|
|
1137
|
+
const getDocumentMetadata = part => {
|
|
1138
|
+
const options = part.options.anthropic;
|
|
1139
|
+
if (Predicate.isNotUndefined(options)) {
|
|
1140
|
+
return {
|
|
1141
|
+
title: options.documentTitle,
|
|
1142
|
+
context: options.documentContext
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
return undefined;
|
|
481
1146
|
};
|
|
1147
|
+
const shouldEnableCitations = part => part.options.anthropic?.citations?.enabled ?? false;
|
|
1148
|
+
const processCitation = /*#__PURE__*/Effect.fnUntraced(function* (citation, citableDocuments, idGenerator) {
|
|
1149
|
+
if (citation.type === "page_location" || citation.type === "char_location") {
|
|
1150
|
+
const citedDocument = citableDocuments[citation.document_index];
|
|
1151
|
+
if (Predicate.isNotUndefined(citedDocument)) {
|
|
1152
|
+
const id = yield* idGenerator.generateId();
|
|
1153
|
+
const metadata = citation.type === "char_location" ? {
|
|
1154
|
+
source: "document",
|
|
1155
|
+
type: citation.type,
|
|
1156
|
+
citedText: citation.cited_text,
|
|
1157
|
+
startCharIndex: citation.start_char_index,
|
|
1158
|
+
endCharIndex: citation.end_char_index
|
|
1159
|
+
} : {
|
|
1160
|
+
source: "document",
|
|
1161
|
+
type: citation.type,
|
|
1162
|
+
citedText: citation.cited_text,
|
|
1163
|
+
startPageNumber: citation.start_page_number,
|
|
1164
|
+
endPageNumber: citation.end_page_number
|
|
1165
|
+
};
|
|
1166
|
+
return {
|
|
1167
|
+
type: "source",
|
|
1168
|
+
sourceType: "document",
|
|
1169
|
+
id,
|
|
1170
|
+
mediaType: citedDocument.mediaType,
|
|
1171
|
+
title: citation.document_title ?? citedDocument.title,
|
|
1172
|
+
fileName: citedDocument.fileName,
|
|
1173
|
+
metadata: {
|
|
1174
|
+
anthropic: metadata
|
|
1175
|
+
}
|
|
1176
|
+
};
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
if (citation.type === "web_search_result_location") {
|
|
1180
|
+
const id = yield* idGenerator.generateId();
|
|
1181
|
+
const metadata = {
|
|
1182
|
+
source: "url",
|
|
1183
|
+
citedText: citation.cited_text,
|
|
1184
|
+
encryptedIndex: citation.encrypted_index
|
|
1185
|
+
};
|
|
1186
|
+
return {
|
|
1187
|
+
type: "source",
|
|
1188
|
+
sourceType: "url",
|
|
1189
|
+
id,
|
|
1190
|
+
url: citation.url,
|
|
1191
|
+
title: citation.title ?? "Untitled",
|
|
1192
|
+
metadata: {
|
|
1193
|
+
anthropic: metadata
|
|
1194
|
+
}
|
|
1195
|
+
};
|
|
1196
|
+
}
|
|
1197
|
+
});
|
|
482
1198
|
//# sourceMappingURL=AnthropicLanguageModel.js.map
|