@llumiverse/drivers 1.0.0-dev.20260202.145450Z → 1.0.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 (240) hide show
  1. package/lib/cjs/adobe/firefly.js +120 -0
  2. package/lib/cjs/adobe/firefly.js.map +1 -0
  3. package/lib/cjs/azure/azure_foundry.js +432 -0
  4. package/lib/cjs/azure/azure_foundry.js.map +1 -0
  5. package/lib/cjs/bedrock/converse.js +359 -0
  6. package/lib/cjs/bedrock/converse.js.map +1 -0
  7. package/lib/cjs/bedrock/index.js +1441 -0
  8. package/lib/cjs/bedrock/index.js.map +1 -0
  9. package/lib/cjs/bedrock/nova-image-payload.js +207 -0
  10. package/lib/cjs/bedrock/nova-image-payload.js.map +1 -0
  11. package/lib/cjs/bedrock/payloads.js +3 -0
  12. package/lib/cjs/bedrock/payloads.js.map +1 -0
  13. package/lib/cjs/bedrock/s3.js +107 -0
  14. package/lib/cjs/bedrock/s3.js.map +1 -0
  15. package/lib/cjs/bedrock/twelvelabs.js +87 -0
  16. package/lib/cjs/bedrock/twelvelabs.js.map +1 -0
  17. package/lib/cjs/groq/index.js +326 -0
  18. package/lib/cjs/groq/index.js.map +1 -0
  19. package/lib/cjs/huggingface_ie.js +201 -0
  20. package/lib/cjs/huggingface_ie.js.map +1 -0
  21. package/lib/cjs/index.js +31 -0
  22. package/lib/cjs/index.js.map +1 -0
  23. package/lib/cjs/mistral/index.js +176 -0
  24. package/lib/cjs/mistral/index.js.map +1 -0
  25. package/lib/cjs/mistral/types.js +83 -0
  26. package/lib/cjs/mistral/types.js.map +1 -0
  27. package/lib/cjs/openai/azure_openai.js +72 -0
  28. package/lib/cjs/openai/azure_openai.js.map +1 -0
  29. package/lib/cjs/openai/index.js +1100 -0
  30. package/lib/cjs/openai/index.js.map +1 -0
  31. package/lib/cjs/openai/openai.js +21 -0
  32. package/lib/cjs/openai/openai.js.map +1 -0
  33. package/lib/cjs/openai/openai_compatible.js +63 -0
  34. package/lib/cjs/openai/openai_compatible.js.map +1 -0
  35. package/lib/cjs/openai/openai_format.js +131 -0
  36. package/lib/cjs/openai/openai_format.js.map +1 -0
  37. package/lib/cjs/package.json +3 -0
  38. package/lib/cjs/replicate.js +275 -0
  39. package/lib/cjs/replicate.js.map +1 -0
  40. package/lib/cjs/test-driver/TestErrorCompletionStream.js +20 -0
  41. package/lib/cjs/test-driver/TestErrorCompletionStream.js.map +1 -0
  42. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js +24 -0
  43. package/lib/cjs/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  44. package/lib/cjs/test-driver/index.js +109 -0
  45. package/lib/cjs/test-driver/index.js.map +1 -0
  46. package/lib/cjs/test-driver/utils.js +30 -0
  47. package/lib/cjs/test-driver/utils.js.map +1 -0
  48. package/lib/cjs/togetherai/index.js +126 -0
  49. package/lib/cjs/togetherai/index.js.map +1 -0
  50. package/lib/cjs/togetherai/interfaces.js +3 -0
  51. package/lib/cjs/togetherai/interfaces.js.map +1 -0
  52. package/lib/cjs/vertexai/debug.js +12 -0
  53. package/lib/cjs/vertexai/debug.js.map +1 -0
  54. package/lib/cjs/vertexai/embeddings/embeddings-image.js +27 -0
  55. package/lib/cjs/vertexai/embeddings/embeddings-image.js.map +1 -0
  56. package/lib/cjs/vertexai/embeddings/embeddings-text.js +23 -0
  57. package/lib/cjs/vertexai/embeddings/embeddings-text.js.map +1 -0
  58. package/lib/cjs/vertexai/index.js +635 -0
  59. package/lib/cjs/vertexai/index.js.map +1 -0
  60. package/lib/cjs/vertexai/models/claude.js +842 -0
  61. package/lib/cjs/vertexai/models/claude.js.map +1 -0
  62. package/lib/cjs/vertexai/models/gemini.js +1110 -0
  63. package/lib/cjs/vertexai/models/gemini.js.map +1 -0
  64. package/lib/cjs/vertexai/models/imagen.js +303 -0
  65. package/lib/cjs/vertexai/models/imagen.js.map +1 -0
  66. package/lib/cjs/vertexai/models/llama.js +183 -0
  67. package/lib/cjs/vertexai/models/llama.js.map +1 -0
  68. package/lib/cjs/vertexai/models.js +35 -0
  69. package/lib/cjs/vertexai/models.js.map +1 -0
  70. package/lib/cjs/watsonx/index.js +161 -0
  71. package/lib/cjs/watsonx/index.js.map +1 -0
  72. package/lib/cjs/watsonx/interfaces.js +3 -0
  73. package/lib/cjs/watsonx/interfaces.js.map +1 -0
  74. package/lib/cjs/xai/index.js +65 -0
  75. package/lib/cjs/xai/index.js.map +1 -0
  76. package/lib/esm/adobe/firefly.js +116 -0
  77. package/lib/esm/adobe/firefly.js.map +1 -0
  78. package/lib/esm/azure/azure_foundry.js +426 -0
  79. package/lib/esm/azure/azure_foundry.js.map +1 -0
  80. package/lib/esm/bedrock/converse.js +352 -0
  81. package/lib/esm/bedrock/converse.js.map +1 -0
  82. package/lib/esm/bedrock/index.js +1434 -0
  83. package/lib/esm/bedrock/index.js.map +1 -0
  84. package/lib/esm/bedrock/nova-image-payload.js +203 -0
  85. package/lib/esm/bedrock/nova-image-payload.js.map +1 -0
  86. package/lib/esm/bedrock/payloads.js +2 -0
  87. package/lib/esm/bedrock/payloads.js.map +1 -0
  88. package/lib/esm/bedrock/s3.js +99 -0
  89. package/lib/esm/bedrock/s3.js.map +1 -0
  90. package/lib/esm/bedrock/twelvelabs.js +84 -0
  91. package/lib/esm/bedrock/twelvelabs.js.map +1 -0
  92. package/lib/esm/groq/index.js +319 -0
  93. package/lib/esm/groq/index.js.map +1 -0
  94. package/lib/esm/huggingface_ie.js +197 -0
  95. package/lib/esm/huggingface_ie.js.map +1 -0
  96. package/lib/esm/index.js +15 -0
  97. package/lib/esm/index.js.map +1 -0
  98. package/lib/esm/mistral/index.js +172 -0
  99. package/lib/esm/mistral/index.js.map +1 -0
  100. package/lib/esm/mistral/types.js +80 -0
  101. package/lib/esm/mistral/types.js.map +1 -0
  102. package/lib/esm/openai/azure_openai.js +68 -0
  103. package/lib/esm/openai/azure_openai.js.map +1 -0
  104. package/lib/esm/openai/index.js +1093 -0
  105. package/lib/esm/openai/index.js.map +1 -0
  106. package/lib/esm/openai/openai.js +14 -0
  107. package/lib/esm/openai/openai.js.map +1 -0
  108. package/lib/esm/openai/openai_compatible.js +56 -0
  109. package/lib/esm/openai/openai_compatible.js.map +1 -0
  110. package/lib/esm/openai/openai_format.js +127 -0
  111. package/lib/esm/openai/openai_format.js.map +1 -0
  112. package/lib/esm/replicate.js +268 -0
  113. package/lib/esm/replicate.js.map +1 -0
  114. package/lib/esm/test-driver/TestErrorCompletionStream.js +16 -0
  115. package/lib/esm/test-driver/TestErrorCompletionStream.js.map +1 -0
  116. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js +20 -0
  117. package/lib/esm/test-driver/TestValidationErrorCompletionStream.js.map +1 -0
  118. package/lib/esm/test-driver/index.js +91 -0
  119. package/lib/esm/test-driver/index.js.map +1 -0
  120. package/lib/esm/test-driver/utils.js +25 -0
  121. package/lib/esm/test-driver/utils.js.map +1 -0
  122. package/lib/esm/togetherai/index.js +122 -0
  123. package/lib/esm/togetherai/index.js.map +1 -0
  124. package/lib/esm/togetherai/interfaces.js +2 -0
  125. package/lib/esm/togetherai/interfaces.js.map +1 -0
  126. package/lib/esm/vertexai/debug.js +6 -0
  127. package/lib/esm/vertexai/debug.js.map +1 -0
  128. package/lib/esm/vertexai/embeddings/embeddings-image.js +24 -0
  129. package/lib/esm/vertexai/embeddings/embeddings-image.js.map +1 -0
  130. package/lib/esm/vertexai/embeddings/embeddings-text.js +20 -0
  131. package/lib/esm/vertexai/embeddings/embeddings-text.js.map +1 -0
  132. package/lib/esm/vertexai/index.js +630 -0
  133. package/lib/esm/vertexai/index.js.map +1 -0
  134. package/lib/esm/vertexai/models/claude.js +833 -0
  135. package/lib/esm/vertexai/models/claude.js.map +1 -0
  136. package/lib/esm/vertexai/models/gemini.js +1104 -0
  137. package/lib/esm/vertexai/models/gemini.js.map +1 -0
  138. package/lib/esm/vertexai/models/imagen.js +299 -0
  139. package/lib/esm/vertexai/models/imagen.js.map +1 -0
  140. package/lib/esm/vertexai/models/llama.js +179 -0
  141. package/lib/esm/vertexai/models/llama.js.map +1 -0
  142. package/lib/esm/vertexai/models.js +32 -0
  143. package/lib/esm/vertexai/models.js.map +1 -0
  144. package/lib/esm/watsonx/index.js +157 -0
  145. package/lib/esm/watsonx/index.js.map +1 -0
  146. package/lib/esm/watsonx/interfaces.js +2 -0
  147. package/lib/esm/watsonx/interfaces.js.map +1 -0
  148. package/lib/esm/xai/index.js +58 -0
  149. package/lib/esm/xai/index.js.map +1 -0
  150. package/lib/types/adobe/firefly.d.ts +30 -0
  151. package/lib/types/adobe/firefly.d.ts.map +1 -0
  152. package/lib/types/azure/azure_foundry.d.ts +52 -0
  153. package/lib/types/azure/azure_foundry.d.ts.map +1 -0
  154. package/lib/types/bedrock/converse.d.ts +8 -0
  155. package/lib/types/bedrock/converse.d.ts.map +1 -0
  156. package/lib/types/bedrock/index.d.ts +135 -0
  157. package/lib/types/bedrock/index.d.ts.map +1 -0
  158. package/lib/types/bedrock/nova-image-payload.d.ts +74 -0
  159. package/lib/types/bedrock/nova-image-payload.d.ts.map +1 -0
  160. package/lib/types/bedrock/payloads.d.ts +12 -0
  161. package/lib/types/bedrock/payloads.d.ts.map +1 -0
  162. package/lib/types/bedrock/s3.d.ts +23 -0
  163. package/lib/types/bedrock/s3.d.ts.map +1 -0
  164. package/lib/types/bedrock/twelvelabs.d.ts +50 -0
  165. package/lib/types/bedrock/twelvelabs.d.ts.map +1 -0
  166. package/lib/types/groq/index.d.ts +27 -0
  167. package/lib/types/groq/index.d.ts.map +1 -0
  168. package/lib/types/huggingface_ie.d.ts +35 -0
  169. package/lib/types/huggingface_ie.d.ts.map +1 -0
  170. package/lib/types/index.d.ts +15 -0
  171. package/lib/types/index.d.ts.map +1 -0
  172. package/lib/types/mistral/index.d.ts +25 -0
  173. package/lib/types/mistral/index.d.ts.map +1 -0
  174. package/lib/types/mistral/types.d.ts +127 -0
  175. package/lib/types/mistral/types.d.ts.map +1 -0
  176. package/lib/types/openai/azure_openai.d.ts +25 -0
  177. package/lib/types/openai/azure_openai.d.ts.map +1 -0
  178. package/lib/types/openai/index.d.ts +126 -0
  179. package/lib/types/openai/index.d.ts.map +1 -0
  180. package/lib/types/openai/openai.d.ts +15 -0
  181. package/lib/types/openai/openai.d.ts.map +1 -0
  182. package/lib/types/openai/openai_compatible.d.ts +31 -0
  183. package/lib/types/openai/openai_compatible.d.ts.map +1 -0
  184. package/lib/types/openai/openai_format.d.ts +21 -0
  185. package/lib/types/openai/openai_format.d.ts.map +1 -0
  186. package/lib/types/replicate.d.ts +48 -0
  187. package/lib/types/replicate.d.ts.map +1 -0
  188. package/lib/types/test-driver/TestErrorCompletionStream.d.ts +9 -0
  189. package/lib/types/test-driver/TestErrorCompletionStream.d.ts.map +1 -0
  190. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts +9 -0
  191. package/lib/types/test-driver/TestValidationErrorCompletionStream.d.ts.map +1 -0
  192. package/lib/types/test-driver/index.d.ts +24 -0
  193. package/lib/types/test-driver/index.d.ts.map +1 -0
  194. package/lib/types/test-driver/utils.d.ts +5 -0
  195. package/lib/types/test-driver/utils.d.ts.map +1 -0
  196. package/lib/types/togetherai/index.d.ts +23 -0
  197. package/lib/types/togetherai/index.d.ts.map +1 -0
  198. package/lib/types/togetherai/interfaces.d.ts +96 -0
  199. package/lib/types/togetherai/interfaces.d.ts.map +1 -0
  200. package/lib/types/vertexai/debug.d.ts +2 -0
  201. package/lib/types/vertexai/debug.d.ts.map +1 -0
  202. package/lib/types/vertexai/embeddings/embeddings-image.d.ts +11 -0
  203. package/lib/types/vertexai/embeddings/embeddings-image.d.ts.map +1 -0
  204. package/lib/types/vertexai/embeddings/embeddings-text.d.ts +10 -0
  205. package/lib/types/vertexai/embeddings/embeddings-text.d.ts.map +1 -0
  206. package/lib/types/vertexai/index.d.ts +79 -0
  207. package/lib/types/vertexai/index.d.ts.map +1 -0
  208. package/lib/types/vertexai/models/claude.d.ts +103 -0
  209. package/lib/types/vertexai/models/claude.d.ts.map +1 -0
  210. package/lib/types/vertexai/models/gemini.d.ts +78 -0
  211. package/lib/types/vertexai/models/gemini.d.ts.map +1 -0
  212. package/lib/types/vertexai/models/imagen.d.ts +75 -0
  213. package/lib/types/vertexai/models/imagen.d.ts.map +1 -0
  214. package/lib/types/vertexai/models/llama.d.ts +20 -0
  215. package/lib/types/vertexai/models/llama.d.ts.map +1 -0
  216. package/lib/types/vertexai/models.d.ts +20 -0
  217. package/lib/types/vertexai/models.d.ts.map +1 -0
  218. package/lib/types/watsonx/index.d.ts +27 -0
  219. package/lib/types/watsonx/index.d.ts.map +1 -0
  220. package/lib/types/watsonx/interfaces.d.ts +65 -0
  221. package/lib/types/watsonx/interfaces.d.ts.map +1 -0
  222. package/lib/types/xai/index.d.ts +18 -0
  223. package/lib/types/xai/index.d.ts.map +1 -0
  224. package/package.json +18 -18
  225. package/src/bedrock/converse.ts +85 -10
  226. package/src/bedrock/error-handling.test.ts +352 -0
  227. package/src/bedrock/index.ts +293 -16
  228. package/src/groq/index.ts +9 -4
  229. package/src/mistral/index.ts +25 -22
  230. package/src/mistral/types.ts +0 -5
  231. package/src/openai/error-handling.test.ts +567 -0
  232. package/src/openai/index.ts +513 -33
  233. package/src/openai/openai_compatible.ts +7 -0
  234. package/src/openai/openai_format.ts +1 -1
  235. package/src/vertexai/index.ts +61 -13
  236. package/src/vertexai/models/claude-error-handling.test.ts +432 -0
  237. package/src/vertexai/models/claude.ts +287 -10
  238. package/src/vertexai/models/gemini-error-handling.test.ts +353 -0
  239. package/src/vertexai/models/gemini.ts +329 -52
  240. package/src/vertexai/models.ts +7 -2
@@ -0,0 +1,353 @@
1
+ import { LlumiverseError } from '@llumiverse/core';
2
+ import { beforeEach, describe, expect, it } from 'vitest';
3
+ import { VertexAIDriver } from '../index.js';
4
+ import { GeminiModelDefinition } from './gemini.js';
5
+
6
+ describe('GeminiModelDefinition Error Handling', () => {
7
+ let driver: VertexAIDriver;
8
+ let modelDef: GeminiModelDefinition;
9
+
10
+ beforeEach(() => {
11
+ driver = new VertexAIDriver({
12
+ project: 'test-project',
13
+ region: 'us-central1',
14
+ });
15
+ modelDef = new GeminiModelDefinition('gemini-2.0-flash');
16
+ });
17
+
18
+ describe('formatLlumiverseError', () => {
19
+ it('should handle INVALID_ARGUMENT error (400)', () => {
20
+ const googleError = {
21
+ status: 400,
22
+ message: 'INVALID_ARGUMENT: Invalid value for temperature. Must be between 0 and 2.',
23
+ };
24
+
25
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
26
+ provider: 'vertexai',
27
+ model: 'gemini-2.0-flash',
28
+ operation: 'execute',
29
+ });
30
+
31
+ expect(error).toBeInstanceOf(LlumiverseError);
32
+ expect(error.code).toBe(400);
33
+ expect(error.retryable).toBe(false);
34
+ expect(error.message).toContain('[400]');
35
+ expect(error.message).toContain('Invalid value for temperature');
36
+ expect(error.name).toBe('INVALID_ARGUMENT');
37
+ expect(error.context.provider).toBe('vertexai');
38
+ });
39
+
40
+ it('should handle UNAUTHENTICATED error (401)', () => {
41
+ const googleError = {
42
+ status: 401,
43
+ message: 'UNAUTHENTICATED: Request had invalid authentication credentials.',
44
+ };
45
+
46
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
47
+ provider: 'vertexai',
48
+ model: 'gemini-2.0-flash',
49
+ operation: 'execute',
50
+ });
51
+
52
+ expect(error.retryable).toBe(false);
53
+ expect(error.code).toBe(401);
54
+ expect(error.name).toBe('UNAUTHENTICATED');
55
+ });
56
+
57
+ it('should handle PERMISSION_DENIED error (403)', () => {
58
+ const googleError = {
59
+ status: 403,
60
+ message: 'PERMISSION_DENIED: The caller does not have permission to execute the specified operation.',
61
+ };
62
+
63
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
64
+ provider: 'vertexai',
65
+ model: 'gemini-2.0-flash',
66
+ operation: 'execute',
67
+ });
68
+
69
+ expect(error.retryable).toBe(false);
70
+ expect(error.code).toBe(403);
71
+ expect(error.name).toBe('PERMISSION_DENIED');
72
+ });
73
+
74
+ it('should handle NOT_FOUND error (404)', () => {
75
+ const googleError = {
76
+ status: 404,
77
+ message: 'NOT_FOUND: Requested entity was not found.',
78
+ };
79
+
80
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
81
+ provider: 'vertexai',
82
+ model: 'gemini-2.0-flash',
83
+ operation: 'execute',
84
+ });
85
+
86
+ expect(error.retryable).toBe(false);
87
+ expect(error.code).toBe(404);
88
+ expect(error.name).toBe('NOT_FOUND');
89
+ });
90
+
91
+ it('should handle RESOURCE_EXHAUSTED error (429) as retryable', () => {
92
+ const googleError = {
93
+ status: 429,
94
+ message: 'RESOURCE_EXHAUSTED: Quota exceeded for quota metric',
95
+ };
96
+
97
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
98
+ provider: 'vertexai',
99
+ model: 'gemini-2.0-flash',
100
+ operation: 'execute',
101
+ });
102
+
103
+ expect(error.retryable).toBe(true);
104
+ expect(error.code).toBe(429);
105
+ expect(error.message).toContain('[429]');
106
+ expect(error.name).toBe('RESOURCE_EXHAUSTED');
107
+ });
108
+
109
+ it('should handle INTERNAL error (500) as retryable', () => {
110
+ const googleError = {
111
+ status: 500,
112
+ message: 'INTERNAL: Internal server error',
113
+ };
114
+
115
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
116
+ provider: 'vertexai',
117
+ model: 'gemini-2.0-flash',
118
+ operation: 'execute',
119
+ });
120
+
121
+ expect(error.retryable).toBe(true);
122
+ expect(error.code).toBe(500);
123
+ expect(error.message).toContain('[500]');
124
+ });
125
+
126
+ it('should handle BAD_GATEWAY error (502) as retryable', () => {
127
+ const googleError = {
128
+ status: 502,
129
+ message: 'Bad gateway',
130
+ };
131
+
132
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
133
+ provider: 'vertexai',
134
+ model: 'gemini-2.0-flash',
135
+ operation: 'execute',
136
+ });
137
+
138
+ expect(error.retryable).toBe(true);
139
+ expect(error.code).toBe(502);
140
+ });
141
+
142
+ it('should handle UNAVAILABLE error (503) as retryable', () => {
143
+ const googleError = {
144
+ status: 503,
145
+ message: 'UNAVAILABLE: The service is currently unavailable.',
146
+ };
147
+
148
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
149
+ provider: 'vertexai',
150
+ model: 'gemini-2.0-flash',
151
+ operation: 'execute',
152
+ });
153
+
154
+ expect(error.retryable).toBe(true);
155
+ expect(error.code).toBe(503);
156
+ expect(error.name).toBe('UNAVAILABLE');
157
+ });
158
+
159
+ it('should handle DEADLINE_EXCEEDED error (504) as retryable', () => {
160
+ const googleError = {
161
+ status: 504,
162
+ message: 'DEADLINE_EXCEEDED: Request timeout',
163
+ };
164
+
165
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
166
+ provider: 'vertexai',
167
+ model: 'gemini-2.0-flash',
168
+ operation: 'execute',
169
+ });
170
+
171
+ expect(error.retryable).toBe(true);
172
+ expect(error.code).toBe(504);
173
+ expect(error.name).toBe('DEADLINE_EXCEEDED');
174
+ });
175
+
176
+ it('should handle REQUEST_TIMEOUT error (408) as retryable', () => {
177
+ const googleError = {
178
+ status: 408,
179
+ message: 'Request timeout',
180
+ };
181
+
182
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
183
+ provider: 'vertexai',
184
+ model: 'gemini-2.0-flash',
185
+ operation: 'execute',
186
+ });
187
+
188
+ expect(error.retryable).toBe(true);
189
+ expect(error.code).toBe(408);
190
+ });
191
+
192
+ it('should preserve original error for debugging', () => {
193
+ const googleError = {
194
+ status: 429,
195
+ message: 'RESOURCE_EXHAUSTED: Quota exceeded',
196
+ };
197
+
198
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
199
+ provider: 'vertexai',
200
+ model: 'gemini-2.0-flash',
201
+ operation: 'execute',
202
+ });
203
+
204
+ expect(error.originalError).toBe(googleError);
205
+ expect((error.originalError as any).status).toBe(429);
206
+ });
207
+
208
+ it('should throw for non-Google API errors', () => {
209
+ const regularError = new Error('Regular error');
210
+
211
+ expect(() => {
212
+ modelDef.formatLlumiverseError(driver, regularError, {
213
+ provider: 'vertexai',
214
+ model: 'gemini-2.0-flash',
215
+ operation: 'execute',
216
+ });
217
+ }).toThrow();
218
+ });
219
+
220
+ it('should extract error name from bracket format', () => {
221
+ const googleError = {
222
+ status: 400,
223
+ message: '[INVALID_ARGUMENT] Invalid parameter',
224
+ };
225
+
226
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
227
+ provider: 'vertexai',
228
+ model: 'gemini-2.0-flash',
229
+ operation: 'execute',
230
+ });
231
+
232
+ expect(error.name).toBe('INVALID_ARGUMENT');
233
+ });
234
+
235
+ it('should extract error name from Error suffix format', () => {
236
+ const googleError = {
237
+ status: 400,
238
+ message: 'ValidationError: Invalid input',
239
+ };
240
+
241
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
242
+ provider: 'vertexai',
243
+ model: 'gemini-2.0-flash',
244
+ operation: 'execute',
245
+ });
246
+
247
+ expect(error.name).toBe('ValidationError');
248
+ });
249
+
250
+ it('should handle errors without extractable name', () => {
251
+ const googleError = {
252
+ status: 500,
253
+ message: 'Something went wrong',
254
+ };
255
+
256
+ const error = modelDef.formatLlumiverseError(driver, googleError, {
257
+ provider: 'vertexai',
258
+ model: 'gemini-2.0-flash',
259
+ operation: 'execute',
260
+ });
261
+
262
+ // When no name is extracted, defaults to 'LlumiverseError'
263
+ expect(error.name).toBe('LlumiverseError');
264
+ expect(error.code).toBe(500);
265
+ });
266
+ });
267
+
268
+ describe('isGeminiErrorRetryable', () => {
269
+ it('should classify retryable status codes correctly', () => {
270
+ const retryableStatusCodes = [408, 429, 500, 502, 503, 504];
271
+
272
+ retryableStatusCodes.forEach((statusCode) => {
273
+ const result = (modelDef as any).isGeminiErrorRetryable(statusCode);
274
+ expect(result, `Status code ${statusCode} should be retryable`).toBe(true);
275
+ });
276
+ });
277
+
278
+ it('should classify non-retryable status codes correctly', () => {
279
+ const nonRetryableStatusCodes = [400, 401, 403, 404, 409];
280
+
281
+ nonRetryableStatusCodes.forEach((statusCode) => {
282
+ const result = (modelDef as any).isGeminiErrorRetryable(statusCode);
283
+ expect(result, `Status code ${statusCode} should not be retryable`).toBe(false);
284
+ });
285
+ });
286
+
287
+ it('should classify other 5xx errors as retryable', () => {
288
+ expect((modelDef as any).isGeminiErrorRetryable(501)).toBe(true);
289
+ expect((modelDef as any).isGeminiErrorRetryable(505)).toBe(true);
290
+ expect((modelDef as any).isGeminiErrorRetryable(599)).toBe(true);
291
+ });
292
+
293
+ it('should classify other 4xx errors as non-retryable', () => {
294
+ expect((modelDef as any).isGeminiErrorRetryable(402)).toBe(false);
295
+ expect((modelDef as any).isGeminiErrorRetryable(405)).toBe(false);
296
+ expect((modelDef as any).isGeminiErrorRetryable(499)).toBe(false);
297
+ });
298
+ });
299
+
300
+ describe('VertexAIDriver error routing', () => {
301
+ it('should route to Gemini-specific error handler', () => {
302
+ const googleError = {
303
+ status: 429,
304
+ message: 'RESOURCE_EXHAUSTED: Quota exceeded',
305
+ };
306
+
307
+ const error = driver.formatLlumiverseError(googleError, {
308
+ provider: 'vertexai',
309
+ model: 'gemini-2.0-flash',
310
+ operation: 'execute',
311
+ });
312
+
313
+ expect(error).toBeInstanceOf(LlumiverseError);
314
+ expect(error.code).toBe(429);
315
+ expect(error.retryable).toBe(true);
316
+ expect(error.name).toBe('RESOURCE_EXHAUSTED');
317
+ });
318
+
319
+ it('should fall back to default handler for non-Google errors', () => {
320
+ const regularError = new Error('Regular error');
321
+
322
+ const error = driver.formatLlumiverseError(regularError, {
323
+ provider: 'vertexai',
324
+ model: 'gemini-2.0-flash',
325
+ operation: 'execute',
326
+ });
327
+
328
+ expect(error).toBeInstanceOf(LlumiverseError);
329
+ expect(error.code).toBeUndefined();
330
+ expect(error.retryable).toBeUndefined(); // Unknown errors - let consumer decide
331
+ });
332
+
333
+ it('should work with different Gemini model versions', () => {
334
+ const googleError = {
335
+ status: 400,
336
+ message: 'INVALID_ARGUMENT: Invalid parameter',
337
+ };
338
+
339
+ const models = ['gemini-2.0-flash', 'gemini-2.5-flash', 'gemini-1.5-pro'];
340
+
341
+ models.forEach((model) => {
342
+ const error = driver.formatLlumiverseError(googleError, {
343
+ provider: 'vertexai',
344
+ model,
345
+ operation: 'execute',
346
+ });
347
+
348
+ expect(error.code).toBe(400);
349
+ expect(error.retryable).toBe(false);
350
+ });
351
+ });
352
+ });
353
+ });