illuma-agents 1.0.60 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "illuma-agents",
3
- "version": "1.0.60",
3
+ "version": "1.0.61",
4
4
  "main": "./dist/cjs/main.cjs",
5
5
  "module": "./dist/esm/main.mjs",
6
6
  "types": "./dist/types/index.d.ts",
@@ -1136,10 +1136,17 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1136
1136
  );
1137
1137
 
1138
1138
  // Check if structured output mode is enabled
1139
- if (
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 =
1140
1145
  agentContext.isStructuredOutputMode &&
1141
- agentContext.structuredOutput
1142
- ) {
1146
+ agentContext.structuredOutput &&
1147
+ !hasTools; // Only use structured output immediately if no tools
1148
+
1149
+ if (shouldUseStructuredOutputNow) {
1143
1150
  const schema = agentContext.getStructuredOutputSchema();
1144
1151
  if (!schema) {
1145
1152
  throw new Error('Structured output schema is not configured');
@@ -1190,7 +1197,7 @@ export class StandardGraph extends Graph<t.BaseGraphState, t.GraphNode> {
1190
1197
  currentModel: structuredModel,
1191
1198
  finalMessages,
1192
1199
  schema,
1193
- structuredOutputConfig: agentContext.structuredOutput,
1200
+ structuredOutputConfig: agentContext.structuredOutput!,
1194
1201
  provider: agentContext.provider,
1195
1202
  },
1196
1203
  config
@@ -1463,6 +1470,107 @@ If I seem to be missing something we discussed earlier, just give me a quick rem
1463
1470
  if (!result) {
1464
1471
  throw new Error('No result after model invocation');
1465
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
+
1466
1574
  agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
1467
1575
  this.cleanupSignalListener();
1468
1576
  return result;