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.
- package/dist/cjs/agents/AgentContext.cjs +50 -5
- package/dist/cjs/agents/AgentContext.cjs.map +1 -1
- package/dist/cjs/graphs/Graph.cjs +29 -1
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/llm/anthropic/index.cjs +1 -1
- package/dist/cjs/llm/anthropic/index.cjs.map +1 -1
- package/dist/cjs/llm/bedrock/index.cjs +1 -17
- package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
- package/dist/cjs/llm/google/index.cjs +1 -1
- package/dist/cjs/llm/google/index.cjs.map +1 -1
- package/dist/cjs/llm/openai/index.cjs +6 -6
- package/dist/cjs/llm/openai/index.cjs.map +1 -1
- package/dist/cjs/llm/openrouter/index.cjs +1 -1
- package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
- package/dist/cjs/messages/cache.cjs +7 -10
- package/dist/cjs/messages/cache.cjs.map +1 -1
- package/dist/esm/agents/AgentContext.mjs +50 -5
- package/dist/esm/agents/AgentContext.mjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +30 -2
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/llm/anthropic/index.mjs +1 -1
- package/dist/esm/llm/anthropic/index.mjs.map +1 -1
- package/dist/esm/llm/bedrock/index.mjs +1 -17
- package/dist/esm/llm/bedrock/index.mjs.map +1 -1
- package/dist/esm/llm/google/index.mjs +1 -1
- package/dist/esm/llm/google/index.mjs.map +1 -1
- package/dist/esm/llm/openai/index.mjs +6 -6
- package/dist/esm/llm/openai/index.mjs.map +1 -1
- package/dist/esm/llm/openrouter/index.mjs +1 -1
- package/dist/esm/llm/openrouter/index.mjs.map +1 -1
- package/dist/esm/messages/cache.mjs +7 -10
- package/dist/esm/messages/cache.mjs.map +1 -1
- package/dist/types/agents/AgentContext.d.ts +34 -1
- package/dist/types/graphs/Graph.d.ts +20 -0
- package/dist/types/llm/anthropic/index.d.ts +1 -1
- package/dist/types/llm/google/index.d.ts +1 -1
- package/dist/types/llm/openai/index.d.ts +3 -3
- package/dist/types/llm/openrouter/index.d.ts +1 -1
- package/dist/types/types/graph.d.ts +7 -0
- package/package.json +1 -7
- package/src/agents/AgentContext.ts +64 -3
- package/src/graphs/Graph.ts +46 -1
- package/src/llm/anthropic/index.ts +2 -2
- package/src/llm/bedrock/index.ts +3 -9
- package/src/llm/google/index.ts +2 -2
- package/src/llm/openai/index.ts +9 -9
- package/src/llm/openrouter/index.ts +2 -2
- package/src/messages/cache.ts +7 -11
- package/src/scripts/programmatic_exec.ts +2 -2
- package/src/scripts/tool_search_regex.ts +2 -2
- package/src/tools/__tests__/ProgrammaticToolCalling.integration.test.ts +2 -2
- package/src/tools/__tests__/ToolSearchRegex.integration.test.ts +2 -2
- 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(): '
|
|
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(): '
|
|
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(): '
|
|
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(): '
|
|
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(): '
|
|
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(): '
|
|
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.
|
|
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
|
-
|
|
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
|
package/src/graphs/Graph.ts
CHANGED
|
@@ -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
|
-
|
|
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(): '
|
|
147
|
-
return '
|
|
146
|
+
static lc_name(): 'IllumaAnthropic' {
|
|
147
|
+
return 'IllumaAnthropic';
|
|
148
148
|
}
|
|
149
149
|
|
|
150
150
|
/**
|
package/src/llm/bedrock/index.ts
CHANGED
|
@@ -42,7 +42,7 @@ export class CustomChatBedrockConverse extends ChatBedrockConverse {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
static lc_name(): string {
|
|
45
|
-
return '
|
|
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
|
-
|
|
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
|
-
|
|
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 = {
|
package/src/llm/google/index.ts
CHANGED
|
@@ -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(): '
|
|
126
|
-
return '
|
|
125
|
+
static lc_name(): 'IllumaGoogleGenerativeAI' {
|
|
126
|
+
return 'IllumaGoogleGenerativeAI';
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
/**
|
package/src/llm/openai/index.ts
CHANGED
|
@@ -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 '
|
|
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(): '
|
|
470
|
-
return '
|
|
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']}:
|
|
543
|
-
: '
|
|
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(): '
|
|
617
|
-
return '
|
|
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(): '
|
|
818
|
-
return '
|
|
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(): '
|
|
48
|
-
return '
|
|
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
|
package/src/messages/cache.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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.
|
|
97
|
+
const apiKey = process.env.CODE_EXECUTOR_API_KEY;
|
|
98
98
|
if (!apiKey) {
|
|
99
99
|
console.error(
|
|
100
|
-
'Error:
|
|
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.
|
|
69
|
+
const apiKey = process.env.CODE_EXECUTOR_API_KEY;
|
|
70
70
|
if (!apiKey) {
|
|
71
71
|
console.error(
|
|
72
|
-
'Error:
|
|
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.
|
|
28
|
+
const apiKey = process.env.CODE_EXECUTOR_API_KEY;
|
|
29
29
|
if (apiKey == null || apiKey === '') {
|
|
30
30
|
throw new Error(
|
|
31
|
-
'
|
|
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.
|
|
20
|
+
const apiKey = process.env.CODE_EXECUTOR_API_KEY;
|
|
21
21
|
if (apiKey == null || apiKey === '') {
|
|
22
22
|
throw new Error(
|
|
23
|
-
'
|
|
23
|
+
'CODE_EXECUTOR_API_KEY not set. Required for integration tests.'
|
|
24
24
|
);
|
|
25
25
|
}
|
|
26
26
|
|
package/src/types/graph.ts
CHANGED
|
@@ -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
|
}
|