@node-llm/core 0.4.0 → 0.5.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 (53) hide show
  1. package/README.md +43 -20
  2. package/dist/chat/Chat.d.ts +1 -1
  3. package/dist/chat/Chat.d.ts.map +1 -1
  4. package/dist/chat/Chat.js +2 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +2 -0
  8. package/dist/llm.d.ts.map +1 -1
  9. package/dist/llm.js +4 -0
  10. package/dist/providers/Provider.d.ts +1 -0
  11. package/dist/providers/Provider.d.ts.map +1 -1
  12. package/dist/providers/anthropic/AnthropicProvider.d.ts +32 -0
  13. package/dist/providers/anthropic/AnthropicProvider.d.ts.map +1 -0
  14. package/dist/providers/anthropic/AnthropicProvider.js +51 -0
  15. package/dist/providers/anthropic/Capabilities.d.ts +47 -0
  16. package/dist/providers/anthropic/Capabilities.d.ts.map +1 -0
  17. package/dist/providers/anthropic/Capabilities.js +153 -0
  18. package/dist/providers/anthropic/Chat.d.ts +8 -0
  19. package/dist/providers/anthropic/Chat.d.ts.map +1 -0
  20. package/dist/providers/anthropic/Chat.js +93 -0
  21. package/dist/providers/anthropic/Errors.d.ts +2 -0
  22. package/dist/providers/anthropic/Errors.d.ts.map +1 -0
  23. package/dist/providers/anthropic/Errors.js +33 -0
  24. package/dist/providers/anthropic/Models.d.ts +8 -0
  25. package/dist/providers/anthropic/Models.d.ts.map +1 -0
  26. package/dist/providers/anthropic/Models.js +63 -0
  27. package/dist/providers/anthropic/Streaming.d.ts +8 -0
  28. package/dist/providers/anthropic/Streaming.d.ts.map +1 -0
  29. package/dist/providers/anthropic/Streaming.js +104 -0
  30. package/dist/providers/anthropic/Utils.d.ts +5 -0
  31. package/dist/providers/anthropic/Utils.d.ts.map +1 -0
  32. package/dist/providers/anthropic/Utils.js +125 -0
  33. package/dist/providers/anthropic/index.d.ts +2 -0
  34. package/dist/providers/anthropic/index.d.ts.map +1 -0
  35. package/dist/providers/anthropic/index.js +11 -0
  36. package/dist/providers/anthropic/types.d.ts +57 -0
  37. package/dist/providers/anthropic/types.d.ts.map +1 -0
  38. package/dist/providers/anthropic/types.js +1 -0
  39. package/dist/providers/gemini/Capabilities.d.ts.map +1 -1
  40. package/dist/providers/gemini/Capabilities.js +5 -2
  41. package/dist/providers/gemini/Chat.d.ts +1 -0
  42. package/dist/providers/gemini/Chat.d.ts.map +1 -1
  43. package/dist/providers/gemini/Chat.js +43 -4
  44. package/dist/providers/gemini/GeminiProvider.d.ts +2 -1
  45. package/dist/providers/gemini/GeminiProvider.d.ts.map +1 -1
  46. package/dist/providers/gemini/GeminiProvider.js +3 -0
  47. package/dist/providers/gemini/Streaming.d.ts +1 -0
  48. package/dist/providers/gemini/Streaming.d.ts.map +1 -1
  49. package/dist/providers/gemini/Streaming.js +34 -4
  50. package/dist/providers/registry.js +1 -1
  51. package/dist/utils/FileLoader.d.ts.map +1 -1
  52. package/dist/utils/FileLoader.js +1 -0
  53. package/package.json +1 -1
@@ -0,0 +1,93 @@
1
+ import { Capabilities } from "./Capabilities.js";
2
+ import { handleAnthropicError } from "./Errors.js";
3
+ import { formatSystemPrompt, formatMessages } from "./Utils.js";
4
+ export class AnthropicChat {
5
+ baseUrl;
6
+ apiKey;
7
+ constructor(baseUrl, apiKey) {
8
+ this.baseUrl = baseUrl;
9
+ this.apiKey = apiKey;
10
+ }
11
+ async execute(request) {
12
+ const model = request.model;
13
+ const maxTokens = request.max_tokens || Capabilities.getMaxOutputTokens(model) || 4096;
14
+ const systemPrompt = formatSystemPrompt(request.messages);
15
+ const messages = formatMessages(request.messages);
16
+ let system = systemPrompt;
17
+ if (request.response_format) {
18
+ let schemaText = "";
19
+ if (request.response_format.type === "json_schema" && request.response_format.json_schema?.schema) {
20
+ schemaText = "\nSchema:\n" + JSON.stringify(request.response_format.json_schema.schema, null, 2);
21
+ }
22
+ const instruction = `CRITICAL: Respond ONLY with a valid JSON object matching the requested schema.${schemaText}\n\nDo not include any other text or explanation.`;
23
+ system = system ? `${system}\n\n${instruction}` : instruction;
24
+ }
25
+ const body = {
26
+ model: model,
27
+ messages: messages,
28
+ max_tokens: maxTokens,
29
+ system: system,
30
+ stream: false, // For now, no streaming
31
+ };
32
+ if (request.temperature !== undefined) {
33
+ body.temperature = request.temperature;
34
+ }
35
+ // Map tools
36
+ if (request.tools && request.tools.length > 0) {
37
+ body.tools = request.tools.map(tool => ({
38
+ name: tool.function.name,
39
+ description: tool.function.description,
40
+ input_schema: tool.function.parameters
41
+ }));
42
+ }
43
+ // Check if any message contains PDF content to add beta header
44
+ const hasPdf = messages.some(msg => Array.isArray(msg.content) && msg.content.some(block => block.type === "document"));
45
+ const headers = {
46
+ "x-api-key": this.apiKey,
47
+ "anthropic-version": "2023-06-01",
48
+ "content-type": "application/json",
49
+ ...request.headers,
50
+ };
51
+ if (hasPdf) {
52
+ headers["anthropic-beta"] = "pdfs-2024-09-25";
53
+ }
54
+ const response = await fetch(`${this.baseUrl}/messages`, {
55
+ method: "POST",
56
+ headers: headers,
57
+ body: JSON.stringify(body),
58
+ });
59
+ if (!response.ok) {
60
+ await handleAnthropicError(response, model);
61
+ }
62
+ const json = (await response.json());
63
+ const contentBlocks = json.content;
64
+ // Extract text content and tool calls
65
+ let content = null;
66
+ const toolCalls = []; // Using any for ToolCall matching Provider.ts interface
67
+ for (const block of contentBlocks) {
68
+ if (block.type === "text") {
69
+ if (content === null)
70
+ content = "";
71
+ content += block.text;
72
+ }
73
+ else if (block.type === "tool_use") {
74
+ toolCalls.push({
75
+ id: block.id,
76
+ type: "function",
77
+ function: {
78
+ name: block.name,
79
+ arguments: JSON.stringify(block.input)
80
+ }
81
+ });
82
+ }
83
+ }
84
+ const usage = json.usage ? {
85
+ input_tokens: json.usage.input_tokens,
86
+ output_tokens: json.usage.output_tokens,
87
+ total_tokens: json.usage.input_tokens + json.usage.output_tokens,
88
+ cached_tokens: json.usage.cache_read_input_tokens,
89
+ cache_creation_tokens: json.usage.cache_creation_input_tokens,
90
+ } : undefined;
91
+ return { content, usage, tool_calls: toolCalls.length > 0 ? toolCalls : undefined };
92
+ }
93
+ }
@@ -0,0 +1,2 @@
1
+ export declare function handleAnthropicError(response: Response, modelId: string): Promise<never>;
2
+ //# sourceMappingURL=Errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Errors.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/Errors.ts"],"names":[],"mappings":"AASA,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC,CAsC9F"}
@@ -0,0 +1,33 @@
1
+ import { BadRequestError, AuthenticationError, RateLimitError, ServerError, ServiceUnavailableError, APIError } from "../../errors/index.js";
2
+ export async function handleAnthropicError(response, modelId) {
3
+ const status = response.status;
4
+ let body;
5
+ let message = `Anthropic error (${status})`;
6
+ try {
7
+ body = await response.json();
8
+ if (body?.error?.message) {
9
+ message = body.error.message;
10
+ }
11
+ }
12
+ catch {
13
+ body = await response.text().catch(() => "Unknown error");
14
+ message = `Anthropic error (${status}): ${body}`;
15
+ }
16
+ const provider = "anthropic";
17
+ if (status === 400) {
18
+ throw new BadRequestError(message, body, provider, modelId);
19
+ }
20
+ if (status === 401 || status === 403) {
21
+ throw new AuthenticationError(message, status, body, provider);
22
+ }
23
+ if (status === 429) {
24
+ throw new RateLimitError(message, body, provider, modelId);
25
+ }
26
+ if (status === 502 || status === 503 || status === 529) {
27
+ throw new ServiceUnavailableError(message, status, body, provider, modelId);
28
+ }
29
+ if (status >= 500) {
30
+ throw new ServerError(message, status, body, provider, modelId);
31
+ }
32
+ throw new APIError(message, status, body, provider, modelId);
33
+ }
@@ -0,0 +1,8 @@
1
+ import { ModelInfo } from "../Provider.js";
2
+ export declare class AnthropicModels {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(): Promise<ModelInfo[]>;
7
+ }
8
+ //# sourceMappingURL=Models.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Models.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/Models.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAG3C,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;CAwDtC"}
@@ -0,0 +1,63 @@
1
+ import { Capabilities, ANTHROPIC_MODELS } from "./Capabilities.js";
2
+ export class AnthropicModels {
3
+ baseUrl;
4
+ apiKey;
5
+ constructor(baseUrl, apiKey) {
6
+ this.baseUrl = baseUrl;
7
+ this.apiKey = apiKey;
8
+ }
9
+ async execute() {
10
+ try {
11
+ const response = await fetch(`${this.baseUrl}/models`, {
12
+ method: "GET",
13
+ headers: {
14
+ "x-api-key": this.apiKey,
15
+ "anthropic-version": "2023-06-01",
16
+ "content-type": "application/json",
17
+ },
18
+ });
19
+ if (!response.ok) {
20
+ throw new Error(`Failed to list models: ${response.statusText}`);
21
+ }
22
+ const data = await response.json();
23
+ const models = data.data || [];
24
+ return models.map((model) => {
25
+ const id = model.id;
26
+ const createdAt = new Date(model.created_at);
27
+ return {
28
+ id: id,
29
+ name: model.display_name || id,
30
+ provider: "anthropic",
31
+ family: Capabilities.getFamily(id),
32
+ context_window: Capabilities.getContextWindow(id),
33
+ max_output_tokens: Capabilities.getMaxOutputTokens(id),
34
+ modalities: Capabilities.getModalities(id),
35
+ capabilities: Capabilities.getCapabilities(id),
36
+ pricing: Capabilities.getPricing(id),
37
+ created_at: createdAt
38
+ };
39
+ });
40
+ }
41
+ catch (error) {
42
+ // Fallback to currently defined static models if API list fails
43
+ return Object.entries(ANTHROPIC_MODELS).filter(([key]) => key !== "other").map(([key, def]) => {
44
+ let id = key.replace(/_/g, "-");
45
+ if (id.includes("claude-3-5"))
46
+ id = "claude-3-5-sonnet-20240620";
47
+ else if (id.includes("claude-3-haiku"))
48
+ id = "claude-3-haiku-20240307";
49
+ return {
50
+ id: id,
51
+ name: id,
52
+ provider: "anthropic",
53
+ family: Capabilities.getFamily(id),
54
+ context_window: def.contextWindow,
55
+ max_output_tokens: def.maxOutputTokens,
56
+ modalities: Capabilities.getModalities(id),
57
+ capabilities: Capabilities.getCapabilities(id),
58
+ pricing: Capabilities.getPricing(id)
59
+ };
60
+ });
61
+ }
62
+ }
63
+ }
@@ -0,0 +1,8 @@
1
+ import { ChatRequest, ChatChunk } from "../Provider.js";
2
+ export declare class AnthropicStreaming {
3
+ private readonly baseUrl;
4
+ private readonly apiKey;
5
+ constructor(baseUrl: string, apiKey: string);
6
+ execute(request: ChatRequest): AsyncGenerator<ChatChunk>;
7
+ }
8
+ //# sourceMappingURL=Streaming.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Streaming.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/Streaming.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,SAAS,EAAE,MAAM,gBAAgB,CAAC;AAMxD,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEtE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,cAAc,CAAC,SAAS,CAAC;CAgHhE"}
@@ -0,0 +1,104 @@
1
+ import { Capabilities } from "./Capabilities.js";
2
+ import { handleAnthropicError } from "./Errors.js";
3
+ import { formatSystemPrompt, formatMessages } from "./Utils.js";
4
+ export class AnthropicStreaming {
5
+ baseUrl;
6
+ apiKey;
7
+ constructor(baseUrl, apiKey) {
8
+ this.baseUrl = baseUrl;
9
+ this.apiKey = apiKey;
10
+ }
11
+ async *execute(request) {
12
+ const model = request.model;
13
+ const maxTokens = request.max_tokens || Capabilities.getMaxOutputTokens(model) || 4096;
14
+ const systemPrompt = formatSystemPrompt(request.messages);
15
+ const messages = formatMessages(request.messages);
16
+ const body = {
17
+ model: model,
18
+ messages: messages,
19
+ max_tokens: maxTokens,
20
+ system: systemPrompt,
21
+ stream: true,
22
+ };
23
+ if (request.temperature !== undefined) {
24
+ body.temperature = request.temperature;
25
+ }
26
+ if (request.tools && request.tools.length > 0) {
27
+ body.tools = request.tools.map(tool => ({
28
+ name: tool.function.name,
29
+ description: tool.function.description,
30
+ input_schema: tool.function.parameters
31
+ }));
32
+ }
33
+ // Check if any message contains PDF content to add beta header
34
+ const hasPdf = messages.some(msg => Array.isArray(msg.content) && msg.content.some(block => block.type === "document"));
35
+ const headers = {
36
+ "x-api-key": this.apiKey,
37
+ "anthropic-version": "2023-06-01",
38
+ "content-type": "application/json",
39
+ ...request.headers,
40
+ };
41
+ if (hasPdf) {
42
+ headers["anthropic-beta"] = "pdfs-2024-09-25";
43
+ }
44
+ const response = await fetch(`${this.baseUrl}/messages`, {
45
+ method: "POST",
46
+ headers: headers,
47
+ body: JSON.stringify(body),
48
+ });
49
+ if (!response.ok) {
50
+ await handleAnthropicError(response, model);
51
+ }
52
+ if (!response.body) {
53
+ throw new Error("No response body for streaming");
54
+ }
55
+ const reader = response.body.getReader();
56
+ const decoder = new TextDecoder();
57
+ let buffer = "";
58
+ while (true) {
59
+ const { value, done } = await reader.read();
60
+ if (done)
61
+ break;
62
+ const chunk = decoder.decode(value, { stream: true });
63
+ buffer += chunk;
64
+ const lines = buffer.split("\n\n");
65
+ buffer = lines.pop() || "";
66
+ for (const line of lines) {
67
+ const trimmed = line.trim();
68
+ if (!trimmed.startsWith("event: "))
69
+ continue;
70
+ // Format is:
71
+ // event: type
72
+ // data: json
73
+ const parts = trimmed.split("\n");
74
+ const eventLine = parts[0];
75
+ const dataLine = parts.find(p => p.startsWith("data: "));
76
+ if (!dataLine || !eventLine)
77
+ continue;
78
+ const eventType = eventLine.replace("event: ", "").trim();
79
+ const dataStr = dataLine.replace("data: ", "").trim();
80
+ try {
81
+ const data = JSON.parse(dataStr);
82
+ // Handle different event types from Anthropic
83
+ if (eventType === "content_block_delta") {
84
+ if (data.delta && data.delta.type === "text_delta") {
85
+ yield { content: data.delta.text };
86
+ }
87
+ }
88
+ else if (eventType === "message_start") {
89
+ // Could extract initial usage here
90
+ }
91
+ else if (eventType === "message_delta") {
92
+ // Update usage or stop reason
93
+ }
94
+ else if (eventType === "error") {
95
+ throw new Error(`Stream error: ${data.error?.message}`);
96
+ }
97
+ }
98
+ catch (e) {
99
+ // console.warn("Parse error", e);
100
+ }
101
+ }
102
+ }
103
+ }
104
+ }
@@ -0,0 +1,5 @@
1
+ import { Message } from "../../chat/Message.js";
2
+ import { AnthropicMessage } from "./types.js";
3
+ export declare function formatSystemPrompt(messages: Message[]): string | undefined;
4
+ export declare function formatMessages(requestMessages: Message[]): AnthropicMessage[];
5
+ //# sourceMappingURL=Utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Utils.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/Utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAEhD,OAAO,EAAE,gBAAgB,EAAyB,MAAM,YAAY,CAAC;AAErE,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,OAAO,EAAE,GAAG,MAAM,GAAG,SAAS,CAiB1E;AAED,wBAAgB,cAAc,CAAC,eAAe,EAAE,OAAO,EAAE,GAAG,gBAAgB,EAAE,CAyB7E"}
@@ -0,0 +1,125 @@
1
+ export function formatSystemPrompt(messages) {
2
+ let systemPrompt;
3
+ for (const msg of messages) {
4
+ if (msg.role === "system") {
5
+ if (typeof msg.content === "string") {
6
+ systemPrompt = msg.content;
7
+ }
8
+ else if (Array.isArray(msg.content)) {
9
+ systemPrompt = msg.content
10
+ .filter((p) => p.type === "text")
11
+ .map(p => p.text)
12
+ .join("\n");
13
+ }
14
+ else if (msg.content) {
15
+ systemPrompt = String(msg.content);
16
+ }
17
+ }
18
+ }
19
+ return systemPrompt;
20
+ }
21
+ export function formatMessages(requestMessages) {
22
+ const messages = [];
23
+ for (const msg of requestMessages) {
24
+ if (msg.role === "system")
25
+ continue;
26
+ const formatted = formatSingleMessage(msg);
27
+ const lastMsg = messages[messages.length - 1];
28
+ if (lastMsg && lastMsg.role === formatted.role) {
29
+ // Merge content
30
+ let existingContent = Array.isArray(lastMsg.content)
31
+ ? lastMsg.content
32
+ : [{ type: "text", text: lastMsg.content }];
33
+ const newContent = Array.isArray(formatted.content)
34
+ ? formatted.content
35
+ : [{ type: "text", text: formatted.content }];
36
+ lastMsg.content = [...existingContent, ...newContent];
37
+ }
38
+ else {
39
+ messages.push(formatted);
40
+ }
41
+ }
42
+ return messages;
43
+ }
44
+ function formatSingleMessage(msg) {
45
+ const role = msg.role === "user" ? "user" : "assistant";
46
+ // Handle Tool Responses (role: "tool")
47
+ if (msg.role === "tool") {
48
+ return {
49
+ role: "user",
50
+ content: [{
51
+ type: "tool_result",
52
+ tool_use_id: msg.tool_call_id,
53
+ content: typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
54
+ }]
55
+ };
56
+ }
57
+ // Handle Assistant Messages (which might have tool_calls)
58
+ if (msg.role === "assistant" && msg.tool_calls) {
59
+ const blocks = [];
60
+ // Assistant text content
61
+ const text = String(msg.content || "");
62
+ if (text.length > 0) {
63
+ blocks.push({ type: "text", text });
64
+ }
65
+ // Assistant tool uses
66
+ for (const toolCall of msg.tool_calls) {
67
+ blocks.push({
68
+ type: "tool_use",
69
+ id: toolCall.id,
70
+ name: toolCall.function.name,
71
+ input: JSON.parse(toolCall.function.arguments)
72
+ });
73
+ }
74
+ return { role: "assistant", content: blocks };
75
+ }
76
+ const contentText = String(msg.content || "");
77
+ if (contentText && typeof msg.content === "string") {
78
+ return { role, content: contentText };
79
+ }
80
+ if (contentText && msg.content instanceof String) {
81
+ return { role, content: contentText };
82
+ }
83
+ // Handle multimodal content (images)
84
+ const blocks = [];
85
+ if (Array.isArray(msg.content)) {
86
+ for (const part of msg.content) {
87
+ if (part.type === "text") {
88
+ blocks.push({ type: "text", text: part.text });
89
+ }
90
+ else if (part.type === "image_url") {
91
+ const url = part.image_url.url;
92
+ if (url.startsWith("data:")) {
93
+ const parts = url.split(",");
94
+ const meta = parts[0];
95
+ const data = parts.slice(1).join(",");
96
+ if (meta && data) {
97
+ const mimeMatch = meta.match(/:(.*?);/);
98
+ const mediaType = mimeMatch ? mimeMatch[1] : "image/jpeg";
99
+ if (mediaType === "application/pdf") {
100
+ blocks.push({
101
+ type: "document",
102
+ source: {
103
+ type: "base64",
104
+ media_type: "application/pdf",
105
+ data: data
106
+ }
107
+ });
108
+ }
109
+ else {
110
+ blocks.push({
111
+ type: "image",
112
+ source: {
113
+ type: "base64",
114
+ media_type: mediaType || "image/jpeg",
115
+ data: data
116
+ }
117
+ });
118
+ }
119
+ }
120
+ }
121
+ }
122
+ }
123
+ }
124
+ return { role, content: blocks };
125
+ }
@@ -0,0 +1,2 @@
1
+ export declare function registerAnthropicProvider(): void;
2
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/index.ts"],"names":[],"mappings":"AAGA,wBAAgB,yBAAyB,SAQxC"}
@@ -0,0 +1,11 @@
1
+ import { providerRegistry } from "../registry.js";
2
+ import { AnthropicProvider } from "./AnthropicProvider.js";
3
+ export function registerAnthropicProvider() {
4
+ providerRegistry.register("anthropic", () => {
5
+ const apiKey = process.env.ANTHROPIC_API_KEY;
6
+ if (!apiKey) {
7
+ throw new Error("ANTHROPIC_API_KEY environment variable is not set");
8
+ }
9
+ return new AnthropicProvider({ apiKey: apiKey.trim() });
10
+ });
11
+ }
@@ -0,0 +1,57 @@
1
+ export interface AnthropicMessage {
2
+ role: "user" | "assistant";
3
+ content: string | Array<AnthropicContentBlock>;
4
+ }
5
+ export interface AnthropicContentBlock {
6
+ type: "text" | "image" | "tool_use" | "tool_result" | "document";
7
+ text?: string;
8
+ source?: {
9
+ type: "base64";
10
+ media_type: string;
11
+ data: string;
12
+ };
13
+ id?: string;
14
+ name?: string;
15
+ input?: any;
16
+ tool_use_id?: string;
17
+ content?: string | Array<AnthropicContentBlock>;
18
+ is_error?: boolean;
19
+ }
20
+ export interface AnthropicMessageRequest {
21
+ model: string;
22
+ messages: AnthropicMessage[];
23
+ max_tokens: number;
24
+ system?: string;
25
+ metadata?: any;
26
+ stop_sequences?: string[];
27
+ stream?: boolean;
28
+ temperature?: number;
29
+ top_p?: number;
30
+ top_k?: number;
31
+ tools?: any[];
32
+ tool_choice?: any;
33
+ }
34
+ export interface AnthropicUsage {
35
+ input_tokens: number;
36
+ output_tokens: number;
37
+ cache_creation_input_tokens?: number;
38
+ cache_read_input_tokens?: number;
39
+ }
40
+ export interface AnthropicMessageResponse {
41
+ id: string;
42
+ type: "message";
43
+ role: "assistant";
44
+ content: AnthropicContentBlock[];
45
+ model: string;
46
+ stop_reason: "end_turn" | "max_tokens" | "stop_sequence" | "tool_use" | null;
47
+ stop_sequence: string | null;
48
+ usage: AnthropicUsage;
49
+ }
50
+ export interface AnthropicErrorResponse {
51
+ type: "error";
52
+ error: {
53
+ type: string;
54
+ message: string;
55
+ };
56
+ }
57
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/providers/anthropic/types.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAC;IAC3B,OAAO,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,CAAC;CAChD;AAED,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,aAAa,GAAG,UAAU,CAAC;IACjE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE;QACP,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC;QACnB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,GAAG,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC,qBAAqB,CAAC,CAAC;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,uBAAuB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,GAAG,CAAC;IACf,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,GAAG,EAAE,CAAC;IACd,WAAW,CAAC,EAAE,GAAG,CAAC;CACnB;AAED,MAAM,WAAW,cAAc;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,2BAA2B,CAAC,EAAE,MAAM,CAAC;IACrC,uBAAuB,CAAC,EAAE,MAAM,CAAC;CAClC;AAED,MAAM,WAAW,wBAAwB;IACvC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,SAAS,CAAC;IAChB,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,qBAAqB,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,EAAE,UAAU,GAAG,YAAY,GAAG,eAAe,GAAG,UAAU,GAAG,IAAI,CAAC;IAC7E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,MAAM,WAAW,sBAAsB;IACrC,IAAI,EAAE,OAAO,CAAC;IACd,KAAK,EAAE;QACL,IAAI,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH"}
@@ -0,0 +1 @@
1
+ export {};
@@ -1 +1 @@
1
- {"version":3,"file":"Capabilities.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Capabilities.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAY;IACvB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAoBvD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAiBzD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAQ/C,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAQ9C,MAAM,CAAC,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKzD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKnD,MAAM,CAAC,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKxD,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKtD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAInD,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI;IAIzG,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAWzC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAY5E,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAUjD,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM;;;;;;;;IA0BjC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIjD,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAGhC"}
1
+ {"version":3,"file":"Capabilities.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Capabilities.ts"],"names":[],"mappings":"AAAA,qBAAa,YAAY;IACvB,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAoBvD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAiBzD,MAAM,CAAC,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAQ/C,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAQ9C,MAAM,CAAC,wBAAwB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAQzD,MAAM,CAAC,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAIjD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKnD,MAAM,CAAC,uBAAuB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKxD,MAAM,CAAC,qBAAqB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAKtD,MAAM,CAAC,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO;IAInD,MAAM,CAAC,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,SAAS,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,GAAG,IAAI;IAIzG,MAAM,CAAC,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAWzC,MAAM,CAAC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG;QAAE,KAAK,EAAE,MAAM,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE;IAY5E,MAAM,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE;IAUjD,MAAM,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM;;;;;;;;IA0BjC,MAAM,CAAC,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM;IAIjD,OAAO,CAAC,MAAM,CAAC,gBAAgB;CAGhC"}
@@ -49,8 +49,11 @@ export class Capabilities {
49
49
  return !!id.match(/gemini|pro|flash/);
50
50
  }
51
51
  static supportsStructuredOutput(modelId) {
52
- // Explicitly disabled until implementation is validated
53
- return false;
52
+ const id = this.normalizeModelId(modelId);
53
+ if (id.match(/text-embedding|embedding-001|aqa|imagen/)) {
54
+ return false;
55
+ }
56
+ return true;
54
57
  }
55
58
  static supportsJsonMode(modelId) {
56
59
  return this.supportsStructuredOutput(modelId);
@@ -4,5 +4,6 @@ export declare class GeminiChat {
4
4
  private readonly apiKey;
5
5
  constructor(baseUrl: string, apiKey: string);
6
6
  execute(request: ChatRequest): Promise<ChatResponse>;
7
+ private sanitizeSchema;
7
8
  }
8
9
  //# sourceMappingURL=Chat.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM3D,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;CAqE3D"}
1
+ {"version":3,"file":"Chat.d.ts","sourceRoot":"","sources":["../../../src/providers/gemini/Chat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAM3D,qBAAa,UAAU;IACT,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAU,OAAO,CAAC,QAAQ,CAAC,MAAM;gBAAxC,OAAO,EAAE,MAAM,EAAmB,MAAM,EAAE,MAAM;IAEvE,OAAO,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC;IA0F1D,OAAO,CAAC,cAAc;CAwBvB"}
@@ -12,12 +12,31 @@ export class GeminiChat {
12
12
  const temperature = Capabilities.normalizeTemperature(request.temperature, request.model);
13
13
  const url = `${this.baseUrl}/models/${request.model}:generateContent?key=${this.apiKey}`;
14
14
  const { contents, systemInstructionParts } = await GeminiChatUtils.convertMessages(request.messages);
15
+ const generationConfig = {
16
+ temperature: temperature ?? undefined,
17
+ maxOutputTokens: request.max_tokens,
18
+ };
19
+ if (request.response_format?.type === "json_object") {
20
+ generationConfig.responseMimeType = "application/json";
21
+ }
22
+ else if (request.response_format?.type === "json_schema") {
23
+ generationConfig.responseMimeType = "application/json";
24
+ if (request.response_format.json_schema?.schema) {
25
+ generationConfig.responseSchema = request.response_format.json_schema.schema;
26
+ }
27
+ }
28
+ if (request.response_format?.type === "json_object") {
29
+ generationConfig.responseMimeType = "application/json";
30
+ }
31
+ else if (request.response_format?.type === "json_schema") {
32
+ generationConfig.responseMimeType = "application/json";
33
+ if (request.response_format.json_schema?.schema) {
34
+ generationConfig.responseSchema = this.sanitizeSchema(request.response_format.json_schema.schema);
35
+ }
36
+ }
15
37
  const payload = {
16
38
  contents,
17
- generationConfig: {
18
- temperature: temperature ?? undefined,
19
- maxOutputTokens: request.max_tokens,
20
- },
39
+ generationConfig,
21
40
  };
22
41
  if (systemInstructionParts.length > 0) {
23
42
  payload.systemInstruction = { parts: systemInstructionParts };
@@ -66,4 +85,24 @@ export class GeminiChat {
66
85
  } : undefined;
67
86
  return { content, tool_calls, usage };
68
87
  }
88
+ sanitizeSchema(schema) {
89
+ if (typeof schema !== "object" || schema === null)
90
+ return schema;
91
+ const sanitized = { ...schema };
92
+ // Remove unsupported fields
93
+ delete sanitized.additionalProperties;
94
+ delete sanitized.$schema;
95
+ delete sanitized.$id;
96
+ delete sanitized.definitions;
97
+ // Recursively sanitize
98
+ if (sanitized.properties) {
99
+ for (const key in sanitized.properties) {
100
+ sanitized.properties[key] = this.sanitizeSchema(sanitized.properties[key]);
101
+ }
102
+ }
103
+ if (sanitized.items) {
104
+ sanitized.items = this.sanitizeSchema(sanitized.items);
105
+ }
106
+ return sanitized;
107
+ }
69
108
  }