@inkeep/agents-run-api 0.23.3 → 0.23.5

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 (3) hide show
  1. package/dist/index.cjs +553 -481
  2. package/dist/index.js +552 -480
  3. package/package.json +2 -2
package/dist/index.js CHANGED
@@ -7677,326 +7677,334 @@ var Agent = class {
7677
7677
  }
7678
7678
  }
7679
7679
  async generate(userMessage, runtimeContext) {
7680
- return tracer.startActiveSpan("agent.generate", async (span) => {
7681
- const contextId = runtimeContext?.contextId || "default";
7682
- const taskId = runtimeContext?.metadata?.taskId || "unknown";
7683
- const streamRequestId = runtimeContext?.metadata?.streamRequestId;
7684
- const sessionId = streamRequestId || "fallback-session";
7685
- try {
7686
- this.streamRequestId = streamRequestId;
7687
- this.streamHelper = streamRequestId ? getStreamHelper(streamRequestId) : void 0;
7688
- const conversationId = runtimeContext?.metadata?.conversationId;
7689
- if (conversationId) {
7690
- this.setConversationId(conversationId);
7680
+ return tracer.startActiveSpan(
7681
+ "agent.generate",
7682
+ {
7683
+ attributes: {
7684
+ "subagent.id": this.config.id,
7685
+ "subagent.name": this.config.name
7691
7686
  }
7692
- const [
7693
- mcpTools,
7694
- systemPrompt,
7695
- thinkingSystemPrompt,
7696
- functionTools,
7697
- relationTools,
7698
- defaultTools
7699
- ] = await tracer.startActiveSpan(
7700
- "agent.load_tools",
7701
- {
7702
- attributes: {
7703
- "subAgent.name": this.config.name,
7704
- "session.id": sessionId
7705
- }
7706
- },
7707
- async (childSpan) => {
7708
- try {
7709
- const result = await Promise.all([
7710
- this.getMcpTools(sessionId, streamRequestId),
7711
- this.buildSystemPrompt(runtimeContext, false),
7712
- // Normal prompt with data components
7713
- this.buildSystemPrompt(runtimeContext, true),
7714
- // Thinking prompt without data components
7715
- this.getFunctionTools(sessionId, streamRequestId),
7716
- Promise.resolve(this.getRelationTools(runtimeContext, sessionId)),
7717
- this.getDefaultTools(streamRequestId)
7718
- ]);
7719
- childSpan.setStatus({ code: SpanStatusCode.OK });
7720
- return result;
7721
- } catch (err) {
7722
- const errorObj = err instanceof Error ? err : new Error(String(err));
7723
- setSpanWithError(childSpan, errorObj);
7724
- throw err;
7725
- } finally {
7726
- childSpan.end();
7727
- }
7728
- }
7729
- );
7730
- const allTools = {
7731
- ...mcpTools,
7732
- ...functionTools,
7733
- ...relationTools,
7734
- ...defaultTools
7735
- };
7736
- const sanitizedTools = this.sanitizeToolsForAISDK(allTools);
7737
- let conversationHistory = "";
7738
- const historyConfig = this.config.conversationHistoryConfig ?? createDefaultConversationHistoryConfig();
7739
- if (historyConfig && historyConfig.mode !== "none") {
7740
- if (historyConfig.mode === "full") {
7741
- conversationHistory = await getFormattedConversationHistory({
7742
- tenantId: this.config.tenantId,
7743
- projectId: this.config.projectId,
7744
- conversationId: contextId,
7745
- currentMessage: userMessage,
7746
- options: historyConfig,
7747
- filters: {}
7748
- });
7749
- } else if (historyConfig.mode === "scoped") {
7750
- conversationHistory = await getFormattedConversationHistory({
7751
- tenantId: this.config.tenantId,
7752
- projectId: this.config.projectId,
7753
- conversationId: contextId,
7754
- currentMessage: userMessage,
7755
- options: historyConfig,
7756
- filters: {
7757
- subAgentId: this.config.id,
7758
- taskId
7759
- }
7760
- });
7687
+ },
7688
+ async (span) => {
7689
+ const contextId = runtimeContext?.contextId || "default";
7690
+ const taskId = runtimeContext?.metadata?.taskId || "unknown";
7691
+ const streamRequestId = runtimeContext?.metadata?.streamRequestId;
7692
+ const sessionId = streamRequestId || "fallback-session";
7693
+ try {
7694
+ this.streamRequestId = streamRequestId;
7695
+ this.streamHelper = streamRequestId ? getStreamHelper(streamRequestId) : void 0;
7696
+ const conversationId = runtimeContext?.metadata?.conversationId;
7697
+ if (conversationId) {
7698
+ this.setConversationId(conversationId);
7761
7699
  }
7762
- }
7763
- const primaryModelSettings = this.getPrimaryModel();
7764
- const modelSettings = ModelFactory.prepareGenerationConfig(primaryModelSettings);
7765
- let response;
7766
- let textResponse;
7767
- const hasStructuredOutput = this.config.dataComponents && this.config.dataComponents.length > 0;
7768
- const shouldStreamPhase1 = this.getStreamingHelper() && !hasStructuredOutput;
7769
- const MAX_ALLOWED_TIMEOUT_MS = 6e5;
7770
- const configuredTimeout = modelSettings.maxDuration ? Math.min(modelSettings.maxDuration * 1e3, MAX_ALLOWED_TIMEOUT_MS) : shouldStreamPhase1 ? CONSTANTS.PHASE_1_TIMEOUT_MS : CONSTANTS.NON_STREAMING_PHASE_1_TIMEOUT_MS;
7771
- const timeoutMs = Math.min(configuredTimeout, MAX_ALLOWED_TIMEOUT_MS);
7772
- if (modelSettings.maxDuration && modelSettings.maxDuration * 1e3 > MAX_ALLOWED_TIMEOUT_MS) {
7773
- logger15.warn(
7700
+ const [
7701
+ mcpTools,
7702
+ systemPrompt,
7703
+ thinkingSystemPrompt,
7704
+ functionTools,
7705
+ relationTools,
7706
+ defaultTools
7707
+ ] = await tracer.startActiveSpan(
7708
+ "agent.load_tools",
7774
7709
  {
7775
- requestedTimeout: modelSettings.maxDuration * 1e3,
7776
- appliedTimeout: timeoutMs,
7777
- maxAllowed: MAX_ALLOWED_TIMEOUT_MS
7778
- },
7779
- "Requested timeout exceeded maximum allowed, capping to 10 minutes"
7780
- );
7781
- }
7782
- const phase1SystemPrompt = hasStructuredOutput ? thinkingSystemPrompt : systemPrompt;
7783
- const messages = [];
7784
- messages.push({ role: "system", content: phase1SystemPrompt });
7785
- if (conversationHistory.trim() !== "") {
7786
- messages.push({ role: "user", content: conversationHistory });
7787
- }
7788
- messages.push({
7789
- role: "user",
7790
- content: userMessage
7791
- });
7792
- if (shouldStreamPhase1) {
7793
- const streamConfig = {
7794
- ...modelSettings,
7795
- toolChoice: "auto"
7796
- // Allow natural text + tools
7797
- };
7798
- const streamResult = streamText({
7799
- ...streamConfig,
7800
- messages,
7801
- tools: sanitizedTools,
7802
- stopWhen: async ({ steps }) => {
7803
- const last = steps.at(-1);
7804
- if (last && "text" in last && last.text) {
7805
- try {
7806
- await agentSessionManager.recordEvent(
7807
- this.getStreamRequestId(),
7808
- "agent_reasoning",
7809
- this.config.id,
7810
- {
7811
- parts: [{ type: "text", content: last.text }]
7812
- }
7813
- );
7814
- } catch (error) {
7815
- logger15.debug({ error }, "Failed to track agent reasoning");
7816
- }
7817
- }
7818
- if (steps.length >= 2) {
7819
- const previousStep = steps[steps.length - 2];
7820
- if (previousStep && "toolCalls" in previousStep && previousStep.toolCalls) {
7821
- const hasTransferCall = previousStep.toolCalls.some(
7822
- (tc) => tc.toolName.startsWith("transfer_to_")
7823
- );
7824
- if (hasTransferCall && "toolResults" in previousStep && previousStep.toolResults) {
7825
- return true;
7826
- }
7827
- }
7710
+ attributes: {
7711
+ "subAgent.name": this.config.name,
7712
+ "session.id": sessionId
7828
7713
  }
7829
- return steps.length >= this.getMaxGenerationSteps();
7830
- },
7831
- experimental_telemetry: {
7832
- isEnabled: true,
7833
- functionId: this.config.id,
7834
- recordInputs: true,
7835
- recordOutputs: true
7836
7714
  },
7837
- abortSignal: AbortSignal.timeout(timeoutMs)
7838
- });
7839
- const streamHelper = this.getStreamingHelper();
7840
- if (!streamHelper) {
7841
- throw new Error("Stream helper is unexpectedly undefined in streaming context");
7842
- }
7843
- const session = toolSessionManager.getSession(sessionId);
7844
- const artifactParserOptions = {
7845
- sessionId,
7846
- taskId: session?.taskId,
7847
- projectId: session?.projectId,
7848
- artifactComponents: this.artifactComponents,
7849
- streamRequestId: this.getStreamRequestId(),
7850
- subAgentId: this.config.id
7851
- };
7852
- const parser = new IncrementalStreamParser(
7853
- streamHelper,
7854
- this.config.tenantId,
7855
- contextId,
7856
- artifactParserOptions
7715
+ async (childSpan) => {
7716
+ try {
7717
+ const result = await Promise.all([
7718
+ this.getMcpTools(sessionId, streamRequestId),
7719
+ this.buildSystemPrompt(runtimeContext, false),
7720
+ // Normal prompt with data components
7721
+ this.buildSystemPrompt(runtimeContext, true),
7722
+ // Thinking prompt without data components
7723
+ this.getFunctionTools(sessionId, streamRequestId),
7724
+ Promise.resolve(this.getRelationTools(runtimeContext, sessionId)),
7725
+ this.getDefaultTools(streamRequestId)
7726
+ ]);
7727
+ childSpan.setStatus({ code: SpanStatusCode.OK });
7728
+ return result;
7729
+ } catch (err) {
7730
+ const errorObj = err instanceof Error ? err : new Error(String(err));
7731
+ setSpanWithError(childSpan, errorObj);
7732
+ throw err;
7733
+ } finally {
7734
+ childSpan.end();
7735
+ }
7736
+ }
7857
7737
  );
7858
- for await (const event of streamResult.fullStream) {
7859
- switch (event.type) {
7860
- case "text-delta":
7861
- await parser.processTextChunk(event.text);
7862
- break;
7863
- case "tool-call":
7864
- parser.markToolResult();
7865
- break;
7866
- case "tool-result":
7867
- parser.markToolResult();
7868
- break;
7869
- case "finish":
7870
- if (event.finishReason === "tool-calls") {
7871
- parser.markToolResult();
7872
- }
7873
- break;
7874
- case "error":
7875
- if (event.error instanceof Error) {
7876
- throw event.error;
7877
- } else {
7878
- const errorMessage = event.error?.error?.message;
7879
- throw new Error(errorMessage);
7738
+ const allTools = {
7739
+ ...mcpTools,
7740
+ ...functionTools,
7741
+ ...relationTools,
7742
+ ...defaultTools
7743
+ };
7744
+ const sanitizedTools = this.sanitizeToolsForAISDK(allTools);
7745
+ let conversationHistory = "";
7746
+ const historyConfig = this.config.conversationHistoryConfig ?? createDefaultConversationHistoryConfig();
7747
+ if (historyConfig && historyConfig.mode !== "none") {
7748
+ if (historyConfig.mode === "full") {
7749
+ conversationHistory = await getFormattedConversationHistory({
7750
+ tenantId: this.config.tenantId,
7751
+ projectId: this.config.projectId,
7752
+ conversationId: contextId,
7753
+ currentMessage: userMessage,
7754
+ options: historyConfig,
7755
+ filters: {}
7756
+ });
7757
+ } else if (historyConfig.mode === "scoped") {
7758
+ conversationHistory = await getFormattedConversationHistory({
7759
+ tenantId: this.config.tenantId,
7760
+ projectId: this.config.projectId,
7761
+ conversationId: contextId,
7762
+ currentMessage: userMessage,
7763
+ options: historyConfig,
7764
+ filters: {
7765
+ subAgentId: this.config.id,
7766
+ taskId
7880
7767
  }
7768
+ });
7881
7769
  }
7882
7770
  }
7883
- await parser.finalize();
7884
- response = await streamResult;
7885
- const collectedParts = parser.getCollectedParts();
7886
- if (collectedParts.length > 0) {
7887
- response.formattedContent = {
7888
- parts: collectedParts.map((part) => ({
7889
- kind: part.kind,
7890
- ...part.kind === "text" && { text: part.text },
7891
- ...part.kind === "data" && { data: part.data }
7892
- }))
7893
- };
7771
+ const primaryModelSettings = this.getPrimaryModel();
7772
+ const modelSettings = ModelFactory.prepareGenerationConfig(primaryModelSettings);
7773
+ let response;
7774
+ let textResponse;
7775
+ const hasStructuredOutput = this.config.dataComponents && this.config.dataComponents.length > 0;
7776
+ const shouldStreamPhase1 = this.getStreamingHelper() && !hasStructuredOutput;
7777
+ const MAX_ALLOWED_TIMEOUT_MS = 6e5;
7778
+ const configuredTimeout = modelSettings.maxDuration ? Math.min(modelSettings.maxDuration * 1e3, MAX_ALLOWED_TIMEOUT_MS) : shouldStreamPhase1 ? CONSTANTS.PHASE_1_TIMEOUT_MS : CONSTANTS.NON_STREAMING_PHASE_1_TIMEOUT_MS;
7779
+ const timeoutMs = Math.min(configuredTimeout, MAX_ALLOWED_TIMEOUT_MS);
7780
+ if (modelSettings.maxDuration && modelSettings.maxDuration * 1e3 > MAX_ALLOWED_TIMEOUT_MS) {
7781
+ logger15.warn(
7782
+ {
7783
+ requestedTimeout: modelSettings.maxDuration * 1e3,
7784
+ appliedTimeout: timeoutMs,
7785
+ maxAllowed: MAX_ALLOWED_TIMEOUT_MS
7786
+ },
7787
+ "Requested timeout exceeded maximum allowed, capping to 10 minutes"
7788
+ );
7894
7789
  }
7895
- const streamedContent = parser.getAllStreamedContent();
7896
- if (streamedContent.length > 0) {
7897
- response.streamedContent = {
7898
- parts: streamedContent.map((part) => ({
7899
- kind: part.kind,
7900
- ...part.kind === "text" && { text: part.text },
7901
- ...part.kind === "data" && { data: part.data }
7902
- }))
7903
- };
7790
+ const phase1SystemPrompt = hasStructuredOutput ? thinkingSystemPrompt : systemPrompt;
7791
+ const messages = [];
7792
+ messages.push({ role: "system", content: phase1SystemPrompt });
7793
+ if (conversationHistory.trim() !== "") {
7794
+ messages.push({ role: "user", content: conversationHistory });
7904
7795
  }
7905
- } else {
7906
- let genConfig;
7907
- if (hasStructuredOutput) {
7908
- genConfig = {
7909
- ...modelSettings,
7910
- toolChoice: "required"
7911
- // Force tool usage, prevent text generation
7912
- };
7913
- } else {
7914
- genConfig = {
7796
+ messages.push({
7797
+ role: "user",
7798
+ content: userMessage
7799
+ });
7800
+ if (shouldStreamPhase1) {
7801
+ const streamConfig = {
7915
7802
  ...modelSettings,
7916
7803
  toolChoice: "auto"
7917
- // Allow both tools and text generation
7804
+ // Allow natural text + tools
7918
7805
  };
7919
- }
7920
- response = await generateText({
7921
- ...genConfig,
7922
- messages,
7923
- tools: sanitizedTools,
7924
- stopWhen: async ({ steps }) => {
7925
- const last = steps.at(-1);
7926
- if (last && "text" in last && last.text) {
7927
- try {
7928
- await agentSessionManager.recordEvent(
7929
- this.getStreamRequestId(),
7930
- "agent_reasoning",
7931
- this.config.id,
7932
- {
7933
- parts: [{ type: "text", content: last.text }]
7934
- }
7935
- );
7936
- } catch (error) {
7937
- logger15.debug({ error }, "Failed to track agent reasoning");
7806
+ const streamResult = streamText({
7807
+ ...streamConfig,
7808
+ messages,
7809
+ tools: sanitizedTools,
7810
+ stopWhen: async ({ steps }) => {
7811
+ const last = steps.at(-1);
7812
+ if (last && "text" in last && last.text) {
7813
+ try {
7814
+ await agentSessionManager.recordEvent(
7815
+ this.getStreamRequestId(),
7816
+ "agent_reasoning",
7817
+ this.config.id,
7818
+ {
7819
+ parts: [{ type: "text", content: last.text }]
7820
+ }
7821
+ );
7822
+ } catch (error) {
7823
+ logger15.debug({ error }, "Failed to track agent reasoning");
7824
+ }
7938
7825
  }
7939
- }
7940
- if (steps.length >= 2) {
7941
- const previousStep = steps[steps.length - 2];
7942
- if (previousStep && "toolCalls" in previousStep && previousStep.toolCalls) {
7943
- const hasStopTool = previousStep.toolCalls.some(
7944
- (tc) => tc.toolName.startsWith("transfer_to_") || tc.toolName === "thinking_complete"
7945
- );
7946
- if (hasStopTool && "toolResults" in previousStep && previousStep.toolResults) {
7947
- return true;
7826
+ if (steps.length >= 2) {
7827
+ const previousStep = steps[steps.length - 2];
7828
+ if (previousStep && "toolCalls" in previousStep && previousStep.toolCalls) {
7829
+ const hasTransferCall = previousStep.toolCalls.some(
7830
+ (tc) => tc.toolName.startsWith("transfer_to_")
7831
+ );
7832
+ if (hasTransferCall && "toolResults" in previousStep && previousStep.toolResults) {
7833
+ return true;
7834
+ }
7948
7835
  }
7949
7836
  }
7837
+ return steps.length >= this.getMaxGenerationSteps();
7838
+ },
7839
+ experimental_telemetry: {
7840
+ isEnabled: true,
7841
+ functionId: this.config.id,
7842
+ recordInputs: true,
7843
+ recordOutputs: true
7844
+ },
7845
+ abortSignal: AbortSignal.timeout(timeoutMs)
7846
+ });
7847
+ const streamHelper = this.getStreamingHelper();
7848
+ if (!streamHelper) {
7849
+ throw new Error("Stream helper is unexpectedly undefined in streaming context");
7850
+ }
7851
+ const session = toolSessionManager.getSession(sessionId);
7852
+ const artifactParserOptions = {
7853
+ sessionId,
7854
+ taskId: session?.taskId,
7855
+ projectId: session?.projectId,
7856
+ artifactComponents: this.artifactComponents,
7857
+ streamRequestId: this.getStreamRequestId(),
7858
+ subAgentId: this.config.id
7859
+ };
7860
+ const parser = new IncrementalStreamParser(
7861
+ streamHelper,
7862
+ this.config.tenantId,
7863
+ contextId,
7864
+ artifactParserOptions
7865
+ );
7866
+ for await (const event of streamResult.fullStream) {
7867
+ switch (event.type) {
7868
+ case "text-delta":
7869
+ await parser.processTextChunk(event.text);
7870
+ break;
7871
+ case "tool-call":
7872
+ parser.markToolResult();
7873
+ break;
7874
+ case "tool-result":
7875
+ parser.markToolResult();
7876
+ break;
7877
+ case "finish":
7878
+ if (event.finishReason === "tool-calls") {
7879
+ parser.markToolResult();
7880
+ }
7881
+ break;
7882
+ case "error":
7883
+ if (event.error instanceof Error) {
7884
+ throw event.error;
7885
+ } else {
7886
+ const errorMessage = event.error?.error?.message;
7887
+ throw new Error(errorMessage);
7888
+ }
7950
7889
  }
7951
- return steps.length >= this.getMaxGenerationSteps();
7952
- },
7953
- experimental_telemetry: {
7954
- isEnabled: true,
7955
- functionId: this.config.id,
7956
- recordInputs: true,
7957
- recordOutputs: true,
7958
- metadata: {
7959
- phase: "planning"
7960
- }
7961
- },
7962
- abortSignal: AbortSignal.timeout(timeoutMs)
7963
- });
7964
- }
7965
- if (response.steps) {
7966
- const resolvedSteps = await response.steps;
7967
- response = { ...response, steps: resolvedSteps };
7968
- }
7969
- if (hasStructuredOutput && !hasToolCallWithPrefix("transfer_to_")(response)) {
7970
- const thinkingCompleteCall = response.steps?.flatMap((s) => s.toolCalls || [])?.find((tc) => tc.toolName === "thinking_complete");
7971
- if (thinkingCompleteCall) {
7972
- const reasoningFlow = [];
7973
- if (response.steps) {
7974
- response.steps.forEach((step) => {
7975
- if (step.toolCalls && step.toolResults) {
7976
- step.toolCalls.forEach((call, index) => {
7977
- const result = step.toolResults[index];
7978
- if (result) {
7979
- const storedResult = toolSessionManager.getToolResult(
7980
- sessionId,
7981
- result.toolCallId
7982
- );
7983
- const toolName = storedResult?.toolName || call.toolName;
7984
- if (toolName === "thinking_complete") {
7985
- return;
7890
+ }
7891
+ await parser.finalize();
7892
+ response = await streamResult;
7893
+ const collectedParts = parser.getCollectedParts();
7894
+ if (collectedParts.length > 0) {
7895
+ response.formattedContent = {
7896
+ parts: collectedParts.map((part) => ({
7897
+ kind: part.kind,
7898
+ ...part.kind === "text" && { text: part.text },
7899
+ ...part.kind === "data" && { data: part.data }
7900
+ }))
7901
+ };
7902
+ }
7903
+ const streamedContent = parser.getAllStreamedContent();
7904
+ if (streamedContent.length > 0) {
7905
+ response.streamedContent = {
7906
+ parts: streamedContent.map((part) => ({
7907
+ kind: part.kind,
7908
+ ...part.kind === "text" && { text: part.text },
7909
+ ...part.kind === "data" && { data: part.data }
7910
+ }))
7911
+ };
7912
+ }
7913
+ } else {
7914
+ let genConfig;
7915
+ if (hasStructuredOutput) {
7916
+ genConfig = {
7917
+ ...modelSettings,
7918
+ toolChoice: "required"
7919
+ // Force tool usage, prevent text generation
7920
+ };
7921
+ } else {
7922
+ genConfig = {
7923
+ ...modelSettings,
7924
+ toolChoice: "auto"
7925
+ // Allow both tools and text generation
7926
+ };
7927
+ }
7928
+ response = await generateText({
7929
+ ...genConfig,
7930
+ messages,
7931
+ tools: sanitizedTools,
7932
+ stopWhen: async ({ steps }) => {
7933
+ const last = steps.at(-1);
7934
+ if (last && "text" in last && last.text) {
7935
+ try {
7936
+ await agentSessionManager.recordEvent(
7937
+ this.getStreamRequestId(),
7938
+ "agent_reasoning",
7939
+ this.config.id,
7940
+ {
7941
+ parts: [{ type: "text", content: last.text }]
7986
7942
  }
7987
- const actualResult = storedResult?.result || result.result || result;
7988
- const actualArgs = storedResult?.args || call.args;
7989
- const cleanResult = actualResult && typeof actualResult === "object" && !Array.isArray(actualResult) ? Object.fromEntries(
7990
- Object.entries(actualResult).filter(
7991
- ([key]) => key !== "_structureHints"
7992
- )
7993
- ) : actualResult;
7994
- const input = actualArgs ? JSON.stringify(actualArgs, null, 2) : "No input";
7995
- const output = typeof cleanResult === "string" ? cleanResult : JSON.stringify(cleanResult, null, 2);
7996
- let structureHintsFormatted = "";
7997
- if (actualResult?._structureHints && this.artifactComponents && this.artifactComponents.length > 0) {
7998
- const hints = actualResult._structureHints;
7999
- structureHintsFormatted = `
7943
+ );
7944
+ } catch (error) {
7945
+ logger15.debug({ error }, "Failed to track agent reasoning");
7946
+ }
7947
+ }
7948
+ if (steps.length >= 2) {
7949
+ const previousStep = steps[steps.length - 2];
7950
+ if (previousStep && "toolCalls" in previousStep && previousStep.toolCalls) {
7951
+ const hasStopTool = previousStep.toolCalls.some(
7952
+ (tc) => tc.toolName.startsWith("transfer_to_") || tc.toolName === "thinking_complete"
7953
+ );
7954
+ if (hasStopTool && "toolResults" in previousStep && previousStep.toolResults) {
7955
+ return true;
7956
+ }
7957
+ }
7958
+ }
7959
+ return steps.length >= this.getMaxGenerationSteps();
7960
+ },
7961
+ experimental_telemetry: {
7962
+ isEnabled: true,
7963
+ functionId: this.config.id,
7964
+ recordInputs: true,
7965
+ recordOutputs: true,
7966
+ metadata: {
7967
+ phase: "planning"
7968
+ }
7969
+ },
7970
+ abortSignal: AbortSignal.timeout(timeoutMs)
7971
+ });
7972
+ }
7973
+ if (response.steps) {
7974
+ const resolvedSteps = await response.steps;
7975
+ response = { ...response, steps: resolvedSteps };
7976
+ }
7977
+ if (hasStructuredOutput && !hasToolCallWithPrefix("transfer_to_")(response)) {
7978
+ const thinkingCompleteCall = response.steps?.flatMap((s) => s.toolCalls || [])?.find((tc) => tc.toolName === "thinking_complete");
7979
+ if (thinkingCompleteCall) {
7980
+ const reasoningFlow = [];
7981
+ if (response.steps) {
7982
+ response.steps.forEach((step) => {
7983
+ if (step.toolCalls && step.toolResults) {
7984
+ step.toolCalls.forEach((call, index) => {
7985
+ const result = step.toolResults[index];
7986
+ if (result) {
7987
+ const storedResult = toolSessionManager.getToolResult(
7988
+ sessionId,
7989
+ result.toolCallId
7990
+ );
7991
+ const toolName = storedResult?.toolName || call.toolName;
7992
+ if (toolName === "thinking_complete") {
7993
+ return;
7994
+ }
7995
+ const actualResult = storedResult?.result || result.result || result;
7996
+ const actualArgs = storedResult?.args || call.args;
7997
+ const cleanResult = actualResult && typeof actualResult === "object" && !Array.isArray(actualResult) ? Object.fromEntries(
7998
+ Object.entries(actualResult).filter(
7999
+ ([key]) => key !== "_structureHints"
8000
+ )
8001
+ ) : actualResult;
8002
+ const input = actualArgs ? JSON.stringify(actualArgs, null, 2) : "No input";
8003
+ const output = typeof cleanResult === "string" ? cleanResult : JSON.stringify(cleanResult, null, 2);
8004
+ let structureHintsFormatted = "";
8005
+ if (actualResult?._structureHints && this.artifactComponents && this.artifactComponents.length > 0) {
8006
+ const hints = actualResult._structureHints;
8007
+ structureHintsFormatted = `
8000
8008
  ### \u{1F4CA} Structure Hints for Artifact Creation
8001
8009
 
8002
8010
  **Terminal Field Paths (${hints.terminalPaths?.length || 0} found):**
@@ -8020,8 +8028,8 @@ ${hints.commonFields?.map((field) => ` \u2022 ${field}`).join("\n") || " None
8020
8028
 
8021
8029
  **Forbidden Syntax:** ${hints.forbiddenSyntax || "Use these paths for artifact base selectors."}
8022
8030
  `;
8023
- }
8024
- const formattedResult = `## Tool: ${call.toolName}
8031
+ }
8032
+ const formattedResult = `## Tool: ${call.toolName}
8025
8033
 
8026
8034
  ### \u{1F527} TOOL_CALL_ID: ${result.toolCallId}
8027
8035
 
@@ -8030,130 +8038,61 @@ ${input}
8030
8038
 
8031
8039
  ### Output
8032
8040
  ${output}${structureHintsFormatted}`;
8033
- reasoningFlow.push({
8034
- role: "assistant",
8035
- content: formattedResult
8036
- });
8037
- }
8038
- });
8039
- }
8040
- });
8041
- }
8042
- const componentSchemas = [];
8043
- if (this.config.dataComponents && this.config.dataComponents.length > 0) {
8044
- this.config.dataComponents.forEach((dc) => {
8045
- const propsSchema = jsonSchemaToZod(dc.props);
8046
- componentSchemas.push(
8047
- z.object({
8048
- id: z.string(),
8049
- name: z.literal(dc.name),
8050
- props: propsSchema
8051
- })
8052
- );
8053
- });
8054
- }
8055
- if (this.artifactComponents.length > 0) {
8056
- const artifactCreateSchemas = ArtifactCreateSchema.getSchemas(
8057
- this.artifactComponents
8058
- );
8059
- componentSchemas.push(...artifactCreateSchemas);
8060
- componentSchemas.push(ArtifactReferenceSchema.getSchema());
8061
- }
8062
- let dataComponentsSchema;
8063
- if (componentSchemas.length === 1) {
8064
- dataComponentsSchema = componentSchemas[0];
8065
- } else {
8066
- dataComponentsSchema = z.union(
8067
- componentSchemas
8068
- );
8069
- }
8070
- const structuredModelSettings = ModelFactory.prepareGenerationConfig(
8071
- this.getStructuredOutputModel()
8072
- );
8073
- const phase2TimeoutMs = structuredModelSettings.maxDuration ? structuredModelSettings.maxDuration * 1e3 : CONSTANTS.PHASE_2_TIMEOUT_MS;
8074
- const shouldStreamPhase2 = this.getStreamingHelper();
8075
- if (shouldStreamPhase2) {
8076
- const phase2Messages = [
8077
- {
8078
- role: "system",
8079
- content: await this.buildPhase2SystemPrompt(runtimeContext)
8080
- }
8081
- ];
8082
- if (conversationHistory.trim() !== "") {
8083
- phase2Messages.push({ role: "user", content: conversationHistory });
8084
- }
8085
- phase2Messages.push({ role: "user", content: userMessage });
8086
- phase2Messages.push(...reasoningFlow);
8087
- const streamResult = streamObject({
8088
- ...structuredModelSettings,
8089
- messages: phase2Messages,
8090
- schema: z.object({
8091
- dataComponents: z.array(dataComponentsSchema)
8092
- }),
8093
- experimental_telemetry: {
8094
- isEnabled: true,
8095
- functionId: this.config.id,
8096
- recordInputs: true,
8097
- recordOutputs: true,
8098
- metadata: {
8099
- phase: "structured_generation"
8041
+ reasoningFlow.push({
8042
+ role: "assistant",
8043
+ content: formattedResult
8044
+ });
8045
+ }
8046
+ });
8100
8047
  }
8101
- },
8102
- abortSignal: AbortSignal.timeout(phase2TimeoutMs)
8103
- });
8104
- const streamHelper = this.getStreamingHelper();
8105
- if (!streamHelper) {
8106
- throw new Error("Stream helper is unexpectedly undefined in streaming context");
8048
+ });
8107
8049
  }
8108
- const session = toolSessionManager.getSession(sessionId);
8109
- const artifactParserOptions = {
8110
- sessionId,
8111
- taskId: session?.taskId,
8112
- projectId: session?.projectId,
8113
- artifactComponents: this.artifactComponents,
8114
- streamRequestId: this.getStreamRequestId(),
8115
- subAgentId: this.config.id
8116
- };
8117
- const parser = new IncrementalStreamParser(
8118
- streamHelper,
8119
- this.config.tenantId,
8120
- contextId,
8121
- artifactParserOptions
8122
- );
8123
- for await (const delta of streamResult.partialObjectStream) {
8124
- if (delta) {
8125
- await parser.processObjectDelta(delta);
8126
- }
8050
+ const componentSchemas = [];
8051
+ if (this.config.dataComponents && this.config.dataComponents.length > 0) {
8052
+ this.config.dataComponents.forEach((dc) => {
8053
+ const propsSchema = jsonSchemaToZod(dc.props);
8054
+ componentSchemas.push(
8055
+ z.object({
8056
+ id: z.string(),
8057
+ name: z.literal(dc.name),
8058
+ props: propsSchema
8059
+ })
8060
+ );
8061
+ });
8127
8062
  }
8128
- await parser.finalize();
8129
- const structuredResponse = await streamResult;
8130
- const collectedParts = parser.getCollectedParts();
8131
- if (collectedParts.length > 0) {
8132
- response.formattedContent = {
8133
- parts: collectedParts.map((part) => ({
8134
- kind: part.kind,
8135
- ...part.kind === "text" && { text: part.text },
8136
- ...part.kind === "data" && { data: part.data }
8137
- }))
8138
- };
8063
+ if (this.artifactComponents.length > 0) {
8064
+ const artifactCreateSchemas = ArtifactCreateSchema.getSchemas(
8065
+ this.artifactComponents
8066
+ );
8067
+ componentSchemas.push(...artifactCreateSchemas);
8068
+ componentSchemas.push(ArtifactReferenceSchema.getSchema());
8139
8069
  }
8140
- response = {
8141
- ...response,
8142
- object: structuredResponse.object
8143
- };
8144
- textResponse = JSON.stringify(structuredResponse.object, null, 2);
8145
- } else {
8146
- const { withJsonPostProcessing } = await import('./json-postprocessor-VOMU4E5L.js');
8147
- const phase2Messages = [
8148
- { role: "system", content: await this.buildPhase2SystemPrompt(runtimeContext) }
8149
- ];
8150
- if (conversationHistory.trim() !== "") {
8151
- phase2Messages.push({ role: "user", content: conversationHistory });
8070
+ let dataComponentsSchema;
8071
+ if (componentSchemas.length === 1) {
8072
+ dataComponentsSchema = componentSchemas[0];
8073
+ } else {
8074
+ dataComponentsSchema = z.union(
8075
+ componentSchemas
8076
+ );
8152
8077
  }
8153
- phase2Messages.push({ role: "user", content: userMessage });
8154
- phase2Messages.push(...reasoningFlow);
8155
- const structuredResponse = await generateObject(
8156
- withJsonPostProcessing({
8078
+ const structuredModelSettings = ModelFactory.prepareGenerationConfig(
8079
+ this.getStructuredOutputModel()
8080
+ );
8081
+ const phase2TimeoutMs = structuredModelSettings.maxDuration ? structuredModelSettings.maxDuration * 1e3 : CONSTANTS.PHASE_2_TIMEOUT_MS;
8082
+ const shouldStreamPhase2 = this.getStreamingHelper();
8083
+ if (shouldStreamPhase2) {
8084
+ const phase2Messages = [
8085
+ {
8086
+ role: "system",
8087
+ content: await this.buildPhase2SystemPrompt(runtimeContext)
8088
+ }
8089
+ ];
8090
+ if (conversationHistory.trim() !== "") {
8091
+ phase2Messages.push({ role: "user", content: conversationHistory });
8092
+ }
8093
+ phase2Messages.push({ role: "user", content: userMessage });
8094
+ phase2Messages.push(...reasoningFlow);
8095
+ const streamResult = streamObject({
8157
8096
  ...structuredModelSettings,
8158
8097
  messages: phase2Messages,
8159
8098
  schema: z.object({
@@ -8169,65 +8108,135 @@ ${output}${structureHintsFormatted}`;
8169
8108
  }
8170
8109
  },
8171
8110
  abortSignal: AbortSignal.timeout(phase2TimeoutMs)
8172
- })
8173
- );
8174
- response = {
8175
- ...response,
8176
- object: structuredResponse.object
8177
- };
8178
- textResponse = JSON.stringify(structuredResponse.object, null, 2);
8111
+ });
8112
+ const streamHelper = this.getStreamingHelper();
8113
+ if (!streamHelper) {
8114
+ throw new Error("Stream helper is unexpectedly undefined in streaming context");
8115
+ }
8116
+ const session = toolSessionManager.getSession(sessionId);
8117
+ const artifactParserOptions = {
8118
+ sessionId,
8119
+ taskId: session?.taskId,
8120
+ projectId: session?.projectId,
8121
+ artifactComponents: this.artifactComponents,
8122
+ streamRequestId: this.getStreamRequestId(),
8123
+ subAgentId: this.config.id
8124
+ };
8125
+ const parser = new IncrementalStreamParser(
8126
+ streamHelper,
8127
+ this.config.tenantId,
8128
+ contextId,
8129
+ artifactParserOptions
8130
+ );
8131
+ for await (const delta of streamResult.partialObjectStream) {
8132
+ if (delta) {
8133
+ await parser.processObjectDelta(delta);
8134
+ }
8135
+ }
8136
+ await parser.finalize();
8137
+ const structuredResponse = await streamResult;
8138
+ const collectedParts = parser.getCollectedParts();
8139
+ if (collectedParts.length > 0) {
8140
+ response.formattedContent = {
8141
+ parts: collectedParts.map((part) => ({
8142
+ kind: part.kind,
8143
+ ...part.kind === "text" && { text: part.text },
8144
+ ...part.kind === "data" && { data: part.data }
8145
+ }))
8146
+ };
8147
+ }
8148
+ response = {
8149
+ ...response,
8150
+ object: structuredResponse.object
8151
+ };
8152
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
8153
+ } else {
8154
+ const { withJsonPostProcessing } = await import('./json-postprocessor-VOMU4E5L.js');
8155
+ const phase2Messages = [
8156
+ { role: "system", content: await this.buildPhase2SystemPrompt(runtimeContext) }
8157
+ ];
8158
+ if (conversationHistory.trim() !== "") {
8159
+ phase2Messages.push({ role: "user", content: conversationHistory });
8160
+ }
8161
+ phase2Messages.push({ role: "user", content: userMessage });
8162
+ phase2Messages.push(...reasoningFlow);
8163
+ const structuredResponse = await generateObject(
8164
+ withJsonPostProcessing({
8165
+ ...structuredModelSettings,
8166
+ messages: phase2Messages,
8167
+ schema: z.object({
8168
+ dataComponents: z.array(dataComponentsSchema)
8169
+ }),
8170
+ experimental_telemetry: {
8171
+ isEnabled: true,
8172
+ functionId: this.config.id,
8173
+ recordInputs: true,
8174
+ recordOutputs: true,
8175
+ metadata: {
8176
+ phase: "structured_generation"
8177
+ }
8178
+ },
8179
+ abortSignal: AbortSignal.timeout(phase2TimeoutMs)
8180
+ })
8181
+ );
8182
+ response = {
8183
+ ...response,
8184
+ object: structuredResponse.object
8185
+ };
8186
+ textResponse = JSON.stringify(structuredResponse.object, null, 2);
8187
+ }
8188
+ } else {
8189
+ textResponse = response.text || "";
8179
8190
  }
8180
8191
  } else {
8181
- textResponse = response.text || "";
8192
+ textResponse = response.steps[response.steps.length - 1].text || "";
8182
8193
  }
8183
- } else {
8184
- textResponse = response.steps[response.steps.length - 1].text || "";
8185
- }
8186
- span.setStatus({ code: SpanStatusCode.OK });
8187
- span.end();
8188
- let formattedContent = response.formattedContent || null;
8189
- if (!formattedContent) {
8190
- const session = toolSessionManager.getSession(sessionId);
8191
- const responseFormatter = new ResponseFormatter(this.config.tenantId, {
8192
- sessionId,
8193
- taskId: session?.taskId,
8194
- projectId: session?.projectId,
8195
- contextId,
8196
- artifactComponents: this.artifactComponents,
8197
- streamRequestId: this.getStreamRequestId(),
8198
- subAgentId: this.config.id
8199
- });
8200
- if (response.object) {
8201
- formattedContent = await responseFormatter.formatObjectResponse(
8202
- response.object,
8203
- contextId
8204
- );
8205
- } else if (textResponse) {
8206
- formattedContent = await responseFormatter.formatResponse(textResponse, contextId);
8194
+ span.setStatus({ code: SpanStatusCode.OK });
8195
+ span.end();
8196
+ let formattedContent = response.formattedContent || null;
8197
+ if (!formattedContent) {
8198
+ const session = toolSessionManager.getSession(sessionId);
8199
+ const responseFormatter = new ResponseFormatter(this.config.tenantId, {
8200
+ sessionId,
8201
+ taskId: session?.taskId,
8202
+ projectId: session?.projectId,
8203
+ contextId,
8204
+ artifactComponents: this.artifactComponents,
8205
+ streamRequestId: this.getStreamRequestId(),
8206
+ subAgentId: this.config.id
8207
+ });
8208
+ if (response.object) {
8209
+ formattedContent = await responseFormatter.formatObjectResponse(
8210
+ response.object,
8211
+ contextId
8212
+ );
8213
+ } else if (textResponse) {
8214
+ formattedContent = await responseFormatter.formatResponse(textResponse, contextId);
8215
+ }
8207
8216
  }
8217
+ const formattedResponse = {
8218
+ ...response,
8219
+ formattedContent
8220
+ };
8221
+ if (streamRequestId) {
8222
+ const generationType = response.object ? "object_generation" : "text_generation";
8223
+ agentSessionManager.recordEvent(streamRequestId, "agent_generate", this.config.id, {
8224
+ parts: (formattedContent?.parts || []).map((part) => ({
8225
+ type: part.kind === "text" ? "text" : part.kind === "data" ? "tool_result" : "text",
8226
+ content: part.text || JSON.stringify(part.data)
8227
+ })),
8228
+ generationType
8229
+ });
8230
+ }
8231
+ return formattedResponse;
8232
+ } catch (error) {
8233
+ const errorToThrow = error instanceof Error ? error : new Error(String(error));
8234
+ setSpanWithError(span, errorToThrow);
8235
+ span.end();
8236
+ throw errorToThrow;
8208
8237
  }
8209
- const formattedResponse = {
8210
- ...response,
8211
- formattedContent
8212
- };
8213
- if (streamRequestId) {
8214
- const generationType = response.object ? "object_generation" : "text_generation";
8215
- agentSessionManager.recordEvent(streamRequestId, "agent_generate", this.config.id, {
8216
- parts: (formattedContent?.parts || []).map((part) => ({
8217
- type: part.kind === "text" ? "text" : part.kind === "data" ? "tool_result" : "text",
8218
- content: part.text || JSON.stringify(part.data)
8219
- })),
8220
- generationType
8221
- });
8222
- }
8223
- return formattedResponse;
8224
- } catch (error) {
8225
- const errorToThrow = error instanceof Error ? error : new Error(String(error));
8226
- setSpanWithError(span, errorToThrow);
8227
- span.end();
8228
- throw errorToThrow;
8229
8238
  }
8230
- });
8239
+ );
8231
8240
  }
8232
8241
  };
8233
8242
 
@@ -10576,7 +10585,17 @@ var generatePreviewRoute = createRoute({
10576
10585
  tenantId: z.string(),
10577
10586
  projectId: z.string(),
10578
10587
  id: z.string()
10579
- })
10588
+ }),
10589
+ body: {
10590
+ content: {
10591
+ "application/json": {
10592
+ schema: z.object({
10593
+ instructions: z.string().optional().describe("Custom instructions for modifying the component"),
10594
+ existingCode: z.string().optional().describe("Existing component code to modify")
10595
+ })
10596
+ }
10597
+ }
10598
+ }
10580
10599
  },
10581
10600
  responses: {
10582
10601
  200: {
@@ -10597,7 +10616,18 @@ var generatePreviewRoute = createRoute({
10597
10616
  });
10598
10617
  app4.openapi(generatePreviewRoute, async (c) => {
10599
10618
  const { tenantId, projectId, id } = c.req.valid("param");
10600
- logger22.info({ tenantId, projectId, dataComponentId: id }, "Generating component preview");
10619
+ const body = c.req.valid("json");
10620
+ const { instructions, existingCode } = body;
10621
+ logger22.info(
10622
+ {
10623
+ tenantId,
10624
+ projectId,
10625
+ dataComponentId: id,
10626
+ hasInstructions: !!instructions,
10627
+ hasExistingCode: !!existingCode
10628
+ },
10629
+ "Generating component preview"
10630
+ );
10601
10631
  const dataComponent = await getDataComponent(dbClient_default)({
10602
10632
  scopes: { tenantId, projectId },
10603
10633
  dataComponentId: id
@@ -10617,7 +10647,7 @@ app4.openapi(generatePreviewRoute, async (c) => {
10617
10647
  message: "Project base model configuration is required"
10618
10648
  });
10619
10649
  }
10620
- const prompt = buildGenerationPrompt(dataComponent);
10650
+ const prompt = buildGenerationPrompt(dataComponent, instructions, existingCode);
10621
10651
  try {
10622
10652
  const modelConfig = ModelFactory.prepareGenerationConfig(project.models.base);
10623
10653
  const previewSchema = z.object({
@@ -10633,10 +10663,12 @@ app4.openapi(generatePreviewRoute, async (c) => {
10633
10663
  c.header("Content-Type", "text/plain; charset=utf-8");
10634
10664
  c.header("Cache-Control", "no-cache");
10635
10665
  c.header("Connection", "keep-alive");
10666
+ const existingData = existingCode && dataComponent.preview?.data ? dataComponent.preview.data : null;
10636
10667
  return stream(c, async (stream3) => {
10637
10668
  try {
10638
10669
  for await (const partialObject of result.partialObjectStream) {
10639
- await stream3.write(JSON.stringify(partialObject) + "\n");
10670
+ const outputObject = instructions && existingData ? { ...partialObject, data: existingData } : partialObject;
10671
+ await stream3.write(JSON.stringify(outputObject) + "\n");
10640
10672
  }
10641
10673
  } catch (error) {
10642
10674
  logger22.error(
@@ -10659,10 +10691,50 @@ app4.openapi(generatePreviewRoute, async (c) => {
10659
10691
  });
10660
10692
  }
10661
10693
  });
10662
- function buildGenerationPrompt(dataComponent) {
10694
+ function buildGenerationPrompt(dataComponent, instructions, existingCode) {
10663
10695
  const propsSchema = dataComponent.props || {};
10664
10696
  const propsJson = JSON.stringify(propsSchema, null, 2);
10665
10697
  const componentName = sanitizeComponentName(dataComponent.name);
10698
+ if (instructions && existingCode) {
10699
+ return `You are an expert React and Tailwind CSS developer. You need to modify an existing React component based on specific instructions.
10700
+
10701
+ COMPONENT DETAILS:
10702
+ - Original Name: ${dataComponent.name}
10703
+ - Component Function Name: ${componentName}
10704
+ - Description: ${dataComponent.description}
10705
+ - Props Schema (JSON Schema): ${propsJson}
10706
+
10707
+ EXISTING COMPONENT CODE:
10708
+ \`\`\`jsx
10709
+ ${existingCode}
10710
+ \`\`\`
10711
+
10712
+ MODIFICATION INSTRUCTIONS:
10713
+ ${instructions}
10714
+
10715
+ REQUIREMENTS:
10716
+ 1. Modify the existing component code according to the instructions
10717
+ 2. Keep using Tailwind CSS SEMANTIC COLOR CLASSES (bg-background, text-foreground, etc.)
10718
+ 3. Maintain the balanced spacing and design principles from the original
10719
+ 4. Keep using lucide-react icons where appropriate
10720
+ 5. DO NOT include export statements - just the imports and function
10721
+ 6. DO NOT include TypeScript type annotations
10722
+ 7. Component name should remain: ${componentName}
10723
+ 8. DO NOT regenerate sample data - keep the same data structure
10724
+
10725
+ OUTPUT FORMAT:
10726
+ You need to generate only one thing:
10727
+ 1. "code": The modified React component code as a string
10728
+
10729
+ Return ONLY the code field, the data field will be reused from the existing preview.
10730
+
10731
+ EXAMPLE OUTPUT:
10732
+ {
10733
+ "code": "import { Mail, User } from 'lucide-react';\\n\\nfunction ${componentName}(props) {\\n // Modified component code here\\n}"
10734
+ }
10735
+
10736
+ Focus on making the requested changes while maintaining the component's quality and design principles.`;
10737
+ }
10666
10738
  return `You are an expert React and Tailwind CSS developer. Generate a beautiful, modern React component for displaying data and sample data to preview it.
10667
10739
 
10668
10740
  COMPONENT DETAILS: