illuma-agents 1.0.17 → 1.0.18

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 (94) hide show
  1. package/dist/cjs/agents/AgentContext.cjs +3 -1
  2. package/dist/cjs/agents/AgentContext.cjs.map +1 -1
  3. package/dist/cjs/graphs/Graph.cjs +18 -9
  4. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  5. package/dist/cjs/llm/bedrock/index.cjs +5 -3
  6. package/dist/cjs/llm/bedrock/index.cjs.map +1 -1
  7. package/dist/cjs/llm/openrouter/index.cjs +10 -1
  8. package/dist/cjs/llm/openrouter/index.cjs.map +1 -1
  9. package/dist/cjs/llm/vertexai/index.cjs +7 -8
  10. package/dist/cjs/llm/vertexai/index.cjs.map +1 -1
  11. package/dist/cjs/main.cjs +2 -0
  12. package/dist/cjs/main.cjs.map +1 -1
  13. package/dist/cjs/messages/cache.cjs +11 -6
  14. package/dist/cjs/messages/cache.cjs.map +1 -1
  15. package/dist/cjs/messages/core.cjs +2 -2
  16. package/dist/cjs/messages/core.cjs.map +1 -1
  17. package/dist/cjs/messages/format.cjs +2 -1
  18. package/dist/cjs/messages/format.cjs.map +1 -1
  19. package/dist/cjs/messages/tools.cjs +2 -2
  20. package/dist/cjs/messages/tools.cjs.map +1 -1
  21. package/dist/cjs/stream.cjs +29 -16
  22. package/dist/cjs/stream.cjs.map +1 -1
  23. package/dist/cjs/tools/ProgrammaticToolCalling.cjs +209 -47
  24. package/dist/cjs/tools/ProgrammaticToolCalling.cjs.map +1 -1
  25. package/dist/cjs/tools/ToolNode.cjs +1 -1
  26. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  27. package/dist/cjs/tools/search/search.cjs.map +1 -1
  28. package/dist/cjs/tools/search/tool.cjs +3 -1
  29. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  30. package/dist/cjs/utils/contextAnalytics.cjs +7 -5
  31. package/dist/cjs/utils/contextAnalytics.cjs.map +1 -1
  32. package/dist/cjs/utils/run.cjs.map +1 -1
  33. package/dist/cjs/utils/toonFormat.cjs +42 -12
  34. package/dist/cjs/utils/toonFormat.cjs.map +1 -1
  35. package/dist/esm/agents/AgentContext.mjs +3 -1
  36. package/dist/esm/agents/AgentContext.mjs.map +1 -1
  37. package/dist/esm/graphs/Graph.mjs +18 -9
  38. package/dist/esm/graphs/Graph.mjs.map +1 -1
  39. package/dist/esm/llm/bedrock/index.mjs +5 -3
  40. package/dist/esm/llm/bedrock/index.mjs.map +1 -1
  41. package/dist/esm/llm/openrouter/index.mjs +10 -1
  42. package/dist/esm/llm/openrouter/index.mjs.map +1 -1
  43. package/dist/esm/llm/vertexai/index.mjs +7 -8
  44. package/dist/esm/llm/vertexai/index.mjs.map +1 -1
  45. package/dist/esm/main.mjs +1 -1
  46. package/dist/esm/messages/cache.mjs +11 -6
  47. package/dist/esm/messages/cache.mjs.map +1 -1
  48. package/dist/esm/messages/core.mjs +2 -2
  49. package/dist/esm/messages/core.mjs.map +1 -1
  50. package/dist/esm/messages/format.mjs +2 -1
  51. package/dist/esm/messages/format.mjs.map +1 -1
  52. package/dist/esm/messages/tools.mjs +2 -2
  53. package/dist/esm/messages/tools.mjs.map +1 -1
  54. package/dist/esm/stream.mjs +29 -16
  55. package/dist/esm/stream.mjs.map +1 -1
  56. package/dist/esm/tools/ProgrammaticToolCalling.mjs +208 -48
  57. package/dist/esm/tools/ProgrammaticToolCalling.mjs.map +1 -1
  58. package/dist/esm/tools/ToolNode.mjs +1 -1
  59. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  60. package/dist/esm/tools/search/search.mjs.map +1 -1
  61. package/dist/esm/tools/search/tool.mjs +3 -1
  62. package/dist/esm/tools/search/tool.mjs.map +1 -1
  63. package/dist/esm/utils/contextAnalytics.mjs +7 -5
  64. package/dist/esm/utils/contextAnalytics.mjs.map +1 -1
  65. package/dist/esm/utils/run.mjs.map +1 -1
  66. package/dist/esm/utils/toonFormat.mjs +42 -12
  67. package/dist/esm/utils/toonFormat.mjs.map +1 -1
  68. package/dist/types/tools/ProgrammaticToolCalling.d.ts +19 -0
  69. package/dist/types/types/tools.d.ts +3 -1
  70. package/package.json +2 -2
  71. package/src/agents/AgentContext.ts +28 -20
  72. package/src/graphs/Graph.ts +76 -37
  73. package/src/llm/bedrock/__tests__/bedrock-caching.test.ts +495 -473
  74. package/src/llm/bedrock/index.ts +47 -35
  75. package/src/llm/openrouter/index.ts +11 -1
  76. package/src/llm/vertexai/index.ts +9 -10
  77. package/src/messages/cache.ts +104 -55
  78. package/src/messages/core.ts +5 -3
  79. package/src/messages/format.ts +6 -2
  80. package/src/messages/tools.ts +2 -2
  81. package/src/scripts/simple.ts +1 -1
  82. package/src/specs/emergency-prune.test.ts +407 -355
  83. package/src/stream.ts +28 -20
  84. package/src/tools/ProgrammaticToolCalling.ts +246 -52
  85. package/src/tools/ToolNode.ts +4 -4
  86. package/src/tools/__tests__/ProgrammaticToolCalling.test.ts +155 -0
  87. package/src/tools/search/jina-reranker.test.ts +32 -28
  88. package/src/tools/search/search.ts +3 -1
  89. package/src/tools/search/tool.ts +16 -7
  90. package/src/types/tools.ts +3 -1
  91. package/src/utils/contextAnalytics.ts +103 -95
  92. package/src/utils/llmConfig.ts +8 -1
  93. package/src/utils/run.ts +5 -4
  94. package/src/utils/toonFormat.ts +475 -437
@@ -1,18 +1,22 @@
1
- import { JinaReranker } from './rerankers';
1
+ import { JinaReranker, createReranker } from './rerankers';
2
2
  import { createDefaultLogger } from './utils';
3
3
 
4
+ // Helper to access private apiUrl property for testing
5
+ const getApiUrl = (reranker: JinaReranker): string =>
6
+ (reranker as unknown as { apiUrl: string }).apiUrl;
7
+
4
8
  describe('JinaReranker', () => {
5
9
  const mockLogger = createDefaultLogger();
6
-
10
+
7
11
  describe('constructor', () => {
8
12
  it('should use default API URL when no apiUrl is provided', () => {
9
13
  const reranker = new JinaReranker({
10
14
  apiKey: 'test-key',
11
15
  logger: mockLogger,
12
16
  });
13
-
17
+
14
18
  // Access private property for testing
15
- const apiUrl = (reranker as any).apiUrl;
19
+ const apiUrl = getApiUrl(reranker);
16
20
  expect(apiUrl).toBe('https://api.jina.ai/v1/rerank');
17
21
  });
18
22
 
@@ -23,25 +27,25 @@ describe('JinaReranker', () => {
23
27
  apiUrl: customUrl,
24
28
  logger: mockLogger,
25
29
  });
26
-
27
- const apiUrl = (reranker as any).apiUrl;
30
+
31
+ const apiUrl = getApiUrl(reranker);
28
32
  expect(apiUrl).toBe(customUrl);
29
33
  });
30
34
 
31
35
  it('should use environment variable JINA_API_URL when available', () => {
32
36
  const originalEnv = process.env.JINA_API_URL;
33
37
  process.env.JINA_API_URL = 'https://env-jina-endpoint.com/v1/rerank';
34
-
38
+
35
39
  const reranker = new JinaReranker({
36
40
  apiKey: 'test-key',
37
41
  logger: mockLogger,
38
42
  });
39
-
40
- const apiUrl = (reranker as any).apiUrl;
43
+
44
+ const apiUrl = getApiUrl(reranker);
41
45
  expect(apiUrl).toBe('https://env-jina-endpoint.com/v1/rerank');
42
-
46
+
43
47
  // Restore original environment
44
- if (originalEnv) {
48
+ if (originalEnv != null && originalEnv !== '') {
45
49
  process.env.JINA_API_URL = originalEnv;
46
50
  } else {
47
51
  delete process.env.JINA_API_URL;
@@ -51,19 +55,19 @@ describe('JinaReranker', () => {
51
55
  it('should prioritize explicit apiUrl over environment variable', () => {
52
56
  const originalEnv = process.env.JINA_API_URL;
53
57
  process.env.JINA_API_URL = 'https://env-jina-endpoint.com/v1/rerank';
54
-
58
+
55
59
  const customUrl = 'https://explicit-jina-endpoint.com/v1/rerank';
56
60
  const reranker = new JinaReranker({
57
61
  apiKey: 'test-key',
58
62
  apiUrl: customUrl,
59
63
  logger: mockLogger,
60
64
  });
61
-
62
- const apiUrl = (reranker as any).apiUrl;
65
+
66
+ const apiUrl = getApiUrl(reranker);
63
67
  expect(apiUrl).toBe(customUrl);
64
-
68
+
65
69
  // Restore original environment
66
- if (originalEnv) {
70
+ if (originalEnv != null && originalEnv !== '') {
67
71
  process.env.JINA_API_URL = originalEnv;
68
72
  } else {
69
73
  delete process.env.JINA_API_URL;
@@ -79,27 +83,27 @@ describe('JinaReranker', () => {
79
83
  apiUrl: customUrl,
80
84
  logger: mockLogger,
81
85
  });
82
-
86
+
83
87
  const logSpy = jest.spyOn(mockLogger, 'debug');
84
-
88
+
85
89
  try {
86
90
  await reranker.rerank('test query', ['document1', 'document2'], 2);
87
- } catch (error) {
91
+ } catch (_error) {
88
92
  // Expected to fail due to missing API key, but we can check the log
89
93
  }
90
-
94
+
91
95
  expect(logSpy).toHaveBeenCalledWith(
92
- expect.stringContaining(`Reranking 2 chunks with Jina using API URL: ${customUrl}`)
96
+ expect.stringContaining(
97
+ `Reranking 2 chunks with Jina using API URL: ${customUrl}`
98
+ )
93
99
  );
94
-
100
+
95
101
  logSpy.mockRestore();
96
102
  });
97
103
  });
98
104
  });
99
105
 
100
106
  describe('createReranker', () => {
101
- const { createReranker } = require('./rerankers');
102
-
103
107
  it('should create JinaReranker with jinaApiUrl when provided', () => {
104
108
  const customUrl = 'https://custom-jina-endpoint.com/v1/rerank';
105
109
  const reranker = createReranker({
@@ -107,9 +111,9 @@ describe('createReranker', () => {
107
111
  jinaApiKey: 'test-key',
108
112
  jinaApiUrl: customUrl,
109
113
  });
110
-
114
+
111
115
  expect(reranker).toBeInstanceOf(JinaReranker);
112
- const apiUrl = (reranker as any).apiUrl;
116
+ const apiUrl = getApiUrl(reranker as JinaReranker);
113
117
  expect(apiUrl).toBe(customUrl);
114
118
  });
115
119
 
@@ -118,9 +122,9 @@ describe('createReranker', () => {
118
122
  rerankerType: 'jina',
119
123
  jinaApiKey: 'test-key',
120
124
  });
121
-
125
+
122
126
  expect(reranker).toBeInstanceOf(JinaReranker);
123
- const apiUrl = (reranker as any).apiUrl;
127
+ const apiUrl = getApiUrl(reranker as JinaReranker);
124
128
  expect(apiUrl).toBe('https://api.jina.ai/v1/rerank');
125
129
  });
126
130
  });
@@ -603,7 +603,9 @@ export const createSourceProcessor = (
603
603
 
604
604
  // If content was already extracted directly (e.g., direct URL extraction), skip scraping
605
605
  if (skipScraping) {
606
- logger_.debug('Skipping additional scraping - content already extracted');
606
+ logger_.debug(
607
+ 'Skipping additional scraping - content already extracted'
608
+ );
607
609
  return result.data;
608
610
  }
609
611
 
@@ -98,15 +98,21 @@ async function extractDirectUrlContent({
98
98
 
99
99
  results.push({
100
100
  position: results.length + 1,
101
- title: getString(metadata.title) ?? getString(metadata.ogTitle) ?? url,
101
+ title:
102
+ getString(metadata.title) ?? getString(metadata.ogTitle) ?? url,
102
103
  link: url,
103
- snippet: getString(metadata.description) ?? getString(metadata.ogDescription) ?? '',
104
+ snippet:
105
+ getString(metadata.description) ??
106
+ getString(metadata.ogDescription) ??
107
+ '',
104
108
  content: content,
105
109
  references: references,
106
110
  processed: true,
107
111
  });
108
112
  } else {
109
- logger.warn(`Failed to extract content from ${url}: ${response.error}`);
113
+ logger.warn(
114
+ `Failed to extract content from ${url}: ${response.error}`
115
+ );
110
116
  // Still add the URL as a result, but without content
111
117
  results.push({
112
118
  position: results.length + 1,
@@ -424,15 +430,17 @@ function createTool({
424
430
  async (params, runnableConfig) => {
425
431
  const { query, date, country: _c, images, videos, news } = params;
426
432
  const country = typeof _c === 'string' && _c ? _c : undefined;
427
-
433
+
428
434
  // Log the incoming query for debugging URL detection
429
435
  const toolLogger = createDefaultLogger();
430
436
  toolLogger.debug(`[web_search] Received query: "${query}"`);
431
437
  const detectedUrls = extractUrlsFromQuery(query);
432
438
  if (detectedUrls.length > 0) {
433
- toolLogger.debug(`[web_search] Detected URLs in query: ${detectedUrls.join(', ')}`);
439
+ toolLogger.debug(
440
+ `[web_search] Detected URLs in query: ${detectedUrls.join(', ')}`
441
+ );
434
442
  }
435
-
443
+
436
444
  const searchResult = await search({
437
445
  query,
438
446
  date,
@@ -452,7 +460,8 @@ function createTool({
452
460
  },
453
461
  {
454
462
  name: Constants.WEB_SEARCH,
455
- description: `Real-time web search and direct URL content extraction. Results have required citation anchors.
463
+ description:
464
+ `Real-time web search and direct URL content extraction. Results have required citation anchors.
456
465
 
457
466
  **CAPABILITIES:**
458
467
  - Search: Query the web for information on any topic
@@ -15,7 +15,9 @@ export type CustomToolCall = {
15
15
  output?: string;
16
16
  };
17
17
 
18
- export type GenericTool = StructuredToolInterface | RunnableToolLike;
18
+ export type GenericTool = (StructuredToolInterface | RunnableToolLike) & {
19
+ mcp?: boolean;
20
+ };
19
21
 
20
22
  export type ToolMap = Map<string, GenericTool>;
21
23
  export type ToolRefs = {
@@ -1,95 +1,103 @@
1
- /**
2
- * Context Analytics Utility
3
- *
4
- * Provides context analytics data for observability/traces.
5
- * No console logging - just data structures for event emission.
6
- */
7
-
8
- import type { BaseMessage } from '@langchain/core/messages';
9
- import type { TokenCounter } from '@/types/run';
10
-
11
- /**
12
- * Context analytics data for traces
13
- */
14
- export interface ContextAnalytics {
15
- /** Total messages in context */
16
- messageCount: number;
17
- /** Total tokens in context */
18
- totalTokens: number;
19
- /** Maximum allowed context tokens */
20
- maxContextTokens?: number;
21
- /** Instruction/system tokens */
22
- instructionTokens?: number;
23
- /** Context utilization percentage (0-100) */
24
- utilizationPercent?: number;
25
- /** Breakdown by message type */
26
- breakdown?: Record<string, { tokens: number; percent: number }>;
27
- }
28
-
29
- /**
30
- * Build context analytics for traces (no logging)
31
- */
32
- export function buildContextAnalytics(
33
- messages: BaseMessage[],
34
- options: {
35
- tokenCounter?: TokenCounter;
36
- maxContextTokens?: number;
37
- instructionTokens?: number;
38
- indexTokenCountMap?: Record<string, number | undefined>;
39
- }
40
- ): ContextAnalytics {
41
- const { tokenCounter, maxContextTokens, instructionTokens, indexTokenCountMap } = options;
42
-
43
- // Calculate total tokens
44
- let totalTokens = 0;
45
- const breakdown: Record<string, { tokens: number; percent: number }> = {};
46
-
47
- for (let i = 0; i < messages.length; i++) {
48
- const msg = messages[i];
49
- const type = msg.getType();
50
-
51
- let tokens = 0;
52
- if (indexTokenCountMap && indexTokenCountMap[i] != null) {
53
- tokens = indexTokenCountMap[i]!;
54
- } else if (tokenCounter) {
55
- try {
56
- tokens = tokenCounter(msg);
57
- } catch {
58
- // Estimate from content length
59
- const content = typeof msg.content === 'string'
60
- ? msg.content
61
- : JSON.stringify(msg.content);
62
- tokens = Math.ceil(content.length / 4);
63
- }
64
- }
65
-
66
- totalTokens += tokens;
67
-
68
- if (!breakdown[type]) {
69
- breakdown[type] = { tokens: 0, percent: 0 };
70
- }
71
- breakdown[type].tokens += tokens;
72
- }
73
-
74
- // Calculate percentages
75
- for (const type of Object.keys(breakdown)) {
76
- breakdown[type].percent = totalTokens > 0
77
- ? Math.round((breakdown[type].tokens / totalTokens) * 1000) / 10
78
- : 0;
79
- }
80
-
81
- // Calculate utilization
82
- let utilizationPercent: number | undefined;
83
- if (maxContextTokens && maxContextTokens > 0) {
84
- utilizationPercent = Math.round((totalTokens / maxContextTokens) * 1000) / 10;
85
- }
86
-
87
- return {
88
- messageCount: messages.length,
89
- totalTokens,
90
- maxContextTokens,
91
- instructionTokens,
92
- utilizationPercent,
93
- breakdown,
94
- };
95
- }
1
+ /**
2
+ * Context Analytics Utility
3
+ *
4
+ * Provides context analytics data for observability/traces.
5
+ * No console logging - just data structures for event emission.
6
+ */
7
+
8
+ import type { BaseMessage } from '@langchain/core/messages';
9
+ import type { TokenCounter } from '@/types/run';
10
+
11
+ /**
12
+ * Context analytics data for traces
13
+ */
14
+ export interface ContextAnalytics {
15
+ /** Total messages in context */
16
+ messageCount: number;
17
+ /** Total tokens in context */
18
+ totalTokens: number;
19
+ /** Maximum allowed context tokens */
20
+ maxContextTokens?: number;
21
+ /** Instruction/system tokens */
22
+ instructionTokens?: number;
23
+ /** Context utilization percentage (0-100) */
24
+ utilizationPercent?: number;
25
+ /** Breakdown by message type */
26
+ breakdown?: Record<string, { tokens: number; percent: number }>;
27
+ }
28
+
29
+ /**
30
+ * Build context analytics for traces (no logging)
31
+ */
32
+ export function buildContextAnalytics(
33
+ messages: BaseMessage[],
34
+ options: {
35
+ tokenCounter?: TokenCounter;
36
+ maxContextTokens?: number;
37
+ instructionTokens?: number;
38
+ indexTokenCountMap?: Record<string, number | undefined>;
39
+ }
40
+ ): ContextAnalytics {
41
+ const {
42
+ tokenCounter,
43
+ maxContextTokens,
44
+ instructionTokens,
45
+ indexTokenCountMap,
46
+ } = options;
47
+
48
+ // Calculate total tokens
49
+ let totalTokens = 0;
50
+ const breakdown: Record<string, { tokens: number; percent: number }> = {};
51
+
52
+ for (let i = 0; i < messages.length; i++) {
53
+ const msg = messages[i];
54
+ const type = msg.getType();
55
+
56
+ let tokens = 0;
57
+ if (indexTokenCountMap && indexTokenCountMap[i] != null) {
58
+ tokens = indexTokenCountMap[i]!;
59
+ } else if (tokenCounter) {
60
+ try {
61
+ tokens = tokenCounter(msg);
62
+ } catch {
63
+ // Estimate from content length
64
+ const content =
65
+ typeof msg.content === 'string'
66
+ ? msg.content
67
+ : JSON.stringify(msg.content);
68
+ tokens = Math.ceil(content.length / 4);
69
+ }
70
+ }
71
+
72
+ totalTokens += tokens;
73
+
74
+ if (!breakdown[type]) {
75
+ breakdown[type] = { tokens: 0, percent: 0 };
76
+ }
77
+ breakdown[type].tokens += tokens;
78
+ }
79
+
80
+ // Calculate percentages
81
+ for (const type of Object.keys(breakdown)) {
82
+ breakdown[type].percent =
83
+ totalTokens > 0
84
+ ? Math.round((breakdown[type].tokens / totalTokens) * 1000) / 10
85
+ : 0;
86
+ }
87
+
88
+ // Calculate utilization
89
+ let utilizationPercent: number | undefined;
90
+ if (maxContextTokens && maxContextTokens > 0) {
91
+ utilizationPercent =
92
+ Math.round((totalTokens / maxContextTokens) * 1000) / 10;
93
+ }
94
+
95
+ return {
96
+ messageCount: messages.length,
97
+ totalTokens,
98
+ maxContextTokens,
99
+ instructionTokens,
100
+ utilizationPercent,
101
+ breakdown,
102
+ };
103
+ }
@@ -56,7 +56,9 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
56
56
  provider: Providers.OPENROUTER,
57
57
  streaming: true,
58
58
  streamUsage: true,
59
- model: 'anthropic/claude-sonnet-4',
59
+ // model: 'anthropic/claude-sonnet-4',
60
+ // model: 'moonshotai/kimi-k2-thinking',
61
+ model: 'google/gemini-3-pro-preview',
60
62
  apiKey: process.env.OPENROUTER_API_KEY,
61
63
  configuration: {
62
64
  baseURL: process.env.OPENROUTER_BASE_URL,
@@ -145,9 +147,14 @@ export const llmConfigs: Record<string, t.LLMConfig | undefined> = {
145
147
  [Providers.VERTEXAI]: {
146
148
  provider: Providers.VERTEXAI,
147
149
  model: 'gemini-2.5-flash',
150
+ // model: 'gemini-2.5-pro',
148
151
  streaming: true,
149
152
  streamUsage: true,
150
153
  keyFile: process.env.VERTEXAI_KEY_FILE,
154
+ // maxRetries: 2,
155
+ // location: 'global',
156
+ // thinkingBudget: -1,
157
+ // includeThoughts: true,
151
158
  } as t.VertexAIClientOptions & t.LLMConfig,
152
159
  [Providers.GOOGLE]: {
153
160
  provider: Providers.GOOGLE,
package/src/utils/run.ts CHANGED
@@ -57,9 +57,10 @@ export class RunnableCallable<I = unknown, O = unknown> extends Runnable<I, O> {
57
57
  ): Promise<O> {
58
58
  return new Promise<O>((resolve, reject) => {
59
59
  // Defensive check: ensure runManager has getChild method before calling
60
- const childCallbacks = typeof runManager?.getChild === 'function'
61
- ? runManager.getChild()
62
- : undefined;
60
+ const childCallbacks =
61
+ typeof runManager?.getChild === 'function'
62
+ ? runManager.getChild()
63
+ : undefined;
63
64
  const childConfig = patchConfig(config, {
64
65
  callbacks: childCallbacks,
65
66
  });
@@ -102,4 +103,4 @@ export class RunnableCallable<I = unknown, O = unknown> extends Runnable<I, O> {
102
103
 
103
104
  return returnValue;
104
105
  }
105
- }
106
+ }