@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.
Files changed (220) hide show
  1. package/LICENSE +21 -0
  2. package/dist/browser/index.d.ts +1104 -0
  3. package/dist/browser/index.d.ts.map +1 -0
  4. package/dist/browser/index.js +7 -0
  5. package/dist/browser/index.js.map +1 -0
  6. package/dist/loggers/index.cjs +1 -0
  7. package/dist/loggers/index.d.ts +151 -0
  8. package/dist/loggers/index.d.ts.map +1 -0
  9. package/dist/loggers/index.js +2 -0
  10. package/dist/loggers/index.js.map +1 -0
  11. package/dist/node/anthropic/index.cjs +1 -0
  12. package/dist/node/anthropic/index.d.ts +158 -0
  13. package/dist/node/anthropic/index.d.ts.map +1 -0
  14. package/dist/node/anthropic/index.js +1 -0
  15. package/dist/node/anthropic--1vgLC-e.js +5 -0
  16. package/dist/node/anthropic--1vgLC-e.js.map +1 -0
  17. package/dist/node/anthropic-BFQ6DSCP.cjs +4 -0
  18. package/dist/node/bytedance/index.cjs +1 -0
  19. package/dist/node/bytedance/index.d.ts +74 -0
  20. package/dist/node/bytedance/index.d.ts.map +1 -0
  21. package/dist/node/bytedance/index.js +1 -0
  22. package/dist/node/bytedance-C_0sF_pJ.js +2 -0
  23. package/dist/node/bytedance-C_0sF_pJ.js.map +1 -0
  24. package/dist/node/bytedance-DVPxqEiC.cjs +1 -0
  25. package/dist/node/chunk-Bmb41Sf3.cjs +1 -0
  26. package/dist/node/deepseek/index.cjs +1 -0
  27. package/dist/node/deepseek/index.d.ts +2 -0
  28. package/dist/node/deepseek/index.js +1 -0
  29. package/dist/node/deepseek-_8Ixx7rA.js +2 -0
  30. package/dist/node/deepseek-_8Ixx7rA.js.map +1 -0
  31. package/dist/node/deepseek-oA2Y6bD0.cjs +1 -0
  32. package/dist/node/gemini/index.cjs +1 -0
  33. package/dist/node/gemini/index.d.ts +173 -0
  34. package/dist/node/gemini/index.d.ts.map +1 -0
  35. package/dist/node/gemini/index.js +1 -0
  36. package/dist/node/gemini-Bh2U87MY.js +4 -0
  37. package/dist/node/gemini-Bh2U87MY.js.map +1 -0
  38. package/dist/node/gemini-DSaNCxZj.cjs +3 -0
  39. package/dist/node/gemma/index.cjs +1 -0
  40. package/dist/node/gemma/index.d.ts +2 -0
  41. package/dist/node/gemma/index.js +1 -0
  42. package/dist/node/gemma-Dp_AfCUR.js +2 -0
  43. package/dist/node/gemma-Dp_AfCUR.js.map +1 -0
  44. package/dist/node/gemma-G-Pf_PnX.cjs +1 -0
  45. package/dist/node/google/index.cjs +1 -0
  46. package/dist/node/google/index.d.ts +14 -0
  47. package/dist/node/google/index.d.ts.map +1 -0
  48. package/dist/node/google/index.js +2 -0
  49. package/dist/node/google/index.js.map +1 -0
  50. package/dist/node/index-B6PnlDMd.d.ts +82 -0
  51. package/dist/node/index-B6PnlDMd.d.ts.map +1 -0
  52. package/dist/node/index-B7UvPJcI.d.ts +315 -0
  53. package/dist/node/index-B7UvPJcI.d.ts.map +1 -0
  54. package/dist/node/index-BLPOTNb5.d.ts +98 -0
  55. package/dist/node/index-BLPOTNb5.d.ts.map +1 -0
  56. package/dist/node/index-BqixM_XD.d.ts +231 -0
  57. package/dist/node/index-BqixM_XD.d.ts.map +1 -0
  58. package/dist/node/index-C3beaqKO.d.ts +231 -0
  59. package/dist/node/index-C3beaqKO.d.ts.map +1 -0
  60. package/dist/node/index-Cp2XRh9G.d.ts +82 -0
  61. package/dist/node/index-Cp2XRh9G.d.ts.map +1 -0
  62. package/dist/node/index-DSv5xruI.d.ts +98 -0
  63. package/dist/node/index-DSv5xruI.d.ts.map +1 -0
  64. package/dist/node/index-w0bV1uaP.d.ts +315 -0
  65. package/dist/node/index-w0bV1uaP.d.ts.map +1 -0
  66. package/dist/node/index.cjs +1 -0
  67. package/dist/node/index.d.ts +8 -0
  68. package/dist/node/index.js +1 -0
  69. package/dist/node/openai/index.cjs +1 -0
  70. package/dist/node/openai/index.d.ts +2 -0
  71. package/dist/node/openai/index.js +1 -0
  72. package/dist/node/openai-CRQjg4xF.js +2 -0
  73. package/dist/node/openai-CRQjg4xF.js.map +1 -0
  74. package/dist/node/openai-compatible-BYfyY5lb.cjs +1 -0
  75. package/dist/node/openai-compatible-Dm4Sof9e.js +2 -0
  76. package/dist/node/openai-compatible-Dm4Sof9e.js.map +1 -0
  77. package/dist/node/openai-xWC6pY7r.cjs +1 -0
  78. package/dist/node/qwen/index.cjs +1 -0
  79. package/dist/node/qwen/index.d.ts +2 -0
  80. package/dist/node/qwen/index.js +1 -0
  81. package/dist/node/qwen-ChUZobTL.js +2 -0
  82. package/dist/node/qwen-ChUZobTL.js.map +1 -0
  83. package/dist/node/qwen-CjT71vSM.cjs +1 -0
  84. package/package.json +157 -0
  85. package/src/anthropic/__tests__/abort-streaming.test.ts +199 -0
  86. package/src/anthropic/__tests__/model-catalog-refresh.test.ts +92 -0
  87. package/src/anthropic/__tests__/provider-definition.test.ts +55 -0
  88. package/src/anthropic/__tests__/provider.test.ts +1357 -0
  89. package/src/anthropic/__tests__/response-parser.test.ts +326 -0
  90. package/src/anthropic/index.ts +22 -0
  91. package/src/anthropic/message-converter.ts +181 -0
  92. package/src/anthropic/model-catalog-refresh.ts +128 -0
  93. package/src/anthropic/parsers/response-parser.ts +184 -0
  94. package/src/anthropic/provider-definition.ts +93 -0
  95. package/src/anthropic/provider.ts +290 -0
  96. package/src/anthropic/streaming-handler.ts +204 -0
  97. package/src/anthropic/types/api-types.ts +158 -0
  98. package/src/anthropic/types.ts +79 -0
  99. package/src/bytedance/http-client.test.ts +288 -0
  100. package/src/bytedance/http-client.ts +163 -0
  101. package/src/bytedance/index.ts +2 -0
  102. package/src/bytedance/provider.spec.ts +320 -0
  103. package/src/bytedance/provider.ts +171 -0
  104. package/src/bytedance/status-mapper.test.ts +299 -0
  105. package/src/bytedance/status-mapper.ts +141 -0
  106. package/src/bytedance/types.ts +68 -0
  107. package/src/deepseek/defaults.ts +4 -0
  108. package/src/deepseek/index.ts +22 -0
  109. package/src/deepseek/model-catalog-refresh.test.ts +57 -0
  110. package/src/deepseek/model-catalog-refresh.ts +105 -0
  111. package/src/deepseek/model-catalog.ts +55 -0
  112. package/src/deepseek/provider-definition.test.ts +109 -0
  113. package/src/deepseek/provider-definition.ts +132 -0
  114. package/src/deepseek/provider.test.ts +324 -0
  115. package/src/deepseek/provider.ts +298 -0
  116. package/src/deepseek/types.ts +37 -0
  117. package/src/gemini/execution-helpers.ts +233 -0
  118. package/src/gemini/genai-transport.test.ts +208 -0
  119. package/src/gemini/image-operations.test.ts +448 -0
  120. package/src/gemini/image-operations.ts +261 -0
  121. package/src/gemini/index.ts +11 -0
  122. package/src/gemini/message-converter.test.ts +616 -0
  123. package/src/gemini/message-converter.ts +140 -0
  124. package/src/gemini/model-catalog-refresh.test.ts +107 -0
  125. package/src/gemini/model-catalog-refresh.ts +92 -0
  126. package/src/gemini/provider-definition.test.ts +70 -0
  127. package/src/gemini/provider-definition.ts +78 -0
  128. package/src/gemini/provider-extended.test.ts +898 -0
  129. package/src/gemini/provider.spec.ts +216 -0
  130. package/src/gemini/provider.ts +279 -0
  131. package/src/gemini/request-converter.ts +226 -0
  132. package/src/gemini/tool-schema-converter.ts +78 -0
  133. package/src/gemini/types/api-types.ts +235 -0
  134. package/src/gemini/types.ts +121 -0
  135. package/src/gemma/index.ts +5 -0
  136. package/src/gemma/message-factory.ts +38 -0
  137. package/src/gemma/provider-definition.test.ts +43 -0
  138. package/src/gemma/provider-definition.ts +84 -0
  139. package/src/gemma/provider-projection.ts +49 -0
  140. package/src/gemma/provider.test.ts +628 -0
  141. package/src/gemma/provider.ts +308 -0
  142. package/src/gemma/pseudo-command-envelope.ts +58 -0
  143. package/src/gemma/pseudo-tool-call-projector.ts +243 -0
  144. package/src/gemma/pseudo-tool-call-tag-parser.ts +153 -0
  145. package/src/gemma/pseudo-tool-call-types.ts +31 -0
  146. package/src/gemma/reasoning-projector.test.ts +52 -0
  147. package/src/gemma/reasoning-projector.ts +144 -0
  148. package/src/gemma/streaming-projection.ts +79 -0
  149. package/src/gemma/tool-call-argument-parser.ts +126 -0
  150. package/src/gemma/tool-call-projector.test.ts +227 -0
  151. package/src/gemma/tool-call-projector.ts +264 -0
  152. package/src/gemma/types.ts +27 -0
  153. package/src/google/index.ts +11 -0
  154. package/src/google/provider-compat.test.ts +19 -0
  155. package/src/google/provider-definition.ts +6 -0
  156. package/src/google/provider.ts +10 -0
  157. package/src/google/types.ts +5 -0
  158. package/src/index.ts +9 -0
  159. package/src/openai/adapter.test.ts +494 -0
  160. package/src/openai/adapter.ts +145 -0
  161. package/src/openai/chat-completions-chat.ts +189 -0
  162. package/src/openai/executor-integration.test.ts +206 -0
  163. package/src/openai/index.ts +21 -0
  164. package/src/openai/interfaces/payload-logger.ts +48 -0
  165. package/src/openai/loggers/console-payload-logger.test.ts +173 -0
  166. package/src/openai/loggers/console-payload-logger.ts +94 -0
  167. package/src/openai/loggers/console.ts +9 -0
  168. package/src/openai/loggers/file-payload-logger.test.ts +238 -0
  169. package/src/openai/loggers/file-payload-logger.ts +112 -0
  170. package/src/openai/loggers/file.ts +9 -0
  171. package/src/openai/loggers/index.ts +12 -0
  172. package/src/openai/loggers/sanitize-openai-log-data.test.ts +89 -0
  173. package/src/openai/loggers/sanitize-openai-log-data.ts +14 -0
  174. package/src/openai/message-converter.ts +22 -0
  175. package/src/openai/model-catalog-refresh.test.ts +92 -0
  176. package/src/openai/model-catalog-refresh.ts +115 -0
  177. package/src/openai/openai-request-format.ts +92 -0
  178. package/src/openai/parsers/response-parser.test.ts +407 -0
  179. package/src/openai/parsers/response-parser.ts +47 -0
  180. package/src/openai/provider-definition.test.ts +75 -0
  181. package/src/openai/provider-definition.ts +132 -0
  182. package/src/openai/provider.test.ts +1402 -0
  183. package/src/openai/provider.ts +237 -0
  184. package/src/openai/responses-chat.ts +258 -0
  185. package/src/openai/responses-converter.ts +112 -0
  186. package/src/openai/responses-parser.ts +285 -0
  187. package/src/openai/responses-stream-utils.ts +45 -0
  188. package/src/openai/responses-types.ts +195 -0
  189. package/src/openai/streaming/stream-assembler.ts +3 -0
  190. package/src/openai/streaming/stream-handler.test.ts +367 -0
  191. package/src/openai/streaming/stream-handler.ts +119 -0
  192. package/src/openai/types/api-types.ts +112 -0
  193. package/src/openai/types.ts +194 -0
  194. package/src/qwen/defaults.ts +26 -0
  195. package/src/qwen/index.ts +5 -0
  196. package/src/qwen/model-catalog-refresh.test.ts +91 -0
  197. package/src/qwen/model-catalog-refresh.ts +97 -0
  198. package/src/qwen/provider-capabilities.ts +34 -0
  199. package/src/qwen/provider-definition.test.ts +139 -0
  200. package/src/qwen/provider-definition.ts +173 -0
  201. package/src/qwen/provider-streaming-assembly.ts +40 -0
  202. package/src/qwen/provider.test.ts +640 -0
  203. package/src/qwen/provider.ts +293 -0
  204. package/src/qwen/responses-chat.ts +194 -0
  205. package/src/qwen/responses-converter.ts +104 -0
  206. package/src/qwen/responses-parser.ts +299 -0
  207. package/src/qwen/responses-stream-utils.ts +38 -0
  208. package/src/qwen/types.ts +228 -0
  209. package/src/shared/openai-compatible/endpoint-probe.test.ts +52 -0
  210. package/src/shared/openai-compatible/endpoint-probe.ts +43 -0
  211. package/src/shared/openai-compatible/index.ts +6 -0
  212. package/src/shared/openai-compatible/message-converter.test.ts +111 -0
  213. package/src/shared/openai-compatible/message-converter.ts +84 -0
  214. package/src/shared/openai-compatible/native-payload-observer.test.ts +43 -0
  215. package/src/shared/openai-compatible/native-payload-observer.ts +26 -0
  216. package/src/shared/openai-compatible/response-parser.test.ts +172 -0
  217. package/src/shared/openai-compatible/response-parser.ts +180 -0
  218. package/src/shared/openai-compatible/stream-assembler.test.ts +266 -0
  219. package/src/shared/openai-compatible/stream-assembler.ts +248 -0
  220. 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,5 @@
1
+ export * from './types';
2
+ export * from './reasoning-projector';
3
+ export * from './tool-call-projector';
4
+ export * from './provider';
5
+ export * from './provider-definition';
@@ -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
+ }