illuma-agents 1.0.65 → 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.
- package/dist/cjs/graphs/Graph.cjs +3 -132
- package/dist/cjs/graphs/Graph.cjs.map +1 -1
- package/dist/cjs/main.cjs +28 -4
- package/dist/cjs/main.cjs.map +1 -1
- package/dist/cjs/messages/format.cjs +0 -50
- package/dist/cjs/messages/format.cjs.map +1 -1
- package/dist/cjs/tools/Calculator.cjs +23 -2
- package/dist/cjs/tools/Calculator.cjs.map +1 -1
- package/dist/cjs/tools/CodeExecutor.cjs +19 -1
- package/dist/cjs/tools/CodeExecutor.cjs.map +1 -1
- package/dist/cjs/tools/ToolNode.cjs +2 -1
- package/dist/cjs/tools/ToolNode.cjs.map +1 -1
- package/dist/cjs/tools/search/schema.cjs +45 -0
- package/dist/cjs/tools/search/schema.cjs.map +1 -1
- package/dist/cjs/tools/search/tool.cjs.map +1 -1
- package/dist/esm/graphs/Graph.mjs +3 -132
- package/dist/esm/graphs/Graph.mjs.map +1 -1
- package/dist/esm/main.mjs +4 -3
- package/dist/esm/main.mjs.map +1 -1
- package/dist/esm/messages/format.mjs +2 -51
- package/dist/esm/messages/format.mjs.map +1 -1
- package/dist/esm/tools/Calculator.mjs +20 -3
- package/dist/esm/tools/Calculator.mjs.map +1 -1
- package/dist/esm/tools/CodeExecutor.mjs +16 -2
- package/dist/esm/tools/CodeExecutor.mjs.map +1 -1
- package/dist/esm/tools/ToolNode.mjs +2 -1
- package/dist/esm/tools/ToolNode.mjs.map +1 -1
- package/dist/esm/tools/search/schema.mjs +42 -1
- package/dist/esm/tools/search/schema.mjs.map +1 -1
- package/dist/esm/tools/search/tool.mjs.map +1 -1
- package/dist/types/messages/format.d.ts +0 -9
- package/dist/types/tools/Calculator.d.ts +26 -0
- package/dist/types/tools/CodeExecutor.d.ts +51 -0
- package/dist/types/tools/search/index.d.ts +1 -0
- package/dist/types/tools/search/schema.d.ts +69 -0
- package/package.json +1 -1
- package/src/graphs/Graph.ts +5 -160
- package/src/messages/format.ts +0 -60
- package/src/tools/Calculator.ts +24 -3
- package/src/tools/CodeExecutor.ts +19 -2
- package/src/tools/ToolNode.ts +2 -1
- package/src/tools/search/index.ts +1 -0
- package/src/tools/search/schema.ts +45 -0
- package/src/tools/search/tool.ts +3 -3
package/src/graphs/Graph.ts
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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;
|
package/src/messages/format.ts
CHANGED
|
@@ -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
|
-
}
|
package/src/tools/Calculator.ts
CHANGED
|
@@ -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 =
|
|
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:
|
|
262
|
+
name: CodeExecutionToolName,
|
|
246
263
|
description,
|
|
247
264
|
schema: CodeExecutionToolSchema,
|
|
248
265
|
responseFormat: Constants.CONTENT_AND_ARTIFACT,
|
package/src/tools/ToolNode.ts
CHANGED
|
@@ -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
|
}
|
|
@@ -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;
|
package/src/tools/search/tool.ts
CHANGED
|
@@ -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';
|