@robota-sdk/agent-provider 3.0.0-beta.64
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 +21 -0
- package/dist/browser/index.d.ts +1104 -0
- package/dist/browser/index.d.ts.map +1 -0
- package/dist/browser/index.js +7 -0
- package/dist/browser/index.js.map +1 -0
- package/dist/loggers/index.cjs +1 -0
- package/dist/loggers/index.d.ts +151 -0
- package/dist/loggers/index.d.ts.map +1 -0
- package/dist/loggers/index.js +2 -0
- package/dist/loggers/index.js.map +1 -0
- package/dist/node/anthropic/index.cjs +1 -0
- package/dist/node/anthropic/index.d.ts +158 -0
- package/dist/node/anthropic/index.d.ts.map +1 -0
- package/dist/node/anthropic/index.js +1 -0
- package/dist/node/anthropic--1vgLC-e.js +5 -0
- package/dist/node/anthropic--1vgLC-e.js.map +1 -0
- package/dist/node/anthropic-BFQ6DSCP.cjs +4 -0
- package/dist/node/bytedance/index.cjs +1 -0
- package/dist/node/bytedance/index.d.ts +74 -0
- package/dist/node/bytedance/index.d.ts.map +1 -0
- package/dist/node/bytedance/index.js +1 -0
- package/dist/node/bytedance-C_0sF_pJ.js +2 -0
- package/dist/node/bytedance-C_0sF_pJ.js.map +1 -0
- package/dist/node/bytedance-DVPxqEiC.cjs +1 -0
- package/dist/node/chunk-Bmb41Sf3.cjs +1 -0
- package/dist/node/deepseek/index.cjs +1 -0
- package/dist/node/deepseek/index.d.ts +2 -0
- package/dist/node/deepseek/index.js +1 -0
- package/dist/node/deepseek-_8Ixx7rA.js +2 -0
- package/dist/node/deepseek-_8Ixx7rA.js.map +1 -0
- package/dist/node/deepseek-oA2Y6bD0.cjs +1 -0
- package/dist/node/gemini/index.cjs +1 -0
- package/dist/node/gemini/index.d.ts +173 -0
- package/dist/node/gemini/index.d.ts.map +1 -0
- package/dist/node/gemini/index.js +1 -0
- package/dist/node/gemini-Bh2U87MY.js +4 -0
- package/dist/node/gemini-Bh2U87MY.js.map +1 -0
- package/dist/node/gemini-DSaNCxZj.cjs +3 -0
- package/dist/node/gemma/index.cjs +1 -0
- package/dist/node/gemma/index.d.ts +2 -0
- package/dist/node/gemma/index.js +1 -0
- package/dist/node/gemma-Dp_AfCUR.js +2 -0
- package/dist/node/gemma-Dp_AfCUR.js.map +1 -0
- package/dist/node/gemma-G-Pf_PnX.cjs +1 -0
- package/dist/node/google/index.cjs +1 -0
- package/dist/node/google/index.d.ts +14 -0
- package/dist/node/google/index.d.ts.map +1 -0
- package/dist/node/google/index.js +2 -0
- package/dist/node/google/index.js.map +1 -0
- package/dist/node/index-B6PnlDMd.d.ts +82 -0
- package/dist/node/index-B6PnlDMd.d.ts.map +1 -0
- package/dist/node/index-B7UvPJcI.d.ts +315 -0
- package/dist/node/index-B7UvPJcI.d.ts.map +1 -0
- package/dist/node/index-BLPOTNb5.d.ts +98 -0
- package/dist/node/index-BLPOTNb5.d.ts.map +1 -0
- package/dist/node/index-BqixM_XD.d.ts +231 -0
- package/dist/node/index-BqixM_XD.d.ts.map +1 -0
- package/dist/node/index-C3beaqKO.d.ts +231 -0
- package/dist/node/index-C3beaqKO.d.ts.map +1 -0
- package/dist/node/index-Cp2XRh9G.d.ts +82 -0
- package/dist/node/index-Cp2XRh9G.d.ts.map +1 -0
- package/dist/node/index-DSv5xruI.d.ts +98 -0
- package/dist/node/index-DSv5xruI.d.ts.map +1 -0
- package/dist/node/index-w0bV1uaP.d.ts +315 -0
- package/dist/node/index-w0bV1uaP.d.ts.map +1 -0
- package/dist/node/index.cjs +1 -0
- package/dist/node/index.d.ts +8 -0
- package/dist/node/index.js +1 -0
- package/dist/node/openai/index.cjs +1 -0
- package/dist/node/openai/index.d.ts +2 -0
- package/dist/node/openai/index.js +1 -0
- package/dist/node/openai-CRQjg4xF.js +2 -0
- package/dist/node/openai-CRQjg4xF.js.map +1 -0
- package/dist/node/openai-compatible-BYfyY5lb.cjs +1 -0
- package/dist/node/openai-compatible-Dm4Sof9e.js +2 -0
- package/dist/node/openai-compatible-Dm4Sof9e.js.map +1 -0
- package/dist/node/openai-xWC6pY7r.cjs +1 -0
- package/dist/node/qwen/index.cjs +1 -0
- package/dist/node/qwen/index.d.ts +2 -0
- package/dist/node/qwen/index.js +1 -0
- package/dist/node/qwen-ChUZobTL.js +2 -0
- package/dist/node/qwen-ChUZobTL.js.map +1 -0
- package/dist/node/qwen-CjT71vSM.cjs +1 -0
- package/package.json +157 -0
- package/src/anthropic/__tests__/abort-streaming.test.ts +199 -0
- package/src/anthropic/__tests__/model-catalog-refresh.test.ts +92 -0
- package/src/anthropic/__tests__/provider-definition.test.ts +55 -0
- package/src/anthropic/__tests__/provider.test.ts +1357 -0
- package/src/anthropic/__tests__/response-parser.test.ts +326 -0
- package/src/anthropic/index.ts +22 -0
- package/src/anthropic/message-converter.ts +181 -0
- package/src/anthropic/model-catalog-refresh.ts +128 -0
- package/src/anthropic/parsers/response-parser.ts +184 -0
- package/src/anthropic/provider-definition.ts +93 -0
- package/src/anthropic/provider.ts +290 -0
- package/src/anthropic/streaming-handler.ts +204 -0
- package/src/anthropic/types/api-types.ts +158 -0
- package/src/anthropic/types.ts +79 -0
- package/src/bytedance/http-client.test.ts +288 -0
- package/src/bytedance/http-client.ts +163 -0
- package/src/bytedance/index.ts +2 -0
- package/src/bytedance/provider.spec.ts +320 -0
- package/src/bytedance/provider.ts +171 -0
- package/src/bytedance/status-mapper.test.ts +299 -0
- package/src/bytedance/status-mapper.ts +141 -0
- package/src/bytedance/types.ts +68 -0
- package/src/deepseek/defaults.ts +4 -0
- package/src/deepseek/index.ts +22 -0
- package/src/deepseek/model-catalog-refresh.test.ts +57 -0
- package/src/deepseek/model-catalog-refresh.ts +105 -0
- package/src/deepseek/model-catalog.ts +55 -0
- package/src/deepseek/provider-definition.test.ts +109 -0
- package/src/deepseek/provider-definition.ts +132 -0
- package/src/deepseek/provider.test.ts +324 -0
- package/src/deepseek/provider.ts +298 -0
- package/src/deepseek/types.ts +37 -0
- package/src/gemini/execution-helpers.ts +233 -0
- package/src/gemini/genai-transport.test.ts +208 -0
- package/src/gemini/image-operations.test.ts +448 -0
- package/src/gemini/image-operations.ts +261 -0
- package/src/gemini/index.ts +11 -0
- package/src/gemini/message-converter.test.ts +616 -0
- package/src/gemini/message-converter.ts +140 -0
- package/src/gemini/model-catalog-refresh.test.ts +107 -0
- package/src/gemini/model-catalog-refresh.ts +92 -0
- package/src/gemini/provider-definition.test.ts +70 -0
- package/src/gemini/provider-definition.ts +78 -0
- package/src/gemini/provider-extended.test.ts +898 -0
- package/src/gemini/provider.spec.ts +216 -0
- package/src/gemini/provider.ts +279 -0
- package/src/gemini/request-converter.ts +226 -0
- package/src/gemini/tool-schema-converter.ts +78 -0
- package/src/gemini/types/api-types.ts +235 -0
- package/src/gemini/types.ts +121 -0
- package/src/gemma/index.ts +5 -0
- package/src/gemma/message-factory.ts +38 -0
- package/src/gemma/provider-definition.test.ts +43 -0
- package/src/gemma/provider-definition.ts +84 -0
- package/src/gemma/provider-projection.ts +49 -0
- package/src/gemma/provider.test.ts +628 -0
- package/src/gemma/provider.ts +308 -0
- package/src/gemma/pseudo-command-envelope.ts +58 -0
- package/src/gemma/pseudo-tool-call-projector.ts +243 -0
- package/src/gemma/pseudo-tool-call-tag-parser.ts +153 -0
- package/src/gemma/pseudo-tool-call-types.ts +31 -0
- package/src/gemma/reasoning-projector.test.ts +52 -0
- package/src/gemma/reasoning-projector.ts +144 -0
- package/src/gemma/streaming-projection.ts +79 -0
- package/src/gemma/tool-call-argument-parser.ts +126 -0
- package/src/gemma/tool-call-projector.test.ts +227 -0
- package/src/gemma/tool-call-projector.ts +264 -0
- package/src/gemma/types.ts +27 -0
- package/src/google/index.ts +11 -0
- package/src/google/provider-compat.test.ts +19 -0
- package/src/google/provider-definition.ts +6 -0
- package/src/google/provider.ts +10 -0
- package/src/google/types.ts +5 -0
- package/src/index.ts +9 -0
- package/src/openai/adapter.test.ts +494 -0
- package/src/openai/adapter.ts +145 -0
- package/src/openai/chat-completions-chat.ts +189 -0
- package/src/openai/executor-integration.test.ts +206 -0
- package/src/openai/index.ts +21 -0
- package/src/openai/interfaces/payload-logger.ts +48 -0
- package/src/openai/loggers/console-payload-logger.test.ts +173 -0
- package/src/openai/loggers/console-payload-logger.ts +94 -0
- package/src/openai/loggers/console.ts +9 -0
- package/src/openai/loggers/file-payload-logger.test.ts +238 -0
- package/src/openai/loggers/file-payload-logger.ts +112 -0
- package/src/openai/loggers/file.ts +9 -0
- package/src/openai/loggers/index.ts +12 -0
- package/src/openai/loggers/sanitize-openai-log-data.test.ts +89 -0
- package/src/openai/loggers/sanitize-openai-log-data.ts +14 -0
- package/src/openai/message-converter.ts +22 -0
- package/src/openai/model-catalog-refresh.test.ts +92 -0
- package/src/openai/model-catalog-refresh.ts +115 -0
- package/src/openai/openai-request-format.ts +92 -0
- package/src/openai/parsers/response-parser.test.ts +407 -0
- package/src/openai/parsers/response-parser.ts +47 -0
- package/src/openai/provider-definition.test.ts +75 -0
- package/src/openai/provider-definition.ts +132 -0
- package/src/openai/provider.test.ts +1402 -0
- package/src/openai/provider.ts +237 -0
- package/src/openai/responses-chat.ts +258 -0
- package/src/openai/responses-converter.ts +112 -0
- package/src/openai/responses-parser.ts +285 -0
- package/src/openai/responses-stream-utils.ts +45 -0
- package/src/openai/responses-types.ts +195 -0
- package/src/openai/streaming/stream-assembler.ts +3 -0
- package/src/openai/streaming/stream-handler.test.ts +367 -0
- package/src/openai/streaming/stream-handler.ts +119 -0
- package/src/openai/types/api-types.ts +112 -0
- package/src/openai/types.ts +194 -0
- package/src/qwen/defaults.ts +26 -0
- package/src/qwen/index.ts +5 -0
- package/src/qwen/model-catalog-refresh.test.ts +91 -0
- package/src/qwen/model-catalog-refresh.ts +97 -0
- package/src/qwen/provider-capabilities.ts +34 -0
- package/src/qwen/provider-definition.test.ts +139 -0
- package/src/qwen/provider-definition.ts +173 -0
- package/src/qwen/provider-streaming-assembly.ts +40 -0
- package/src/qwen/provider.test.ts +640 -0
- package/src/qwen/provider.ts +293 -0
- package/src/qwen/responses-chat.ts +194 -0
- package/src/qwen/responses-converter.ts +104 -0
- package/src/qwen/responses-parser.ts +299 -0
- package/src/qwen/responses-stream-utils.ts +38 -0
- package/src/qwen/types.ts +228 -0
- package/src/shared/openai-compatible/endpoint-probe.test.ts +52 -0
- package/src/shared/openai-compatible/endpoint-probe.ts +43 -0
- package/src/shared/openai-compatible/index.ts +6 -0
- package/src/shared/openai-compatible/message-converter.test.ts +111 -0
- package/src/shared/openai-compatible/message-converter.ts +84 -0
- package/src/shared/openai-compatible/native-payload-observer.test.ts +43 -0
- package/src/shared/openai-compatible/native-payload-observer.ts +26 -0
- package/src/shared/openai-compatible/response-parser.test.ts +172 -0
- package/src/shared/openai-compatible/response-parser.ts +180 -0
- package/src/shared/openai-compatible/stream-assembler.test.ts +266 -0
- package/src/shared/openai-compatible/stream-assembler.ts +248 -0
- package/src/shared/openai-compatible/types.ts +59 -0
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Type } from '@google/genai';
|
|
2
|
+
import type { FunctionDeclaration, Schema } from '@google/genai';
|
|
3
|
+
import type { IParameterSchema, IToolSchema, TJSONSchemaKind } from '@robota-sdk/agent-core';
|
|
4
|
+
|
|
5
|
+
const GOOGLE_SCHEMA_TYPE_BY_JSON_KIND: Record<Exclude<TJSONSchemaKind, 'null'>, Type> = {
|
|
6
|
+
string: Type.STRING,
|
|
7
|
+
number: Type.NUMBER,
|
|
8
|
+
integer: Type.INTEGER,
|
|
9
|
+
boolean: Type.BOOLEAN,
|
|
10
|
+
array: Type.ARRAY,
|
|
11
|
+
object: Type.OBJECT,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
/** Converts Robota tool schemas to Gemini function declarations. */
|
|
15
|
+
export function convertToolsToGeminiFormat(tools: IToolSchema[]): FunctionDeclaration[] {
|
|
16
|
+
return tools.map((tool) => ({
|
|
17
|
+
name: tool.name,
|
|
18
|
+
description: tool.description,
|
|
19
|
+
parameters: {
|
|
20
|
+
type: Type.OBJECT,
|
|
21
|
+
properties: convertParameterProperties(tool.parameters.properties),
|
|
22
|
+
required: tool.parameters.required,
|
|
23
|
+
},
|
|
24
|
+
}));
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function convertParameterProperties(
|
|
28
|
+
properties: Record<string, IParameterSchema>,
|
|
29
|
+
): Record<string, Schema> {
|
|
30
|
+
const convertedProperties: Record<string, Schema> = {};
|
|
31
|
+
for (const [key, value] of Object.entries(properties)) {
|
|
32
|
+
convertedProperties[key] = convertParameterSchema(value);
|
|
33
|
+
}
|
|
34
|
+
return convertedProperties;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
function convertParameterSchema(schema: IParameterSchema): Schema {
|
|
38
|
+
const convertedSchema: Schema = {};
|
|
39
|
+
const schemaType = convertSchemaKind(schema.type);
|
|
40
|
+
if (schemaType) {
|
|
41
|
+
convertedSchema.type = schemaType;
|
|
42
|
+
}
|
|
43
|
+
if (schema.description) {
|
|
44
|
+
convertedSchema.description = schema.description;
|
|
45
|
+
}
|
|
46
|
+
if (schema.enum) {
|
|
47
|
+
convertedSchema.enum = schema.enum.map(String);
|
|
48
|
+
}
|
|
49
|
+
if (schema.items) {
|
|
50
|
+
convertedSchema.items = convertParameterSchema(schema.items);
|
|
51
|
+
}
|
|
52
|
+
if (schema.properties) {
|
|
53
|
+
convertedSchema.properties = convertParameterProperties(schema.properties);
|
|
54
|
+
}
|
|
55
|
+
if (typeof schema.minimum === 'number') {
|
|
56
|
+
convertedSchema.minimum = schema.minimum;
|
|
57
|
+
}
|
|
58
|
+
if (typeof schema.maximum === 'number') {
|
|
59
|
+
convertedSchema.maximum = schema.maximum;
|
|
60
|
+
}
|
|
61
|
+
if (schema.pattern) {
|
|
62
|
+
convertedSchema.pattern = schema.pattern;
|
|
63
|
+
}
|
|
64
|
+
if (schema.format) {
|
|
65
|
+
convertedSchema.format = schema.format;
|
|
66
|
+
}
|
|
67
|
+
if (schema.default !== undefined) {
|
|
68
|
+
convertedSchema.default = schema.default;
|
|
69
|
+
}
|
|
70
|
+
return convertedSchema;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
function convertSchemaKind(kind: TJSONSchemaKind): Type | undefined {
|
|
74
|
+
if (kind === 'null') {
|
|
75
|
+
return undefined;
|
|
76
|
+
}
|
|
77
|
+
return GOOGLE_SCHEMA_TYPE_BY_JSON_KIND[kind];
|
|
78
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Google AI API-specific type definitions
|
|
3
|
+
*
|
|
4
|
+
* This file contains type definitions specific to Google AI's Gemini API,
|
|
5
|
+
* ensuring complete type safety without any/unknown types.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// Google AI Request Types
|
|
9
|
+
export interface IGoogleModelConfig {
|
|
10
|
+
temperature?: number;
|
|
11
|
+
topK?: number;
|
|
12
|
+
topP?: number;
|
|
13
|
+
maxOutputTokens?: number;
|
|
14
|
+
stopSequences?: string[];
|
|
15
|
+
candidateCount?: number;
|
|
16
|
+
responseMimeType?: string;
|
|
17
|
+
responseSchema?: Record<string, TGoogleJsonValue>;
|
|
18
|
+
responseJsonSchema?: Record<string, TGoogleJsonValue>;
|
|
19
|
+
responseModalities?: Array<'TEXT' | 'IMAGE'>;
|
|
20
|
+
tools?: IGoogleTool[];
|
|
21
|
+
toolConfig?: Record<string, TGoogleJsonValue>;
|
|
22
|
+
safetySettings?: IGoogleSafetySetting[];
|
|
23
|
+
thinkingConfig?: IGoogleThinkingConfig;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export interface IGoogleGenerateContentRequest {
|
|
27
|
+
model: string;
|
|
28
|
+
contents: IGoogleContent[];
|
|
29
|
+
systemInstruction?: IGoogleContent;
|
|
30
|
+
config?: IGoogleModelConfig;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface IGoogleStreamGenerateContentRequest extends IGoogleGenerateContentRequest {
|
|
34
|
+
// Streaming uses the same request structure
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Content Types
|
|
38
|
+
export interface IGoogleContent {
|
|
39
|
+
parts: IGooglePart[];
|
|
40
|
+
role?: 'user' | 'model';
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface IGooglePart {
|
|
44
|
+
text?: string;
|
|
45
|
+
inlineData?: {
|
|
46
|
+
mimeType: string;
|
|
47
|
+
data: string;
|
|
48
|
+
};
|
|
49
|
+
functionCall?: IGoogleFunctionCall;
|
|
50
|
+
functionResponse?: IGoogleFunctionResponse;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface IGoogleFunctionCall {
|
|
54
|
+
id?: string;
|
|
55
|
+
name: string;
|
|
56
|
+
args: Record<string, string | number | boolean | object>;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export interface IGoogleFunctionResponse {
|
|
60
|
+
id?: string;
|
|
61
|
+
name: string;
|
|
62
|
+
response: Record<string, TGoogleJsonValue>;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
export type TGoogleJsonValue =
|
|
66
|
+
| string
|
|
67
|
+
| number
|
|
68
|
+
| boolean
|
|
69
|
+
| null
|
|
70
|
+
| TGoogleJsonValue[]
|
|
71
|
+
| { [key: string]: TGoogleJsonValue };
|
|
72
|
+
|
|
73
|
+
export interface IGoogleSafetySetting {
|
|
74
|
+
category: string;
|
|
75
|
+
threshold: string;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface IGoogleThinkingConfig {
|
|
79
|
+
includeThoughts?: boolean;
|
|
80
|
+
thinkingBudget?: number;
|
|
81
|
+
thinkingLevel?: string;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Tool Types
|
|
85
|
+
export interface IGoogleTool {
|
|
86
|
+
functionDeclarations: IGoogleFunctionDeclaration[];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export interface IGoogleFunctionDeclaration {
|
|
90
|
+
name: string;
|
|
91
|
+
description?: string;
|
|
92
|
+
parameters: IGoogleFunctionParameters;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface IGoogleFunctionParameters {
|
|
96
|
+
type: 'object';
|
|
97
|
+
properties: Record<string, IGooglePropertySchema>;
|
|
98
|
+
required?: string[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface IGooglePropertySchema {
|
|
102
|
+
type: 'string' | 'number' | 'integer' | 'boolean' | 'array' | 'object';
|
|
103
|
+
description?: string;
|
|
104
|
+
enum?: string[];
|
|
105
|
+
items?: IGooglePropertySchema;
|
|
106
|
+
properties?: Record<string, IGooglePropertySchema>;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Response Types
|
|
110
|
+
export interface IGoogleGenerateContentResponse {
|
|
111
|
+
candidates: IGoogleCandidate[];
|
|
112
|
+
promptFeedback?: IGooglePromptFeedback;
|
|
113
|
+
usageMetadata?: IGoogleUsageMetadata;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export interface IGoogleCandidate {
|
|
117
|
+
content: IGoogleContent;
|
|
118
|
+
finishReason?: TGoogleFinishReason;
|
|
119
|
+
index: number;
|
|
120
|
+
safetyRatings?: IGoogleSafetyRating[];
|
|
121
|
+
citationMetadata?: IGoogleCitationMetadata;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export type TGoogleFinishReason =
|
|
125
|
+
| 'FINISH_REASON_UNSPECIFIED'
|
|
126
|
+
| 'STOP'
|
|
127
|
+
| 'MAX_TOKENS'
|
|
128
|
+
| 'SAFETY'
|
|
129
|
+
| 'RECITATION'
|
|
130
|
+
| 'OTHER';
|
|
131
|
+
|
|
132
|
+
export interface IGoogleSafetyRating {
|
|
133
|
+
category: TGoogleHarmCategory;
|
|
134
|
+
probability: TGoogleHarmProbability;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
export type TGoogleHarmCategory =
|
|
138
|
+
| 'HARM_CATEGORY_UNSPECIFIED'
|
|
139
|
+
| 'HARM_CATEGORY_DEROGATORY'
|
|
140
|
+
| 'HARM_CATEGORY_TOXICITY'
|
|
141
|
+
| 'HARM_CATEGORY_VIOLENCE'
|
|
142
|
+
| 'HARM_CATEGORY_SEXUAL'
|
|
143
|
+
| 'HARM_CATEGORY_MEDICAL'
|
|
144
|
+
| 'HARM_CATEGORY_DANGEROUS';
|
|
145
|
+
|
|
146
|
+
export type TGoogleHarmProbability =
|
|
147
|
+
| 'HARM_PROBABILITY_UNSPECIFIED'
|
|
148
|
+
| 'NEGLIGIBLE'
|
|
149
|
+
| 'LOW'
|
|
150
|
+
| 'MEDIUM'
|
|
151
|
+
| 'HIGH';
|
|
152
|
+
|
|
153
|
+
export interface IGoogleCitationMetadata {
|
|
154
|
+
citationSources: IGoogleCitationSource[];
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface IGoogleCitationSource {
|
|
158
|
+
startIndex?: number;
|
|
159
|
+
endIndex?: number;
|
|
160
|
+
uri?: string;
|
|
161
|
+
license?: string;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export interface IGooglePromptFeedback {
|
|
165
|
+
blockReason?: TGoogleBlockReason;
|
|
166
|
+
safetyRatings?: IGoogleSafetyRating[];
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
export type TGoogleBlockReason = 'BLOCK_REASON_UNSPECIFIED' | 'SAFETY' | 'OTHER';
|
|
170
|
+
|
|
171
|
+
export interface IGoogleUsageMetadata {
|
|
172
|
+
promptTokenCount: number;
|
|
173
|
+
candidatesTokenCount: number;
|
|
174
|
+
totalTokenCount: number;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Streaming Types
|
|
178
|
+
export interface IGoogleStreamChunk {
|
|
179
|
+
candidates?: IGoogleCandidate[];
|
|
180
|
+
promptFeedback?: IGooglePromptFeedback;
|
|
181
|
+
usageMetadata?: IGoogleUsageMetadata;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// Error Types
|
|
185
|
+
export interface IGoogleError {
|
|
186
|
+
error: {
|
|
187
|
+
code: number;
|
|
188
|
+
message: string;
|
|
189
|
+
status: string;
|
|
190
|
+
details?: IGoogleErrorDetail[];
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
export interface IGoogleErrorDetail {
|
|
195
|
+
'@type': string;
|
|
196
|
+
reason?: string;
|
|
197
|
+
domain?: string;
|
|
198
|
+
metadata?: Record<string, string>;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Provider Configuration
|
|
202
|
+
export interface IGoogleLogData {
|
|
203
|
+
model: string;
|
|
204
|
+
messagesCount: number;
|
|
205
|
+
hasTools: boolean;
|
|
206
|
+
temperature?: number;
|
|
207
|
+
maxOutputTokens?: number;
|
|
208
|
+
timestamp: string;
|
|
209
|
+
requestId?: string;
|
|
210
|
+
usage?: IGoogleUsageMetadata;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Tool Call Types for Internal Processing
|
|
214
|
+
export interface IGoogleToolCall {
|
|
215
|
+
id: string;
|
|
216
|
+
type: 'function';
|
|
217
|
+
function: {
|
|
218
|
+
name: string;
|
|
219
|
+
arguments: string;
|
|
220
|
+
};
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Message Conversion Types
|
|
224
|
+
export interface IGoogleMessageConversionResult {
|
|
225
|
+
contents: IGoogleContent[];
|
|
226
|
+
systemInstruction?: IGoogleContent;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// Stream Context for Managing State
|
|
230
|
+
export interface IGoogleStreamContext {
|
|
231
|
+
currentMessage: string;
|
|
232
|
+
currentToolCalls: IGoogleToolCall[];
|
|
233
|
+
isComplete: boolean;
|
|
234
|
+
usage?: IGoogleUsageMetadata;
|
|
235
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import type { IExecutor, TProviderOptionValueBase } from '@robota-sdk/agent-core';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Valid provider option value types
|
|
5
|
+
*/
|
|
6
|
+
export type TGeminiProviderOptionValue =
|
|
7
|
+
| string
|
|
8
|
+
| number
|
|
9
|
+
| boolean
|
|
10
|
+
| undefined
|
|
11
|
+
| null
|
|
12
|
+
| IExecutor
|
|
13
|
+
| TProviderOptionValueBase
|
|
14
|
+
| TGeminiProviderOptionValue[]
|
|
15
|
+
| { [key: string]: TGeminiProviderOptionValue };
|
|
16
|
+
|
|
17
|
+
export interface IGeminiSafetySetting {
|
|
18
|
+
[key: string]: TGeminiProviderOptionValue;
|
|
19
|
+
category: string;
|
|
20
|
+
threshold: string;
|
|
21
|
+
method?: string;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface IGeminiThinkingConfig {
|
|
25
|
+
[key: string]: TGeminiProviderOptionValue;
|
|
26
|
+
includeThoughts?: boolean;
|
|
27
|
+
thinkingBudget?: number;
|
|
28
|
+
thinkingLevel?: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Gemini API provider options
|
|
33
|
+
*/
|
|
34
|
+
export interface IGeminiProviderOptions {
|
|
35
|
+
/**
|
|
36
|
+
* Additional provider-specific options
|
|
37
|
+
*/
|
|
38
|
+
[key: string]: TGeminiProviderOptionValue;
|
|
39
|
+
|
|
40
|
+
/** Google AI API key */
|
|
41
|
+
apiKey: string;
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Default model used when chat options do not provide a model.
|
|
45
|
+
*/
|
|
46
|
+
defaultModel?: string;
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Response MIME type
|
|
50
|
+
* - 'text/plain': Plain text response (default)
|
|
51
|
+
* - 'application/json': JSON response format
|
|
52
|
+
*/
|
|
53
|
+
responseMimeType?: 'text/plain' | 'application/json';
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Response schema for JSON output (only used when responseMimeType is 'application/json')
|
|
57
|
+
*/
|
|
58
|
+
responseSchema?: Record<string, TGeminiProviderOptionValue>;
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* JSON Schema response format for current Gemini structured output support.
|
|
62
|
+
* Mutually exclusive with responseSchema.
|
|
63
|
+
*/
|
|
64
|
+
responseJsonSchema?: Record<string, TGeminiProviderOptionValue>;
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Default safety settings applied to every direct Gemini request.
|
|
68
|
+
* Per-request google.safetySettings overrides this value.
|
|
69
|
+
*/
|
|
70
|
+
safetySettings?: IGeminiSafetySetting[];
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Default thinking configuration for Gemini models that support thinking.
|
|
74
|
+
*/
|
|
75
|
+
thinkingConfig?: IGeminiThinkingConfig;
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Provider-level function calling config passed through to Gemini config.
|
|
79
|
+
*/
|
|
80
|
+
toolConfig?: Record<string, TGeminiProviderOptionValue>;
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Optional default response modalities for Gemini generation config.
|
|
84
|
+
* Example: ['TEXT', 'IMAGE']
|
|
85
|
+
*/
|
|
86
|
+
defaultResponseModalities?: Array<'TEXT' | 'IMAGE'>;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Optional allowlist of models that support image generation/editing.
|
|
90
|
+
* If not provided, provider validates using model name heuristics.
|
|
91
|
+
*/
|
|
92
|
+
imageCapableModels?: string[];
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Optional executor for handling AI requests
|
|
96
|
+
*
|
|
97
|
+
* When provided, the provider will delegate all chat operations to this executor
|
|
98
|
+
* instead of making direct API calls. This enables remote execution capabilities.
|
|
99
|
+
*
|
|
100
|
+
* @example
|
|
101
|
+
* ```typescript
|
|
102
|
+
* import { LocalExecutor, RemoteExecutor } from '@robota-sdk/agent-core';
|
|
103
|
+
*
|
|
104
|
+
* // Local execution (registers this provider)
|
|
105
|
+
* const localExecutor = new LocalExecutor();
|
|
106
|
+
* localExecutor.registerProvider('gemini', new GeminiProvider({ apiKey: 'AIza...' }));
|
|
107
|
+
*
|
|
108
|
+
* // Remote execution
|
|
109
|
+
* const remoteExecutor = new RemoteExecutor({
|
|
110
|
+
* serverUrl: 'https://api.robota.io',
|
|
111
|
+
* userApiKey: 'user-token-123'
|
|
112
|
+
* });
|
|
113
|
+
*
|
|
114
|
+
* const provider = new GeminiProvider({
|
|
115
|
+
* apiKey: 'placeholder', // Required for type safety but not used
|
|
116
|
+
* executor: remoteExecutor
|
|
117
|
+
* });
|
|
118
|
+
* ```
|
|
119
|
+
*/
|
|
120
|
+
executor?: IExecutor;
|
|
121
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import type OpenAI from 'openai';
|
|
3
|
+
import type { IToolCall, TUniversalMessage } from '@robota-sdk/agent-core';
|
|
4
|
+
|
|
5
|
+
export function createStreamTextMessage(
|
|
6
|
+
content: string,
|
|
7
|
+
finishReason: OpenAI.Chat.ChatCompletionChunk.Choice['finish_reason'],
|
|
8
|
+
): TUniversalMessage {
|
|
9
|
+
return {
|
|
10
|
+
id: randomUUID(),
|
|
11
|
+
role: 'assistant',
|
|
12
|
+
content,
|
|
13
|
+
state: 'complete',
|
|
14
|
+
timestamp: new Date(),
|
|
15
|
+
metadata: {
|
|
16
|
+
isStreamChunk: true,
|
|
17
|
+
isComplete: finishReason === 'stop' || finishReason === 'tool_calls',
|
|
18
|
+
},
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function createStreamToolCallMessage(
|
|
23
|
+
toolCalls: IToolCall[],
|
|
24
|
+
finishReason: OpenAI.Chat.ChatCompletionChunk.Choice['finish_reason'],
|
|
25
|
+
): TUniversalMessage {
|
|
26
|
+
return {
|
|
27
|
+
id: randomUUID(),
|
|
28
|
+
role: 'assistant',
|
|
29
|
+
content: '',
|
|
30
|
+
toolCalls,
|
|
31
|
+
state: 'complete',
|
|
32
|
+
timestamp: new Date(),
|
|
33
|
+
metadata: {
|
|
34
|
+
isStreamChunk: true,
|
|
35
|
+
isComplete: finishReason === 'stop' || finishReason === 'tool_calls',
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { createGemmaProviderDefinition, GemmaProvider } from './index';
|
|
3
|
+
|
|
4
|
+
vi.mock('openai', () => {
|
|
5
|
+
const MockOpenAI = vi.fn().mockImplementation(() => ({
|
|
6
|
+
chat: {
|
|
7
|
+
completions: {
|
|
8
|
+
create: vi.fn(),
|
|
9
|
+
},
|
|
10
|
+
},
|
|
11
|
+
}));
|
|
12
|
+
return { default: MockOpenAI };
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
describe('createGemmaProviderDefinition', () => {
|
|
16
|
+
it('exposes local setup help through the provider-definition contract', () => {
|
|
17
|
+
const definition = createGemmaProviderDefinition();
|
|
18
|
+
|
|
19
|
+
expect(definition.type).toBe('gemma');
|
|
20
|
+
expect(definition.setupHelpLinks).toEqual([
|
|
21
|
+
{
|
|
22
|
+
kind: 'official',
|
|
23
|
+
label: 'LM Studio local API documentation',
|
|
24
|
+
url: 'https://lmstudio.ai/docs/developer',
|
|
25
|
+
sourceUrl: 'https://lmstudio.ai/docs/developer',
|
|
26
|
+
lastVerifiedAt: '2026-05-08',
|
|
27
|
+
},
|
|
28
|
+
]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('creates a GemmaProvider from a resolved provider profile', () => {
|
|
32
|
+
const definition = createGemmaProviderDefinition();
|
|
33
|
+
|
|
34
|
+
const provider = definition.createProvider({
|
|
35
|
+
name: 'gemma',
|
|
36
|
+
model: 'supergemma4-26b-uncensored-v2',
|
|
37
|
+
apiKey: 'lm-studio',
|
|
38
|
+
baseURL: 'http://localhost:1234/v1',
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
expect(provider).toBeInstanceOf(GemmaProvider);
|
|
42
|
+
});
|
|
43
|
+
});
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import type { IProviderDefinition } from '@robota-sdk/agent-core';
|
|
2
|
+
import { probeOpenAICompatibleProfile } from '../shared/openai-compatible/index.js';
|
|
3
|
+
import { GemmaProvider } from './provider';
|
|
4
|
+
|
|
5
|
+
export const DEFAULT_GEMMA_PROVIDER_MODEL = 'supergemma4-26b-uncensored-v2';
|
|
6
|
+
export const DEFAULT_GEMMA_PROVIDER_API_KEY = 'lm-studio';
|
|
7
|
+
export const DEFAULT_GEMMA_PROVIDER_BASE_URL = 'http://localhost:1234/v1';
|
|
8
|
+
const GEMMA_MODEL_SOURCE_URL = 'https://ai.google.dev/gemma';
|
|
9
|
+
const GEMMA_MODEL_LAST_VERIFIED_AT = '2026-05-04';
|
|
10
|
+
const GEMMA_SETUP_URL = 'https://lmstudio.ai/docs/developer';
|
|
11
|
+
const GEMMA_SETUP_LAST_VERIFIED_AT = '2026-05-08';
|
|
12
|
+
const GEMMA_SETUP_HELP_LINKS: NonNullable<IProviderDefinition['setupHelpLinks']> = [
|
|
13
|
+
{
|
|
14
|
+
kind: 'official',
|
|
15
|
+
label: 'LM Studio local API documentation',
|
|
16
|
+
url: GEMMA_SETUP_URL,
|
|
17
|
+
sourceUrl: GEMMA_SETUP_URL,
|
|
18
|
+
lastVerifiedAt: GEMMA_SETUP_LAST_VERIFIED_AT,
|
|
19
|
+
},
|
|
20
|
+
];
|
|
21
|
+
const GEMMA_MODEL_CATALOG: NonNullable<IProviderDefinition['modelCatalog']> = {
|
|
22
|
+
status: 'fallback',
|
|
23
|
+
sourceUrl: GEMMA_MODEL_SOURCE_URL,
|
|
24
|
+
lastVerifiedAt: GEMMA_MODEL_LAST_VERIFIED_AT,
|
|
25
|
+
entries: [
|
|
26
|
+
{
|
|
27
|
+
id: DEFAULT_GEMMA_PROVIDER_MODEL,
|
|
28
|
+
displayName: 'SuperGemma 4 26B',
|
|
29
|
+
capabilities: ['tools', 'streaming'],
|
|
30
|
+
lifecycle: 'active',
|
|
31
|
+
sourceUrl: GEMMA_MODEL_SOURCE_URL,
|
|
32
|
+
lastVerifiedAt: GEMMA_MODEL_LAST_VERIFIED_AT,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
export function createGemmaProviderDefinition(): IProviderDefinition {
|
|
38
|
+
return {
|
|
39
|
+
type: 'gemma',
|
|
40
|
+
displayName: 'Gemma',
|
|
41
|
+
description: 'Gemma-family local models through an OpenAI-compatible endpoint',
|
|
42
|
+
defaults: {
|
|
43
|
+
model: DEFAULT_GEMMA_PROVIDER_MODEL,
|
|
44
|
+
apiKey: DEFAULT_GEMMA_PROVIDER_API_KEY,
|
|
45
|
+
baseURL: DEFAULT_GEMMA_PROVIDER_BASE_URL,
|
|
46
|
+
},
|
|
47
|
+
modelCatalog: GEMMA_MODEL_CATALOG,
|
|
48
|
+
setupHelpLinks: GEMMA_SETUP_HELP_LINKS,
|
|
49
|
+
setupSteps: [
|
|
50
|
+
{
|
|
51
|
+
key: 'baseURL',
|
|
52
|
+
title: 'Gemma OpenAI-compatible base URL',
|
|
53
|
+
defaultValue: DEFAULT_GEMMA_PROVIDER_BASE_URL,
|
|
54
|
+
},
|
|
55
|
+
{
|
|
56
|
+
key: 'model',
|
|
57
|
+
title: 'Gemma model',
|
|
58
|
+
defaultValue: DEFAULT_GEMMA_PROVIDER_MODEL,
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
key: 'apiKey',
|
|
62
|
+
title: 'Gemma OpenAI-compatible API key',
|
|
63
|
+
defaultValue: DEFAULT_GEMMA_PROVIDER_API_KEY,
|
|
64
|
+
masked: true,
|
|
65
|
+
},
|
|
66
|
+
],
|
|
67
|
+
requiresApiKey: true,
|
|
68
|
+
probeProfile: probeOpenAICompatibleProfile,
|
|
69
|
+
createProvider: (config) =>
|
|
70
|
+
new GemmaProvider({
|
|
71
|
+
apiKey: requireApiKey(config.apiKey),
|
|
72
|
+
...(config.baseURL !== undefined && { baseURL: config.baseURL }),
|
|
73
|
+
...(config.timeout !== undefined && { timeout: config.timeout }),
|
|
74
|
+
defaultModel: config.model,
|
|
75
|
+
}),
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function requireApiKey(apiKey: string | undefined): string {
|
|
80
|
+
if (!apiKey) {
|
|
81
|
+
throw new Error('Provider gemma requires apiKey');
|
|
82
|
+
}
|
|
83
|
+
return apiKey;
|
|
84
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type OpenAI from 'openai';
|
|
2
|
+
import type { IChatOptions, ILogger, TUniversalMessage } from '@robota-sdk/agent-core';
|
|
3
|
+
import { OpenAICompatibleResponseParser } from '../shared/openai-compatible/index.js';
|
|
4
|
+
import { projectGemmaReasoningText } from './reasoning-projector';
|
|
5
|
+
import { createGemmaToolCallProjector } from './tool-call-projector';
|
|
6
|
+
|
|
7
|
+
export function parseGemmaChatCompletion(
|
|
8
|
+
response: OpenAI.Chat.ChatCompletion,
|
|
9
|
+
logger: ILogger,
|
|
10
|
+
options: IChatOptions | undefined,
|
|
11
|
+
): TUniversalMessage {
|
|
12
|
+
const rawContent = response.choices?.[0]?.message.content || '';
|
|
13
|
+
const parser = new OpenAICompatibleResponseParser({
|
|
14
|
+
logger,
|
|
15
|
+
...(options?.tools && {
|
|
16
|
+
toolCallTextProjector: createGemmaToolCallProjector(options.tools),
|
|
17
|
+
}),
|
|
18
|
+
});
|
|
19
|
+
const parsed = parser.parseResponse(response);
|
|
20
|
+
const projection = projectGemmaReasoningText(parsed.content ?? '');
|
|
21
|
+
|
|
22
|
+
return withGemmaProjectionMetadata(
|
|
23
|
+
{
|
|
24
|
+
...parsed,
|
|
25
|
+
content: projection.visibleText,
|
|
26
|
+
},
|
|
27
|
+
rawContent,
|
|
28
|
+
projection.removedReasoning,
|
|
29
|
+
);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function withGemmaProjectionMetadata(
|
|
33
|
+
message: TUniversalMessage,
|
|
34
|
+
rawContent: string,
|
|
35
|
+
removedReasoning: boolean,
|
|
36
|
+
): TUniversalMessage {
|
|
37
|
+
if (!removedReasoning) {
|
|
38
|
+
return message;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return {
|
|
42
|
+
...message,
|
|
43
|
+
metadata: {
|
|
44
|
+
...(message.metadata ?? {}),
|
|
45
|
+
gemmaReasoningFiltered: true,
|
|
46
|
+
gemmaRawContent: rawContent,
|
|
47
|
+
},
|
|
48
|
+
};
|
|
49
|
+
}
|