illuma-agents 1.0.11 → 1.0.13

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 (53) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +50 -5
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +29 -1
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/llm/anthropic/index.cjs +1 -1
  6. package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
  7. package/dist/cjs/llm/bedrock/index.cjs +1 -17
  8. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  9. package/dist/cjs/llm/google/index.cjs +1 -1
  10. package/dist/cjs/llm/google/index.cjs.map +1 -1
  11. package/dist/cjs/llm/openai/index.cjs +6 -6
  12. package/dist/cjs/llm/openai/index.cjs.map +1 -1
  13. package/dist/cjs/llm/openrouter/index.cjs +1 -1
  14. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  15. package/dist/cjs/messages/cache.cjs +7 -10
  16. package/dist/cjs/messages/cache.cjs.map +1 -1
  17. package/dist/esm/agents/AgentContext.mjs +50 -5
  18. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  19. package/dist/esm/graphs/Graph.mjs +30 -2
  20. package/dist/esm/graphs/Graph.mjs.map +1 -1
  21. package/dist/esm/llm/anthropic/index.mjs +1 -1
  22. package/dist/esm/llm/anthropic/index.mjs.map +1 -1
  23. package/dist/esm/llm/bedrock/index.mjs +1 -17
  24. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  25. package/dist/esm/llm/google/index.mjs +1 -1
  26. package/dist/esm/llm/google/index.mjs.map +1 -1
  27. package/dist/esm/llm/openai/index.mjs +6 -6
  28. package/dist/esm/llm/openai/index.mjs.map +1 -1
  29. package/dist/esm/llm/openrouter/index.mjs +1 -1
  30. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  31. package/dist/esm/messages/cache.mjs +7 -10
  32. package/dist/esm/messages/cache.mjs.map +1 -1
  33. package/dist/types/agents/AgentContext.d.ts +34 -1
  34. package/dist/types/graphs/Graph.d.ts +20 -0
  35. package/dist/types/llm/anthropic/index.d.ts +1 -1
  36. package/dist/types/llm/google/index.d.ts +1 -1
  37. package/dist/types/llm/openai/index.d.ts +3 -3
  38. package/dist/types/llm/openrouter/index.d.ts +1 -1
  39. package/dist/types/types/graph.d.ts +7 -0
  40. package/package.json +1 -7
  41. package/src/agents/AgentContext.ts +64 -3
  42. package/src/graphs/Graph.ts +46 -1
  43. package/src/llm/anthropic/index.ts +2 -2
  44. package/src/llm/bedrock/index.ts +3 -9
  45. package/src/llm/google/index.ts +2 -2
  46. package/src/llm/openai/index.ts +9 -9
  47. package/src/llm/openrouter/index.ts +2 -2
  48. package/src/messages/cache.ts +7 -11
  49. package/src/scripts/programmatic_exec.ts +2 -2
  50. package/src/scripts/tool_search_regex.ts +2 -2
  51. package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +2 -2
  52. package/src/tools/__tests__/ToolSearchRegex.integration.test.ts +2 -2
  53. package/src/types/graph.ts +7 -0
@@ -21,7 +21,7 @@ export declare class CustomAnthropic extends ChatAnthropicMessages {
21
21
  private emitted_usage?;
22
22
  top_k: number | undefined;
23
23
  constructor(fields?: CustomAnthropicInput);
24
- static lc_name(): 'LibreChatAnthropic';
24
+ static lc_name(): 'IllumaAnthropic';
25
25
  /**
26
26
  * Get the parameters used to invoke the model
27
27
  */
@@ -12,7 +12,7 @@ export declare class CustomChatGoogleGenerativeAI extends ChatGoogleGenerativeAI
12
12
  */
13
13
  get _isMultimodalModel(): boolean;
14
14
  constructor(fields: GoogleClientOptions);
15
- static lc_name(): 'LibreChatGoogleGenerativeAI';
15
+ static lc_name(): 'IllumaGoogleGenerativeAI';
16
16
  /**
17
17
  * Helper function to convert Gemini API usage metadata to LangChain format
18
18
  * Includes support for cached tokens and tier-based tracking for gemini-3-pro-preview
@@ -63,7 +63,7 @@ export declare class AzureChatOpenAI extends OriginalAzureChatOpenAI {
63
63
  _lc_stream_delay?: number;
64
64
  });
65
65
  get exposedClient(): CustomOpenAIClient;
66
- static lc_name(): 'LibreChatAzureOpenAI';
66
+ static lc_name(): 'IllumaAzureOpenAI';
67
67
  /**
68
68
  * Returns backwards compatible reasoning parameters from constructor params and call options
69
69
  * @internal
@@ -75,7 +75,7 @@ export declare class AzureChatOpenAI extends OriginalAzureChatOpenAI {
75
75
  }
76
76
  export declare class ChatDeepSeek extends OriginalChatDeepSeek {
77
77
  get exposedClient(): CustomOpenAIClient;
78
- static lc_name(): 'LibreChatDeepSeek';
78
+ static lc_name(): 'IllumaDeepSeek';
79
79
  protected _getClientOptions(options?: OpenAICoreRequestOptions): OpenAICoreRequestOptions;
80
80
  _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
81
81
  }
@@ -106,7 +106,7 @@ export declare class ChatXAI extends OriginalChatXAI {
106
106
  };
107
107
  _lc_stream_delay?: number;
108
108
  });
109
- static lc_name(): 'LibreChatXAI';
109
+ static lc_name(): 'IllumaXAI';
110
110
  get exposedClient(): CustomOpenAIClient;
111
111
  protected _getClientOptions(options?: OpenAICoreRequestOptions): OpenAICoreRequestOptions;
112
112
  _streamResponseChunks(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
@@ -9,7 +9,7 @@ export interface ChatOpenRouterCallOptions extends ChatOpenAICallOptions {
9
9
  }
10
10
  export declare class ChatOpenRouter extends ChatOpenAI {
11
11
  constructor(_fields: Partial<ChatOpenRouterCallOptions>);
12
- static lc_name(): 'LibreChatOpenRouter';
12
+ static lc_name(): 'IllumaOpenRouter';
13
13
  protected _convertOpenAIDeltaToBaseMessageChunk(delta: Record<string, any>, rawResponse: OpenAIClient.ChatCompletionChunk, defaultRole?: 'function' | 'user' | 'system' | 'developer' | 'assistant' | 'tool'): AIMessageChunk | HumanMessageChunk | SystemMessageChunk | FunctionMessageChunk | ToolMessageChunk | ChatMessageChunk;
14
14
  _streamResponseChunks2(messages: BaseMessage[], options: this['ParsedCallOptions'], runManager?: CallbackManagerForLLMRun): AsyncGenerator<ChatGenerationChunk>;
15
15
  }
@@ -254,4 +254,11 @@ export interface AgentInputs {
254
254
  * Maps tool name to LCTool definition.
255
255
  */
256
256
  toolRegistry?: Map<string, LCTool>;
257
+ /**
258
+ * Dynamic context that changes per-request (e.g., current time, user info).
259
+ * This is injected as a user message rather than system prompt to preserve cache.
260
+ * Keeping this separate from instructions ensures the system message stays static
261
+ * and can be cached by Bedrock/Anthropic prompt caching.
262
+ */
263
+ dynamicContext?: string;
257
264
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "illuma-agents",
3
- "version": "1.0.11",
3
+ "version": "1.0.13",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -15,12 +15,6 @@
15
15
  "description": "Illuma AI Agents Library",
16
16
  "author": "Varun Muppidi",
17
17
  "license": "MIT",
18
- "licenses": [
19
- {
20
- "type": "MIT",
21
- "url": "https://github.com/danny-avila/agents/blob/main/LICENSE"
22
- }
23
- ],
24
18
  "packageManager": "npm@10.5.2",
25
19
  "engines": {
26
20
  "node": ">=14.0.0"
@@ -39,6 +39,7 @@ export class AgentContext {
39
39
  maxContextTokens,
40
40
  reasoningKey,
41
41
  useLegacyContent,
42
+ dynamicContext,
42
43
  } = agentConfig;
43
44
 
44
45
  const agentContext = new AgentContext({
@@ -57,6 +58,7 @@ export class AgentContext {
57
58
  instructionTokens: 0,
58
59
  tokenCounter,
59
60
  useLegacyContent,
61
+ dynamicContext,
60
62
  });
61
63
 
62
64
  if (tokenCounter) {
@@ -120,6 +122,12 @@ export class AgentContext {
120
122
  instructions?: string;
121
123
  /** Additional instructions for this agent */
122
124
  additionalInstructions?: string;
125
+ /**
126
+ * Dynamic context that changes per-request (e.g., current time, user info).
127
+ * This is NOT included in the system message to preserve cache.
128
+ * Instead, it's injected as a user message at the start of the conversation.
129
+ */
130
+ dynamicContext?: string;
123
131
  /** Reasoning key for this agent */
124
132
  reasoningKey: 'reasoning_content' | 'reasoning' = 'reasoning_content';
125
133
  /** Last token for reasoning detection */
@@ -145,6 +153,10 @@ export class AgentContext {
145
153
  tokenCalculationPromise?: Promise<void>;
146
154
  /** Format content blocks as strings (for legacy compatibility) */
147
155
  useLegacyContent: boolean = false;
156
+ /** Detailed per-tool token breakdown for admin tracking */
157
+ private toolsDetail: Array<{ name: string; tokens: number }> = [];
158
+ /** Total tool tokens (sum of all toolsDetail) */
159
+ private toolTokensTotal: number = 0;
148
160
 
149
161
  constructor({
150
162
  agentId,
@@ -158,6 +170,7 @@ export class AgentContext {
158
170
  toolRegistry,
159
171
  instructions,
160
172
  additionalInstructions,
173
+ dynamicContext,
161
174
  reasoningKey,
162
175
  toolEnd,
163
176
  instructionTokens,
@@ -174,6 +187,7 @@ export class AgentContext {
174
187
  toolRegistry?: t.LCToolRegistry;
175
188
  instructions?: string;
176
189
  additionalInstructions?: string;
190
+ dynamicContext?: string;
177
191
  reasoningKey?: 'reasoning_content' | 'reasoning';
178
192
  toolEnd?: boolean;
179
193
  instructionTokens?: number;
@@ -190,6 +204,7 @@ export class AgentContext {
190
204
  this.toolRegistry = toolRegistry;
191
205
  this.instructions = instructions;
192
206
  this.additionalInstructions = additionalInstructions;
207
+ this.dynamicContext = dynamicContext;
193
208
  if (reasoningKey) {
194
209
  this.reasoningKey = reasoningKey;
195
210
  }
@@ -375,8 +390,6 @@ export class AgentContext {
375
390
  const supportsCaching = modelId.includes('claude') || modelId.includes('anthropic') || modelId.includes('nova');
376
391
 
377
392
  if (bedrockOptions?.promptCache === true && supportsCaching) {
378
- // Always log system cache structure
379
- console.log(`[Cache] 📝 System | chars=${instructionsString.length} | tokens=${this.systemMessageTokens} | model=${modelId}`);
380
393
 
381
394
  finalInstructions = {
382
395
  content: [
@@ -412,6 +425,8 @@ export class AgentContext {
412
425
  reset(): void {
413
426
  this.instructionTokens = 0;
414
427
  this.systemMessageTokens = 0;
428
+ this.toolsDetail = [];
429
+ this.toolTokensTotal = 0;
415
430
  this.cachedSystemRunnable = undefined;
416
431
  this.systemRunnableStale = true;
417
432
  this.lastToken = undefined;
@@ -447,11 +462,14 @@ export class AgentContext {
447
462
  /**
448
463
  * Calculate tool tokens and add to instruction tokens
449
464
  * Note: System message tokens are calculated during systemRunnable creation
465
+ * Also tracks per-tool token breakdown for admin reporting
450
466
  */
451
467
  async calculateInstructionTokens(
452
468
  tokenCounter: t.TokenCounter
453
469
  ): Promise<void> {
454
470
  let toolTokens = 0;
471
+ this.toolsDetail = []; // Reset per-tool breakdown
472
+
455
473
  if (this.tools && this.tools.length > 0) {
456
474
  for (const tool of this.tools) {
457
475
  const genericTool = tool as Record<string, unknown>;
@@ -469,17 +487,60 @@ export class AgentContext {
469
487
  describedSchema as Parameters<typeof zodToJsonSchema>[0],
470
488
  (genericTool.name as string) || ''
471
489
  );
472
- toolTokens += tokenCounter(
490
+ const toolName = (genericTool.name as string) || 'unknown';
491
+ const tokens = tokenCounter(
473
492
  new SystemMessage(JSON.stringify(jsonSchema))
474
493
  );
494
+
495
+ // Track per-tool breakdown
496
+ this.toolsDetail.push({ name: toolName, tokens });
497
+ toolTokens += tokens;
475
498
  }
476
499
  }
477
500
  }
478
501
 
502
+ // Store total tool tokens for breakdown reporting
503
+ this.toolTokensTotal = toolTokens;
504
+
479
505
  // Add tool tokens to existing instruction tokens (which may already include system message tokens)
480
506
  this.instructionTokens += toolTokens;
481
507
  }
482
508
 
509
+ /**
510
+ * Get a detailed breakdown of context tokens for admin reporting.
511
+ * This provides visibility into what's consuming the input token budget.
512
+ * @returns ContextBreakdown object with per-component token counts
513
+ */
514
+ getContextBreakdown(): {
515
+ instructions: number;
516
+ artifacts: number;
517
+ tools: number;
518
+ toolCount: number;
519
+ toolContext: number;
520
+ total: number;
521
+ toolsDetail: Array<{ name: string; tokens: number }>;
522
+ toolContextDetail: Array<{ name: string; tokens: number }>;
523
+ } {
524
+ return {
525
+ // System message tokens (instructions + additional_instructions)
526
+ instructions: this.systemMessageTokens,
527
+ // Artifacts are not currently tracked separately, set to 0
528
+ artifacts: 0,
529
+ // Total tool definition tokens
530
+ tools: this.toolTokensTotal,
531
+ // Number of tools
532
+ toolCount: this.toolsDetail.length,
533
+ // Tool context/usage instructions (currently embedded in system message)
534
+ toolContext: 0,
535
+ // Total tracked context tokens
536
+ total: this.instructionTokens,
537
+ // Per-tool token breakdown
538
+ toolsDetail: [...this.toolsDetail],
539
+ // Tool context detail (currently not tracked separately)
540
+ toolContextDetail: [],
541
+ };
542
+ }
543
+
483
544
  /**
484
545
  * Gets the tool registry for deferred tools (for tool search).
485
546
  * @param onlyDeferred If true, only returns tools with defer_loading=true
@@ -21,6 +21,7 @@ import {
21
21
  ToolMessage,
22
22
  SystemMessage,
23
23
  AIMessageChunk,
24
+ HumanMessage,
24
25
  } from '@langchain/core/messages';
25
26
  import type {
26
27
  BaseMessageFields,
@@ -390,6 +391,27 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
390
391
  return contentPartAgentMap;
391
392
  }
392
393
 
394
+ /**
395
+ * Get the context breakdown from the primary agent for admin token tracking.
396
+ * Returns detailed token counts for instructions, tools, etc.
397
+ */
398
+ getContextBreakdown(): {
399
+ instructions: number;
400
+ artifacts: number;
401
+ tools: number;
402
+ toolCount: number;
403
+ toolContext: number;
404
+ total: number;
405
+ toolsDetail: Array<{ name: string; tokens: number }>;
406
+ toolContextDetail: Array<{ name: string; tokens: number }>;
407
+ } | null {
408
+ const primaryContext = this.agentContexts.get(this.defaultAgentId);
409
+ if (!primaryContext) {
410
+ return null;
411
+ }
412
+ return primaryContext.getContextBreakdown();
413
+ }
414
+
393
415
  /* Graph */
394
416
 
395
417
  createSystemRunnable({
@@ -624,7 +646,30 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
624
646
  throw new Error('No config provided');
625
647
  }
626
648
 
627
- const { messages } = state;
649
+ let { messages } = state;
650
+
651
+ // CACHE OPTIMIZATION: Inject dynamicContext as a HumanMessage at the start of conversation
652
+ // This keeps the system message static (cacheable) while providing dynamic context
653
+ // (timestamps, user info, tool context) as conversation content instead.
654
+ // Only inject on the first turn when messages don't already have the context marker.
655
+ if (
656
+ agentContext.dynamicContext &&
657
+ messages.length > 0 &&
658
+ !messages.some(
659
+ (m) =>
660
+ m instanceof HumanMessage &&
661
+ typeof m.content === 'string' &&
662
+ m.content.startsWith('[SESSION_CONTEXT]')
663
+ )
664
+ ) {
665
+ const dynamicContextMessage = new HumanMessage({
666
+ content: `[SESSION_CONTEXT]\n${agentContext.dynamicContext}`,
667
+ });
668
+ const ackMessage = new AIMessageChunk({
669
+ content: 'Understood. I have noted the session context including the current date/time (CST) and will apply it appropriately.',
670
+ });
671
+ messages = [dynamicContextMessage, ackMessage, ...messages];
672
+ }
628
673
 
629
674
  // Extract tool discoveries from current turn only (similar to formatArtifactPayload pattern)
630
675
  const discoveredNames = extractToolDiscoveries(messages);
@@ -143,8 +143,8 @@ export class CustomAnthropic extends ChatAnthropicMessages {
143
143
  this._lc_stream_delay = fields?._lc_stream_delay ?? 25;
144
144
  }
145
145
 
146
- static lc_name(): 'LibreChatAnthropic' {
147
- return 'LibreChatAnthropic';
146
+ static lc_name(): 'IllumaAnthropic' {
147
+ return 'IllumaAnthropic';
148
148
  }
149
149
 
150
150
  /**
@@ -42,7 +42,7 @@ export class CustomChatBedrockConverse extends ChatBedrockConverse {
42
42
  }
43
43
 
44
44
  static lc_name(): string {
45
- return 'LibreChatBedrockConverse';
45
+ return 'IllumaBedrockConverse';
46
46
  }
47
47
 
48
48
  /**
@@ -92,8 +92,7 @@ export class CustomChatBedrockConverse extends ChatBedrockConverse {
92
92
  }
93
93
  }
94
94
 
95
- // Always log cache structure (INFO level for tracking)
96
- console.log(`[Cache] 🔧 Tools | Core: [${coreToolNames.join(', ')}] (${coreTools.length}) | MCP: [${mcpToolNames.join(', ')}] (${mcpTools.length})`);
95
+
97
96
 
98
97
  // Build tools array with strategic cachePoints:
99
98
  // [CoreTool1, CoreTool2, cachePoint] + [MCPTool1, MCPTool2, cachePoint]
@@ -120,7 +119,7 @@ export class CustomChatBedrockConverse extends ChatBedrockConverse {
120
119
  cachePointCount++;
121
120
  }
122
121
 
123
- console.log(`[Cache] 📍 Tool cachePoints: ${cachePointCount} | Order: [${coreToolNames.length > 0 ? 'CoreTools→CP' : ''}${mcpToolNames.length > 0 ? '→MCPTools→CP' : ''}]`);
122
+
124
123
 
125
124
  params.toolConfig.tools = toolsWithCache;
126
125
  }
@@ -176,11 +175,6 @@ export class CustomChatBedrockConverse extends ChatBedrockConverse {
176
175
  const outputTokens = (usage.outputTokens as number) ?? 0;
177
176
 
178
177
  if (cacheRead > 0 || cacheWrite > 0) {
179
- // Always log cache results for tracking
180
- const cacheStatus = cacheRead > 0 && cacheWrite === 0 ? '✅ HIT' :
181
- cacheWrite > 0 && cacheRead === 0 ? '📝 WRITE' :
182
- cacheRead > 0 && cacheWrite > 0 ? '🔄 PARTIAL' : '❌ MISS';
183
- console.log(`[Cache] ${cacheStatus} | read=${cacheRead} | write=${cacheWrite} | input=${inputTokens} | output=${outputTokens}`);
184
178
 
185
179
  needsModification = true;
186
180
  enhancedUsageMetadata = {
@@ -122,8 +122,8 @@ export class CustomChatGoogleGenerativeAI extends ChatGoogleGenerativeAI {
122
122
  this.streamUsage = fields.streamUsage ?? this.streamUsage;
123
123
  }
124
124
 
125
- static lc_name(): 'LibreChatGoogleGenerativeAI' {
126
- return 'LibreChatGoogleGenerativeAI';
125
+ static lc_name(): 'IllumaGoogleGenerativeAI' {
126
+ return 'IllumaGoogleGenerativeAI';
127
127
  }
128
128
 
129
129
  /**
@@ -211,7 +211,7 @@ export class ChatOpenAI extends OriginalChatOpenAI<t.ChatOpenAICallOptions> {
211
211
  return this.client;
212
212
  }
213
213
  static lc_name(): string {
214
- return 'LibreChatOpenAI';
214
+ return 'IllumaOpenAI';
215
215
  }
216
216
  protected _getClientOptions(
217
217
  options?: OpenAICoreRequestOptions
@@ -466,8 +466,8 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
466
466
  public get exposedClient(): CustomOpenAIClient {
467
467
  return this.client;
468
468
  }
469
- static lc_name(): 'LibreChatAzureOpenAI' {
470
- return 'LibreChatAzureOpenAI';
469
+ static lc_name(): 'IllumaAzureOpenAI' {
470
+ return 'IllumaAzureOpenAI';
471
471
  }
472
472
  /**
473
473
  * Returns backwards compatible reasoning parameters from constructor params and call options
@@ -539,8 +539,8 @@ export class AzureChatOpenAI extends OriginalAzureChatOpenAI {
539
539
  ...params.defaultHeaders,
540
540
  'User-Agent':
541
541
  defaultHeaders['User-Agent'] != null
542
- ? `${defaultHeaders['User-Agent']}: librechat-azure-openai-v2`
543
- : 'librechat-azure-openai-v2',
542
+ ? `${defaultHeaders['User-Agent']}: illuma-azure-openai-v2`
543
+ : 'illuma-azure-openai-v2',
544
544
  };
545
545
 
546
546
  this.client = new CustomAzureOpenAIClient({
@@ -613,8 +613,8 @@ export class ChatDeepSeek extends OriginalChatDeepSeek {
613
613
  public get exposedClient(): CustomOpenAIClient {
614
614
  return this.client;
615
615
  }
616
- static lc_name(): 'LibreChatDeepSeek' {
617
- return 'LibreChatDeepSeek';
616
+ static lc_name(): 'IllumaDeepSeek' {
617
+ return 'IllumaDeepSeek';
618
618
  }
619
619
  protected _getClientOptions(
620
620
  options?: OpenAICoreRequestOptions
@@ -814,8 +814,8 @@ export class ChatXAI extends OriginalChatXAI {
814
814
  }
815
815
  }
816
816
 
817
- static lc_name(): 'LibreChatXAI' {
818
- return 'LibreChatXAI';
817
+ static lc_name(): 'IllumaXAI' {
818
+ return 'IllumaXAI';
819
819
  }
820
820
 
821
821
  public get exposedClient(): CustomOpenAIClient {
@@ -44,8 +44,8 @@ export class ChatOpenRouter extends ChatOpenAI {
44
44
  },
45
45
  });
46
46
  }
47
- static lc_name(): 'LibreChatOpenRouter' {
48
- return 'LibreChatOpenRouter';
47
+ static lc_name(): 'IllumaOpenRouter' {
48
+ return 'IllumaOpenRouter';
49
49
  }
50
50
  protected override _convertOpenAIDeltaToBaseMessageChunk(
51
51
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
@@ -7,14 +7,10 @@ type MessageWithContent = {
7
7
  content?: string | MessageContentComplex[];
8
8
  };
9
9
 
10
- /** Always-on logger for cache operations */
11
- const logCache = (message: string) => {
12
- console.log(`[Cache] ${message}`);
13
- };
14
-
15
10
  /** Debug logger for cache operations - set ILLUMA_DEBUG_CACHE=true to enable */
16
11
  const debugCache = (message: string, data?: unknown) => {
17
12
  if (process.env.ILLUMA_DEBUG_CACHE === 'true') {
13
+ // eslint-disable-next-line no-console
18
14
  console.log(`[Cache] ${message}`, data !== undefined ? JSON.stringify(data, null, 2) : '');
19
15
  }
20
16
  };
@@ -266,12 +262,12 @@ export function addBedrockCacheControl<
266
262
  }
267
263
 
268
264
  // Log message summary
269
- logCache(`📨 Messages | total=${updatedMessages.length} | ${Object.entries(messageTypes).map(([k,v]) => `${k}:${v}`).join(' ')} | skippedReasoning=${skippedWithReasoning}`);
265
+ debugCache(`📨 Messages | total=${updatedMessages.length} | ${Object.entries(messageTypes).map(([k,v]) => `${k}:${v}`).join(' ')} | skippedReasoning=${skippedWithReasoning}`);
270
266
 
271
267
  // If no suitable assistant message found, skip conversation caching
272
268
  // (System and Tools caching are still handled separately)
273
269
  if (lastAssistantIndex === -1) {
274
- logCache('📨 Messages | No suitable assistant message for cachePoint (first turn or all have reasoning)');
270
+ debugCache('📨 Messages | No suitable assistant message for cachePoint (first turn or all have reasoning)');
275
271
  return updatedMessages;
276
272
  }
277
273
 
@@ -284,7 +280,7 @@ export function addBedrockCacheControl<
284
280
  { type: ContentTypes.TEXT, text: content },
285
281
  { cachePoint: { type: 'default' } },
286
282
  ] as MessageContentComplex[];
287
- logCache(`📍 Message cachePoint at index ${lastAssistantIndex} (string, ${content.length} chars)`);
283
+ debugCache(`📍 Message cachePoint at index ${lastAssistantIndex} (string, ${content.length} chars)`);
288
284
  debugCache('addBedrockCacheControl: Added cachePoint to assistant message (string content)', {
289
285
  index: lastAssistantIndex,
290
286
  contentLength: content.length,
@@ -293,7 +289,7 @@ export function addBedrockCacheControl<
293
289
  // Double-check: If this message has reasoning blocks, skip adding cache point entirely
294
290
  // This handles edge cases where the initial skip check might have missed it
295
291
  if (hasReasoningBlock(assistantMessage)) {
296
- logCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (has reasoning blocks)`);
292
+ debugCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (has reasoning blocks)`);
297
293
  debugCache('addBedrockCacheControl: Skipping - assistant message has reasoning blocks (safety check)', {
298
294
  index: lastAssistantIndex,
299
295
  });
@@ -312,7 +308,7 @@ export function addBedrockCacheControl<
312
308
  cachePoint: { type: 'default' },
313
309
  } as MessageContentComplex);
314
310
  inserted = true;
315
- logCache(`📍 Message cachePoint at index ${lastAssistantIndex} (array, block ${j}, ${text.length} chars)`);
311
+ debugCache(`📍 Message cachePoint at index ${lastAssistantIndex} (array, block ${j}, ${text.length} chars)`);
316
312
  debugCache('addBedrockCacheControl: Added cachePoint after text block in assistant message', {
317
313
  index: lastAssistantIndex,
318
314
  textBlockIndex: j,
@@ -326,7 +322,7 @@ export function addBedrockCacheControl<
326
322
  // If no text block found, don't append cache point as the message structure is unexpected
327
323
  if (!inserted) {
328
324
  const contentTypes = assistantMessage.content.map((b) => (b as { type?: string }).type);
329
- logCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (no text block, types: ${contentTypes.join(',')})`);
325
+ debugCache(`⚠️ Message cachePoint SKIPPED at index ${lastAssistantIndex} (no text block, types: ${contentTypes.join(',')})`);
330
326
  debugCache('addBedrockCacheControl: No suitable text block found, skipping cache point', {
331
327
  index: lastAssistantIndex,
332
328
  contentTypes,
@@ -94,10 +94,10 @@ async function main(): Promise<void> {
94
94
  console.log('==============================================');
95
95
  console.log('Demonstrating runtime toolMap injection\n');
96
96
 
97
- const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
97
+ const apiKey = process.env.CODE_EXECUTOR_API_KEY;
98
98
  if (!apiKey) {
99
99
  console.error(
100
- 'Error: LIBRECHAT_CODE_API_KEY environment variable is not set.'
100
+ 'Error: CODE_EXECUTOR_API_KEY environment variable is not set.'
101
101
  );
102
102
  console.log('Please set it in your .env file or environment.');
103
103
  process.exit(1);
@@ -66,10 +66,10 @@ async function main(): Promise<void> {
66
66
  console.log('================================');
67
67
  console.log('Demonstrating runtime tool registry injection\n');
68
68
 
69
- const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
69
+ const apiKey = process.env.CODE_EXECUTOR_API_KEY;
70
70
  if (!apiKey) {
71
71
  console.error(
72
- 'Error: LIBRECHAT_CODE_API_KEY environment variable is not set.'
72
+ 'Error: CODE_EXECUTOR_API_KEY environment variable is not set.'
73
73
  );
74
74
  console.log('Please set it in your .env file or environment.');
75
75
  process.exit(1);
@@ -25,10 +25,10 @@ describe('ProgrammaticToolCalling - Live API Integration', () => {
25
25
  let toolDefinitions: t.LCTool[];
26
26
 
27
27
  beforeAll(() => {
28
- const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
28
+ const apiKey = process.env.CODE_EXECUTOR_API_KEY;
29
29
  if (apiKey == null || apiKey === '') {
30
30
  throw new Error(
31
- 'LIBRECHAT_CODE_API_KEY not set. Required for integration tests.'
31
+ 'CODE_EXECUTOR_API_KEY not set. Required for integration tests.'
32
32
  );
33
33
  }
34
34
 
@@ -17,10 +17,10 @@ describe('ToolSearchRegex - Live API Integration', () => {
17
17
  const toolRegistry = createToolSearchToolRegistry();
18
18
 
19
19
  beforeAll(() => {
20
- const apiKey = process.env.LIBRECHAT_CODE_API_KEY;
20
+ const apiKey = process.env.CODE_EXECUTOR_API_KEY;
21
21
  if (apiKey == null || apiKey === '') {
22
22
  throw new Error(
23
- 'LIBRECHAT_CODE_API_KEY not set. Required for integration tests.'
23
+ 'CODE_EXECUTOR_API_KEY not set. Required for integration tests.'
24
24
  );
25
25
  }
26
26
 
@@ -375,4 +375,11 @@ export interface AgentInputs {
375
375
  * Maps tool name to LCTool definition.
376
376
  */
377
377
  toolRegistry?: Map<string, LCTool>;
378
+ /**
379
+ * Dynamic context that changes per-request (e.g., current time, user info).
380
+ * This is injected as a user message rather than system prompt to preserve cache.
381
+ * Keeping this separate from instructions ensures the system message stays static
382
+ * and can be cached by Bedrock/Anthropic prompt caching.
383
+ */
384
+ dynamicContext?: string;
378
385
  }