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.
@@ -500,13 +500,11 @@ class StandardGraph extends Graph {
500
500
  });
501
501
  let lastError;
502
502
  let attempts = 0;
503
- // Create a silent config for structured output - we don't want tool call events
504
- // to be emitted for the synthetic "response" tool used by withStructuredOutput()
505
- // This prevents the UI from showing a fake tool call
506
- const silentConfig = config ? { ...config, callbacks: undefined } : undefined;
507
503
  while (attempts <= maxRetries) {
508
504
  try {
509
- const result = await structuredModel.invoke(finalMessages, silentConfig);
505
+ // Note: We pass the original config here. The stream aggregator will filter out
506
+ // the synthetic "response" tool call events from withStructuredOutput()
507
+ const result = await structuredModel.invoke(finalMessages, config);
510
508
  // Debug: log what we got back
511
509
  console.log('[Graph] Structured output raw result type:', typeof result);
512
510
  if (result?.raw) {
@@ -766,8 +764,15 @@ class StandardGraph extends Graph {
766
764
  analytics: contextAnalytics,
767
765
  }, config);
768
766
  // Check if structured output mode is enabled
769
- if (agentContext.isStructuredOutputMode &&
770
- agentContext.structuredOutput) {
767
+ // IMPORTANT: If tools are available, we need to let the model use them first.
768
+ // Only use structured output when:
769
+ // 1. No tools are configured, OR
770
+ // 2. The model has already used tools and is ready to give final response
771
+ const hasTools = agentContext.tools && agentContext.tools.length > 0;
772
+ const shouldUseStructuredOutputNow = agentContext.isStructuredOutputMode &&
773
+ agentContext.structuredOutput &&
774
+ !hasTools; // Only use structured output immediately if no tools
775
+ if (shouldUseStructuredOutputNow) {
771
776
  const schema = agentContext.getStructuredOutputSchema();
772
777
  if (!schema) {
773
778
  throw new Error('Structured output schema is not configured');
@@ -1017,6 +1022,87 @@ If I seem to be missing something we discussed earlier, just give me a quick rem
1017
1022
  if (!result) {
1018
1023
  throw new Error('No result after model invocation');
1019
1024
  }
1025
+ // Check if we need to apply structured output for the final response
1026
+ // This handles the case where tools were used, and now the model is giving its final answer
1027
+ const resultMessage = result.messages?.[0];
1028
+ const hasToolCalls = (resultMessage?.tool_calls?.length ?? 0) > 0;
1029
+ if (agentContext.isStructuredOutputMode &&
1030
+ agentContext.structuredOutput &&
1031
+ !hasToolCalls && // Model is giving final response (no tool calls)
1032
+ hasTools // We skipped structured output earlier because tools were available
1033
+ ) {
1034
+ const schema = agentContext.getStructuredOutputSchema();
1035
+ if (schema) {
1036
+ try {
1037
+ console.log('[Graph] Applying structured output for final response after tool execution');
1038
+ // Get a fresh model for structured output
1039
+ const structuredClientOptions = { ...agentContext.clientOptions };
1040
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1041
+ structuredClientOptions.streaming = false;
1042
+ // Remove thinking configuration
1043
+ if (agentContext.provider === Providers.BEDROCK) {
1044
+ const bedrockOpts = structuredClientOptions;
1045
+ if (bedrockOpts.additionalModelRequestFields) {
1046
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
1047
+ const additionalFields = Object.assign({}, bedrockOpts.additionalModelRequestFields);
1048
+ delete additionalFields.thinking;
1049
+ delete additionalFields.budgetTokens;
1050
+ bedrockOpts.additionalModelRequestFields = additionalFields;
1051
+ }
1052
+ }
1053
+ if (agentContext.provider === Providers.ANTHROPIC) {
1054
+ const anthropicOpts = structuredClientOptions;
1055
+ if (anthropicOpts.thinking) {
1056
+ delete anthropicOpts.thinking;
1057
+ }
1058
+ }
1059
+ const structuredModel = this.getNewModel({
1060
+ provider: agentContext.provider,
1061
+ clientOptions: structuredClientOptions,
1062
+ });
1063
+ // Include the current result in the messages so the model knows what it just said
1064
+ const messagesWithResult = [...finalMessages];
1065
+ if (resultMessage) {
1066
+ messagesWithResult.push(resultMessage);
1067
+ }
1068
+ const { structuredResponse, rawMessage } = await this.attemptStructuredInvoke({
1069
+ currentModel: structuredModel,
1070
+ finalMessages: messagesWithResult,
1071
+ schema,
1072
+ structuredOutputConfig: agentContext.structuredOutput,
1073
+ provider: agentContext.provider,
1074
+ }, config);
1075
+ // Emit structured output event
1076
+ await safeDispatchCustomEvent(GraphEvents.ON_STRUCTURED_OUTPUT, {
1077
+ structuredResponse,
1078
+ schema,
1079
+ raw: rawMessage,
1080
+ }, config);
1081
+ agentContext.currentUsage = rawMessage
1082
+ ? this.getUsageMetadata(rawMessage)
1083
+ : undefined;
1084
+ this.cleanupSignalListener();
1085
+ // Return clean message without tool_calls
1086
+ let cleanMessage;
1087
+ if (rawMessage) {
1088
+ cleanMessage = new AIMessageChunk({
1089
+ content: JSON.stringify(structuredResponse, null, 2),
1090
+ id: rawMessage.id,
1091
+ response_metadata: rawMessage.response_metadata,
1092
+ usage_metadata: rawMessage.usage_metadata,
1093
+ });
1094
+ }
1095
+ return {
1096
+ messages: cleanMessage ? [cleanMessage] : [],
1097
+ structuredResponse,
1098
+ };
1099
+ }
1100
+ catch (structuredError) {
1101
+ console.error('[Graph] Structured output failed after tool execution:', structuredError);
1102
+ // Fall through to return normal result
1103
+ }
1104
+ }
1105
+ }
1020
1106
  agentContext.currentUsage = this.getUsageMetadata(result.messages?.[0]);
1021
1107
  this.cleanupSignalListener();
1022
1108
  return result;