@juspay/neurolink 12.2.6 → 12.4.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 (33) hide show
  1. package/CHANGELOG.md +3 -3
  2. package/README.md +1 -0
  3. package/dist/adapters/providerImageAdapter.js +3 -0
  4. package/dist/browser/neurolink.min.js +364 -364
  5. package/dist/cli/commands/setup.js +2 -1
  6. package/dist/cli/proxy-clients/gemini.d.ts +51 -0
  7. package/dist/cli/proxy-clients/gemini.js +278 -0
  8. package/dist/cli/proxy-clients/openCode.d.ts +41 -0
  9. package/dist/cli/proxy-clients/openCode.js +212 -27
  10. package/dist/cli/proxy-clients/registry.js +2 -0
  11. package/dist/cli/proxy-clients/snapshot.d.ts +13 -0
  12. package/dist/cli/proxy-clients/snapshot.js +18 -0
  13. package/dist/constants/contextWindows.js +11 -0
  14. package/dist/constants/enums.d.ts +26 -0
  15. package/dist/constants/enums.js +27 -0
  16. package/dist/constants/proxyModels.d.ts +22 -0
  17. package/dist/constants/proxyModels.js +36 -0
  18. package/dist/factories/providerDescriptors.js +16 -1
  19. package/dist/models/manifestRegistry.js +2 -0
  20. package/dist/models/manifests/sambanova.d.ts +11 -0
  21. package/dist/models/manifests/sambanova.js +42 -0
  22. package/dist/providers/openaiChatCompletionsClient.d.ts +1 -1
  23. package/dist/providers/openaiChatCompletionsClient.js +20 -3
  24. package/dist/providers/openaiCompatCatalog.d.ts +1 -1
  25. package/dist/providers/openaiCompatCatalog.js +43 -3
  26. package/dist/proxy/proxyTranslationEngine.js +3 -22
  27. package/dist/types/providers.d.ts +4 -0
  28. package/dist/types/proxyClient.d.ts +33 -0
  29. package/dist/utils/modelChoices.js +29 -1
  30. package/dist/utils/pricing.js +16 -0
  31. package/dist/utils/providerConfig.d.ts +1 -0
  32. package/dist/utils/providerConfig.js +14 -0
  33. package/package.json +1 -1
@@ -0,0 +1,42 @@
1
+ /**
2
+ * Context windows from the vendor's SambaCloud model specifications page
3
+ * (docs.sambanova.ai, checked 2026-08-27): 128K on the production mainline
4
+ * (Meta-Llama-3.3-70B-Instruct, gpt-oss-120b, DeepSeek-V3.1), 192K on
5
+ * MiniMax-M2.7, 32K on the DeepSeek-V3.2 preview. Max output is not
6
+ * published — the 8192 floor stays deliberately conservative, same
7
+ * pattern as groq.ts/cerebras.ts. gemma-4-31B-it is the one vision model
8
+ * (text+image+video per the vendor page).
9
+ */
10
+ export const sambanovaManifest = {
11
+ defaultContextWindow: 131072,
12
+ models: {
13
+ _default: {
14
+ aliases: [],
15
+ contextWindow: 131072,
16
+ maxOutputTokens: 8192,
17
+ vision: false,
18
+ functionCalling: true,
19
+ },
20
+ "MiniMax-M2.7": {
21
+ aliases: [],
22
+ contextWindow: 196608,
23
+ maxOutputTokens: 8192,
24
+ vision: false,
25
+ functionCalling: true,
26
+ },
27
+ "DeepSeek-V3.2": {
28
+ aliases: [],
29
+ contextWindow: 32768,
30
+ maxOutputTokens: 8192,
31
+ vision: false,
32
+ functionCalling: true,
33
+ },
34
+ "gemma-4-31B-it": {
35
+ aliases: [],
36
+ contextWindow: 131072,
37
+ maxOutputTokens: 8192,
38
+ vision: true,
39
+ functionCalling: true,
40
+ },
41
+ },
42
+ };
@@ -42,7 +42,7 @@ export declare const estimateWireTokens: (messages: ReadonlyArray<OpenAICompatCh
42
42
  export declare const safeStringify: (value: unknown) => string;
43
43
  export declare const stringifyToolInput: (input: unknown) => string;
44
44
  export declare const stringifyToolOutput: (output: unknown) => string;
45
- export declare const imageDataToURL: (data: unknown) => string | undefined;
45
+ export declare const imageDataToURL: (data: unknown, mediaType?: string) => string | undefined;
46
46
  export declare const convertContentForOpenAI: (content: unknown) => string | OpenAICompatMessageContent[];
47
47
  export declare const messageBuilderToOpenAI: (messages: ReadonlyArray<OpenAICompatMessage>, toolNameToWire?: Map<string, string>) => OpenAICompatChatMessage[];
48
48
  export declare const buildToolsForOpenAI: (tools: Record<string, Tool>, toolNameToWire?: Map<string, string>) => OpenAICompatChatTool[] | undefined;
@@ -150,18 +150,19 @@ export const stringifyToolOutput = (output) => {
150
150
  return safeStringify(output);
151
151
  }
152
152
  };
153
- export const imageDataToURL = (data) => {
153
+ export const imageDataToURL = (data, mediaType) => {
154
+ const mime = mediaType && mediaType.includes("/") ? mediaType : "image/png";
154
155
  if (typeof data === "string") {
155
156
  if (data.startsWith("data:") || /^https?:\/\//i.test(data)) {
156
157
  return data;
157
158
  }
158
- return `data:image/png;base64,${data}`;
159
+ return `data:${mime};base64,${data}`;
159
160
  }
160
161
  if (data instanceof URL) {
161
162
  return data.toString();
162
163
  }
163
164
  if (data instanceof Uint8Array) {
164
- return `data:image/png;base64,${Buffer.from(data).toString("base64")}`;
165
+ return `data:${mime};base64,${Buffer.from(data).toString("base64")}`;
165
166
  }
166
167
  return undefined;
167
168
  };
@@ -197,6 +198,22 @@ export const convertContentForOpenAI = (content) => {
197
198
  out.push({ type: "image_url", image_url: { url } });
198
199
  }
199
200
  }
201
+ else if (p.type === "file") {
202
+ // ai@6 delivers images as FILE parts ({type:"file", mediaType, data}),
203
+ // not "image" parts. The hand-rolled client that replaced
204
+ // @ai-sdk/openai-compatible only handled "image"/"image_url", so every
205
+ // image reaching a catalog provider was silently dropped — the wire
206
+ // carried a text-only message (found live on sambanova/gemma-4-31B-it,
207
+ // 2026-08-28; affected xai vision too). Non-image file parts are still
208
+ // skipped: the OpenAI chat wire format has no generic file slot.
209
+ const fp = part;
210
+ if (fp.mediaType?.startsWith("image/")) {
211
+ const url = imageDataToURL(fp.data, fp.mediaType);
212
+ if (url) {
213
+ out.push({ type: "image_url", image_url: { url } });
214
+ }
215
+ }
216
+ }
200
217
  }
201
218
  if (out.length === 1 && out[0].type === "text") {
202
219
  return out[0].text;
@@ -1,6 +1,6 @@
1
1
  import type { OpenAICompatCatalogEntry } from "../types/index.js";
2
2
  /**
3
- * Config-driven catalog of the 8 zero-quirk OpenAI-compatible providers.
3
+ * Config-driven catalog of the 9 zero-quirk OpenAI-compatible providers.
4
4
  * Each entry fully replaces what used to be a hand-written
5
5
  * OpenAIChatCompletionsProvider subclass — see ConfiguredOpenAICompatProvider
6
6
  * for the class that reads these entries, and providerRegistry.ts for the
@@ -1,13 +1,13 @@
1
1
  import { AIProviderName } from "../constants/enums.js";
2
- import { CerebrasModels, CloudflareModels, FireworksModels, GroqModels, MistralModels, PerplexityModels, TogetherAIModels, XaiModels, } from "../constants/enums.js";
2
+ import { CerebrasModels, SambanovaModels, CloudflareModels, FireworksModels, GroqModels, MistralModels, PerplexityModels, TogetherAIModels, XaiModels, } from "../constants/enums.js";
3
3
  import { AuthenticationError, InvalidModelError, ProviderError, } from "../types/index.js";
4
4
  import { DEFAULT_ERROR_RULES } from "../utils/errorClassifier.js";
5
- import { createCerebrasConfig, createCloudflareConfig, createFireworksConfig, createGroqConfig, createMistralConfig, createPerplexityConfig, createTogetherAIConfig, createXaiConfig, } from "../utils/providerConfig.js";
5
+ import { createCerebrasConfig, createSambanovaConfig, createCloudflareConfig, createFireworksConfig, createGroqConfig, createMistralConfig, createPerplexityConfig, createTogetherAIConfig, createXaiConfig, } from "../utils/providerConfig.js";
6
6
  function buildCloudflareBaseURL(accountId) {
7
7
  return `https://api.cloudflare.com/client/v4/accounts/${accountId}/ai/v1`;
8
8
  }
9
9
  /**
10
- * Config-driven catalog of the 8 zero-quirk OpenAI-compatible providers.
10
+ * Config-driven catalog of the 9 zero-quirk OpenAI-compatible providers.
11
11
  * Each entry fully replaces what used to be a hand-written
12
12
  * OpenAIChatCompletionsProvider subclass — see ConfiguredOpenAICompatProvider
13
13
  * for the class that reads these entries, and providerRegistry.ts for the
@@ -29,6 +29,46 @@ function buildCloudflareBaseURL(accountId) {
29
29
  * Task 14's docs task for the deciding criteria).
30
30
  */
31
31
  export const OPENAI_COMPAT_CATALOG = [
32
+ {
33
+ providerName: AIProviderName.SAMBANOVA,
34
+ aliases: ["sambanova"],
35
+ apiKeyEnvVar: "SAMBANOVA_API_KEY",
36
+ baseURLEnvVar: "SAMBANOVA_BASE_URL",
37
+ defaultBaseURL: "https://api.sambanova.ai/v1",
38
+ configOptions: createSambanovaConfig(),
39
+ modelEnvVar: "SAMBANOVA_MODEL",
40
+ defaultModel: SambanovaModels.META_LLAMA_3_3_70B_INSTRUCT,
41
+ registryDefaultModel: SambanovaModels.META_LLAMA_3_3_70B_INSTRUCT,
42
+ registryDefaultModelChecksEnvVar: true,
43
+ fallbackModelName: SambanovaModels.GPT_OSS_120B,
44
+ fallbackModels: [
45
+ SambanovaModels.META_LLAMA_3_3_70B_INSTRUCT,
46
+ SambanovaModels.GPT_OSS_120B,
47
+ ],
48
+ errorRules: [
49
+ {
50
+ // Probed live 2026-08-27: a bad key gets HTTP 401 with an
51
+ // OpenAI-shaped body {"error":{"message":"Incorrect API key
52
+ // provided: ...","type":"authentication_error","code":
53
+ // "invalid_api_key"}}.
54
+ match: (ctx) => ctx.statusCode === 401 ||
55
+ /invalid_api_key|Incorrect API key|authentication_error/i.test(ctx.message),
56
+ errorClass: AuthenticationError,
57
+ message: "Invalid SambaNova API key. Check SAMBANOVA_API_KEY. Get one at https://cloud.sambanova.ai/apis",
58
+ },
59
+ {
60
+ // Probed live 2026-08-27: a zero-balance account gets HTTP 402 with
61
+ // {"error":{"balance_units":0,"code":"PAYMENT_METHOD_REQUIRED",
62
+ // "billing_portal_url":"https://cloud.sambanova.ai/plans/billing"}}.
63
+ // New accounts have NO free allowance — credits must be purchased.
64
+ match: (ctx) => ctx.statusCode === 402 ||
65
+ /PAYMENT_METHOD_REQUIRED|balance_units/i.test(ctx.message),
66
+ errorClass: ProviderError,
67
+ message: "SambaNova account has no credits (new accounts have no free allowance). Add a payment method and purchase credits at https://cloud.sambanova.ai/plans/billing",
68
+ },
69
+ ...DEFAULT_ERROR_RULES,
70
+ ],
71
+ },
32
72
  {
33
73
  providerName: AIProviderName.CEREBRAS,
34
74
  aliases: ["cerebras"],
@@ -14,6 +14,7 @@
14
14
  import { ClaudeStreamSerializer, generateToolUseId, serializeClaudeResponse, } from "./claudeFormat.js";
15
15
  import { buildGeminiResponse, createGeminiSerializerAdapter, } from "./geminiFormat.js";
16
16
  import { generateOpenAIToolCallId, OpenAIStreamSerializer, serializeOpenAIResponse, } from "./openaiFormat.js";
17
+ import { DEFAULT_PROXY_MODEL_IDS } from "../constants/proxyModels.js";
17
18
  import { logRequest } from "./requestLogger.js";
18
19
  import { recordAttempt, recordAttemptError, recordFinalError, recordFinalSuccess, } from "./usageStats.js";
19
20
  import { ErrorCategory, ErrorSeverity } from "../constants/enums.js";
@@ -677,7 +678,7 @@ export function buildModelsListResponse(modelRouter) {
677
678
  }
678
679
  // Always include a default entry if nothing else is configured
679
680
  if (models.length === 0) {
680
- for (const id of DEFAULT_MODEL_IDS) {
681
+ for (const id of DEFAULT_PROXY_MODEL_IDS) {
681
682
  models.push({
682
683
  id,
683
684
  object: "model",
@@ -691,26 +692,6 @@ export function buildModelsListResponse(modelRouter) {
691
692
  data: models,
692
693
  };
693
694
  }
694
- /**
695
- * Canonical default model IDs surfaced when no router is configured. Format
696
- * matches the IDs used throughout `src/lib/models/` and `src/lib/constants/`
697
- * (e.g. `claude-3-5-haiku-20241022`, not `claude-haiku-3.5-20241022`).
698
- */
699
- const DEFAULT_MODEL_IDS = [
700
- // Claude 4-series (current generation, hyphen-suffix family)
701
- "claude-opus-4-6",
702
- "claude-sonnet-4-6",
703
- "claude-haiku-4-5",
704
- // Claude 4 dated variant
705
- "claude-sonnet-4-20250514",
706
- // Claude 3.5-series (canonical Anthropic form: claude-3-5-{variant}-{date})
707
- "claude-3-5-sonnet-20241022",
708
- "claude-3-5-haiku-20241022",
709
- // OpenAI / Google for translated-fallback users
710
- "gpt-4o",
711
- "gemini-2.5-pro",
712
- "gemini-2.5-flash",
713
- ];
714
695
  /**
715
696
  * Build an Anthropic-shaped `/v1/models` list response.
716
697
  *
@@ -736,7 +717,7 @@ export function buildAnthropicModelsListResponse(modelRouter) {
736
717
  }
737
718
  }
738
719
  if (ids.length === 0) {
739
- ids.push(...DEFAULT_MODEL_IDS);
720
+ ids.push(...DEFAULT_PROXY_MODEL_IDS);
740
721
  }
741
722
  // Deduplicate while preserving order — multiple router sources can publish
742
723
  // the same id (e.g. both an explicit mapping and a passthrough entry).
@@ -182,6 +182,10 @@ export type NeurolinkCredentials = {
182
182
  apiKey?: string;
183
183
  baseURL?: string;
184
184
  };
185
+ sambanova?: {
186
+ apiKey?: string;
187
+ baseURL?: string;
188
+ };
185
189
  cohere?: {
186
190
  apiKey?: string;
187
191
  baseURL?: string;
@@ -47,6 +47,39 @@ export type CliProxyClientRestoreResult = {
47
47
  restored: boolean;
48
48
  error?: Error;
49
49
  };
50
+ /**
51
+ * Snapshot of the user's pre-existing OpenCode `provider.neurolink`.
52
+ *
53
+ * Persisted to `~/.neurolink/opencode-proxy-snapshot.json`, never inside
54
+ * `opencode.json` — OpenCode validates against a closed schema and rejects
55
+ * unknown top-level keys, so an in-file snapshot made the CLI unstartable.
56
+ */
57
+ export type CliOpenCodeSnapshot = {
58
+ /** The user's provider.neurolink before the proxy first touched it. */
59
+ original: unknown;
60
+ /** What the writer last wrote, so apply() can recognise its own block. */
61
+ written?: unknown;
62
+ };
63
+ /**
64
+ * Snapshot of the user's pre-existing Gemini CLI `~/.gemini/.env`.
65
+ *
66
+ * The whole file is kept rather than the managed keys alone: restoring must
67
+ * reproduce the user's comments, ordering and unrelated variables exactly.
68
+ */
69
+ export type CliGeminiSnapshot = {
70
+ /** The whole prior `.env`, or null when the user had no such file. */
71
+ originalEnv: string | null;
72
+ /**
73
+ * What the writer last wrote for each managed variable. Compared against the
74
+ * file on disk to detect a snapshot that has gone stale — one left behind by
75
+ * a restore whose cleanup failed, or overtaken by a user edit. Reusing such a
76
+ * record would make the next restore replay outdated values.
77
+ */
78
+ written?: {
79
+ baseUrl: string;
80
+ apiKey: string;
81
+ };
82
+ };
50
83
  /**
51
84
  * Raw contents of a Qwen Code `settings.json`. Deliberately open-ended: the
52
85
  * configurator rewrites only `security.auth` and must round-trip every other
@@ -2,7 +2,7 @@
2
2
  * Centralized model choices for CLI commands
3
3
  * Derives choices from model enums to ensure consistency
4
4
  */
5
- import { AIProviderName, OpenAIModels, AnthropicModels, GoogleAIModels, BedrockModels, VertexModels, MistralModels, OllamaModels, AzureOpenAIModels, LiteLLMModels, HuggingFaceModels, SageMakerModels, OpenRouterModels, DeepSeekModels, NvidiaNimModels, XaiModels, GroqModels, CerebrasModels, CohereModels, TogetherAIModels, FireworksModels, PerplexityModels, CloudflareModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
5
+ import { AIProviderName, OpenAIModels, AnthropicModels, GoogleAIModels, BedrockModels, VertexModels, MistralModels, OllamaModels, AzureOpenAIModels, LiteLLMModels, HuggingFaceModels, SageMakerModels, OpenRouterModels, DeepSeekModels, NvidiaNimModels, XaiModels, GroqModels, CerebrasModels, SambanovaModels, CohereModels, TogetherAIModels, FireworksModels, PerplexityModels, CloudflareModels, VoyageModels, JinaModels, StabilityModels, IdeogramModels, RecraftModels, ReplicateModels, } from "../constants/enums.js";
6
6
  /**
7
7
  * Top models per provider with descriptions for CLI prompts
8
8
  * These are curated lists of the most commonly used/recommended models
@@ -302,6 +302,33 @@ const TOP_MODELS_CONFIG = {
302
302
  description: "Mistral 8x7B MoE, 32K context",
303
303
  },
304
304
  ],
305
+ [AIProviderName.SAMBANOVA]: [
306
+ {
307
+ model: SambanovaModels.META_LLAMA_3_3_70B_INSTRUCT,
308
+ description: "Recommended - Meta Llama 3.3 70B; production, 128K context",
309
+ },
310
+ {
311
+ model: SambanovaModels.GPT_OSS_120B,
312
+ description: "OpenAI GPT-OSS 120B (open-weight)",
313
+ },
314
+ {
315
+ model: SambanovaModels.DEEPSEEK_V3_1,
316
+ description: "DeepSeek V3.1 (reasoning)",
317
+ },
318
+ {
319
+ model: SambanovaModels.DEEPSEEK_V3_2,
320
+ description: "DeepSeek V3.2 (reasoning; vendor preview, 32K context)",
321
+ },
322
+ {
323
+ model: SambanovaModels.MINIMAX_M2_7,
324
+ description: "MiniMax M2.7, 192K context",
325
+ },
326
+ { model: SambanovaModels.MINIMAX_M3, description: "MiniMax M3 (vision)" },
327
+ {
328
+ model: SambanovaModels.GEMMA_4_31B_IT,
329
+ description: "Google Gemma 4 31B IT (vision; vendor preview)",
330
+ },
331
+ ],
305
332
  [AIProviderName.CEREBRAS]: [
306
333
  {
307
334
  model: CerebrasModels.GPT_OSS_120B,
@@ -550,6 +577,7 @@ const MODEL_ENUMS = {
550
577
  [AIProviderName.XAI]: XaiModels,
551
578
  [AIProviderName.GROQ]: GroqModels,
552
579
  [AIProviderName.CEREBRAS]: CerebrasModels,
580
+ [AIProviderName.SAMBANOVA]: SambanovaModels,
553
581
  [AIProviderName.COHERE]: CohereModels,
554
582
  [AIProviderName.TOGETHER_AI]: TogetherAIModels,
555
583
  [AIProviderName.FIREWORKS]: FireworksModels,
@@ -527,6 +527,21 @@ const PRICING = {
527
527
  "gpt-oss-120b": { input: 0.35 / 1_000_000, output: 0.75 / 1_000_000 },
528
528
  "gemma-4-31b": { input: 0.99 / 1_000_000, output: 1.49 / 1_000_000 },
529
529
  },
530
+ // cloud.sambanova.ai/plans/pricing, checked 2026-08-27. MiniMax-M2.7
531
+ // also has a $0.06/M cached-input rate the flat model here can't express.
532
+ sambanova: {
533
+ _default: { input: 0.6 / 1_000_000, output: 1.2 / 1_000_000 },
534
+ "Meta-Llama-3.3-70B-Instruct": {
535
+ input: 0.6 / 1_000_000,
536
+ output: 1.2 / 1_000_000,
537
+ },
538
+ "gpt-oss-120b": { input: 0.22 / 1_000_000, output: 0.59 / 1_000_000 },
539
+ "DeepSeek-V3.1": { input: 3.0 / 1_000_000, output: 4.5 / 1_000_000 },
540
+ "DeepSeek-V3.2": { input: 3.0 / 1_000_000, output: 4.5 / 1_000_000 },
541
+ "MiniMax-M2.7": { input: 0.6 / 1_000_000, output: 2.4 / 1_000_000 },
542
+ "MiniMax-M3": { input: 0.6 / 1_000_000, output: 2.4 / 1_000_000 },
543
+ "gemma-4-31B-it": { input: 0.38 / 1_000_000, output: 1.15 / 1_000_000 },
544
+ },
530
545
  cohere: {
531
546
  _default: { input: 2.5 / 1_000_000, output: 10.0 / 1_000_000 },
532
547
  "command-r-plus": { input: 2.5 / 1_000_000, output: 10.0 / 1_000_000 },
@@ -695,6 +710,7 @@ const PROVIDER_ALIASES = {
695
710
  grok: "xai",
696
711
  groq: "groq",
697
712
  cerebras: "cerebras",
713
+ sambanova: "sambanova",
698
714
  cohere: "cohere",
699
715
  togetherai: "together-ai",
700
716
  together: "together-ai",
@@ -138,6 +138,7 @@ export declare function createXaiConfig(): ProviderConfigOptions;
138
138
  /**
139
139
  * Creates Cerebras provider configuration.
140
140
  */
141
+ export declare function createSambanovaConfig(): ProviderConfigOptions;
141
142
  export declare function createCerebrasConfig(): ProviderConfigOptions;
142
143
  /**
143
144
  * Creates Groq provider configuration.
@@ -454,6 +454,20 @@ export function createXaiConfig() {
454
454
  /**
455
455
  * Creates Cerebras provider configuration.
456
456
  */
457
+ export function createSambanovaConfig() {
458
+ return {
459
+ providerName: "SambaNova",
460
+ envVarName: "SAMBANOVA_API_KEY",
461
+ setupUrl: "https://cloud.sambanova.ai/apis",
462
+ description: "API key",
463
+ instructions: [
464
+ "1. Visit: https://cloud.sambanova.ai (Google/Microsoft OAuth works)",
465
+ "2. Complete the profile step; note new accounts have NO free allowance — a payment method and purchased credits are required before calls succeed",
466
+ "3. Create an API key under API Keys",
467
+ "4. Set SAMBANOVA_API_KEY in your .env file",
468
+ ],
469
+ };
470
+ }
457
471
  export function createCerebrasConfig() {
458
472
  return {
459
473
  providerName: "Cerebras",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@juspay/neurolink",
3
- "version": "12.2.6",
3
+ "version": "12.4.0",
4
4
  "packageManager": "pnpm@10.15.1",
5
5
  "description": "TypeScript AI SDK with 24+ LLM providers behind one consistent API. MCP-native (connect any MCP server), voice TTS/STT/realtime, RAG, agents, memory, context compaction. OpenAI · Anthropic · Gemini · Bedrock · Azure · Ollama · DeepSeek · NVIDIA NIM and more.",
6
6
  "author": {