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