cyberia 3.2.12 → 3.2.70

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 (194) hide show
  1. package/.env.example +127 -68
  2. package/.github/workflows/cyberia-client.cd.yml +40 -0
  3. package/.github/workflows/cyberia-server.cd.yml +40 -0
  4. package/.github/workflows/docker-image.cyberia-client.ci.yml +49 -0
  5. package/.github/workflows/docker-image.cyberia-client.dev.ci.yml +48 -0
  6. package/.github/workflows/docker-image.cyberia-server.ci.yml +69 -0
  7. package/.github/workflows/docker-image.cyberia-server.dev.ci.yml +69 -0
  8. package/.github/workflows/docker-image.engine-cyberia.ci.yml +52 -0
  9. package/.github/workflows/docker-image.engine-cyberia.dev.ci.yml +52 -0
  10. package/.github/workflows/engine-cyberia.cd.yml +34 -24
  11. package/.github/workflows/engine-cyberia.ci.yml +27 -5
  12. package/.github/workflows/ghpkg.ci.yml +89 -1
  13. package/.github/workflows/gitlab.ci.yml +1 -1
  14. package/.github/workflows/hardhat.ci.yml +1 -1
  15. package/.github/workflows/npmpkg.ci.yml +19 -12
  16. package/.github/workflows/publish.ci.yml +2 -2
  17. package/.github/workflows/publish.cyberia.ci.yml +5 -16
  18. package/.github/workflows/pwa-microservices-template-page.cd.yml +1 -8
  19. package/.github/workflows/pwa-microservices-template-test.ci.yml +1 -1
  20. package/CHANGELOG.md +451 -1
  21. package/CLI-HELP.md +1040 -1130
  22. package/Dockerfile +141 -43
  23. package/Dockerfile.dev +143 -0
  24. package/Dockerfile.test +165 -0
  25. package/README.md +1 -1
  26. package/baremetal/commission-workflows.json +1 -0
  27. package/bin/build.js +128 -136
  28. package/bin/build.template.js +25 -179
  29. package/bin/cyberia.js +1089 -188
  30. package/bin/deploy.js +6 -3
  31. package/bin/index.js +1089 -188
  32. package/bump.config.js +1 -0
  33. package/compose.env +131 -0
  34. package/conf.js +19 -1
  35. package/deployment.yaml +74 -2
  36. package/docker-compose.yml +316 -0
  37. package/hardhat/hardhat.config.js +2 -2
  38. package/hardhat/package-lock.json +620 -2041
  39. package/hardhat/package.json +7 -5
  40. package/hardhat/scripts/deployObjectLayerToken.js +18 -18
  41. package/hardhat/test/ObjectLayerToken.js +378 -274
  42. package/ipfs/configure-ipfs.sh +13 -0
  43. package/manifests/cronjobs/dd-cron/dd-cron-backup.yaml +2 -2
  44. package/manifests/cronjobs/dd-cron/dd-cron-dns.yaml +1 -1
  45. package/manifests/deployment/dd-cyberia-development/deployment.yaml +74 -2
  46. package/manifests/deployment/dd-cyberia-development/grpc-service.yaml +17 -0
  47. package/manifests/deployment/dd-cyberia-development/pv-pvc.yaml +32 -0
  48. package/manifests/deployment/dd-default-development/deployment.yaml +2 -2
  49. package/mongodb/entrypoint.sh +76 -0
  50. package/nginx.conf +87 -0
  51. package/package.json +34 -22
  52. package/pv-pvc.yaml +32 -0
  53. package/scripts/disk-clean.sh +85 -60
  54. package/scripts/kubeadm-node-setup.sh +317 -0
  55. package/scripts/link-local-underpost-cli.sh +6 -0
  56. package/scripts/rocky-kickstart.sh +877 -185
  57. package/scripts/rpmfusion-ffmpeg-setup.sh +26 -50
  58. package/scripts/test-monitor.sh +248 -0
  59. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.router.js +43 -7
  60. package/src/api/atlas-sprite-sheet/atlas-sprite-sheet.service.js +17 -25
  61. package/src/api/cyberia-action/cyberia-action.controller.js +19 -0
  62. package/src/api/cyberia-action/cyberia-action.model.js +21 -29
  63. package/src/api/cyberia-action/cyberia-action.router.js +42 -7
  64. package/src/api/cyberia-action/cyberia-action.service.js +20 -4
  65. package/src/api/cyberia-client-hints/cyberia-client-hints.model.js +58 -57
  66. package/src/api/cyberia-dialogue/cyberia-dialogue.router.js +37 -6
  67. package/src/api/cyberia-dialogue/cyberia-dialogue.service.js +8 -2
  68. package/src/api/cyberia-entity/cyberia-entity.router.js +39 -7
  69. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.controller.js +74 -0
  70. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.model.js +67 -0
  71. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.router.js +63 -0
  72. package/src/api/cyberia-entity-type-default/cyberia-entity-type-default.service.js +46 -0
  73. package/src/api/cyberia-instance/cyberia-fallback-world.js +62 -10
  74. package/src/api/cyberia-instance/cyberia-instance.model.js +32 -2
  75. package/src/api/cyberia-instance/cyberia-instance.router.js +6 -6
  76. package/src/api/cyberia-instance/cyberia-world-generator.js +116 -3
  77. package/src/api/cyberia-instance-conf/cyberia-instance-conf.model.js +3 -0
  78. package/src/api/cyberia-instance-conf/cyberia-instance-conf.router.js +39 -7
  79. package/src/api/cyberia-map/cyberia-map.router.js +21 -6
  80. package/src/api/cyberia-quest/cyberia-quest.controller.js +38 -0
  81. package/src/api/cyberia-quest/cyberia-quest.router.js +47 -7
  82. package/src/api/cyberia-quest/cyberia-quest.service.js +59 -4
  83. package/src/api/cyberia-saga/cyberia-saga.controller.js +74 -0
  84. package/src/api/cyberia-saga/cyberia-saga.model.js +59 -0
  85. package/src/api/cyberia-saga/cyberia-saga.router.js +63 -0
  86. package/src/api/cyberia-saga/cyberia-saga.service.js +42 -0
  87. package/src/api/cyberia-server-defaults/cyberia-server-defaults.js +551 -122
  88. package/src/api/cyberia-skill/cyberia-skill.controller.js +74 -0
  89. package/src/api/cyberia-skill/cyberia-skill.model.js +50 -0
  90. package/src/api/cyberia-skill/cyberia-skill.router.js +63 -0
  91. package/src/api/cyberia-skill/cyberia-skill.service.js +42 -0
  92. package/src/api/ipfs/ipfs.service.js +28 -15
  93. package/src/api/object-layer/object-layer.router.js +25 -15
  94. package/src/api/object-layer/object-layer.service.js +15 -20
  95. package/src/api/object-layer-render-frames/object-layer-render-frames.router.js +39 -7
  96. package/src/cli/baremetal.js +717 -16
  97. package/src/cli/cluster.js +80 -5
  98. package/src/cli/deploy.js +326 -292
  99. package/src/cli/docker-compose.js +648 -0
  100. package/src/cli/env.js +12 -6
  101. package/src/cli/fs.js +75 -30
  102. package/src/cli/image.js +187 -55
  103. package/src/cli/index.js +157 -6
  104. package/src/cli/kickstart.js +142 -20
  105. package/src/cli/monitor.js +387 -6
  106. package/src/cli/release.js +72 -15
  107. package/src/cli/repository.js +339 -40
  108. package/src/cli/run.js +678 -186
  109. package/src/cli/secrets.js +82 -48
  110. package/src/cli/ssh.js +234 -0
  111. package/src/cli/static.js +2 -2
  112. package/src/client/components/core/PanelForm.js +44 -44
  113. package/src/client/components/cyberia/ActionEngineCyberia.js +1867 -0
  114. package/src/client/components/cyberia/EntityEngineCyberia.js +585 -0
  115. package/src/client/components/cyberia/InstanceEngineCyberia.js +219 -13
  116. package/src/client/components/cyberia/MapEngineCyberia.js +154 -71
  117. package/src/client/components/cyberia/ObjectLayerEngineModal.js +40 -63
  118. package/src/client/components/cyberia/ObjectLayerEngineViewer.js +34 -20
  119. package/src/client/components/cyberia/SharedDefaultsCyberia.js +195 -4
  120. package/src/client/components/cyberia-portal/AppShellCyberiaPortal.js +66 -0
  121. package/src/client/components/cyberia-portal/RouterCyberiaPortal.js +8 -0
  122. package/src/client/components/cyberia-portal/TranslateCyberiaPortal.js +8 -0
  123. package/src/client/public/cyberia-docs/ACTION-SYSTEM.md +92 -20
  124. package/src/client/public/cyberia-docs/ARCHITECTURE.md +272 -50
  125. package/src/client/public/cyberia-docs/CYBERIA-CLI.md +3 -3
  126. package/src/client/public/cyberia-docs/CYBERIA-CLIENT.md +39 -22
  127. package/src/client/public/cyberia-docs/CYBERIA-LORE.md +88 -0
  128. package/src/client/public/cyberia-docs/CYBERIA-SAGA.md +394 -0
  129. package/src/client/public/cyberia-docs/CYBERIA-SERVER.md +28 -12
  130. package/src/client/public/cyberia-docs/CYBERIA.md +1 -1
  131. package/src/client/public/cyberia-docs/QUEST-SYSTEM.md +27 -5
  132. package/src/client/public/cyberia-docs/ROADMAP.md +1 -1
  133. package/src/client/public/cyberia-docs/WHITE-PAPER.md +1 -1
  134. package/src/client/services/cyberia-entity-type-default/cyberia-entity-type-default.service.js +99 -0
  135. package/src/client/services/cyberia-instance/cyberia-instance.management.js +2 -2
  136. package/src/client/services/cyberia-map/cyberia-map.management.js +2 -2
  137. package/src/client/services/cyberia-saga/cyberia-saga.service.js +99 -0
  138. package/src/client/services/cyberia-skill/cyberia-skill.service.js +99 -0
  139. package/src/client/services/object-layer/object-layer.management.js +6 -6
  140. package/src/{server → client-builder}/client-build-docs.js +15 -5
  141. package/src/{server → client-builder}/client-build-live.js +3 -3
  142. package/src/{server → client-builder}/client-build.js +25 -22
  143. package/src/{server → client-builder}/client-dev-server.js +3 -3
  144. package/src/{server → client-builder}/client-icons.js +2 -2
  145. package/src/{server → client-builder}/ssr.js +5 -5
  146. package/src/client.build.js +1 -3
  147. package/src/client.dev.js +1 -1
  148. package/src/db/mongo/MongoBootstrap.js +12 -12
  149. package/src/db/mongo/MongooseDB.js +2 -1
  150. package/src/grpc/cyberia/grpc-server.js +255 -70
  151. package/src/index.js +12 -1
  152. package/src/mailer/EmailRender.js +1 -1
  153. package/src/{server → projects/cyberia}/atlas-sprite-sheet-generator.js +2 -2
  154. package/src/{server → projects/cyberia}/besu-genesis-generator.js +3 -3
  155. package/src/projects/cyberia/catalog-cyberia.js +81 -0
  156. package/src/projects/cyberia/gemini-client.js +175 -0
  157. package/src/projects/cyberia/generate-saga.js +2107 -0
  158. package/src/{server → projects/cyberia}/ipfs-client.js +6 -4
  159. package/src/{server → projects/cyberia}/object-layer.js +12 -108
  160. package/src/{server → projects/cyberia}/semantic-layer-generator-floor.js +1 -1
  161. package/src/{server → projects/cyberia}/semantic-layer-generator-resource.js +1 -1
  162. package/src/{server → projects/cyberia}/semantic-layer-generator-skin.js +1 -1
  163. package/src/{server → projects/cyberia}/semantic-layer-generator.js +2 -2
  164. package/src/{server → projects/cyberia}/shape-generator.js +2 -2
  165. package/src/projects/underpost/catalog-underpost.js +60 -0
  166. package/src/runtime/cyberia-client/Dockerfile +31 -83
  167. package/src/runtime/cyberia-client/Dockerfile.dev +23 -30
  168. package/src/runtime/cyberia-server/Dockerfile +23 -42
  169. package/src/runtime/cyberia-server/Dockerfile.dev +20 -35
  170. package/src/runtime/engine-cyberia/Dockerfile +143 -0
  171. package/src/runtime/engine-cyberia/Dockerfile.dev +143 -0
  172. package/src/runtime/engine-cyberia/Dockerfile.test +165 -0
  173. package/src/runtime/engine-cyberia/compose.env +131 -0
  174. package/src/runtime/engine-cyberia/docker-compose.yml +316 -0
  175. package/src/runtime/engine-cyberia/ipfs/configure-ipfs.sh +13 -0
  176. package/src/runtime/engine-cyberia/mongodb/entrypoint.sh +76 -0
  177. package/src/runtime/engine-cyberia/nginx.conf +87 -0
  178. package/src/runtime/express/Express.js +2 -2
  179. package/src/runtime/nginx/Nginx.js +250 -0
  180. package/src/runtime/wp/Dockerfile +3 -3
  181. package/src/server/catalog.js +72 -0
  182. package/src/server/conf.js +415 -60
  183. package/src/server/runtime-status.js +252 -0
  184. package/src/server/start.js +42 -11
  185. package/src/server.js +6 -2
  186. package/test/cyberia-instance-conf-defaults.test.js +140 -0
  187. package/test/deploy-monitor.test.js +267 -0
  188. package/test/shape-generator.test.js +7 -1
  189. package/typedoc.dd-cyberia.json +3 -1
  190. package/typedoc.json +3 -1
  191. package/manifests/deployment/dd-test-development/deployment.yaml +0 -256
  192. package/manifests/deployment/dd-test-development/proxy.yaml +0 -102
  193. /package/src/client/ssr/{Render.js → RootDocument.js} +0 -0
  194. /package/src/{server → client-builder}/client-formatted.js +0 -0
@@ -0,0 +1,81 @@
1
+ /**
2
+ * Cyberia CLI content catalog.
3
+ *
4
+ * A per-deploy product catalog: pure data, loaded dynamically by deploy id via
5
+ * {@link module:src/server/catalog} so the base build and template assembly never
6
+ * statically depend on it. Exports the uniform product-catalog shape:
7
+ *
8
+ * - `sourceMoves` — public `[src, dest]` pairs moved into the engine tree before a build.
9
+ * - `privateConfPaths` — extra payloads synced into the deploy's private repo.
10
+ * - `templatePaths` — engine paths packaged into the standalone product CLI template.
11
+ * - `stripPaths` — paths removed from the base `pwa-microservices-template`.
12
+ * - `moves` — `[src, dest]` pairs moved into the template during assembly (like sourceMoves but into the template target).
13
+ * - `copies` — `[src, dest]` pairs copied into the template during assembly (like moves but copied instead of moved).
14
+ * - `keywords` — npm keywords for the standalone product CLI package.
15
+ * - `description` — npm description for the standalone product CLI package.
16
+ *
17
+ * @module src/projects/cyberia/catalog-cyberia.js
18
+ * @namespace CyberiaCatalog
19
+ */
20
+
21
+ export default {
22
+ sourceMoves: [],
23
+ privateConfPaths: ['cyberia-instances/amethyst-strata-expansion'],
24
+ templatePaths: [
25
+ '/src/grpc/cyberia',
26
+ '/src/client/ssr/views/CyberiaServerMetrics.js',
27
+ '/test/cyberia-instance-conf-defaults.test.js',
28
+ '/test/shape-generator.test.js',
29
+ '/src/projects/cyberia',
30
+ '/src/runtime/cyberia-server',
31
+ '/src/runtime/cyberia-client',
32
+ '/src/runtime/engine-cyberia',
33
+ '/.github/workflows/hardhat.ci.yml',
34
+ '/src/client/public/cyberia-docs',
35
+ '/src/api/cyberia-server-defaults',
36
+ '/.github/workflows/docker-image.cyberia-client.ci.yml',
37
+ '/.github/workflows/docker-image.cyberia-client.dev.ci.yml',
38
+ '/.github/workflows/docker-image.cyberia-server.ci.yml',
39
+ '/.github/workflows/docker-image.cyberia-server.dev.ci.yml',
40
+ '/.github/workflows/cyberia-client.cd.yml',
41
+ '/.github/workflows/cyberia-server.cd.yml',
42
+ ],
43
+ stripPaths: [
44
+ './src/projects/cyberia',
45
+ './src/grpc/cyberia',
46
+ './src/runtime/cyberia-server',
47
+ './src/runtime/cyberia-client',
48
+ './src/runtime/engine-cyberia',
49
+ './test/cyberia-instance-conf-defaults.test.js',
50
+ './test/shape-generator.test.js',
51
+ './src/client/public/cyberia-docs',
52
+ 'bin/cyberia.js',
53
+ './hardhat',
54
+ ],
55
+ moves: [],
56
+ copies: [
57
+ ['./src/runtime/engine-cyberia/docker-compose.yml', './docker-compose.yml'],
58
+ ['./src/runtime/engine-cyberia/compose.env', './.env.example'],
59
+ ['./src/runtime/engine-cyberia/.', './'],
60
+ ],
61
+ keywords: [
62
+ 'cyberia',
63
+ 'cyberia-cli',
64
+ 'engine-cyberia',
65
+ 'sidecar',
66
+ 'data-layer',
67
+ 'object-layer',
68
+ 'atlas-sprite-sheet',
69
+ 'ipfs',
70
+ 'erc-1155',
71
+ 'object-layer-token',
72
+ 'hardhat',
73
+ 'hyperledger-besu',
74
+ 'blockchain',
75
+ 'web3',
76
+ 'underpost-platform',
77
+ 'mmorpg',
78
+ ],
79
+ description:
80
+ 'Cyberia CLI — toolchain for the Cyberia MMO data layer, content pipeline, persistence, gRPC services, and ERC-1155 lifecycle on Hyperledger Besu.',
81
+ };
@@ -0,0 +1,175 @@
1
+ /**
2
+ * Minimal Google Gemini (Generative Language API) chat client.
3
+ *
4
+ * Kept intentionally thin: a single text/JSON completion helper used by the
5
+ * Top-Down PCG saga generator. No streaming, no tool-calls — the saga
6
+ * orchestration only needs one structured JSON payload per request.
7
+ *
8
+ * General purpose, but for now only the `:generateContent` endpoint is wired,
9
+ * matching the Gemma model family (e.g. `gemma-4-26b-a4b-it`). Authentication
10
+ * uses the `x-goog-api-key` header sourced from `GEMINI_API_KEY`.
11
+ *
12
+ * @module src/projects/cyberia/gemini-client.js
13
+ * @namespace GeminiClient
14
+ */
15
+
16
+ import axios from 'axios';
17
+ import { loggerFactory } from '../../server/logger.js';
18
+
19
+ const logger = loggerFactory(import.meta);
20
+
21
+ /** Generative Language API model base. The model id + `:generateContent` is appended. */
22
+ const GEMINI_API_BASE = 'https://generativelanguage.googleapis.com/v1beta/models';
23
+
24
+ /** Default model id (Gemma instruction-tuned model). */
25
+ const GEMINI_DEFAULT_MODEL = 'gemma-4-26b-a4b-it';
26
+
27
+ /**
28
+ * Best-effort extraction of a single JSON object from a model text response.
29
+ * Tolerates markdown fences and leading/trailing prose.
30
+ *
31
+ * @param {string} text
32
+ * @returns {Object}
33
+ */
34
+ function parseJsonLoose(text) {
35
+ let candidate = String(text || '').trim();
36
+
37
+ // Strip a ```json ... ``` (or bare ``` ... ```) fence if present.
38
+ const fence = candidate.match(/```(?:json)?\s*([\s\S]*?)```/i);
39
+ if (fence) candidate = fence[1].trim();
40
+
41
+ try {
42
+ return JSON.parse(candidate);
43
+ } catch {
44
+ // Fall back to the widest {...} span.
45
+ const start = candidate.indexOf('{');
46
+ const end = candidate.lastIndexOf('}');
47
+ if (start !== -1 && end > start) {
48
+ return JSON.parse(candidate.slice(start, end + 1));
49
+ }
50
+ throw new Error('Failed to parse JSON from Gemini response.');
51
+ }
52
+ }
53
+
54
+ class GeminiClient {
55
+ /**
56
+ * @param {Object} [options]
57
+ * @param {string} [options.apiKey] - Gemini API key. Falls back to `process.env.GEMINI_API_KEY`.
58
+ * @param {string} [options.model] - Model id (default: `gemma-4-26b-a4b-it`).
59
+ * @param {string} [options.baseURL] - Override the model base URL.
60
+ * @param {number} [options.timeout] - Request timeout in ms (default: 300000).
61
+ * @param {number} [options.maxRetries] - Retry attempts on transient failure (default: 2).
62
+ */
63
+ constructor({
64
+ apiKey,
65
+ model = GEMINI_DEFAULT_MODEL,
66
+ baseURL = GEMINI_API_BASE,
67
+ timeout = 300000,
68
+ maxRetries = 2,
69
+ } = {}) {
70
+ this.apiKey = apiKey || process.env.GEMINI_API_KEY;
71
+ this.model = model;
72
+ this.baseURL = baseURL;
73
+ this.timeout = timeout;
74
+ this.maxRetries = maxRetries;
75
+ if (!this.apiKey) {
76
+ throw new Error('GEMINI_API_KEY is not set. Export it or add it to your --env-path file.');
77
+ }
78
+ }
79
+
80
+ /**
81
+ * Run a single `:generateContent` request and return the answer text,
82
+ * skipping any thinking parts the model emits.
83
+ *
84
+ * @async
85
+ * @param {Object} params
86
+ * @param {string} params.prompt - Full prompt text (system + user merged).
87
+ * @param {Object} [params.generationConfig] - Passed through to the API.
88
+ * @returns {Promise<string>} The concatenated answer text.
89
+ */
90
+ async generateContent({ prompt, generationConfig = {} }) {
91
+ const url = `${this.baseURL}/${this.model}:generateContent`;
92
+ logger.info(`Gemini request → model=${this.model}`);
93
+
94
+ const { data } = await axios.post(
95
+ url,
96
+ {
97
+ contents: [{ parts: [{ text: prompt }] }],
98
+ generationConfig,
99
+ },
100
+ {
101
+ headers: { 'x-goog-api-key': this.apiKey, 'Content-Type': 'application/json' },
102
+ timeout: this.timeout,
103
+ },
104
+ );
105
+
106
+ const parts = data?.candidates?.[0]?.content?.parts || [];
107
+ const text = parts
108
+ .filter((p) => p && typeof p.text === 'string' && !p.thought)
109
+ .map((p) => p.text)
110
+ .join('');
111
+
112
+ if (!text) throw new Error('Gemini returned an empty completion.');
113
+
114
+ const usage = data?.usageMetadata;
115
+ if (usage) {
116
+ logger.info(
117
+ `Gemini usage → prompt=${usage.promptTokenCount} candidates=${usage.candidatesTokenCount} ` +
118
+ `total=${usage.totalTokenCount}`,
119
+ );
120
+ }
121
+
122
+ return text;
123
+ }
124
+
125
+ /**
126
+ * Run a single completion and parse the answer as JSON.
127
+ *
128
+ * Gemma models do not support a dedicated JSON response mode, so the schema
129
+ * is requested in-prompt and the response is parsed leniently.
130
+ *
131
+ * @async
132
+ * @param {Object} params
133
+ * @param {string} params.system - System prompt (defines the output ontology / schema).
134
+ * @param {string} params.user - User prompt (the high-level theme seed).
135
+ * @param {string} [params.thinkingLevel='high'] - Gemini thinking level.
136
+ * @param {number} [params.temperature] - Sampling temperature (higher = more varied).
137
+ * @returns {Promise<Object>} Parsed JSON object from the model response.
138
+ */
139
+ async chatJson({ system, user, thinkingLevel = 'high', temperature }) {
140
+ const prompt = [
141
+ system,
142
+ '',
143
+ user,
144
+ '',
145
+ 'Respond with ONLY a single valid JSON object. Do not wrap it in markdown fences and do not add any prose.',
146
+ ].join('\n');
147
+
148
+ const generationConfig = { thinkingConfig: { thinkingLevel } };
149
+ if (typeof temperature === 'number') generationConfig.temperature = temperature;
150
+
151
+ // Retry on transient failures (timeouts, 5xx, empty/invalid JSON) which the
152
+ // generateContent endpoint surfaces intermittently under load.
153
+ let lastError;
154
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
155
+ try {
156
+ const text = await this.generateContent({ prompt, generationConfig });
157
+ return parseJsonLoose(text);
158
+ } catch (error) {
159
+ console.error(error);
160
+ lastError = error;
161
+ if (attempt < this.maxRetries) {
162
+ const backoffMs = 1000 * (attempt + 1);
163
+ logger.warn(
164
+ `Gemini attempt ${attempt + 1}/${this.maxRetries + 1} failed (${error.message}); ` +
165
+ `retrying in ${backoffMs}ms`,
166
+ );
167
+ await new Promise((resolve) => setTimeout(resolve, backoffMs));
168
+ }
169
+ }
170
+ }
171
+ throw lastError;
172
+ }
173
+ }
174
+
175
+ export { GeminiClient, GEMINI_API_BASE, GEMINI_DEFAULT_MODEL, parseJsonLoose };