illuma-agents 1.0.12 β†’ 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.
@@ -75,6 +75,10 @@ export declare class AgentContext {
75
75
  tokenCalculationPromise?: Promise<void>;
76
76
  /** Format content blocks as strings (for legacy compatibility) */
77
77
  useLegacyContent: boolean;
78
+ /** Detailed per-tool token breakdown for admin tracking */
79
+ private toolsDetail;
80
+ /** Total tool tokens (sum of all toolsDetail) */
81
+ private toolTokensTotal;
78
82
  constructor({ agentId, provider, clientOptions, maxContextTokens, streamBuffer, tokenCounter, tools, toolMap, toolRegistry, instructions, additionalInstructions, dynamicContext, reasoningKey, toolEnd, instructionTokens, useLegacyContent, }: {
79
83
  agentId: string;
80
84
  provider: Providers;
@@ -134,8 +138,30 @@ export declare class AgentContext {
134
138
  /**
135
139
  * Calculate tool tokens and add to instruction tokens
136
140
  * Note: System message tokens are calculated during systemRunnable creation
141
+ * Also tracks per-tool token breakdown for admin reporting
137
142
  */
138
143
  calculateInstructionTokens(tokenCounter: t.TokenCounter): Promise<void>;
144
+ /**
145
+ * Get a detailed breakdown of context tokens for admin reporting.
146
+ * This provides visibility into what's consuming the input token budget.
147
+ * @returns ContextBreakdown object with per-component token counts
148
+ */
149
+ getContextBreakdown(): {
150
+ instructions: number;
151
+ artifacts: number;
152
+ tools: number;
153
+ toolCount: number;
154
+ toolContext: number;
155
+ total: number;
156
+ toolsDetail: Array<{
157
+ name: string;
158
+ tokens: number;
159
+ }>;
160
+ toolContextDetail: Array<{
161
+ name: string;
162
+ tokens: number;
163
+ }>;
164
+ };
139
165
  /**
140
166
  * Gets the tool registry for deferred tools (for tool search).
141
167
  * @param onlyDeferred If true, only returns tools with defer_loading=true
@@ -85,6 +85,26 @@ export declare class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode>
85
85
  * Returns a map where key is the contentPart index and value is the agentId
86
86
  */
87
87
  getContentPartAgentMap(): Map<number, string>;
88
+ /**
89
+ * Get the context breakdown from the primary agent for admin token tracking.
90
+ * Returns detailed token counts for instructions, tools, etc.
91
+ */
92
+ getContextBreakdown(): {
93
+ instructions: number;
94
+ artifacts: number;
95
+ tools: number;
96
+ toolCount: number;
97
+ toolContext: number;
98
+ total: number;
99
+ toolsDetail: Array<{
100
+ name: string;
101
+ tokens: number;
102
+ }>;
103
+ toolContextDetail: Array<{
104
+ name: string;
105
+ tokens: number;
106
+ }>;
107
+ } | null;
88
108
  createSystemRunnable({ provider, clientOptions, instructions, additional_instructions, }: {
89
109
  provider?: Providers;
90
110
  clientOptions?: t.ClientOptions;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "illuma-agents",
3
- "version": "1.0.12",
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",
@@ -153,6 +153,10 @@ export class AgentContext {
153
153
  tokenCalculationPromise?: Promise<void>;
154
154
  /** Format content blocks as strings (for legacy compatibility) */
155
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;
156
160
 
157
161
  constructor({
158
162
  agentId,
@@ -386,8 +390,6 @@ export class AgentContext {
386
390
  const supportsCaching = modelId.includes('claude') || modelId.includes('anthropic') || modelId.includes('nova');
387
391
 
388
392
  if (bedrockOptions?.promptCache === true && supportsCaching) {
389
- // Always log system cache structure
390
- console.log(`[Cache] πŸ“ System | chars=${instructionsString.length} | tokens=${this.systemMessageTokens} | model=${modelId}`);
391
393
 
392
394
  finalInstructions = {
393
395
  content: [
@@ -423,6 +425,8 @@ export class AgentContext {
423
425
  reset(): void {
424
426
  this.instructionTokens = 0;
425
427
  this.systemMessageTokens = 0;
428
+ this.toolsDetail = [];
429
+ this.toolTokensTotal = 0;
426
430
  this.cachedSystemRunnable = undefined;
427
431
  this.systemRunnableStale = true;
428
432
  this.lastToken = undefined;
@@ -458,11 +462,14 @@ export class AgentContext {
458
462
  /**
459
463
  * Calculate tool tokens and add to instruction tokens
460
464
  * Note: System message tokens are calculated during systemRunnable creation
465
+ * Also tracks per-tool token breakdown for admin reporting
461
466
  */
462
467
  async calculateInstructionTokens(
463
468
  tokenCounter: t.TokenCounter
464
469
  ): Promise<void> {
465
470
  let toolTokens = 0;
471
+ this.toolsDetail = []; // Reset per-tool breakdown
472
+
466
473
  if (this.tools && this.tools.length > 0) {
467
474
  for (const tool of this.tools) {
468
475
  const genericTool = tool as Record<string, unknown>;
@@ -480,17 +487,60 @@ export class AgentContext {
480
487
  describedSchema as Parameters<typeof zodToJsonSchema>[0],
481
488
  (genericTool.name as string) || ''
482
489
  );
483
- toolTokens += tokenCounter(
490
+ const toolName = (genericTool.name as string) || 'unknown';
491
+ const tokens = tokenCounter(
484
492
  new SystemMessage(JSON.stringify(jsonSchema))
485
493
  );
494
+
495
+ // Track per-tool breakdown
496
+ this.toolsDetail.push({ name: toolName, tokens });
497
+ toolTokens += tokens;
486
498
  }
487
499
  }
488
500
  }
489
501
 
502
+ // Store total tool tokens for breakdown reporting
503
+ this.toolTokensTotal = toolTokens;
504
+
490
505
  // Add tool tokens to existing instruction tokens (which may already include system message tokens)
491
506
  this.instructionTokens += toolTokens;
492
507
  }
493
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
+
494
544
  /**
495
545
  * Gets the tool registry for deferred tools (for tool search).
496
546
  * @param onlyDeferred If true, only returns tools with defer_loading=true
@@ -391,6 +391,27 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
391
391
  return contentPartAgentMap;
392
392
  }
393
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
+
394
415
  /* Graph */
395
416
 
396
417
  createSystemRunnable({
@@ -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 = {
@@ -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,