enigma-memory 0.1.17 → 0.1.22

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 (290) hide show
  1. package/README.md +85 -27
  2. package/apps/cli/bin/enigma-desktop.mjs +140 -0
  3. package/apps/cli/bin/enigma-terminal.mjs +78 -0
  4. package/apps/cli/bin/enigma.mjs +4979 -3263
  5. package/apps/desktop/electron-main.cjs +217 -0
  6. package/apps/desktop/package.json +12 -0
  7. package/apps/desktop/src/app.js +264 -7
  8. package/apps/desktop/src/index.html +3514 -1373
  9. package/apps/desktop/src/launch-electron.mjs +51 -0
  10. package/apps/desktop/src/server.mjs +2914 -0
  11. package/apps/desktop/src/styles.css +2972 -260
  12. package/apps/desktop/src/zk-browser-prove.mjs +53 -0
  13. package/apps/desktop/src/zk-state.mjs +1789 -0
  14. package/apps/gateway/bin/enigma-gateway.mjs +102 -5
  15. package/apps/gateway/src/server.mjs +271 -8
  16. package/apps/ios/EnigmaCore/Package.swift +12 -0
  17. package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
  18. package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
  19. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
  20. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
  21. package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
  22. package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
  23. package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
  24. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
  25. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
  26. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
  27. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
  28. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
  29. package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
  30. package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
  31. package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
  32. package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
  33. package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
  34. package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
  35. package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
  36. package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
  37. package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
  38. package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
  39. package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
  40. package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
  41. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
  42. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
  43. package/apps/native-host/README.md +19 -8
  44. package/apps/native-host/bin/enigma-native-host.mjs +229 -13
  45. package/apps/relay/bin/enigma-relay.mjs +103 -5
  46. package/apps/relay/src/federation-runtime.mjs +618 -0
  47. package/apps/relay/src/server.mjs +310 -9
  48. package/apps/verifier/bin/enigma-verify.mjs +327 -11
  49. package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
  50. package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
  51. package/cortex-v3/circuits/build/vk_bytes.json +32 -0
  52. package/cortex-v3/proving-assets.json +64 -0
  53. package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
  54. package/cortex-v3/zk/action-transition-vk.json +119 -0
  55. package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
  56. package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
  57. package/cortex-v3/zk/intent-witness.mjs +365 -0
  58. package/cortex-v3/zk/intent-witness.test.mjs +485 -0
  59. package/cortex-v3/zk/proving-assets.mjs +203 -0
  60. package/cortex-v3/zk/sale-witness.mjs +783 -0
  61. package/cortex-v3/zk/sale-witness.test.mjs +784 -0
  62. package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
  63. package/cortex-v3/zk/settlement-evidence.mjs +722 -0
  64. package/cortex-v3/zk/setup-intent.mjs +688 -0
  65. package/cortex-v3/zk/setup-sale.mjs +666 -0
  66. package/cortex-v3/zk/setup.mjs +594 -0
  67. package/cortex-v3/zk/witness.mjs +184 -0
  68. package/cortex-v3/zk/zk-codec.mjs +232 -0
  69. package/cortex-v3/zk/zk-codec.test.mjs +293 -0
  70. package/cortex-v3/zk/zk-settle.mjs +370 -0
  71. package/cortex-v3/zk/zk-tree.mjs +256 -0
  72. package/cortex-v3/zk/zk-tree.test.mjs +419 -0
  73. package/deploy/SIMULATION.md +14 -9
  74. package/deploy/docker-compose.local-production-simulation.yml +54 -12
  75. package/docs/benchmark-attestation-network.md +487 -487
  76. package/docs/benchmark-reproducibility.md +289 -289
  77. package/docs/blockchain-only-mechanisms.md +400 -400
  78. package/docs/browser-extension-install.md +8 -6
  79. package/docs/client-connectors.md +16 -12
  80. package/docs/demo-proof-network.md +275 -275
  81. package/docs/developer-ecosystem.md +15 -13
  82. package/docs/developer-proof-quickstart.md +325 -325
  83. package/docs/enigma-memory-ready-conformance.md +378 -376
  84. package/docs/install-anywhere.md +64 -30
  85. package/docs/installers-and-desktop.md +8 -7
  86. package/docs/memory-benchmarks.md +1 -1
  87. package/docs/memory-drive-health-model.md +690 -690
  88. package/docs/novelty-invention-candidates.md +161 -161
  89. package/docs/proof-network-build-notes.md +240 -240
  90. package/docs/proof-network-claim-boundaries.md +320 -318
  91. package/docs/proof-network.md +339 -339
  92. package/docs/sdk-api.md +324 -324
  93. package/docs/solana-proof-rail.md +453 -453
  94. package/examples/01-quickstart-agent/index.mjs +49 -0
  95. package/examples/01_agent_memory_quickstart.mjs +57 -0
  96. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  97. package/examples/02_cross_model_passport.mjs +64 -0
  98. package/examples/03-langchain-memory/index.mjs +41 -0
  99. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  100. package/examples/04-python-trading-agent/trader.py +49 -0
  101. package/examples/README.md +27 -0
  102. package/examples/ci/github-actions.yml +7 -2
  103. package/package.json +410 -278
  104. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  105. package/packages/connectors/src/index.js +196 -4
  106. package/packages/connectors/swarm-router.mjs +168 -0
  107. package/packages/core/src/index.js +249 -2
  108. package/packages/core/src/version.mjs +7 -0
  109. package/packages/dev-tools/package.json +19 -0
  110. package/packages/dev-tools/src/index.js +4 -0
  111. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  112. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  113. package/packages/dev-tools/src/vault-inspector.js +114 -0
  114. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  115. package/packages/developer-platform/src/access-credentials.js +341 -0
  116. package/packages/developer-platform/src/http.js +132 -0
  117. package/packages/developer-platform/src/index.js +4 -0
  118. package/packages/developer-platform/src/usage-http.js +60 -0
  119. package/packages/developer-platform/src/usage.js +295 -0
  120. package/packages/enclave-runtime/attestation.mjs +159 -0
  121. package/packages/enclave-runtime/index.mjs +47 -0
  122. package/packages/enclave-runtime/session-manager.mjs +253 -0
  123. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  124. package/packages/enigma-reflex/package.json +14 -0
  125. package/packages/enigma-reflex/src/index.js +204 -0
  126. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  127. package/packages/enigma-reflex/training/requirements.txt +8 -0
  128. package/packages/enigma-reflex/training/train.py +314 -0
  129. package/packages/enigma-weave/LICENSE +22 -0
  130. package/packages/enigma-weave/UPSTREAM.json +21 -0
  131. package/packages/enigma-weave/package.json +14 -0
  132. package/packages/enigma-weave/src/index.js +286 -0
  133. package/packages/hosted-cloud/src/index.js +80 -5
  134. package/packages/importers/src/index.js +432 -0
  135. package/packages/inference-runtime/src/browser.js +401 -0
  136. package/packages/inference-runtime/src/chat.js +265 -0
  137. package/packages/inference-runtime/src/code.js +407 -0
  138. package/packages/inference-runtime/src/contracts.js +162 -0
  139. package/packages/inference-runtime/src/http.js +232 -0
  140. package/packages/inference-runtime/src/image.js +186 -0
  141. package/packages/inference-runtime/src/index.js +10 -0
  142. package/packages/inference-runtime/src/model-router.js +320 -0
  143. package/packages/inference-runtime/src/platform.js +125 -0
  144. package/packages/inference-runtime/src/privacy.js +400 -0
  145. package/packages/inference-runtime/src/video.js +253 -0
  146. package/packages/mcp-server/README.md +22 -6
  147. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  148. package/packages/mcp-server/src/index.js +2498 -1185
  149. package/packages/mcp-server/src/oauth.js +561 -0
  150. package/packages/mcp-server/src/private-handoff.js +84 -0
  151. package/packages/mcp-server/src/remote-http.js +273 -0
  152. package/packages/mcp-server/src/remote-policy.js +72 -0
  153. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  154. package/packages/mesh/index.d.ts +283 -0
  155. package/packages/mesh/package.json +23 -0
  156. package/packages/mesh/src/crypto.js +189 -0
  157. package/packages/mesh/src/federation-packets.js +353 -0
  158. package/packages/mesh/src/gossip.js +311 -0
  159. package/packages/mesh/src/index.js +6 -0
  160. package/packages/mesh/src/protocol.js +255 -0
  161. package/packages/mesh/src/router.js +279 -0
  162. package/packages/mesh/src/transport.js +306 -0
  163. package/packages/passport/src/index.js +436 -7
  164. package/packages/private-economy/src/credits-http.js +100 -0
  165. package/packages/private-economy/src/credits.js +447 -0
  166. package/packages/private-economy/src/index.js +5 -0
  167. package/packages/private-economy/src/payments-http.js +120 -0
  168. package/packages/private-economy/src/payments.js +509 -0
  169. package/packages/private-economy/src/x402.js +346 -0
  170. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  171. package/packages/rag/index.d.ts +182 -0
  172. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  173. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  174. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  175. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  176. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  177. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  178. package/packages/rag/package.json +27 -0
  179. package/packages/rag/src/blinded-search.js +109 -0
  180. package/packages/rag/src/bm25.js +169 -0
  181. package/packages/rag/src/embeddings.js +459 -0
  182. package/packages/rag/src/hybrid.js +76 -0
  183. package/packages/rag/src/index.js +38 -0
  184. package/packages/rag/src/reranker.js +61 -0
  185. package/packages/rag/src/research.js +107 -0
  186. package/packages/rag/src/vector-store.js +430 -0
  187. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  188. package/packages/sdk/index.d.ts +760 -0
  189. package/packages/sdk/package.json +33 -0
  190. package/packages/sdk/python/README.md +24 -0
  191. package/packages/sdk/python/enigma_sdk.py +250 -0
  192. package/packages/sdk/python/pyproject.toml +34 -0
  193. package/packages/sdk/python/requirements.txt +1 -0
  194. package/packages/sdk/python/setup.py +20 -0
  195. package/packages/sdk/src/federation/capability-grant.js +389 -0
  196. package/packages/sdk/src/federation/federation-router.js +360 -0
  197. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  198. package/packages/sdk/src/federation/index.js +3 -0
  199. package/packages/sdk/src/index.js +1796 -0
  200. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  201. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  202. package/packages/sdk/src/intelligence/index.js +4 -0
  203. package/packages/sdk/src/intelligence/ontology.js +122 -0
  204. package/packages/sdk/src/intelligence/temporal.js +123 -0
  205. package/packages/sdk/src/market-client.js +142 -0
  206. package/packages/sdk/src/mesh-client.js +110 -0
  207. package/packages/sdk/src/middleware/index.js +3 -0
  208. package/packages/sdk/src/middleware/langchain.js +159 -0
  209. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  210. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  211. package/packages/sdk/src/rag-client.js +85 -0
  212. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  213. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  214. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  215. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  216. package/packages/snapcompact/index.d.ts +284 -0
  217. package/packages/snapcompact/package.json +25 -0
  218. package/packages/snapcompact/src/index.js +716 -0
  219. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  220. package/packages/terminal-console/animations.mjs +240 -0
  221. package/packages/terminal-console/auto-anchor.mjs +220 -0
  222. package/packages/terminal-console/banner.mjs +91 -0
  223. package/packages/terminal-console/commands.mjs +459 -0
  224. package/packages/terminal-console/delegation.mjs +152 -0
  225. package/packages/terminal-console/index.mjs +5 -0
  226. package/packages/terminal-console/outbox.mjs +143 -0
  227. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  228. package/packages/terminal-console/repl.mjs +136 -0
  229. package/packages/terminal-console/signer-store.mjs +130 -0
  230. package/packages/terminal-console/solana-rpc.mjs +214 -0
  231. package/packages/terminal-console/solana-transport.mjs +189 -0
  232. package/packages/terminal-tui/dashboard.mjs +214 -0
  233. package/packages/terminal-tui/index.mjs +28 -0
  234. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  235. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  236. package/packages/vault/index.d.ts +449 -0
  237. package/packages/vault/package.json +27 -0
  238. package/packages/vault/src/e2ee.mjs +393 -0
  239. package/packages/vault/src/enclave.js +481 -0
  240. package/packages/vault/src/erasure.js +207 -0
  241. package/packages/vault/src/index.js +1150 -125
  242. package/packages/vault/src/persistence.js +307 -0
  243. package/packages/vault/src/poseidon.js +354 -0
  244. package/packages/vault/src/receipt.js +459 -0
  245. package/scripts/benchmark-optical-context.mjs +166 -0
  246. package/scripts/bootstrap-enigma.mjs +502 -0
  247. package/scripts/build-edge-backend-workers.mjs +20 -5
  248. package/scripts/build-goal-completion-audit.mjs +72 -25
  249. package/scripts/build-hosted-api-key-lifecycle.mjs +292 -274
  250. package/scripts/build-hosted-customer-lifecycle.mjs +493 -476
  251. package/scripts/build-hosted-probe-worker.mjs +19 -4
  252. package/scripts/build-installer-assets.mjs +409 -389
  253. package/scripts/build-operator-evidence-starter.mjs +59 -1
  254. package/scripts/build-production-backend-env-kit.mjs +2 -0
  255. package/scripts/build-production-unblocker.mjs +4 -1
  256. package/scripts/build-proof-network-packet.mjs +213 -213
  257. package/scripts/check.mjs +25 -4
  258. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  259. package/scripts/install-enigma-local.mjs +18 -5
  260. package/scripts/release-audit.mjs +74 -115
  261. package/scripts/release-provenance.mjs +12 -2
  262. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  263. package/scripts/run-standard-memory-benchmarks.mjs +1354 -1352
  264. package/scripts/scan-secrets.mjs +178 -0
  265. package/scripts/simulate-production-env.mjs +71 -10
  266. package/scripts/validate-hosted-backend-live.mjs +112 -1
  267. package/specs/antibody-pack-v1.schema.json +95 -0
  268. package/specs/antigen-envelope-v1.schema.json +81 -0
  269. package/specs/boundary-manifest-v1.schema.json +35 -35
  270. package/specs/capsule-v1.schema.json +55 -55
  271. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  272. package/specs/claim-ledger-v1.schema.json +291 -0
  273. package/specs/context-passport-v1.schema.json +59 -0
  274. package/specs/deletion-tombstone-v1.schema.json +26 -26
  275. package/specs/evidence-packet-v1.schema.json +177 -0
  276. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  277. package/specs/immune-scan-report-v1.schema.json +112 -0
  278. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  279. package/specs/memory-atom-v1.schema.json +59 -0
  280. package/specs/memory-event-v1.schema.json +42 -42
  281. package/specs/passport-v1.schema.json +50 -50
  282. package/specs/proof-of-non-use-v1.schema.json +65 -0
  283. package/specs/quarantine-record-v1.schema.json +126 -0
  284. package/specs/receipt-v1.schema.json +61 -61
  285. package/specs/state-checkpoint-v1.schema.json +37 -37
  286. package/specs/trust-bundle-v1.schema.json +56 -56
  287. package/specs/trust-card-v1.schema.json +119 -0
  288. package/docs/proof-network-launch-plan.md +0 -421
  289. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  290. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -0,0 +1,320 @@
1
+ import { randomUUID } from 'node:crypto';
2
+
3
+ export const ENIGMA_ROUTE_RECEIPT_SCHEMA = 'enigma.route_receipt.v1';
4
+ const TRUST_LEVELS = new Set(['self-hosted', 'confidential-compute', 'external']);
5
+
6
+ function requiredString(value, field, maxLength = 16_000) {
7
+ if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${field} must be a non-empty string`);
8
+ const normalized = value.trim();
9
+ if (normalized.length > maxLength) throw new TypeError(`${field} exceeds ${maxLength} characters`);
10
+ return normalized;
11
+ }
12
+
13
+
14
+ function normalizeMessages(messages) {
15
+ if (!Array.isArray(messages) || !messages.length) throw new TypeError('messages must be a non-empty array');
16
+ return messages.map((message, index) => {
17
+ if (!message || typeof message !== 'object') throw new TypeError(`messages[${index}] must be an object`);
18
+ const role = String(message.role || '');
19
+ if (!['system', 'user', 'assistant', 'tool'].includes(role)) throw new TypeError(`messages[${index}].role is invalid`);
20
+ if (typeof message.content !== 'string' && !Array.isArray(message.content)) throw new TypeError(`messages[${index}].content is invalid`);
21
+
22
+ return { ...message, role };
23
+ });
24
+ }
25
+ function normalizeRetentionEvidence(value) {
26
+ if (!value || typeof value !== 'object') return null;
27
+ const type = String(value.type || '').slice(0, 64);
28
+ const reference = String(value.reference || '').slice(0, 512);
29
+ if (!type || !reference) return null;
30
+ return Object.freeze({
31
+ type,
32
+ reference,
33
+ ...(value.verifiedAt ? { verifiedAt: String(value.verifiedAt).slice(0, 64) } : {}),
34
+ });
35
+ }
36
+
37
+ function normalizeModel(model, provider) {
38
+ const id = requiredString(model.id, 'model id', 160);
39
+ return Object.freeze({
40
+ id,
41
+ label: String(model.label || id),
42
+ providerModel: String(model.providerModel || model.provider_model || id),
43
+ provider: provider.id,
44
+ trust: provider.trust,
45
+ retentionPolicy: String(model.retentionPolicy || model.retention_policy || provider.retentionPolicy || 'unknown'),
46
+ retentionEvidence: normalizeRetentionEvidence(model.retentionEvidence || model.retention_evidence || provider.retentionEvidence),
47
+ contextWindow: Number.isInteger(model.contextWindow) ? model.contextWindow : 128_000,
48
+ inputPrice: Number(model.inputPrice || 0),
49
+ outputPrice: Number(model.outputPrice || 0),
50
+ latencyClass: model.latencyClass || 'standard',
51
+ quality: Number.isFinite(model.quality) ? model.quality : 0.7,
52
+ capabilities: Object.freeze([...new Set(model.capabilities || [])]),
53
+ inputModalities: Object.freeze([...new Set(model.inputModalities || ['text'])]),
54
+ tags: Object.freeze([...new Set(model.tags || [])]),
55
+ });
56
+ }
57
+
58
+ function modelPublic(model) {
59
+ return {
60
+ id: model.id,
61
+ object: 'model',
62
+ owned_by: model.provider,
63
+ label: model.label,
64
+ trust: model.trust,
65
+ retention_policy: model.retentionPolicy,
66
+ retention_evidence: model.retentionEvidence,
67
+ context_window: model.contextWindow,
68
+ capabilities: model.capabilities,
69
+ input_modalities: model.inputModalities,
70
+ pricing: { input_per_million_tokens: model.inputPrice, output_per_million_tokens: model.outputPrice },
71
+ };
72
+ }
73
+
74
+ function taskProfile(messages, options = {}) {
75
+ const text = messages.map((message) => typeof message.content === 'string' ? message.content : JSON.stringify(message.content)).join('\n').toLowerCase();
76
+ const estimatedTokens = Math.ceil(text.length / 3.6);
77
+ const code = /\b(code|repository|repo|debug|function|typescript|javascript|python|rust|compile|test|implementation)\b/.test(text);
78
+ const current = /\b(today|current|latest|news|weather|price|search|look up|browse|source)\b/.test(text);
79
+ const reasoning = /\b(prove|derive|analyze|audit|compare|investigate|architecture|security|strategy|reasoning)\b/.test(text);
80
+ const highRisk = /\b(secret|credential|private key|wallet|payment|medical|legal|identity|personal|confidential)\b/.test(text);
81
+ const vision = messages.some((message) => Array.isArray(message.content) && message.content.some((part) => /image/.test(part?.type || '')));
82
+ return {
83
+ task: code ? 'code' : current ? 'current' : reasoning ? 'reasoning' : 'general',
84
+ estimatedTokens,
85
+ needsWeb: options.webSearch === true || current,
86
+ needsVision: vision,
87
+ highRisk,
88
+ };
89
+ }
90
+
91
+ function routeScore(model, profile, health, options) {
92
+ if (health.openUntil > Date.now()) return -Infinity;
93
+ if (profile.estimatedTokens > model.contextWindow) return -Infinity;
94
+ if (profile.needsVision && !model.capabilities.includes('vision')) return -Infinity;
95
+ if (profile.needsWeb && !model.capabilities.includes('web-search')) return -Infinity;
96
+ if (profile.task === 'code' && !model.capabilities.includes('code')) return -Infinity;
97
+ let score = model.quality * 100;
98
+ if (model.trust === 'self-hosted') score += profile.highRisk ? 50 : 8;
99
+ if (model.trust === 'confidential-compute') score += profile.highRisk ? 35 : 5;
100
+ if (profile.task === 'reasoning' && model.capabilities.includes('reasoning')) score += 20;
101
+ if (profile.task === 'code' && model.tags.includes('code-specialist')) score += 20;
102
+ if (model.latencyClass === 'fast') score += options.preferLatency ? 18 : 6;
103
+ const price = model.inputPrice + model.outputPrice;
104
+ score -= Math.log10(1 + Math.max(0, price)) * (options.preferCost === false ? 2 : 8);
105
+ score -= health.failureCount * 10;
106
+ score -= health.emaLatencyMs / 10_000;
107
+ return score;
108
+ }
109
+
110
+ async function parseOpenAIStream(response, callbacks = {}) {
111
+ if (!response.body) throw new Error('model provider returned no stream body');
112
+ const reader = response.body.getReader();
113
+ const decoder = new TextDecoder();
114
+ let buffer = '';
115
+ let answer = '';
116
+ let thinking = '';
117
+ let usage = null;
118
+ let finishReason = null;
119
+ while (true) {
120
+ const { value, done } = await reader.read();
121
+ if (done) break;
122
+ buffer += decoder.decode(value, { stream: true });
123
+ const parts = buffer.split('\n\n');
124
+ buffer = parts.pop() || '';
125
+ for (const part of parts) processPart(part);
126
+ }
127
+ if (buffer.trim()) processPart(buffer);
128
+ return { answer, thinking: thinking || null, usage, finishReason, streamed: true };
129
+
130
+ function processPart(part) {
131
+ const values = part.split(/\r?\n/).filter((line) => line.startsWith('data:')).map((line) => line.slice(5).trim());
132
+ if (!values.length || values[0] === '[DONE]') return;
133
+ let frame;
134
+ try { frame = JSON.parse(values.join('\n')); } catch { return; }
135
+ if (frame.error) throw new Error(frame.error.message || frame.error);
136
+ if (frame.usage) { usage = frame.usage; callbacks.onEvent?.({ type: 'usage', usage }); }
137
+ for (const choice of frame.choices || []) {
138
+ const delta = choice.delta || {};
139
+ const reasoning = delta.reasoning_content || delta.reasoning || delta.thinking || '';
140
+ if (reasoning) { thinking += reasoning; callbacks.onEvent?.({ type: 'thinking', delta: reasoning }); }
141
+ if (typeof delta.content === 'string' && delta.content) {
142
+ answer += delta.content;
143
+ callbacks.onEvent?.({ type: 'delta', delta: delta.content });
144
+ }
145
+ if (choice.finish_reason) finishReason = choice.finish_reason;
146
+ }
147
+ }
148
+ }
149
+
150
+ export function createOpenAICompatibleProvider(options = {}) {
151
+ const id = requiredString(options.id, 'provider id', 160);
152
+ const trust = String(options.trust || 'external');
153
+ if (!TRUST_LEVELS.has(trust)) throw new TypeError('provider trust must be self-hosted, confidential-compute, or external');
154
+ const baseUrl = new URL(requiredString(options.baseUrl, 'provider baseUrl', 4_096));
155
+ const apiKey = options.apiKey ? requiredString(options.apiKey, 'provider apiKey', 4_096) : null;
156
+ if (!apiKey && options.auth !== 'none') throw new TypeError(`provider ${id} requires apiKey`);
157
+ const retentionPolicy = String(options.retentionPolicy || 'unknown');
158
+ const retentionEvidence = normalizeRetentionEvidence(options.retentionEvidence);
159
+ if (retentionPolicy === 'none' && !retentionEvidence) {
160
+ throw new TypeError(`provider ${id} requires retentionEvidence before claiming zero retention`);
161
+ }
162
+ const provider = { id, trust, retentionPolicy, retentionEvidence };
163
+ const models = (options.models || []).map((model) => normalizeModel(typeof model === 'string' ? { id: model } : model, provider));
164
+ if (!models.length) throw new TypeError(`provider ${id} requires models`);
165
+ const timeoutMs = Number.isInteger(options.timeoutMs) ? options.timeoutMs : 120_000;
166
+ return Object.freeze({
167
+ id,
168
+ trust,
169
+ models: Object.freeze(models),
170
+ async complete(request, callbacks = {}) {
171
+ const controller = new AbortController();
172
+ const timer = setTimeout(() => controller.abort(new Error(`provider ${id} timed out`)), timeoutMs);
173
+ const signal = request.signal ? AbortSignal.any([request.signal, controller.signal]) : controller.signal;
174
+ try {
175
+ const response = await fetch(new URL('chat/completions', baseUrl), {
176
+ method: 'POST',
177
+ headers: {
178
+ 'Content-Type': 'application/json',
179
+ ...(apiKey ? { Authorization: `Bearer ${apiKey}` } : {}),
180
+ ...(options.headers || {}),
181
+ },
182
+ body: JSON.stringify({
183
+ model: request.model.providerModel,
184
+ messages: request.messages,
185
+ temperature: request.temperature,
186
+ max_tokens: request.maxTokens,
187
+ stream: request.stream === true,
188
+ ...(request.reasoningEffort ? { reasoning_effort: request.reasoningEffort } : {}),
189
+ ...(request.tools ? { tools: request.tools } : {}),
190
+ }),
191
+ signal,
192
+ });
193
+ if (!response.ok) {
194
+ const body = await response.text();
195
+ throw new Error(`provider ${id} failed with HTTP ${response.status}: ${body.slice(0, 500)}`);
196
+ }
197
+ if (request.stream === true) return parseOpenAIStream(response, callbacks);
198
+ const payload = await response.json();
199
+ const choice = payload.choices?.[0] || {};
200
+ const answer = choice.message?.content;
201
+ if (typeof answer !== 'string') throw new Error(`provider ${id} returned no text answer`);
202
+ return {
203
+ answer,
204
+ thinking: choice.message?.reasoning_content || null,
205
+ usage: payload.usage || null,
206
+ finishReason: choice.finish_reason || null,
207
+ providerRequestId: response.headers.get('x-request-id'),
208
+ };
209
+ } finally {
210
+ clearTimeout(timer);
211
+ }
212
+ },
213
+ });
214
+ }
215
+
216
+ export function createModelRouter(options = {}) {
217
+ const providers = new Map();
218
+ const models = new Map();
219
+ const health = new Map();
220
+ for (const provider of options.providers || []) {
221
+ if (!provider || typeof provider.complete !== 'function') throw new TypeError('model provider requires complete()');
222
+ if (providers.has(provider.id)) throw new TypeError(`duplicate model provider: ${provider.id}`);
223
+ providers.set(provider.id, provider);
224
+ for (const model of provider.models || []) {
225
+ if (models.has(model.id)) throw new TypeError(`duplicate model id: ${model.id}`);
226
+ models.set(model.id, { ...model, providerRef: provider });
227
+ health.set(model.id, { failureCount: 0, emaLatencyMs: 0, openUntil: 0 });
228
+ }
229
+ }
230
+ if (!models.size) throw new TypeError('model router requires at least one model');
231
+ const autoModelId = options.autoModelId || 'enigma-auto';
232
+ const circuitFailures = Number.isInteger(options.circuitFailures) ? options.circuitFailures : 3;
233
+ const circuitCooldownMs = Number.isInteger(options.circuitCooldownMs) ? options.circuitCooldownMs : 30_000;
234
+
235
+ async function select(request) {
236
+ const messages = normalizeMessages(request.messages);
237
+ const baseProfile = taskProfile(messages, request);
238
+ const semanticProfile = options.classifier ? await options.classifier.classify({ messages, profile: baseProfile }) : {};
239
+ const profile = { ...baseProfile, ...(semanticProfile || {}) };
240
+ const requestedModel = request.model || autoModelId;
241
+ if (requestedModel !== autoModelId) {
242
+ const model = models.get(requestedModel);
243
+ if (!model) throw new Error(`unknown model: ${requestedModel}`);
244
+ if (request.requirePrivateRoute && model.trust === 'external') throw new Error(`model ${requestedModel} is not an approved private route`);
245
+ if (request.safeForExternal === false && model.trust === 'external') throw new Error(`Smart Privacy did not clear model ${requestedModel} for external routing`);
246
+ return { model, profile, reason: 'explicit model selection' };
247
+ }
248
+ const candidates = [...models.values()].filter((model) => {
249
+ if (request.requirePrivateRoute && model.trust === 'external') return false;
250
+ if (request.safeForExternal === false && model.trust === 'external') return false;
251
+ return true;
252
+ });
253
+ const scored = candidates.map((model) => ({ model, score: routeScore(model, profile, health.get(model.id), request) }))
254
+ .filter(({ score }) => Number.isFinite(score)).sort((a, b) => b.score - a.score || a.model.id.localeCompare(b.model.id));
255
+ if (!scored.length) throw new Error('no healthy model satisfies this request and privacy policy');
256
+ return { model: scored[0].model, profile, reason: `auto route selected for ${profile.task}` };
257
+ }
258
+
259
+ return Object.freeze({
260
+ autoModelId,
261
+ listModels() {
262
+ return [{ id: autoModelId, object: 'model', owned_by: 'enigma', label: 'Enigma Auto', trust: 'policy-routed' }, ...[...models.values()].map(modelPublic)];
263
+ },
264
+ async route(request = {}, callbacks = {}) {
265
+ const selection = await select(request);
266
+ callbacks.onEvent?.({ type: 'route', model: selection.model.id, provider: selection.model.provider, reason: selection.reason, trust: selection.model.trust, retentionPolicy: selection.model.retentionPolicy });
267
+ return selection;
268
+ },
269
+ async complete(request = {}, callbacks = {}) {
270
+ const selection = await select(request);
271
+ const { model } = selection;
272
+ callbacks.onEvent?.({ type: 'route', model: model.id, provider: model.provider, reason: selection.reason, trust: model.trust, retentionPolicy: model.retentionPolicy });
273
+ const startedAt = Date.now();
274
+ try {
275
+ const result = await model.providerRef.complete({
276
+ ...request,
277
+ messages: normalizeMessages(request.messages),
278
+ model,
279
+ temperature: Number.isFinite(request.temperature) ? Math.max(0, Math.min(2, request.temperature)) : 0.7,
280
+ maxTokens: Number.isInteger(request.maxTokens) ? Math.max(1, Math.min(request.maxTokens, 131_072)) : 2_048,
281
+ }, callbacks);
282
+ const elapsedMs = Date.now() - startedAt;
283
+ const state = health.get(model.id);
284
+ state.failureCount = 0;
285
+ state.openUntil = 0;
286
+ state.emaLatencyMs = state.emaLatencyMs ? state.emaLatencyMs * 0.8 + elapsedMs * 0.2 : elapsedMs;
287
+ return {
288
+ ...result,
289
+ route: {
290
+ model: model.id,
291
+ provider: model.provider,
292
+ trust: model.trust,
293
+ retentionPolicy: model.retentionPolicy || 'unknown',
294
+ retentionEvidence: model.retentionEvidence || null,
295
+ reason: selection.reason,
296
+ profile: selection.profile,
297
+ },
298
+ receipt: {
299
+ schema: ENIGMA_ROUTE_RECEIPT_SCHEMA,
300
+ model: model.id,
301
+ provider: model.provider,
302
+ trust: model.trust,
303
+ retentionPolicy: model.retentionPolicy || 'unknown',
304
+ retentionEvidence: model.retentionEvidence || null,
305
+ receiptId: randomUUID(),
306
+ elapsedMs,
307
+ },
308
+ };
309
+ } catch (error) {
310
+ const state = health.get(model.id);
311
+ state.failureCount += 1;
312
+ if (state.failureCount >= circuitFailures) state.openUntil = Date.now() + circuitCooldownMs;
313
+ throw error;
314
+ }
315
+ },
316
+ health() {
317
+ return [...health].map(([model, state]) => ({ model, ...state, available: state.openUntil <= Date.now() }));
318
+ },
319
+ });
320
+ }
@@ -0,0 +1,125 @@
1
+ import { createChatBackend } from './chat.js';
2
+ import { createCodeSandboxRuntime } from './code.js';
3
+ import { createImageBackend, createOpenAIImageProvider } from './image.js';
4
+ import { createModelRouter, createOpenAICompatibleProvider } from './model-router.js';
5
+ import { createLocalEmbeddingSemanticClassifier, createSemanticPrivacyEngine } from './privacy.js';
6
+ import { createHttpVideoProvider, createVideoBackend } from './video.js';
7
+ import { createDisposableBrowserRuntime, createEgressAttestationVerifier, createRemoteBrowserBrokerProvider } from './browser.js';
8
+
9
+ function parseJsonEnvironment(environment, name, fallback) {
10
+ const raw = environment[name];
11
+ if (!raw) return fallback;
12
+ try { return JSON.parse(raw); }
13
+ catch { throw new Error(`${name} must contain valid JSON`); }
14
+ }
15
+
16
+ function configuredApiKey(config, environment) {
17
+ if (config.apiKey !== undefined) throw new Error(`provider ${config.id || 'unknown'} must reference apiKeyEnv instead of embedding a key in configuration`);
18
+ const name = String(config.apiKeyEnv || '');
19
+ if (!name) return null;
20
+ const value = environment[name];
21
+ if (!value) throw new Error(`provider ${config.id || 'unknown'} requires environment variable ${name}`);
22
+ return value;
23
+ }
24
+
25
+ function createTextProviders(configs, environment) {
26
+ return configs.map((config) => createOpenAICompatibleProvider({
27
+ id: config.id,
28
+ baseUrl: config.baseUrl,
29
+ apiKey: configuredApiKey(config, environment),
30
+ auth: config.auth,
31
+ trust: config.trust,
32
+ retentionPolicy: config.retentionPolicy,
33
+ retentionEvidence: config.retentionEvidence,
34
+ models: config.models,
35
+ headers: config.headers,
36
+ timeoutMs: config.timeoutMs,
37
+ }));
38
+ }
39
+
40
+ function createImageProviders(configs, environment) {
41
+ return configs.map((config) => createOpenAIImageProvider({
42
+ id: config.id,
43
+ baseUrl: config.baseUrl,
44
+ apiKey: configuredApiKey(config, environment),
45
+ models: config.models,
46
+ }));
47
+ }
48
+
49
+ function createVideoProviders(configs, environment) {
50
+ return configs.map((config) => createHttpVideoProvider({
51
+ id: config.id,
52
+ baseUrl: config.baseUrl,
53
+ apiKey: configuredApiKey(config, environment),
54
+ models: config.models,
55
+ queuePath: config.queuePath,
56
+ retrievePath: config.retrievePath,
57
+ cancelPath: config.cancelPath,
58
+ headers: config.headers,
59
+ }));
60
+ }
61
+
62
+ export function createPlatformRuntime(options = {}) {
63
+ const textProviders = options.textProviders || [];
64
+ const imageProviders = options.imageProviders || [];
65
+ const videoProviders = options.videoProviders || [];
66
+ const privacyClassifier = options.privacyClassifier || createLocalEmbeddingSemanticClassifier(options.privacyClassifierOptions);
67
+ const privacy = options.privacy || createSemanticPrivacyEngine({ classifier: privacyClassifier, ...(options.privacyOptions || {}) });
68
+ const router = options.router || (textProviders.length ? createModelRouter({ providers: textProviders, ...(options.routerOptions || {}) }) : null);
69
+ const usage = options.usage || null;
70
+ const chat = options.chat || (router ? createChatBackend({ router, privacy, onUsage: usage ? (entry) => usage.record(entry) : undefined }) : null);
71
+ const images = options.images || (imageProviders.length ? createImageBackend({ providers: imageProviders, onUsage: usage ? (entry) => usage.record(entry) : undefined }) : null);
72
+ const videos = options.videos || (videoProviders.length ? createVideoBackend({ providers: videoProviders, onUsage: usage ? (entry) => usage.record(entry) : undefined }) : null);
73
+ const code = options.code === false ? null : options.code || createCodeSandboxRuntime({ oci: options.oci });
74
+ const browser = options.browser || null;
75
+
76
+ return Object.freeze({
77
+ chat,
78
+ images,
79
+ videos,
80
+ code,
81
+ browser,
82
+ async close() {
83
+ const settled = await Promise.allSettled([
84
+ browser?.close?.(),
85
+ code?.close?.(),
86
+ privacyClassifier?.dispose?.(),
87
+ ]);
88
+ const errors = settled.filter((result) => result.status === 'rejected').map((result) => result.reason);
89
+ if (errors.length) throw new AggregateError(errors, 'platform runtime cleanup failed');
90
+ },
91
+ });
92
+ }
93
+
94
+ export function createEnvironmentPlatformRuntime(options = {}) {
95
+ const environment = options.environment || process.env;
96
+ const textConfigs = parseJsonEnvironment(environment, 'ENIGMA_MODEL_PROVIDERS_JSON', []);
97
+ const imageConfigs = parseJsonEnvironment(environment, 'ENIGMA_IMAGE_PROVIDERS_JSON', []);
98
+ const videoConfigs = parseJsonEnvironment(environment, 'ENIGMA_VIDEO_PROVIDERS_JSON', []);
99
+ if (!Array.isArray(textConfigs) || !Array.isArray(imageConfigs) || !Array.isArray(videoConfigs)) {
100
+ throw new Error('Enigma provider configuration values must be JSON arrays');
101
+ }
102
+ let browser = null;
103
+ if (environment.ENIGMA_BROWSER_BROKER_URL) {
104
+ if (!environment.ENIGMA_BROWSER_EGRESS_PUBLIC_KEY || !environment.ENIGMA_BROWSER_VIEWER_ORIGIN) {
105
+ throw new Error('ENIGMA_BROWSER_EGRESS_PUBLIC_KEY and ENIGMA_BROWSER_VIEWER_ORIGIN are required before interactive browser streaming can be enabled');
106
+ }
107
+ const provider = createRemoteBrowserBrokerProvider({
108
+ baseUrl: environment.ENIGMA_BROWSER_BROKER_URL,
109
+ viewerOrigin: environment.ENIGMA_BROWSER_VIEWER_ORIGIN,
110
+ apiKey: environment.ENIGMA_BROWSER_BROKER_API_KEY || null,
111
+ });
112
+ browser = createDisposableBrowserRuntime({
113
+ provider,
114
+ viewerOrigin: environment.ENIGMA_BROWSER_VIEWER_ORIGIN,
115
+ verifyEgressAttestation: createEgressAttestationVerifier({ publicKey: environment.ENIGMA_BROWSER_EGRESS_PUBLIC_KEY }),
116
+ });
117
+ }
118
+ return createPlatformRuntime({
119
+ ...options,
120
+ textProviders: options.textProviders || createTextProviders(textConfigs, environment),
121
+ imageProviders: options.imageProviders || createImageProviders(imageConfigs, environment),
122
+ videoProviders: options.videoProviders || createVideoProviders(videoConfigs, environment),
123
+ browser,
124
+ });
125
+ }