illuma-agents 1.0.59 → 1.0.61
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/src/graphs/Graph.ts
CHANGED
|
@@ -785,14 +785,11 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
785
785
|
let lastError: Error | undefined;
|
|
786
786
|
let attempts = 0;
|
|
787
787
|
|
|
788
|
-
// Create a silent config for structured output - we don't want tool call events
|
|
789
|
-
// to be emitted for the synthetic "response" tool used by withStructuredOutput()
|
|
790
|
-
// This prevents the UI from showing a fake tool call
|
|
791
|
-
const silentConfig = config ? { ...config, callbacks: undefined } : undefined;
|
|
792
|
-
|
|
793
788
|
while (attempts <= maxRetries) {
|
|
794
789
|
try {
|
|
795
|
-
|
|
790
|
+
// Note: We pass the original config here. The stream aggregator will filter out
|
|
791
|
+
// the synthetic "response" tool call events from withStructuredOutput()
|
|
792
|
+
const result = await structuredModel.invoke(finalMessages, config);
|
|
796
793
|
|
|
797
794
|
// Debug: log what we got back
|
|
798
795
|
console.log('[Graph] Structured output raw result type:', typeof result);
|
|
@@ -1139,10 +1136,17 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1139
1136
|
);
|
|
1140
1137
|
|
|
1141
1138
|
// Check if structured output mode is enabled
|
|
1142
|
-
|
|
1139
|
+
// IMPORTANT: If tools are available, we need to let the model use them first.
|
|
1140
|
+
// Only use structured output when:
|
|
1141
|
+
// 1. No tools are configured, OR
|
|
1142
|
+
// 2. The model has already used tools and is ready to give final response
|
|
1143
|
+
const hasTools = agentContext.tools && agentContext.tools.length > 0;
|
|
1144
|
+
const shouldUseStructuredOutputNow =
|
|
1143
1145
|
agentContext.isStructuredOutputMode &&
|
|
1144
|
-
agentContext.structuredOutput
|
|
1145
|
-
|
|
1146
|
+
agentContext.structuredOutput &&
|
|
1147
|
+
!hasTools; // Only use structured output immediately if no tools
|
|
1148
|
+
|
|
1149
|
+
if (shouldUseStructuredOutputNow) {
|
|
1146
1150
|
const schema = agentContext.getStructuredOutputSchema();
|
|
1147
1151
|
if (!schema) {
|
|
1148
1152
|
throw new Error('Structured output schema is not configured');
|
|
@@ -1193,7 +1197,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
|
|
|
1193
1197
|
currentModel: structuredModel,
|
|
1194
1198
|
finalMessages,
|
|
1195
1199
|
schema,
|
|
1196
|
-
structuredOutputConfig: agentContext.structuredOutput
|
|
1200
|
+
structuredOutputConfig: agentContext.structuredOutput!,
|
|
1197
1201
|
provider: agentContext.provider,
|
|
1198
1202
|
},
|
|
1199
1203
|
config
|
|
@@ -1466,6 +1470,107 @@ If I seem to be missing something we discussed earlier, just give me a quick rem
|
|
|
1466
1470
|
if (!result) {
|
|
1467
1471
|
throw new Error('No result after model invocation');
|
|
1468
1472
|
}
|
|
1473
|
+
|
|
1474
|
+
// Check if we need to apply structured output for the final response
|
|
1475
|
+
// This handles the case where tools were used, and now the model is giving its final answer
|
|
1476
|
+
const resultMessage = result.messages?.[0] as AIMessageChunk | undefined;
|
|
1477
|
+
const hasToolCalls = (resultMessage?.tool_calls?.length ?? 0) > 0;
|
|
1478
|
+
|
|
1479
|
+
if (
|
|
1480
|
+
agentContext.isStructuredOutputMode &&
|
|
1481
|
+
agentContext.structuredOutput &&
|
|
1482
|
+
!hasToolCalls && // Model is giving final response (no tool calls)
|
|
1483
|
+
hasTools // We skipped structured output earlier because tools were available
|
|
1484
|
+
) {
|
|
1485
|
+
const schema = agentContext.getStructuredOutputSchema();
|
|
1486
|
+
if (schema) {
|
|
1487
|
+
try {
|
|
1488
|
+
console.log('[Graph] Applying structured output for final response after tool execution');
|
|
1489
|
+
|
|
1490
|
+
// Get a fresh model for structured output
|
|
1491
|
+
const structuredClientOptions = { ...agentContext.clientOptions } as t.ClientOptions;
|
|
1492
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1493
|
+
(structuredClientOptions as any).streaming = false;
|
|
1494
|
+
|
|
1495
|
+
// Remove thinking configuration
|
|
1496
|
+
if (agentContext.provider === Providers.BEDROCK) {
|
|
1497
|
+
const bedrockOpts = structuredClientOptions as t.BedrockAnthropicClientOptions;
|
|
1498
|
+
if (bedrockOpts.additionalModelRequestFields) {
|
|
1499
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
1500
|
+
const additionalFields = Object.assign({}, bedrockOpts.additionalModelRequestFields) as any;
|
|
1501
|
+
delete additionalFields.thinking;
|
|
1502
|
+
delete additionalFields.budgetTokens;
|
|
1503
|
+
bedrockOpts.additionalModelRequestFields = additionalFields;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
if (agentContext.provider === Providers.ANTHROPIC) {
|
|
1507
|
+
const anthropicOpts = structuredClientOptions as t.AnthropicClientOptions;
|
|
1508
|
+
if (anthropicOpts.thinking) {
|
|
1509
|
+
delete anthropicOpts.thinking;
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
|
|
1513
|
+
const structuredModel = this.getNewModel({
|
|
1514
|
+
provider: agentContext.provider,
|
|
1515
|
+
clientOptions: structuredClientOptions,
|
|
1516
|
+
});
|
|
1517
|
+
|
|
1518
|
+
// Include the current result in the messages so the model knows what it just said
|
|
1519
|
+
const messagesWithResult = [...finalMessages];
|
|
1520
|
+
if (resultMessage) {
|
|
1521
|
+
messagesWithResult.push(resultMessage);
|
|
1522
|
+
}
|
|
1523
|
+
|
|
1524
|
+
const { structuredResponse, rawMessage } =
|
|
1525
|
+
await this.attemptStructuredInvoke(
|
|
1526
|
+
{
|
|
1527
|
+
currentModel: structuredModel,
|
|
1528
|
+
finalMessages: messagesWithResult,
|
|
1529
|
+
schema,
|
|
1530
|
+
structuredOutputConfig: agentContext.structuredOutput!,
|
|
1531
|
+
provider: agentContext.provider,
|
|
1532
|
+
},
|
|
1533
|
+
config
|
|
1534
|
+
);
|
|
1535
|
+
|
|
1536
|
+
// Emit structured output event
|
|
1537
|
+
await safeDispatchCustomEvent(
|
|
1538
|
+
GraphEvents.ON_STRUCTURED_OUTPUT,
|
|
1539
|
+
{
|
|
1540
|
+
structuredResponse,
|
|
1541
|
+
schema,
|
|
1542
|
+
raw: rawMessage,
|
|
1543
|
+
},
|
|
1544
|
+
config
|
|
1545
|
+
);
|
|
1546
|
+
|
|
1547
|
+
agentContext.currentUsage = rawMessage
|
|
1548
|
+
? this.getUsageMetadata(rawMessage)
|
|
1549
|
+
: undefined;
|
|
1550
|
+
this.cleanupSignalListener();
|
|
1551
|
+
|
|
1552
|
+
// Return clean message without tool_calls
|
|
1553
|
+
let cleanMessage: AIMessageChunk | undefined;
|
|
1554
|
+
if (rawMessage) {
|
|
1555
|
+
cleanMessage = new AIMessageChunk({
|
|
1556
|
+
content: JSON.stringify(structuredResponse, null, 2),
|
|
1557
|
+
id: rawMessage.id,
|
|
1558
|
+
response_metadata: rawMessage.response_metadata,
|
|
1559
|
+
usage_metadata: rawMessage.usage_metadata,
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
return {
|
|
1564
|
+
messages: cleanMessage ? [cleanMessage] : [],
|
|
1565
|
+
structuredResponse,
|
|
1566
|
+
};
|
|
1567
|
+
} catch (structuredError) {
|
|
1568
|
+
console.error('[Graph] Structured output failed after tool execution:', structuredError);
|
|
1569
|
+
// Fall through to return normal result
|
|
1570
|
+
}
|
|
1571
|
+
}
|
|
1572
|
+
}
|
|
1573
|
+
|
|
1469
1574
|
agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
|
|
1470
1575
|
this.cleanupSignalListener();
|
|
1471
1576
|
return result;
|