langfx.js 0.1.0-alpha.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/LICENSE +202 -0
- package/NOTICE +11 -0
- package/README.md +107 -0
- package/dist/agentic.d.ts +128 -0
- package/dist/agentic.js +265 -0
- package/dist/agentic.js.map +1 -0
- package/dist/cache.d.ts +32 -0
- package/dist/cache.js +135 -0
- package/dist/cache.js.map +1 -0
- package/dist/cancellation.d.ts +9 -0
- package/dist/cancellation.js +70 -0
- package/dist/cancellation.js.map +1 -0
- package/dist/errors.d.ts +40 -0
- package/dist/errors.js +44 -0
- package/dist/errors.js.map +1 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/json-stream.d.ts +73 -0
- package/dist/json-stream.js +222 -0
- package/dist/json-stream.js.map +1 -0
- package/dist/langfunc.d.ts +20 -0
- package/dist/langfunc.js +28 -0
- package/dist/langfunc.js.map +1 -0
- package/dist/language-model.d.ts +78 -0
- package/dist/language-model.js +218 -0
- package/dist/language-model.js.map +1 -0
- package/dist/llms/anthropic.d.ts +30 -0
- package/dist/llms/anthropic.js +365 -0
- package/dist/llms/anthropic.js.map +1 -0
- package/dist/llms/gemini.d.ts +34 -0
- package/dist/llms/gemini.js +380 -0
- package/dist/llms/gemini.js.map +1 -0
- package/dist/llms/images.d.ts +10 -0
- package/dist/llms/images.js +43 -0
- package/dist/llms/images.js.map +1 -0
- package/dist/llms/index.d.ts +7 -0
- package/dist/llms/index.js +4 -0
- package/dist/llms/index.js.map +1 -0
- package/dist/llms/openai.d.ts +30 -0
- package/dist/llms/openai.js +398 -0
- package/dist/llms/openai.js.map +1 -0
- package/dist/llms/transport.d.ts +4 -0
- package/dist/llms/transport.js +90 -0
- package/dist/llms/transport.js.map +1 -0
- package/dist/mapping.d.ts +71 -0
- package/dist/mapping.js +190 -0
- package/dist/mapping.js.map +1 -0
- package/dist/message.d.ts +56 -0
- package/dist/message.js +86 -0
- package/dist/message.js.map +1 -0
- package/dist/python-preview.d.ts +24 -0
- package/dist/python-preview.js +368 -0
- package/dist/python-preview.js.map +1 -0
- package/dist/python-stream.d.ts +15 -0
- package/dist/python-stream.js +29 -0
- package/dist/python-stream.js.map +1 -0
- package/dist/python.d.ts +85 -0
- package/dist/python.js +728 -0
- package/dist/python.js.map +1 -0
- package/dist/query.d.ts +31 -0
- package/dist/query.js +151 -0
- package/dist/query.js.map +1 -0
- package/dist/retry.d.ts +12 -0
- package/dist/retry.js +56 -0
- package/dist/retry.js.map +1 -0
- package/dist/schema/zod.d.ts +4 -0
- package/dist/schema/zod.js +7 -0
- package/dist/schema/zod.js.map +1 -0
- package/dist/schema.d.ts +10 -0
- package/dist/schema.js +7 -0
- package/dist/schema.js.map +1 -0
- package/dist/template.d.ts +14 -0
- package/dist/template.js +75 -0
- package/dist/template.js.map +1 -0
- package/dist/testing/index.d.ts +33 -0
- package/dist/testing/index.js +56 -0
- package/dist/testing/index.js.map +1 -0
- package/dist/tool-call.d.ts +27 -0
- package/dist/tool-call.js +16 -0
- package/dist/tool-call.js.map +1 -0
- package/dist/tools.d.ts +43 -0
- package/dist/tools.js +155 -0
- package/dist/tools.js.map +1 -0
- package/docs/ANTHROPIC.md +43 -0
- package/docs/API_DESIGN.md +200 -0
- package/docs/GEMINI.md +68 -0
- package/docs/IMPLEMENTATION_STATUS.md +77 -0
- package/docs/LIVE_TESTING.md +24 -0
- package/docs/MAPPING.md +54 -0
- package/docs/OPENAI.md +40 -0
- package/docs/PORTING_PLAN.md +135 -0
- package/docs/PROMPT_PARITY.md +379 -0
- package/docs/PYTHON_PROTOCOL.md +109 -0
- package/docs/PYTHON_PROTOCOL_PARITY.md +964 -0
- package/docs/PYTHON_SCHEMA_EVALUATION.md +93 -0
- package/docs/PYTHON_STREAMING_PARITY.md +59 -0
- package/docs/RELEASING.md +25 -0
- package/docs/RETRIES_AND_CACHE.md +56 -0
- package/docs/SESSION_EVENTS.md +40 -0
- package/docs/SOURCE_AUDIT.md +133 -0
- package/docs/STREAMING.md +76 -0
- package/docs/TOOL_STREAMING.md +31 -0
- package/package.json +95 -0
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
import { canonical } from './cache.js';
|
|
2
|
+
import { backoff, retryable, retryPolicy } from './retry.js';
|
|
3
|
+
import { abortable, cancellationScope, checkCancelled } from './cancellation.js';
|
|
4
|
+
import { EmptyGenerationError, LMError, UnsupportedCapabilityError } from './errors.js';
|
|
5
|
+
import { AIMessage, Message, Modality, UserMessage } from './message.js';
|
|
6
|
+
let modelSerial = 0;
|
|
7
|
+
export class LanguageModel {
|
|
8
|
+
resultCache = new WeakMap();
|
|
9
|
+
responseCache = new WeakMap();
|
|
10
|
+
modelId;
|
|
11
|
+
cache;
|
|
12
|
+
cacheScope = ++modelSerial;
|
|
13
|
+
runtimeOptions;
|
|
14
|
+
samplingOptions;
|
|
15
|
+
capabilities = Object.freeze({ streaming: false, nativeStructuredOutput: false, media: false });
|
|
16
|
+
constructor(options = {}) {
|
|
17
|
+
const { model, cache = null, cacheSeed = 0, cacheNamespace = '', maxAttempts, retryInterval, exponentialBackoff, maxRetryInterval, ...samplingOptions } = options;
|
|
18
|
+
this.cache = cache;
|
|
19
|
+
this.runtimeOptions = Object.freeze({ cache, cacheSeed, cacheNamespace, ...retryPolicy({
|
|
20
|
+
...(maxAttempts !== undefined ? { maxAttempts } : {}),
|
|
21
|
+
...(retryInterval !== undefined ? { retryInterval: typeof retryInterval === 'number' ? retryInterval : Object.freeze([...retryInterval]) } : {}),
|
|
22
|
+
...(exponentialBackoff !== undefined ? { exponentialBackoff } : {}),
|
|
23
|
+
...(maxRetryInterval !== undefined ? { maxRetryInterval } : {}),
|
|
24
|
+
}) });
|
|
25
|
+
this.modelId = model ?? this.constructor.name;
|
|
26
|
+
this.samplingOptions = Object.freeze({ ...samplingOptions });
|
|
27
|
+
}
|
|
28
|
+
_stream(_prompt, _context) {
|
|
29
|
+
throw new UnsupportedCapabilityError(`${this.modelId} does not support streaming.`);
|
|
30
|
+
}
|
|
31
|
+
async sample(prompts, options = {}) {
|
|
32
|
+
const scope = cancellationScope([options.signal]);
|
|
33
|
+
try {
|
|
34
|
+
checkCancelled(scope.signal);
|
|
35
|
+
const messages = prompts.map(prompt => typeof prompt === 'string' ? new UserMessage(prompt) : prompt);
|
|
36
|
+
const context = this.context(options, scope.signal);
|
|
37
|
+
this.validate(messages, context);
|
|
38
|
+
if (!messages.length)
|
|
39
|
+
return [];
|
|
40
|
+
const runtime = { ...this.runtimeOptions, ...options };
|
|
41
|
+
const policy = retryPolicy(runtime);
|
|
42
|
+
const cache = runtime.cache;
|
|
43
|
+
const seed = runtime.cacheSeed;
|
|
44
|
+
if (seed !== null && seed !== undefined && !Number.isSafeInteger(seed))
|
|
45
|
+
throw new RangeError('cacheSeed must be a safe integer or null.');
|
|
46
|
+
if (!cache && policy.maxAttempts === 1)
|
|
47
|
+
return await this.sampleAttempt(messages, context);
|
|
48
|
+
const results = [];
|
|
49
|
+
// Isolate requests so a later batch failure never repeats a completed prompt.
|
|
50
|
+
for (const message of messages) {
|
|
51
|
+
checkCancelled(scope.signal);
|
|
52
|
+
let key;
|
|
53
|
+
if (cache && seed !== null) {
|
|
54
|
+
const { signal: _signal, ...sampling } = context;
|
|
55
|
+
try {
|
|
56
|
+
key = canonical({ version: 1, instance: this.cacheScope, model: this.modelId, namespace: runtime.cacheNamespace, seed, message, sampling });
|
|
57
|
+
}
|
|
58
|
+
catch { /* Non-data inputs (e.g. Blob/custom classes) bypass caching. */ }
|
|
59
|
+
}
|
|
60
|
+
if (cache && key !== undefined) {
|
|
61
|
+
const hit = await abortable(cache.get(key), scope.signal);
|
|
62
|
+
checkCancelled(scope.signal);
|
|
63
|
+
if (hit) {
|
|
64
|
+
this.validateResults([hit], 1);
|
|
65
|
+
results.push({ ...hit, cacheHit: true, ...(hit.usage ? { cachedUsage: hit.usage } : {}), usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 } });
|
|
66
|
+
this.resultCache.set(results.at(-1), { cache, key });
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
let result;
|
|
71
|
+
for (let attempt = 1;; attempt++) {
|
|
72
|
+
try {
|
|
73
|
+
result = (await this.sampleAttempt([message], context))[0];
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
checkCancelled(scope.signal);
|
|
78
|
+
if (!retryable(error) || attempt >= policy.maxAttempts)
|
|
79
|
+
throw error;
|
|
80
|
+
await backoff(policy, attempt, scope.signal);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
checkCancelled(scope.signal);
|
|
84
|
+
if (cache && key !== undefined)
|
|
85
|
+
await abortable(cache.put(key, result), scope.signal);
|
|
86
|
+
checkCancelled(scope.signal);
|
|
87
|
+
results.push({ ...result, cacheHit: false });
|
|
88
|
+
if (cache && key !== undefined)
|
|
89
|
+
this.resultCache.set(results.at(-1), { cache, key });
|
|
90
|
+
}
|
|
91
|
+
return results;
|
|
92
|
+
}
|
|
93
|
+
finally {
|
|
94
|
+
scope.abort();
|
|
95
|
+
scope.dispose();
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
async call(prompt, options = {}) {
|
|
99
|
+
const input = typeof prompt === 'string' ? new UserMessage(prompt) : prompt;
|
|
100
|
+
const [result] = await this.sample([input], options);
|
|
101
|
+
const response = result.samples[0].response;
|
|
102
|
+
const output = new AIMessage(response.parts, {
|
|
103
|
+
source: input,
|
|
104
|
+
metadata: { ...response.metadata, ...(result.usage ? { usage: result.usage } : {}), cacheHit: result.cacheHit ?? false, ...(result.cachedUsage ? { cachedUsage: result.cachedUsage } : {}) },
|
|
105
|
+
});
|
|
106
|
+
const entry = this.resultCache.get(result);
|
|
107
|
+
if (entry)
|
|
108
|
+
this.responseCache.set(output, entry);
|
|
109
|
+
return output;
|
|
110
|
+
}
|
|
111
|
+
/** Evict the exact entry associated with a response from this model's call(). */
|
|
112
|
+
async invalidateCache(response) {
|
|
113
|
+
const entry = this.responseCache.get(response);
|
|
114
|
+
if (entry) {
|
|
115
|
+
await entry.cache.delete(entry.key);
|
|
116
|
+
this.responseCache.delete(response);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/** Always returns an async iterable directly, never a Promise. */
|
|
120
|
+
async *stream(prompt, options = {}) {
|
|
121
|
+
const scope = cancellationScope([options.signal]);
|
|
122
|
+
let iterator;
|
|
123
|
+
try {
|
|
124
|
+
checkCancelled(scope.signal);
|
|
125
|
+
if ((options.tools ?? this.samplingOptions.tools)?.length && !this.capabilities.toolStreaming)
|
|
126
|
+
throw new UnsupportedCapabilityError(`${this.modelId} does not support streamed tool calls.`);
|
|
127
|
+
if (!this.capabilities.streaming)
|
|
128
|
+
throw new UnsupportedCapabilityError(`${this.modelId} does not support streaming.`);
|
|
129
|
+
const message = typeof prompt === 'string' ? new UserMessage(prompt) : prompt;
|
|
130
|
+
const context = this.context(options, scope.signal);
|
|
131
|
+
this.validate([message], context);
|
|
132
|
+
const policy = retryPolicy({ ...this.runtimeOptions, ...options });
|
|
133
|
+
let emitted = false;
|
|
134
|
+
for (let attempt = 1;; attempt++) {
|
|
135
|
+
const attemptScope = cancellationScope([scope.signal]);
|
|
136
|
+
try {
|
|
137
|
+
iterator = this._stream(message, { ...context, signal: attemptScope.signal })[Symbol.asyncIterator]();
|
|
138
|
+
while (true) {
|
|
139
|
+
const next = await abortable(iterator.next(), attemptScope.signal);
|
|
140
|
+
checkCancelled(scope.signal);
|
|
141
|
+
if (next.done)
|
|
142
|
+
throw new LMError('Provider stream ended without a terminal chunk.');
|
|
143
|
+
if (next.value.index !== 0)
|
|
144
|
+
throw new UnsupportedCapabilityError('Only one stream candidate is supported.');
|
|
145
|
+
emitted = true; // Even an empty visible chunk prevents replay.
|
|
146
|
+
yield next.value;
|
|
147
|
+
if (next.value.isFinal)
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
catch (error) {
|
|
152
|
+
checkCancelled(scope.signal);
|
|
153
|
+
if (emitted || !retryable(error) || attempt >= policy.maxAttempts)
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
attemptScope.abort();
|
|
158
|
+
attemptScope.dispose();
|
|
159
|
+
const current = iterator;
|
|
160
|
+
iterator = undefined;
|
|
161
|
+
await current?.return?.();
|
|
162
|
+
}
|
|
163
|
+
await backoff(policy, attempt, scope.signal);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
finally {
|
|
167
|
+
scope.abort();
|
|
168
|
+
scope.dispose();
|
|
169
|
+
await iterator?.return?.();
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async sampleAttempt(messages, context) {
|
|
173
|
+
const attempt = cancellationScope([context.signal]);
|
|
174
|
+
try {
|
|
175
|
+
checkCancelled(attempt.signal);
|
|
176
|
+
const results = await abortable(this._sample(Object.freeze([...messages]), { ...context, signal: attempt.signal }), attempt.signal);
|
|
177
|
+
checkCancelled(attempt.signal);
|
|
178
|
+
this.validateResults(results, messages.length);
|
|
179
|
+
return [...results];
|
|
180
|
+
}
|
|
181
|
+
finally {
|
|
182
|
+
attempt.abort();
|
|
183
|
+
attempt.dispose();
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
validateResults(results, count) {
|
|
187
|
+
if (results.length !== count)
|
|
188
|
+
throw new LMError('Provider returned a different number of results than prompts.');
|
|
189
|
+
for (const result of results) {
|
|
190
|
+
if (!result.samples.length)
|
|
191
|
+
throw new EmptyGenerationError('Provider returned no candidates.');
|
|
192
|
+
if (result.samples.length !== 1)
|
|
193
|
+
throw new UnsupportedCapabilityError('This milestone supports one candidate per prompt.');
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
context(options, signal) {
|
|
197
|
+
const { cache: _cache, cacheSeed: _seed, cacheNamespace: _namespace, maxAttempts: _attempts, retryInterval: _interval, exponentialBackoff: _backoff, maxRetryInterval: _maxInterval, ...sampling } = options;
|
|
198
|
+
return Object.freeze({ ...this.samplingOptions, ...sampling, signal });
|
|
199
|
+
}
|
|
200
|
+
validate(messages, context) {
|
|
201
|
+
if ((context.tools?.length || context.toolChoice !== undefined) && !this.capabilities.tools) {
|
|
202
|
+
throw new UnsupportedCapabilityError(`${this.modelId} does not support tools.`);
|
|
203
|
+
}
|
|
204
|
+
if (context.toolChoice !== undefined && !context.tools?.length)
|
|
205
|
+
throw new TypeError('toolChoice requires tools.');
|
|
206
|
+
if (context.responseSchema && !this.capabilities.nativeStructuredOutput) {
|
|
207
|
+
throw new UnsupportedCapabilityError(`${this.modelId} does not support native structured output.`);
|
|
208
|
+
}
|
|
209
|
+
if (!this.capabilities.media && messages.some(message => message.sections.some(section => section.parts.some(part => part instanceof Modality)))) {
|
|
210
|
+
throw new UnsupportedCapabilityError(`${this.modelId} does not support media input.`);
|
|
211
|
+
}
|
|
212
|
+
if (context.maxTokens !== undefined && (!Number.isInteger(context.maxTokens) || context.maxTokens < 1))
|
|
213
|
+
throw new RangeError('maxTokens must be a positive integer.');
|
|
214
|
+
if (context.temperature !== undefined && !Number.isFinite(context.temperature))
|
|
215
|
+
throw new RangeError('temperature must be finite.');
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
//# sourceMappingURL=language-model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language-model.js","sourceRoot":"","sources":["../src/language-model.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { LanguageModel } from '../language-model.js';
|
|
2
|
+
import type { LanguageModelOptions, ModelContext, SamplingResult, StreamChunk } from '../language-model.js';
|
|
3
|
+
import { Message } from '../message.js';
|
|
4
|
+
import type { Transport } from './transport.js';
|
|
5
|
+
export interface AnthropicOptions extends LanguageModelOptions {
|
|
6
|
+
readonly model: string;
|
|
7
|
+
readonly apiKey?: string | ((signal: AbortSignal) => string | Promise<string>);
|
|
8
|
+
/** API version root; default https://api.anthropic.com/v1. */
|
|
9
|
+
readonly baseUrl?: string;
|
|
10
|
+
readonly transport?: Transport;
|
|
11
|
+
}
|
|
12
|
+
/** Messages API: text, complete client tools, and text SSE. No SDK/global credentials. */
|
|
13
|
+
export declare class Anthropic extends LanguageModel {
|
|
14
|
+
readonly capabilities: Readonly<{
|
|
15
|
+
streaming: true;
|
|
16
|
+
nativeStructuredOutput: false;
|
|
17
|
+
media: true;
|
|
18
|
+
tools: true;
|
|
19
|
+
toolStreaming: true;
|
|
20
|
+
}>;
|
|
21
|
+
private readonly endpoint;
|
|
22
|
+
private readonly transport;
|
|
23
|
+
private readonly apiKey;
|
|
24
|
+
constructor(options: AnthropicOptions);
|
|
25
|
+
protected _sample(prompts: readonly Message[], context: ModelContext): Promise<SamplingResult[]>;
|
|
26
|
+
protected _stream(prompt: Message, context: ModelContext): AsyncIterable<StreamChunk>;
|
|
27
|
+
private message;
|
|
28
|
+
private body;
|
|
29
|
+
private request;
|
|
30
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
import { JsonStreamParser } from '../json-stream.js';
|
|
2
|
+
import { encodeImage, validateImageRole } from './images.js';
|
|
3
|
+
import { LanguageModel } from '../language-model.js';
|
|
4
|
+
import { AIMessage, Image, Message } from '../message.js';
|
|
5
|
+
import { ToolCall } from '../tool-call.js';
|
|
6
|
+
import { abortable, checkCancelled } from '../cancellation.js';
|
|
7
|
+
import { AuthenticationError, ContentFilteredError, EmptyGenerationError, IncompleteGenerationError, LMError, RateLimitError, TemporaryLMError, UnsupportedCapabilityError } from '../errors.js';
|
|
8
|
+
import { readJson, sse } from './transport.js';
|
|
9
|
+
function object(value) {
|
|
10
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
11
|
+
throw new LMError('Invalid Anthropic object.');
|
|
12
|
+
return value;
|
|
13
|
+
}
|
|
14
|
+
function string(value) {
|
|
15
|
+
if (typeof value !== 'string')
|
|
16
|
+
throw new LMError('Invalid Anthropic text field.');
|
|
17
|
+
return value;
|
|
18
|
+
}
|
|
19
|
+
function count(value) {
|
|
20
|
+
if (typeof value !== 'number' || !Number.isSafeInteger(value) || value < 0)
|
|
21
|
+
throw new LMError('Invalid Anthropic usage.');
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
function usage(value) {
|
|
25
|
+
if (value['input_tokens'] === undefined || value['output_tokens'] === undefined)
|
|
26
|
+
return undefined;
|
|
27
|
+
const promptTokens = count(value['input_tokens']) + count(value['cache_creation_input_tokens'] ?? 0) + count(value['cache_read_input_tokens'] ?? 0);
|
|
28
|
+
const completionTokens = count(value['output_tokens']);
|
|
29
|
+
if (!Number.isSafeInteger(promptTokens + completionTokens))
|
|
30
|
+
throw new LMError('Anthropic token count overflow.');
|
|
31
|
+
return { promptTokens, completionTokens, totalTokens: promptTokens + completionTokens };
|
|
32
|
+
}
|
|
33
|
+
function finish(reason, tools) {
|
|
34
|
+
if (reason === 'max_tokens' || reason === 'model_context_window_exceeded')
|
|
35
|
+
throw new IncompleteGenerationError('Anthropic generation was truncated.');
|
|
36
|
+
if (reason === 'refusal')
|
|
37
|
+
throw new ContentFilteredError('Anthropic refused the request.');
|
|
38
|
+
if (tools ? reason !== 'tool_use' : !['end_turn', 'stop_sequence'].includes(String(reason)))
|
|
39
|
+
throw new LMError('Unsupported or inconsistent Anthropic stop reason.');
|
|
40
|
+
return string(reason);
|
|
41
|
+
}
|
|
42
|
+
function providerError(type) {
|
|
43
|
+
if (type === 'rate_limit_error')
|
|
44
|
+
return new RateLimitError('Anthropic rate limit.');
|
|
45
|
+
if (type === 'overloaded_error' || type === 'api_error')
|
|
46
|
+
return new TemporaryLMError('Anthropic temporarily unavailable.');
|
|
47
|
+
if (type === 'authentication_error' || type === 'permission_error')
|
|
48
|
+
return new AuthenticationError('Anthropic authentication failed.');
|
|
49
|
+
return new LMError('Anthropic request failed.');
|
|
50
|
+
}
|
|
51
|
+
function freeze(value) {
|
|
52
|
+
if (value && typeof value === 'object') {
|
|
53
|
+
for (const child of Object.values(value))
|
|
54
|
+
freeze(child);
|
|
55
|
+
Object.freeze(value);
|
|
56
|
+
}
|
|
57
|
+
return value;
|
|
58
|
+
}
|
|
59
|
+
/** Messages API: text, complete client tools, and text SSE. No SDK/global credentials. */
|
|
60
|
+
export class Anthropic extends LanguageModel {
|
|
61
|
+
capabilities = Object.freeze({ streaming: true, nativeStructuredOutput: false, media: true, tools: true, toolStreaming: true });
|
|
62
|
+
endpoint;
|
|
63
|
+
transport;
|
|
64
|
+
apiKey;
|
|
65
|
+
constructor(options) {
|
|
66
|
+
const { model, apiKey, baseUrl = 'https://api.anthropic.com/v1', transport, ...settings } = options;
|
|
67
|
+
if (!model || !/^[\w.-]+$/.test(model))
|
|
68
|
+
throw new TypeError('Expected an Anthropic model ID.');
|
|
69
|
+
super({ maxTokens: 4096, ...settings, model });
|
|
70
|
+
this.endpoint = baseUrl.replace(/\/$/, '');
|
|
71
|
+
this.apiKey = apiKey;
|
|
72
|
+
this.transport = transport ?? ((url, init) => fetch(url, init));
|
|
73
|
+
}
|
|
74
|
+
async _sample(prompts, context) {
|
|
75
|
+
const results = [];
|
|
76
|
+
for (const prompt of prompts) {
|
|
77
|
+
const response = await this.request(prompt, context, false);
|
|
78
|
+
const data = object(await readJson(response, context.signal));
|
|
79
|
+
if (data['type'] === 'error')
|
|
80
|
+
throw providerError(object(data['error'])['type']);
|
|
81
|
+
if (data['type'] !== 'message' || data['role'] !== 'assistant' || !Array.isArray(data['content']))
|
|
82
|
+
throw new LMError('Invalid Anthropic message.');
|
|
83
|
+
const blocks = data['content'].map(object);
|
|
84
|
+
finish(data['stop_reason'], blocks.some(block => block['type'] === 'tool_use'));
|
|
85
|
+
const parsed = this.message(blocks);
|
|
86
|
+
const tokens = data['usage'] === undefined ? undefined : usage(object(data['usage']));
|
|
87
|
+
results.push({ samples: [{ response: parsed }], ...(tokens ? { usage: tokens } : {}) });
|
|
88
|
+
}
|
|
89
|
+
return results;
|
|
90
|
+
}
|
|
91
|
+
async *_stream(prompt, context) {
|
|
92
|
+
const response = await this.request(prompt, context, true);
|
|
93
|
+
let started = false, ending = false, blockOpen = false, index = -1, text = '', reason;
|
|
94
|
+
let tokens = {};
|
|
95
|
+
const blocks = [], ids = new Set();
|
|
96
|
+
let current, args = '';
|
|
97
|
+
let totalChars = 0;
|
|
98
|
+
const bound = (piece) => { totalChars += piece.length; if (totalChars > 16_777_216)
|
|
99
|
+
throw new LMError('Anthropic stream exceeds size limit.'); };
|
|
100
|
+
const partial = () => new AIMessage(text);
|
|
101
|
+
for await (const raw of sse(response, context.signal)) {
|
|
102
|
+
let event;
|
|
103
|
+
try {
|
|
104
|
+
event = object(JSON.parse(raw));
|
|
105
|
+
}
|
|
106
|
+
catch (cause) {
|
|
107
|
+
throw new LMError('Invalid Anthropic SSE event.', { cause });
|
|
108
|
+
}
|
|
109
|
+
const type = event['type'];
|
|
110
|
+
if (type === 'ping')
|
|
111
|
+
continue;
|
|
112
|
+
if (type === 'error')
|
|
113
|
+
throw providerError(object(event['error'])['type']);
|
|
114
|
+
if (type === 'message_start') {
|
|
115
|
+
if (started)
|
|
116
|
+
throw new LMError('Duplicate Anthropic message_start.');
|
|
117
|
+
const message = object(event['message']);
|
|
118
|
+
if (message['role'] !== 'assistant' || !Array.isArray(message['content']) || message['content'].length)
|
|
119
|
+
throw new LMError('Invalid Anthropic stream start.');
|
|
120
|
+
tokens = object(message['usage']);
|
|
121
|
+
started = true;
|
|
122
|
+
}
|
|
123
|
+
else if (type === 'content_block_start') {
|
|
124
|
+
if (!started || ending || blockOpen || event['index'] !== index + 1)
|
|
125
|
+
throw new LMError('Invalid Anthropic block order.');
|
|
126
|
+
const block = object(event['content_block']);
|
|
127
|
+
if (block['type'] !== 'text' && block['type'] !== 'tool_use')
|
|
128
|
+
throw new UnsupportedCapabilityError('Unsupported Anthropic streamed block.');
|
|
129
|
+
if (blocks.length >= 1024)
|
|
130
|
+
throw new LMError('Anthropic stream exceeds block limit.');
|
|
131
|
+
index++;
|
|
132
|
+
blockOpen = true;
|
|
133
|
+
current = { ...block };
|
|
134
|
+
args = '';
|
|
135
|
+
blocks.push(current);
|
|
136
|
+
if (block['type'] === 'tool_use') {
|
|
137
|
+
const id = string(block['id']), name = string(block['name']);
|
|
138
|
+
if (!id || !name || ids.has(id) || Object.keys(object(block['input'])).length)
|
|
139
|
+
throw new LMError('Invalid Anthropic streamed tool start.');
|
|
140
|
+
ids.add(id);
|
|
141
|
+
bound(id + name);
|
|
142
|
+
yield { delta: new AIMessage(''), aggregated: partial(), index: 0, isFinal: false, toolEvent: Object.freeze({ type: 'toolCallStart', id, name }) };
|
|
143
|
+
continue;
|
|
144
|
+
}
|
|
145
|
+
const delta = string(block['text']);
|
|
146
|
+
text += delta;
|
|
147
|
+
bound(delta);
|
|
148
|
+
if (text.length > 16_777_216)
|
|
149
|
+
throw new LMError('Anthropic stream exceeds size limit.');
|
|
150
|
+
if (delta)
|
|
151
|
+
yield { delta: new AIMessage(delta), aggregated: new AIMessage(text), index: 0, isFinal: false };
|
|
152
|
+
}
|
|
153
|
+
else if (type === 'content_block_delta') {
|
|
154
|
+
if (!blockOpen || event['index'] !== index || ending)
|
|
155
|
+
throw new LMError('Invalid Anthropic content delta order.');
|
|
156
|
+
const delta = object(event['delta']);
|
|
157
|
+
if (current?.['type'] === 'tool_use') {
|
|
158
|
+
if (delta['type'] !== 'input_json_delta')
|
|
159
|
+
throw new LMError('Invalid Anthropic tool delta type.');
|
|
160
|
+
const piece = string(delta['partial_json']);
|
|
161
|
+
bound(piece);
|
|
162
|
+
args += piece;
|
|
163
|
+
if (args.length > 1_048_576)
|
|
164
|
+
throw new LMError('Tool arguments exceed size limit.');
|
|
165
|
+
yield { delta: new AIMessage(''), aggregated: partial(), index: 0, isFinal: false, toolEvent: Object.freeze({ type: 'toolCallDelta', id: string(current['id']), delta: piece }) };
|
|
166
|
+
continue;
|
|
167
|
+
}
|
|
168
|
+
if (delta['type'] !== 'text_delta')
|
|
169
|
+
throw new UnsupportedCapabilityError('Unsupported Anthropic delta type.');
|
|
170
|
+
const piece = string(delta['text']);
|
|
171
|
+
text += piece;
|
|
172
|
+
bound(piece);
|
|
173
|
+
current['text'] = string(current['text']) + piece;
|
|
174
|
+
if (text.length > 16_777_216)
|
|
175
|
+
throw new LMError('Anthropic stream exceeds size limit.');
|
|
176
|
+
yield { delta: new AIMessage(piece), aggregated: new AIMessage(text), index: 0, isFinal: false };
|
|
177
|
+
}
|
|
178
|
+
else if (type === 'content_block_stop') {
|
|
179
|
+
if (!blockOpen || event['index'] !== index)
|
|
180
|
+
throw new LMError('Invalid Anthropic block stop.');
|
|
181
|
+
blockOpen = false;
|
|
182
|
+
if (current?.['type'] === 'tool_use') {
|
|
183
|
+
try {
|
|
184
|
+
const parser = new JsonStreamParser();
|
|
185
|
+
for (const _event of parser.feed(args || '{}')) { /* Only complete arguments are exposed. */ }
|
|
186
|
+
for (const _event of parser.finish()) { /* Validate terminal parser state. */ }
|
|
187
|
+
current['input'] = object(parser.value);
|
|
188
|
+
}
|
|
189
|
+
catch (cause) {
|
|
190
|
+
throw new LMError('Invalid streamed tool arguments.', { cause });
|
|
191
|
+
}
|
|
192
|
+
const call = freeze(new ToolCall(string(current['id']), string(current['name']), object(current['input'])));
|
|
193
|
+
yield { delta: new AIMessage(''), aggregated: partial(), index: 0, isFinal: false, toolEvent: Object.freeze({ type: 'toolCallEnd', call }) };
|
|
194
|
+
}
|
|
195
|
+
current = undefined;
|
|
196
|
+
}
|
|
197
|
+
else if (type === 'message_delta') {
|
|
198
|
+
if (!started || blockOpen)
|
|
199
|
+
throw new LMError('Invalid Anthropic message delta order.');
|
|
200
|
+
ending = true;
|
|
201
|
+
const delta = object(event['delta']);
|
|
202
|
+
if (delta['stop_reason'] != null)
|
|
203
|
+
reason = delta['stop_reason'];
|
|
204
|
+
if (event['usage'] !== undefined)
|
|
205
|
+
tokens = { ...tokens, ...object(event['usage']) };
|
|
206
|
+
}
|
|
207
|
+
else if (type === 'message_stop') {
|
|
208
|
+
if (!started || !ending || blockOpen)
|
|
209
|
+
throw new LMError('Incomplete Anthropic stream.');
|
|
210
|
+
const finishReason = finish(reason, ids.size > 0);
|
|
211
|
+
if (!text && !ids.size)
|
|
212
|
+
throw new EmptyGenerationError('Anthropic returned no text.');
|
|
213
|
+
const finalUsage = usage(tokens);
|
|
214
|
+
yield { delta: new AIMessage(''), aggregated: this.message(blocks), index: 0, isFinal: true, finishReason, ...(finalUsage ? { usage: finalUsage } : {}) };
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
else if (typeof type !== 'string')
|
|
218
|
+
throw new LMError('Missing Anthropic event type.');
|
|
219
|
+
// Unknown future event types are ignored; unsupported content blocks fail explicitly.
|
|
220
|
+
}
|
|
221
|
+
throw new IncompleteGenerationError('Anthropic stream ended before message_stop.');
|
|
222
|
+
}
|
|
223
|
+
message(blocks) {
|
|
224
|
+
let text = '';
|
|
225
|
+
const calls = [];
|
|
226
|
+
const ids = new Set();
|
|
227
|
+
for (const block of blocks) {
|
|
228
|
+
if (block['type'] === 'text')
|
|
229
|
+
text += string(block['text']);
|
|
230
|
+
else if (block['type'] === 'tool_use') {
|
|
231
|
+
const call = new ToolCall(string(block['id']), string(block['name']), object(block['input']));
|
|
232
|
+
if (ids.has(call.id))
|
|
233
|
+
throw new LMError('Duplicate Anthropic tool-call ID.');
|
|
234
|
+
ids.add(call.id);
|
|
235
|
+
calls.push(call);
|
|
236
|
+
}
|
|
237
|
+
else
|
|
238
|
+
throw new UnsupportedCapabilityError('Unsupported Anthropic response content block.');
|
|
239
|
+
}
|
|
240
|
+
if (!text && !calls.length)
|
|
241
|
+
throw new EmptyGenerationError('Anthropic returned no content.');
|
|
242
|
+
return new AIMessage(text, { metadata: freeze({ toolCalls: calls, anthropic: { model: this.modelId, endpoint: this.endpoint, content: blocks } }) });
|
|
243
|
+
}
|
|
244
|
+
async body(prompt, context, stream) {
|
|
245
|
+
const system = [], messages = [];
|
|
246
|
+
const pending = new Set();
|
|
247
|
+
for (const section of prompt.sections) {
|
|
248
|
+
validateImageRole(section);
|
|
249
|
+
if (section.role === 'system') {
|
|
250
|
+
if (messages.length)
|
|
251
|
+
throw new LMError('Anthropic system messages must precede conversation turns.');
|
|
252
|
+
if (section.text)
|
|
253
|
+
system.push({ type: 'text', text: section.text });
|
|
254
|
+
continue;
|
|
255
|
+
}
|
|
256
|
+
let content = [];
|
|
257
|
+
if (section.role === 'tool') {
|
|
258
|
+
const id = section.metadata['toolCallId'];
|
|
259
|
+
if (typeof id !== 'string' || !pending.delete(id))
|
|
260
|
+
throw new LMError('Unmatched Anthropic tool result.');
|
|
261
|
+
content = [{ type: 'tool_result', tool_use_id: id, content: section.text }];
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
if (pending.size)
|
|
265
|
+
throw new LMError('Missing Anthropic tool results.');
|
|
266
|
+
if (section.parts.some(part => part instanceof Image)) {
|
|
267
|
+
for (const part of section.parts) {
|
|
268
|
+
if (typeof part === 'string')
|
|
269
|
+
content.push({ type: 'text', text: part });
|
|
270
|
+
else {
|
|
271
|
+
const image = await encodeImage(part, context.signal);
|
|
272
|
+
content.push({ type: 'image', source: 'url' in image ? { type: 'url', url: image.url } : { type: 'base64', media_type: image.mimeType, data: image.data } });
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
else if (section.text)
|
|
277
|
+
content.push({ type: 'text', text: section.text });
|
|
278
|
+
if (section.toolCalls.length && section.role !== 'assistant')
|
|
279
|
+
throw new LMError('Tool calls require an assistant message.');
|
|
280
|
+
const continuation = section.metadata['anthropic'];
|
|
281
|
+
if (continuation !== undefined) {
|
|
282
|
+
const data = object(continuation);
|
|
283
|
+
if (section.role !== 'assistant' || data['model'] !== this.modelId || data['endpoint'] !== this.endpoint || !Array.isArray(data['content']))
|
|
284
|
+
throw new LMError('Anthropic continuation belongs to another model or endpoint.');
|
|
285
|
+
content = data['content'].map(object);
|
|
286
|
+
this.message(content); // Validate supported complete blocks before replay.
|
|
287
|
+
}
|
|
288
|
+
else
|
|
289
|
+
for (const call of section.toolCalls)
|
|
290
|
+
content.push({ type: 'tool_use', id: call.id, name: call.name, input: call.args });
|
|
291
|
+
for (const block of content)
|
|
292
|
+
if (block['type'] === 'tool_use') {
|
|
293
|
+
const id = string(block['id']);
|
|
294
|
+
if (pending.has(id))
|
|
295
|
+
throw new LMError('Duplicate Anthropic tool-call ID.');
|
|
296
|
+
pending.add(id);
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!content.length)
|
|
300
|
+
throw new LMError('Empty Anthropic conversation turn.');
|
|
301
|
+
const role = section.role === 'assistant' ? 'assistant' : 'user';
|
|
302
|
+
const previous = messages.at(-1);
|
|
303
|
+
if (previous?.role === role)
|
|
304
|
+
previous.content.push(...content);
|
|
305
|
+
else
|
|
306
|
+
messages.push({ role, content });
|
|
307
|
+
}
|
|
308
|
+
if (pending.size)
|
|
309
|
+
throw new LMError('Missing Anthropic tool results.');
|
|
310
|
+
if (messages[0]?.role !== 'user')
|
|
311
|
+
throw new LMError('Anthropic conversation must begin with a user message.');
|
|
312
|
+
const body = { model: this.modelId, max_tokens: context.maxTokens, messages, stream };
|
|
313
|
+
if (system.length)
|
|
314
|
+
body['system'] = system;
|
|
315
|
+
if (context.temperature !== undefined)
|
|
316
|
+
body['temperature'] = context.temperature;
|
|
317
|
+
if (context.tools?.length)
|
|
318
|
+
body['tools'] = context.tools.map(tool => ({ name: tool.name, description: tool.description, input_schema: tool.inputSchema }));
|
|
319
|
+
if (context.toolChoice !== undefined) {
|
|
320
|
+
if (typeof context.toolChoice === 'object') {
|
|
321
|
+
if (!context.tools?.some(tool => tool.name === context.toolChoice.name))
|
|
322
|
+
throw new TypeError('Unknown toolChoice name.');
|
|
323
|
+
body['tool_choice'] = { type: 'tool', name: context.toolChoice.name };
|
|
324
|
+
}
|
|
325
|
+
else
|
|
326
|
+
body['tool_choice'] = { type: context.toolChoice };
|
|
327
|
+
}
|
|
328
|
+
return body;
|
|
329
|
+
}
|
|
330
|
+
async request(prompt, context, stream) {
|
|
331
|
+
const body = JSON.stringify(await this.body(prompt, context, stream));
|
|
332
|
+
checkCancelled(context.signal);
|
|
333
|
+
const headers = { 'content-type': 'application/json', 'anthropic-version': '2023-06-01' };
|
|
334
|
+
const key = typeof this.apiKey === 'function' ? await abortable(Promise.resolve(this.apiKey(context.signal)), context.signal) : this.apiKey;
|
|
335
|
+
if (key !== undefined) {
|
|
336
|
+
if (!key)
|
|
337
|
+
throw new AuthenticationError('Empty Anthropic API key.');
|
|
338
|
+
headers['x-api-key'] = key;
|
|
339
|
+
}
|
|
340
|
+
checkCancelled(context.signal);
|
|
341
|
+
const response = await abortable(this.transport(`${this.endpoint}/messages`, { method: 'POST', headers, body, signal: context.signal }), context.signal);
|
|
342
|
+
if (!response.ok) {
|
|
343
|
+
try {
|
|
344
|
+
await response.body?.cancel();
|
|
345
|
+
}
|
|
346
|
+
catch { /* Preserve classified error. */ }
|
|
347
|
+
if (response.status === 401 || response.status === 403)
|
|
348
|
+
throw new AuthenticationError('Anthropic authentication failed.');
|
|
349
|
+
if (response.status === 429)
|
|
350
|
+
throw new RateLimitError('Anthropic rate limit.');
|
|
351
|
+
if (response.status >= 500)
|
|
352
|
+
throw new TemporaryLMError('Anthropic temporarily unavailable.');
|
|
353
|
+
throw new LMError(`Anthropic HTTP ${response.status}.`);
|
|
354
|
+
}
|
|
355
|
+
if (stream && !response.headers.get('content-type')?.includes('text/event-stream')) {
|
|
356
|
+
try {
|
|
357
|
+
await response.body?.cancel();
|
|
358
|
+
}
|
|
359
|
+
catch { /* Preserve error. */ }
|
|
360
|
+
throw new LMError('Expected Anthropic SSE response.');
|
|
361
|
+
}
|
|
362
|
+
return response;
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=anthropic.js.map
|