illuma-agents 1.0.64 → 1.0.66

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 (44) hide show
  1. package/dist/cjs/graphs/Graph.cjs +3 -132
  2. package/dist/cjs/graphs/Graph.cjs.map +1 -1
  3. package/dist/cjs/main.cjs +28 -4
  4. package/dist/cjs/main.cjs.map +1 -1
  5. package/dist/cjs/messages/format.cjs +0 -50
  6. package/dist/cjs/messages/format.cjs.map +1 -1
  7. package/dist/cjs/tools/Calculator.cjs +23 -2
  8. package/dist/cjs/tools/Calculator.cjs.map +1 -1
  9. package/dist/cjs/tools/CodeExecutor.cjs +19 -1
  10. package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
  11. package/dist/cjs/tools/ToolNode.cjs +2 -1
  12. package/dist/cjs/tools/ToolNode.cjs.map +1 -1
  13. package/dist/cjs/tools/search/schema.cjs +45 -0
  14. package/dist/cjs/tools/search/schema.cjs.map +1 -1
  15. package/dist/cjs/tools/search/tool.cjs.map +1 -1
  16. package/dist/esm/graphs/Graph.mjs +3 -132
  17. package/dist/esm/graphs/Graph.mjs.map +1 -1
  18. package/dist/esm/main.mjs +4 -3
  19. package/dist/esm/main.mjs.map +1 -1
  20. package/dist/esm/messages/format.mjs +2 -51
  21. package/dist/esm/messages/format.mjs.map +1 -1
  22. package/dist/esm/tools/Calculator.mjs +20 -3
  23. package/dist/esm/tools/Calculator.mjs.map +1 -1
  24. package/dist/esm/tools/CodeExecutor.mjs +16 -2
  25. package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
  26. package/dist/esm/tools/ToolNode.mjs +2 -1
  27. package/dist/esm/tools/ToolNode.mjs.map +1 -1
  28. package/dist/esm/tools/search/schema.mjs +42 -1
  29. package/dist/esm/tools/search/schema.mjs.map +1 -1
  30. package/dist/esm/tools/search/tool.mjs.map +1 -1
  31. package/dist/types/messages/format.d.ts +0 -9
  32. package/dist/types/tools/Calculator.d.ts +26 -0
  33. package/dist/types/tools/CodeExecutor.d.ts +51 -0
  34. package/dist/types/tools/search/index.d.ts +1 -0
  35. package/dist/types/tools/search/schema.d.ts +69 -0
  36. package/package.json +1 -1
  37. package/src/graphs/Graph.ts +5 -160
  38. package/src/messages/format.ts +0 -60
  39. package/src/tools/Calculator.ts +24 -3
  40. package/src/tools/CodeExecutor.ts +19 -2
  41. package/src/tools/ToolNode.ts +2 -1
  42. package/src/tools/search/index.ts +1 -0
  43. package/src/tools/search/schema.ts +45 -0
  44. package/src/tools/search/tool.ts +3 -3
@@ -731,7 +731,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
731
731
  const {
732
732
  name = 'StructuredResponse',
733
733
  mode = 'auto',
734
- includeRaw = false,
734
+ includeRaw: _includeRaw = false,
735
735
  handleErrors = true,
736
736
  maxRetries = 2,
737
737
  } = structuredOutputConfig;
@@ -793,7 +793,6 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
793
793
 
794
794
  // Debug: log what we got back
795
795
  console.log('[Graph] Structured output raw result type:', typeof result);
796
- console.log('[Graph] Structured output result keys:', result ? Object.keys(result) : 'null');
797
796
  if (result?.raw) {
798
797
  const rawMsg = result.raw;
799
798
  console.log('[Graph] Raw message content type:', typeof rawMsg?.content);
@@ -801,31 +800,17 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
801
800
  if (rawMsg?.content && typeof rawMsg.content === 'string' && rawMsg.content.length > 0) {
802
801
  console.log('[Graph] Raw message text content (first 200):', rawMsg.content.substring(0, 200));
803
802
  }
804
- // Log the parsed result if available
805
- if (result?.parsed) {
806
- console.log('[Graph] Parsed result keys:', Object.keys(result.parsed));
807
- }
808
803
  }
809
804
 
810
805
  // Handle response - we always use includeRaw internally
811
806
  if (result?.raw && result?.parsed !== undefined) {
812
- console.log('[Graph] Using parsed result from structured output');
813
807
  return {
814
808
  structuredResponse: result.parsed as Record<string, unknown>,
815
809
  rawMessage: result.raw as AIMessageChunk,
816
810
  };
817
811
  }
818
812
 
819
- // Fallback: If result itself is the parsed object (no raw wrapper)
820
- if (result && typeof result === 'object' && !result.raw && !result.parsed) {
821
- console.log('[Graph] Result is the structured object directly');
822
- return {
823
- structuredResponse: result as Record<string, unknown>,
824
- };
825
- }
826
-
827
813
  // Fallback for models that don't support includeRaw
828
- console.log('[Graph] Using fallback - treating result as structured response');
829
814
  return {
830
815
  structuredResponse: result as Record<string, unknown>,
831
816
  };
@@ -1151,17 +1136,10 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1151
1136
  );
1152
1137
 
1153
1138
  // Check if structured output mode is enabled
1154
- // IMPORTANT: If tools are available, we need to let the model use them first.
1155
- // Only use structured output when:
1156
- // 1. No tools are configured, OR
1157
- // 2. The model has already used tools and is ready to give final response
1158
- const hasTools = agentContext.tools && agentContext.tools.length > 0;
1159
- const shouldUseStructuredOutputNow =
1139
+ if (
1160
1140
  agentContext.isStructuredOutputMode &&
1161
- agentContext.structuredOutput &&
1162
- !hasTools; // Only use structured output immediately if no tools
1163
-
1164
- if (shouldUseStructuredOutputNow) {
1141
+ agentContext.structuredOutput
1142
+ ) {
1165
1143
  const schema = agentContext.getStructuredOutputSchema();
1166
1144
  if (!schema) {
1167
1145
  throw new Error('Structured output schema is not configured');
@@ -1206,16 +1184,13 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1206
1184
  clientOptions: structuredClientOptions,
1207
1185
  });
1208
1186
 
1209
- // For no-tools case, we pass the original messages directly
1210
- // There shouldn't be thinking blocks since this is the first invocation
1211
-
1212
1187
  const { structuredResponse, rawMessage } =
1213
1188
  await this.attemptStructuredInvoke(
1214
1189
  {
1215
1190
  currentModel: structuredModel,
1216
1191
  finalMessages,
1217
1192
  schema,
1218
- structuredOutputConfig: agentContext.structuredOutput!,
1193
+ structuredOutputConfig: agentContext.structuredOutput,
1219
1194
  provider: agentContext.provider,
1220
1195
  },
1221
1196
  config
@@ -1488,136 +1463,6 @@ If I seem to be missing something we discussed earlier, just give me a quick rem
1488
1463
  if (!result) {
1489
1464
  throw new Error('No result after model invocation');
1490
1465
  }
1491
-
1492
- // Check if we need to apply structured output for the final response
1493
- // This handles the case where tools were used, and now the model is giving its final answer
1494
- const resultMessage = result.messages?.[0] as AIMessageChunk | undefined;
1495
- const hasToolCalls = (resultMessage?.tool_calls?.length ?? 0) > 0;
1496
-
1497
- if (
1498
- agentContext.isStructuredOutputMode &&
1499
- agentContext.structuredOutput &&
1500
- !hasToolCalls && // Model is giving final response (no tool calls)
1501
- hasTools // We skipped structured output earlier because tools were available
1502
- ) {
1503
- const schema = agentContext.getStructuredOutputSchema();
1504
- if (schema) {
1505
- try {
1506
- console.log('[Graph] Applying structured output for final response after tool execution');
1507
-
1508
- // Get a fresh model for structured output
1509
- const structuredClientOptions = { ...agentContext.clientOptions } as t.ClientOptions;
1510
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1511
- (structuredClientOptions as any).streaming = false;
1512
-
1513
- // Remove thinking configuration
1514
- if (agentContext.provider === Providers.BEDROCK) {
1515
- const bedrockOpts = structuredClientOptions as t.BedrockAnthropicClientOptions;
1516
- if (bedrockOpts.additionalModelRequestFields) {
1517
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
1518
- const additionalFields = Object.assign({}, bedrockOpts.additionalModelRequestFields) as any;
1519
- delete additionalFields.thinking;
1520
- delete additionalFields.budgetTokens;
1521
- bedrockOpts.additionalModelRequestFields = additionalFields;
1522
- }
1523
- }
1524
- if (agentContext.provider === Providers.ANTHROPIC) {
1525
- const anthropicOpts = structuredClientOptions as t.AnthropicClientOptions;
1526
- if (anthropicOpts.thinking) {
1527
- delete anthropicOpts.thinking;
1528
- }
1529
- }
1530
-
1531
- const structuredModel = this.getNewModel({
1532
- provider: agentContext.provider,
1533
- clientOptions: structuredClientOptions,
1534
- });
1535
-
1536
- // Following LangGraph's Option 2 pattern:
1537
- // Instead of passing the full conversation (which has thinking blocks),
1538
- // just pass the model's final response text as a HumanMessage asking for structured output.
1539
- // This avoids issues with thinking blocks and is more token-efficient.
1540
- let responseContent = '';
1541
- if (resultMessage) {
1542
- if (typeof resultMessage.content === 'string') {
1543
- responseContent = resultMessage.content;
1544
- } else if (Array.isArray(resultMessage.content)) {
1545
- // Extract text parts only (skip thinking blocks, tool_use, etc.)
1546
- responseContent = resultMessage.content
1547
- .filter((c): c is { type: string; text: string } =>
1548
- typeof c === 'object' && c !== null &&
1549
- (c as { type?: string }).type === 'text' &&
1550
- typeof (c as { text?: string }).text === 'string'
1551
- )
1552
- .map(c => c.text)
1553
- .join('\n');
1554
- }
1555
- }
1556
-
1557
- if (!responseContent) {
1558
- console.log('[Graph] No response content to structure, skipping');
1559
- throw new Error('No response content available for structured output');
1560
- }
1561
-
1562
- console.log('[Graph] Structuring response content (first 200 chars):', responseContent.substring(0, 200));
1563
-
1564
- // Create a simple message asking to structure the response
1565
- const structuredMessages: BaseMessage[] = [
1566
- new HumanMessage({
1567
- content: `Based on the following response, extract and return the data in the required structured format:\n\n${responseContent}`,
1568
- }),
1569
- ];
1570
-
1571
- const { structuredResponse, rawMessage } =
1572
- await this.attemptStructuredInvoke(
1573
- {
1574
- currentModel: structuredModel,
1575
- finalMessages: structuredMessages,
1576
- schema,
1577
- structuredOutputConfig: agentContext.structuredOutput!,
1578
- provider: agentContext.provider,
1579
- },
1580
- config
1581
- );
1582
-
1583
- // Emit structured output event
1584
- await safeDispatchCustomEvent(
1585
- GraphEvents.ON_STRUCTURED_OUTPUT,
1586
- {
1587
- structuredResponse,
1588
- schema,
1589
- raw: rawMessage,
1590
- },
1591
- config
1592
- );
1593
-
1594
- agentContext.currentUsage = rawMessage
1595
- ? this.getUsageMetadata(rawMessage)
1596
- : undefined;
1597
- this.cleanupSignalListener();
1598
-
1599
- // Return clean message without tool_calls
1600
- let cleanMessage: AIMessageChunk | undefined;
1601
- if (rawMessage) {
1602
- cleanMessage = new AIMessageChunk({
1603
- content: JSON.stringify(structuredResponse, null, 2),
1604
- id: rawMessage.id,
1605
- response_metadata: rawMessage.response_metadata,
1606
- usage_metadata: rawMessage.usage_metadata,
1607
- });
1608
- }
1609
-
1610
- return {
1611
- messages: cleanMessage ? [cleanMessage] : [],
1612
- structuredResponse,
1613
- };
1614
- } catch (structuredError) {
1615
- console.error('[Graph] Structured output failed after tool execution:', structuredError);
1616
- // Fall through to return normal result
1617
- }
1618
- }
1619
- }
1620
-
1621
1466
  agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
1622
1467
  this.cleanupSignalListener();
1623
1468
  return result;
@@ -934,63 +934,3 @@ export function ensureThinkingBlockInMessages(
934
934
 
935
935
  return result;
936
936
  }
937
-
938
- /**
939
- * Strips thinking blocks from messages for structured output invocation.
940
- * When switching from thinking-enabled mode to structured output (which requires thinking disabled),
941
- * we need to remove thinking/reasoning blocks from the conversation to avoid Bedrock errors.
942
- *
943
- * @param messages - Array of messages to process
944
- * @returns The messages array with thinking blocks stripped from AI messages
945
- */
946
- export function stripThinkingBlocksFromMessages(
947
- messages: BaseMessage[]
948
- ): BaseMessage[] {
949
- return messages.map((msg) => {
950
- const isAI = msg instanceof AIMessage || msg instanceof AIMessageChunk;
951
-
952
- if (!isAI) {
953
- return msg;
954
- }
955
-
956
- const aiMsg = msg as AIMessage | AIMessageChunk;
957
- const content = aiMsg.content;
958
-
959
- // If content is not an array, nothing to strip
960
- if (!Array.isArray(content)) {
961
- return msg;
962
- }
963
-
964
- // Filter out thinking/reasoning blocks
965
- const filteredContent = content.filter((c) => {
966
- if (typeof c !== 'object' || c === null) {
967
- return true;
968
- }
969
- const type = (c as ExtendedMessageContent).type;
970
- return (
971
- type !== ContentTypes.THINKING &&
972
- type !== ContentTypes.REASONING_CONTENT &&
973
- type !== ContentTypes.REASONING &&
974
- type !== 'thinking' &&
975
- type !== 'redacted_thinking'
976
- );
977
- });
978
-
979
- // If no content left after filtering, add a placeholder
980
- if (filteredContent.length === 0) {
981
- filteredContent.push({
982
- type: 'text',
983
- text: '(previous response)',
984
- });
985
- }
986
-
987
- // Create a new AI message with the filtered content
988
- return new AIMessageChunk({
989
- content: filteredContent,
990
- id: aiMsg.id,
991
- response_metadata: aiMsg.response_metadata,
992
- usage_metadata: aiMsg.usage_metadata,
993
- // Don't include tool_calls - we're stripping those for structured output context
994
- });
995
- });
996
- }
@@ -1,6 +1,28 @@
1
1
  import { Tool } from '@langchain/core/tools';
2
2
  import * as math from 'mathjs';
3
3
 
4
+ export const CalculatorToolName = 'calculator';
5
+
6
+ export const CalculatorToolDescription =
7
+ 'Useful for getting the result of a math expression. The input to this tool should be a valid mathematical expression that could be executed by a simple calculator.';
8
+
9
+ export const CalculatorSchema = {
10
+ type: 'object',
11
+ properties: {
12
+ input: {
13
+ type: 'string',
14
+ description: 'A valid mathematical expression to evaluate',
15
+ },
16
+ },
17
+ required: ['input'],
18
+ } as const;
19
+
20
+ export const CalculatorToolDefinition = {
21
+ name: CalculatorToolName,
22
+ description: CalculatorToolDescription,
23
+ schema: CalculatorSchema,
24
+ } as const;
25
+
4
26
  export class Calculator extends Tool {
5
27
  static lc_name(): string {
6
28
  return 'Calculator';
@@ -10,7 +32,7 @@ export class Calculator extends Tool {
10
32
  return [...super.lc_namespace, 'calculator'];
11
33
  }
12
34
 
13
- name = 'calculator';
35
+ name = CalculatorToolName;
14
36
 
15
37
  async _call(input: string): Promise<string> {
16
38
  try {
@@ -20,6 +42,5 @@ export class Calculator extends Tool {
20
42
  }
21
43
  }
22
44
 
23
- description =
24
- 'Useful for getting the result of a math expression. The input to this tool should be a valid mathematical expression that could be executed by a simple calculator.';
45
+ description = CalculatorToolDescription;
25
46
  }
@@ -35,7 +35,7 @@ const SUPPORTED_LANGUAGES = [
35
35
  'r',
36
36
  ] as const;
37
37
 
38
- const CodeExecutionToolSchema = {
38
+ export const CodeExecutionToolSchema = {
39
39
  type: 'object',
40
40
  properties: {
41
41
  lang: {
@@ -74,6 +74,23 @@ const EXEC_ENDPOINT = `${baseEndpoint}/exec`;
74
74
 
75
75
  type SupportedLanguage = (typeof SUPPORTED_LANGUAGES)[number];
76
76
 
77
+ export const CodeExecutionToolDescription = `
78
+ Runs code and returns stdout/stderr output from a stateless execution environment, similar to running scripts in a command-line interface. Each execution is isolated and independent.
79
+
80
+ Usage:
81
+ - No network access available.
82
+ - Generated files are automatically delivered; **DO NOT** provide download links.
83
+ - NEVER use this tool to execute malicious code.
84
+ `.trim();
85
+
86
+ export const CodeExecutionToolName = Constants.EXECUTE_CODE;
87
+
88
+ export const CodeExecutionToolDefinition = {
89
+ name: CodeExecutionToolName,
90
+ description: CodeExecutionToolDescription,
91
+ schema: CodeExecutionToolSchema,
92
+ } as const;
93
+
77
94
  function createCodeExecutionTool(
78
95
  params: t.CodeExecutionToolParams = {}
79
96
  ): DynamicStructuredTool {
@@ -242,7 +259,7 @@ Rules:
242
259
  }
243
260
  },
244
261
  {
245
- name: Constants.EXECUTE_CODE,
262
+ name: CodeExecutionToolName,
246
263
  description,
247
264
  schema: CodeExecutionToolSchema,
248
265
  responseFormat: Constants.CONTENT_AND_ARTIFACT,
@@ -392,8 +392,9 @@ export class ToolNode<T = any> extends RunnableCallable<T, T> {
392
392
  : JSON.stringify(result.content);
393
393
  toolMessage = new ToolMessage({
394
394
  status: 'success',
395
- content: contentString,
396
395
  name: toolName,
396
+ content: contentString,
397
+ artifact: result.artifact,
397
398
  tool_call_id: result.toolCallId,
398
399
  });
399
400
  }
@@ -1,2 +1,3 @@
1
1
  export * from './tool';
2
+ export * from './schema';
2
3
  export type * from './types';
@@ -66,3 +66,48 @@ export const newsSchema = {
66
66
  type: 'boolean',
67
67
  description: 'Whether to also run a news search.',
68
68
  } as const;
69
+
70
+ /** Combined web search tool schema with all properties */
71
+ export const WebSearchToolSchema = {
72
+ type: 'object',
73
+ properties: {
74
+ query: querySchema,
75
+ date: dateSchema,
76
+ country: countrySchema,
77
+ images: imagesSchema,
78
+ videos: videosSchema,
79
+ news: newsSchema,
80
+ },
81
+ required: ['query'],
82
+ } as const;
83
+
84
+ export const WebSearchToolName = 'web_search';
85
+
86
+ export const WebSearchToolDescription = `Real-time search. Results have required citation anchors.
87
+
88
+ Note: Use ONCE per reply unless instructed otherwise.
89
+
90
+ Anchors:
91
+ - \\ue202turnXtypeY
92
+ - X = turn idx, type = 'search' | 'news' | 'image' | 'ref', Y = item idx
93
+
94
+ Special Markers:
95
+ - \\ue203...\\ue204 — highlight start/end of cited text (for Standalone or Group citations)
96
+ - \\ue200...\\ue201 — group block (e.g. \\ue200\\ue202turn0search1\\ue202turn0news2\\ue201)
97
+
98
+ **CITE EVERY NON-OBVIOUS FACT/QUOTE:**
99
+ Use anchor marker(s) immediately after the statement:
100
+ - Standalone: "Pure functions produce same output. \\ue202turn0search0"
101
+ - Standalone (multiple): "Today's News \\ue202turn0search0\\ue202turn0news0"
102
+ - Highlight: "\\ue203Highlight text.\\ue204\\ue202turn0news1"
103
+ - Group: "Sources. \\ue200\\ue202turn0search0\\ue202turn0news1\\ue201"
104
+ - Group Highlight: "\\ue203Highlight for group.\\ue204 \\ue200\\ue202turn0search0\\ue202turn0news1\\ue201"
105
+ - Image: "See photo \\ue202turn0image0."
106
+
107
+ **NEVER use markdown links, [1], or footnotes. CITE ONLY with anchors provided.**`;
108
+
109
+ export const WebSearchToolDefinition = {
110
+ name: WebSearchToolName,
111
+ description: WebSearchToolDescription,
112
+ schema: WebSearchToolSchema,
113
+ } as const;
@@ -2,13 +2,13 @@ import { tool, DynamicStructuredTool } from '@langchain/core/tools';
2
2
  import type { RunnableConfig } from '@langchain/core/runnables';
3
3
  import type * as t from './types';
4
4
  import {
5
- DATE_RANGE,
6
- querySchema,
7
- dateSchema,
8
5
  countrySchema,
9
6
  imagesSchema,
10
7
  videosSchema,
8
+ querySchema,
9
+ dateSchema,
11
10
  newsSchema,
11
+ DATE_RANGE,
12
12
  } from './schema';
13
13
  import { createSearchAPI, createSourceProcessor } from './search';
14
14
  import { createSerperScraper } from './serper-scraper';