@stacksjs/ai 0.70.55 → 0.70.56
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/package.json +10 -7
- package/src/agents/claude/index.ts +0 -310
- package/src/agents/index.ts +0 -7
- package/src/buddy.ts +0 -619
- package/src/drivers/anthropic/index.ts +0 -430
- package/src/drivers/claude-agent-sdk/index.ts +0 -370
- package/src/drivers/index.ts +0 -14
- package/src/drivers/ollama/index.ts +0 -514
- package/src/drivers/openai/index.ts +0 -529
- package/src/image.ts +0 -607
- package/src/index.ts +0 -53
- package/src/mcp.ts +0 -658
- package/src/personalization.ts +0 -490
- package/src/search.ts +0 -555
- package/src/text.ts +0 -79
- package/src/types.ts +0 -229
- package/src/utils/client-bedrock-runtime.ts +0 -51
- package/src/utils/client-bedrock.ts +0 -75
- package/src/utils/model-access.ts +0 -32
- package/src/utils/retry.ts +0 -124
- package/src/utils/tokens.ts +0 -159
- package/src/utils/usage.ts +0 -98
- package/src/utils/vision.ts +0 -119
- /package/dist/{src/agents → agents}/claude/index.d.ts +0 -0
- /package/dist/{src/agents → agents}/index.d.ts +0 -0
- /package/dist/{src/buddy.d.ts → buddy.d.ts} +0 -0
- /package/dist/{src/drivers → drivers}/anthropic/index.d.ts +0 -0
- /package/dist/{src/drivers → drivers}/claude-agent-sdk/index.d.ts +0 -0
- /package/dist/{src/drivers → drivers}/index.d.ts +0 -0
- /package/dist/{src/drivers → drivers}/ollama/index.d.ts +0 -0
- /package/dist/{src/drivers → drivers}/openai/index.d.ts +0 -0
- /package/dist/{src/image.d.ts → image.d.ts} +0 -0
- /package/dist/{src/index.d.ts → index.d.ts} +0 -0
- /package/dist/{src/index.js → index.js} +0 -0
- /package/dist/{src/mcp.d.ts → mcp.d.ts} +0 -0
- /package/dist/{src/personalization.d.ts → personalization.d.ts} +0 -0
- /package/dist/{src/search.d.ts → search.d.ts} +0 -0
- /package/dist/{src/text.d.ts → text.d.ts} +0 -0
- /package/dist/{src/types.d.ts → types.d.ts} +0 -0
- /package/dist/{src/utils → utils}/client-bedrock-runtime.d.ts +0 -0
- /package/dist/{src/utils → utils}/client-bedrock.d.ts +0 -0
- /package/dist/{src/utils → utils}/model-access.d.ts +0 -0
- /package/dist/{src/utils → utils}/retry.d.ts +0 -0
- /package/dist/{src/utils → utils}/tokens.d.ts +0 -0
- /package/dist/{src/utils → utils}/usage.d.ts +0 -0
- /package/dist/{src/utils → utils}/vision.d.ts +0 -0
|
@@ -1,430 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Anthropic Claude API Driver
|
|
3
|
-
*
|
|
4
|
-
* Direct API integration with Anthropic's Claude models.
|
|
5
|
-
* Supports chat completions and streaming.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import type { AIDriver, AIDriverConfig, AIMessage, AIResult, ChatCompletionOptions, ClaudeAPIResponse, ClaudeStreamEvent } from '../../types'
|
|
9
|
-
import { fetchWithRetry } from '../../utils/retry'
|
|
10
|
-
import { recordUsage } from '../../utils/usage'
|
|
11
|
-
import { normalizeMessagesForProvider } from '../../utils/vision'
|
|
12
|
-
|
|
13
|
-
export interface AnthropicDriverConfig extends AIDriverConfig {
|
|
14
|
-
apiKey: string
|
|
15
|
-
model?: string
|
|
16
|
-
maxTokens?: number
|
|
17
|
-
anthropicVersion?: string
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
const DEFAULT_MODEL = 'claude-sonnet-4-20250514'
|
|
21
|
-
const DEFAULT_MAX_TOKENS = 4096
|
|
22
|
-
const DEFAULT_VERSION = '2023-06-01'
|
|
23
|
-
const BASE_URL = 'https://api.anthropic.com/v1'
|
|
24
|
-
|
|
25
|
-
let globalConfig: AnthropicDriverConfig | null = null
|
|
26
|
-
|
|
27
|
-
/**
|
|
28
|
-
* Configure Anthropic globally
|
|
29
|
-
*/
|
|
30
|
-
export function configure(config: AnthropicDriverConfig): void {
|
|
31
|
-
globalConfig = config
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
function getConfig(config?: Partial<AnthropicDriverConfig>): AnthropicDriverConfig {
|
|
35
|
-
const merged = { ...globalConfig, ...config }
|
|
36
|
-
if (!merged.apiKey) {
|
|
37
|
-
merged.apiKey = process.env.ANTHROPIC_API_KEY || ''
|
|
38
|
-
}
|
|
39
|
-
return merged as AnthropicDriverConfig
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export function createAnthropicDriver(config: AnthropicDriverConfig): AIDriver {
|
|
43
|
-
const {
|
|
44
|
-
apiKey,
|
|
45
|
-
model = DEFAULT_MODEL,
|
|
46
|
-
maxTokens = DEFAULT_MAX_TOKENS,
|
|
47
|
-
anthropicVersion = DEFAULT_VERSION,
|
|
48
|
-
} = config
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
name: 'Claude API',
|
|
52
|
-
|
|
53
|
-
async process(command: string, systemPrompt: string, history: AIMessage[]): Promise<string> {
|
|
54
|
-
if (!apiKey) {
|
|
55
|
-
throw new Error('Anthropic API key not set. Configure your API key in settings.')
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// Retry-aware fetch (stacksjs/stacks#1878 A-5). Honors 429
|
|
59
|
-
// Retry-After + exponential backoff on 5xx (overloaded
|
|
60
|
-
// capacity is the common Anthropic blocker).
|
|
61
|
-
const response = await fetchWithRetry(`${BASE_URL}/messages`, {
|
|
62
|
-
method: 'POST',
|
|
63
|
-
headers: {
|
|
64
|
-
'Content-Type': 'application/json',
|
|
65
|
-
'x-api-key': apiKey,
|
|
66
|
-
'anthropic-version': anthropicVersion,
|
|
67
|
-
},
|
|
68
|
-
body: JSON.stringify({
|
|
69
|
-
model,
|
|
70
|
-
max_tokens: maxTokens,
|
|
71
|
-
system: systemPrompt,
|
|
72
|
-
messages: [...history, { role: 'user', content: command }],
|
|
73
|
-
}),
|
|
74
|
-
})
|
|
75
|
-
|
|
76
|
-
if (!response.ok) {
|
|
77
|
-
const error = await response.text()
|
|
78
|
-
throw new Error(`Claude API error: ${error}`)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const data = (await response.json()) as ClaudeAPIResponse
|
|
82
|
-
if (!data.content || data.content.length === 0) {
|
|
83
|
-
throw new Error('Claude API returned empty content')
|
|
84
|
-
}
|
|
85
|
-
return data.content[0].text
|
|
86
|
-
},
|
|
87
|
-
|
|
88
|
-
async *stream(command: string, systemPrompt: string, history: AIMessage[]): AsyncGenerator<string> {
|
|
89
|
-
if (!apiKey) {
|
|
90
|
-
throw new Error('Anthropic API key not set. Configure your API key in settings.')
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
const response = await fetch(`${BASE_URL}/messages`, {
|
|
94
|
-
method: 'POST',
|
|
95
|
-
headers: {
|
|
96
|
-
'Content-Type': 'application/json',
|
|
97
|
-
'x-api-key': apiKey,
|
|
98
|
-
'anthropic-version': anthropicVersion,
|
|
99
|
-
},
|
|
100
|
-
body: JSON.stringify({
|
|
101
|
-
model,
|
|
102
|
-
max_tokens: maxTokens,
|
|
103
|
-
system: systemPrompt,
|
|
104
|
-
stream: true,
|
|
105
|
-
messages: [...history, { role: 'user', content: command }],
|
|
106
|
-
}),
|
|
107
|
-
})
|
|
108
|
-
|
|
109
|
-
if (!response.ok) {
|
|
110
|
-
const error = await response.text()
|
|
111
|
-
throw new Error(`Claude API error: ${error}`)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
const reader = response.body?.getReader()
|
|
115
|
-
if (!reader) throw new Error('No response body')
|
|
116
|
-
|
|
117
|
-
const decoder = new TextDecoder()
|
|
118
|
-
let buffer = ''
|
|
119
|
-
|
|
120
|
-
// Mid-stream error visibility (stacksjs/stacks#1878 A-2).
|
|
121
|
-
// Anthropic surfaces stream errors as `event: error` /
|
|
122
|
-
// `data: { type: 'error', error: { type, message } }`.
|
|
123
|
-
// The pre-fix code dropped these silently — the consumer
|
|
124
|
-
// saw a truncated response and assumed success. Now: throw
|
|
125
|
-
// so the caller knows the stream was cut short.
|
|
126
|
-
const handlePayload = function* (data: string) {
|
|
127
|
-
if (data === '[DONE]') return
|
|
128
|
-
let event: ClaudeStreamEvent & { type: string, error?: { type?: string, message?: string } }
|
|
129
|
-
try {
|
|
130
|
-
event = JSON.parse(data) as any
|
|
131
|
-
}
|
|
132
|
-
catch {
|
|
133
|
-
return
|
|
134
|
-
}
|
|
135
|
-
if (event.type === 'error') {
|
|
136
|
-
const msg = event.error?.message ?? JSON.stringify(event.error ?? event)
|
|
137
|
-
throw new Error(`[anthropic/stream] mid-stream error: ${msg}`)
|
|
138
|
-
}
|
|
139
|
-
if (event.type === 'content_block_delta' && event.delta?.text) {
|
|
140
|
-
yield event.delta.text
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
while (true) {
|
|
145
|
-
const { done, value } = await reader.read()
|
|
146
|
-
if (done) break
|
|
147
|
-
|
|
148
|
-
buffer += decoder.decode(value, { stream: true })
|
|
149
|
-
const lines = buffer.split('\n')
|
|
150
|
-
buffer = lines.pop() || ''
|
|
151
|
-
|
|
152
|
-
for (const line of lines) {
|
|
153
|
-
if (line.startsWith('data: ')) {
|
|
154
|
-
yield * handlePayload(line.slice(6))
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
// Process any remaining data in the buffer
|
|
160
|
-
if (buffer.startsWith('data: ')) {
|
|
161
|
-
yield * handlePayload(buffer.slice(6))
|
|
162
|
-
}
|
|
163
|
-
},
|
|
164
|
-
}
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
/**
|
|
168
|
-
* Chat completion with full options. Supports tools + structured
|
|
169
|
-
* output via `responseFormat` (stacksjs/stacks#1878 A-1).
|
|
170
|
-
*/
|
|
171
|
-
export async function chat(
|
|
172
|
-
messages: AIMessage[],
|
|
173
|
-
options: ChatCompletionOptions & { system?: string } = {},
|
|
174
|
-
): Promise<AIResult> {
|
|
175
|
-
const config = getConfig()
|
|
176
|
-
const {
|
|
177
|
-
model = DEFAULT_MODEL,
|
|
178
|
-
maxTokens = DEFAULT_MAX_TOKENS,
|
|
179
|
-
temperature,
|
|
180
|
-
topP,
|
|
181
|
-
stop,
|
|
182
|
-
system,
|
|
183
|
-
tools,
|
|
184
|
-
toolChoice,
|
|
185
|
-
responseFormat,
|
|
186
|
-
} = options
|
|
187
|
-
|
|
188
|
-
// Build the request body. Tools and tool_choice map directly to
|
|
189
|
-
// Claude's Messages API. responseFormat is mapped to the
|
|
190
|
-
// tools-as-json pattern (Claude 3.5+ doesn't have a first-class
|
|
191
|
-
// JSON-mode parameter; the standard idiom is "define a tool whose
|
|
192
|
-
// input is the JSON shape and force the model to call it").
|
|
193
|
-
// Normalize content arrays into Anthropic's wire format
|
|
194
|
-
// (stacksjs/stacks#1878 A-3). Apps that authored their messages
|
|
195
|
-
// with OpenAI-style `image_url` blocks (or use cross-driver
|
|
196
|
-
// helpers) get the right shape on the wire.
|
|
197
|
-
const normalizedMessages = normalizeMessagesForProvider(messages, 'anthropic')
|
|
198
|
-
|
|
199
|
-
// Track wall-clock duration for usage reporters (#1878 A-6).
|
|
200
|
-
const startedAt = Date.now()
|
|
201
|
-
|
|
202
|
-
const body: Record<string, unknown> = {
|
|
203
|
-
model,
|
|
204
|
-
max_tokens: maxTokens,
|
|
205
|
-
temperature,
|
|
206
|
-
top_p: topP,
|
|
207
|
-
stop_sequences: stop ? (Array.isArray(stop) ? stop : [stop]) : undefined,
|
|
208
|
-
system,
|
|
209
|
-
messages: normalizedMessages,
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
if (tools && tools.length > 0) {
|
|
213
|
-
body.tools = tools.map(t => ({
|
|
214
|
-
name: t.name,
|
|
215
|
-
description: t.description,
|
|
216
|
-
input_schema: t.parameters ?? { type: 'object', properties: {} },
|
|
217
|
-
}))
|
|
218
|
-
if (toolChoice !== undefined)
|
|
219
|
-
body.tool_choice = mapAnthropicToolChoice(toolChoice)
|
|
220
|
-
}
|
|
221
|
-
|
|
222
|
-
// responseFormat → tools-as-json shape. If callers provide both
|
|
223
|
-
// explicit tools AND responseFormat, the structured-output tool
|
|
224
|
-
// is appended and forced via tool_choice. Caller's explicit
|
|
225
|
-
// tool_choice wins.
|
|
226
|
-
if (responseFormat && responseFormat.type !== 'text') {
|
|
227
|
-
const outputTool = buildAnthropicJsonTool(responseFormat)
|
|
228
|
-
const existing = Array.isArray(body.tools) ? body.tools as unknown[] : []
|
|
229
|
-
body.tools = [...existing, outputTool]
|
|
230
|
-
if (toolChoice === undefined) {
|
|
231
|
-
body.tool_choice = { type: 'tool', name: outputTool.name }
|
|
232
|
-
}
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
const response = await fetch(`${BASE_URL}/messages`, {
|
|
236
|
-
method: 'POST',
|
|
237
|
-
headers: {
|
|
238
|
-
'Content-Type': 'application/json',
|
|
239
|
-
'x-api-key': config.apiKey,
|
|
240
|
-
'anthropic-version': config.anthropicVersion || DEFAULT_VERSION,
|
|
241
|
-
},
|
|
242
|
-
body: JSON.stringify(body),
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
if (!response.ok) {
|
|
246
|
-
const error = await response.text()
|
|
247
|
-
throw new Error(`Claude API error: ${error}`)
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const data = (await response.json()) as any
|
|
251
|
-
|
|
252
|
-
if (!data.content || data.content.length === 0) {
|
|
253
|
-
throw new Error('Claude API returned empty content')
|
|
254
|
-
}
|
|
255
|
-
|
|
256
|
-
// Extract the content. For tool-use-as-json, the response is a
|
|
257
|
-
// tool_use block whose `input` field holds the structured object;
|
|
258
|
-
// we JSON.stringify it for the `content` string field so callers
|
|
259
|
-
// can JSON.parse back out. For freeform, the first text block.
|
|
260
|
-
const block = data.content.find((b: { type: string }) => b.type === 'tool_use')
|
|
261
|
-
?? data.content.find((b: { type: string }) => b.type === 'text')
|
|
262
|
-
?? data.content[0]
|
|
263
|
-
const content = block?.type === 'tool_use'
|
|
264
|
-
? JSON.stringify(block.input)
|
|
265
|
-
: (block?.text ?? '')
|
|
266
|
-
|
|
267
|
-
const result: AIResult = {
|
|
268
|
-
content,
|
|
269
|
-
model: data.model,
|
|
270
|
-
usage: {
|
|
271
|
-
promptTokens: data.usage?.input_tokens || 0,
|
|
272
|
-
completionTokens: data.usage?.output_tokens || 0,
|
|
273
|
-
totalTokens: (data.usage?.input_tokens || 0) + (data.usage?.output_tokens || 0),
|
|
274
|
-
},
|
|
275
|
-
finishReason: data.stop_reason,
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
// Fire registered usage reporters (#1878 A-6).
|
|
279
|
-
recordUsage({
|
|
280
|
-
provider: 'anthropic',
|
|
281
|
-
model: data.model,
|
|
282
|
-
promptTokens: result.usage!.promptTokens,
|
|
283
|
-
completionTokens: result.usage!.completionTokens,
|
|
284
|
-
totalTokens: result.usage!.totalTokens,
|
|
285
|
-
durationMs: Date.now() - startedAt,
|
|
286
|
-
timestamp: Date.now(),
|
|
287
|
-
})
|
|
288
|
-
|
|
289
|
-
return result
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Map the cross-driver `toolChoice` shape to Anthropic's
|
|
294
|
-
* Messages-API representation.
|
|
295
|
-
*/
|
|
296
|
-
function mapAnthropicToolChoice(choice: NonNullable<ChatCompletionOptions['toolChoice']>): Record<string, unknown> {
|
|
297
|
-
if (choice === 'auto') return { type: 'auto' }
|
|
298
|
-
if (choice === 'required') return { type: 'any' }
|
|
299
|
-
if (choice === 'none') return { type: 'auto', disable_parallel_tool_use: true }
|
|
300
|
-
return { type: 'tool', name: choice.name }
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/**
|
|
304
|
-
* Build a synthetic tool that captures the requested JSON shape,
|
|
305
|
-
* used to coerce structured output via the tool-use idiom.
|
|
306
|
-
*/
|
|
307
|
-
function buildAnthropicJsonTool(format: NonNullable<ChatCompletionOptions['responseFormat']>): { name: string, description: string, input_schema: Record<string, unknown> } {
|
|
308
|
-
if (format.type === 'json_schema') {
|
|
309
|
-
return {
|
|
310
|
-
name: format.json_schema.name,
|
|
311
|
-
description: `Returns the result as JSON matching the '${format.json_schema.name}' schema.`,
|
|
312
|
-
input_schema: format.json_schema.schema,
|
|
313
|
-
}
|
|
314
|
-
}
|
|
315
|
-
// json_object — no schema, just "object with any keys"
|
|
316
|
-
return {
|
|
317
|
-
name: 'structured_output',
|
|
318
|
-
description: 'Returns the result as a JSON object.',
|
|
319
|
-
input_schema: { type: 'object', additionalProperties: true },
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
/**
|
|
324
|
-
* Stream chat completion
|
|
325
|
-
*/
|
|
326
|
-
export async function* streamChat(
|
|
327
|
-
messages: AIMessage[],
|
|
328
|
-
options: ChatCompletionOptions & { system?: string } = {},
|
|
329
|
-
): AsyncGenerator<string> {
|
|
330
|
-
const config = getConfig()
|
|
331
|
-
const {
|
|
332
|
-
model = DEFAULT_MODEL,
|
|
333
|
-
maxTokens = DEFAULT_MAX_TOKENS,
|
|
334
|
-
temperature,
|
|
335
|
-
topP,
|
|
336
|
-
stop,
|
|
337
|
-
system,
|
|
338
|
-
} = options
|
|
339
|
-
|
|
340
|
-
const response = await fetch(`${BASE_URL}/messages`, {
|
|
341
|
-
method: 'POST',
|
|
342
|
-
headers: {
|
|
343
|
-
'Content-Type': 'application/json',
|
|
344
|
-
'x-api-key': config.apiKey,
|
|
345
|
-
'anthropic-version': config.anthropicVersion || DEFAULT_VERSION,
|
|
346
|
-
},
|
|
347
|
-
body: JSON.stringify({
|
|
348
|
-
model,
|
|
349
|
-
max_tokens: maxTokens,
|
|
350
|
-
temperature,
|
|
351
|
-
top_p: topP,
|
|
352
|
-
stop_sequences: stop ? (Array.isArray(stop) ? stop : [stop]) : undefined,
|
|
353
|
-
system,
|
|
354
|
-
stream: true,
|
|
355
|
-
messages: normalizeMessagesForProvider(messages, 'anthropic'),
|
|
356
|
-
}),
|
|
357
|
-
})
|
|
358
|
-
|
|
359
|
-
if (!response.ok) {
|
|
360
|
-
const error = await response.text()
|
|
361
|
-
throw new Error(`Claude API error: ${error}`)
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
const reader = response.body?.getReader()
|
|
365
|
-
if (!reader) throw new Error('No response body')
|
|
366
|
-
|
|
367
|
-
const decoder = new TextDecoder()
|
|
368
|
-
let buffer = ''
|
|
369
|
-
|
|
370
|
-
while (true) {
|
|
371
|
-
const { done, value } = await reader.read()
|
|
372
|
-
if (done) break
|
|
373
|
-
|
|
374
|
-
buffer += decoder.decode(value, { stream: true })
|
|
375
|
-
const lines = buffer.split('\n')
|
|
376
|
-
buffer = lines.pop() || ''
|
|
377
|
-
|
|
378
|
-
for (const line of lines) {
|
|
379
|
-
if (line.startsWith('data: ')) {
|
|
380
|
-
const data = line.slice(6)
|
|
381
|
-
if (data === '[DONE]') continue
|
|
382
|
-
|
|
383
|
-
try {
|
|
384
|
-
const event = JSON.parse(data) as ClaudeStreamEvent
|
|
385
|
-
if (event.type === 'content_block_delta' && event.delta?.text) {
|
|
386
|
-
yield event.delta.text
|
|
387
|
-
}
|
|
388
|
-
}
|
|
389
|
-
catch {
|
|
390
|
-
// Skip invalid JSON
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
}
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Simple prompt helper
|
|
399
|
-
*/
|
|
400
|
-
export async function prompt(
|
|
401
|
-
text: string,
|
|
402
|
-
options: ChatCompletionOptions & { system?: string } = {},
|
|
403
|
-
): Promise<string> {
|
|
404
|
-
const result = await chat([{ role: 'user', content: text }], options)
|
|
405
|
-
return result.content
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Count tokens (approximate)
|
|
410
|
-
* Note: This is a rough estimate. For accurate counts, use the tokenizer.
|
|
411
|
-
*/
|
|
412
|
-
export function estimateTokens(text: string): number {
|
|
413
|
-
// Rough estimate: ~4 characters per token for English text
|
|
414
|
-
return Math.ceil(text.length / 4)
|
|
415
|
-
}
|
|
416
|
-
|
|
417
|
-
export const anthropicDriver: { create: typeof createAnthropicDriver } = {
|
|
418
|
-
create: createAnthropicDriver,
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
export const anthropic = {
|
|
422
|
-
configure,
|
|
423
|
-
chat,
|
|
424
|
-
streamChat,
|
|
425
|
-
prompt,
|
|
426
|
-
estimateTokens,
|
|
427
|
-
createDriver: createAnthropicDriver,
|
|
428
|
-
}
|
|
429
|
-
|
|
430
|
-
export default anthropic
|