This is an automated email from the ASF dual-hosted git repository.

github-merge-queue[bot] pushed a commit to branch 
gh-readonly-queue/main/pr-7638-50dd7d5969e746ff02b11af240a4067d4a96e3ba
in repository https://gitbox.apache.org/repos/asf/texera.git

commit 14a574f0cfd6feab99c90b58fb1492ce76d68b15
Author: anthonychengit <[email protected]>
AuthorDate: Sun Aug 30 03:41:16 2026 +0000

    fix(agent-service): handle falsy model throws (#7638)
    
    ### What changes were proposed in this PR?
    
    The model adapter can throw arbitrary JavaScript values, including
    `null` and `undefined`. The previous error path immediately read
    `error.name`, so those values caused `sendMessage` itself to reject
    instead of returning Texera's normal error result.
    
    ```text
    Before: falsy model throw -> error.name dereference -> rejected sendMessage
    After:  falsy model throw -> normalized error text -> resolved ReAct error 
step
    ```
    
    This change safely normalizes thrown values and uses optional access for
    optional error metadata. The regression test covers `null`, `undefined`,
    `false`, `0`, and the empty string, and verifies both the resolved
    response and its recorded error step.
    
    ### Any related issues, documentation, discussions?
    
    Closes #7485
    
    ### How was this PR tested?
    
    ```bash
    npx --yes [email protected] test src/agent/texera-agent.spec.ts
    npx --yes [email protected] run typecheck
    npx --yes [email protected] run format:check
    ```
    
    The test file passed 56 tests. Type checking and formatting checks also
    passed.
    
    ### Was this PR authored or co-authored using generative AI tooling?
    
    Generated-by: OpenAI Codex (GPT-5)
---
 agent-service/src/agent/texera-agent.spec.ts | 19 +++++++++++++++++++
 agent-service/src/agent/texera-agent.ts      |  7 ++++---
 2 files changed, 23 insertions(+), 3 deletions(-)

diff --git a/agent-service/src/agent/texera-agent.spec.ts 
b/agent-service/src/agent/texera-agent.spec.ts
index 416fee5444..52d9103866 100644
--- a/agent-service/src/agent/texera-agent.spec.ts
+++ b/agent-service/src/agent/texera-agent.spec.ts
@@ -670,6 +670,25 @@ describe("sendMessage", () => {
     expect(agent.getAllSteps()[1].content).toBe("Error: just-a-string");
   });
 
+  test.each([null, undefined, false, 0, ""])("a falsy throw resolves as an 
error step: %p", async thrown => {
+    const model = new MockLanguageModelV4({
+      doGenerate: async () => {
+        throw thrown;
+      },
+    });
+    const agent = makeAgentWith(model);
+    const res = await agent.sendMessage("hi");
+    const expected = String(thrown);
+    expect(res).toEqual({
+      response: "",
+      messages: [],
+      usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
+      stopped: false,
+      error: expected,
+    });
+    expect(agent.getAllSteps()[1].content).toBe(`Error: ${expected}`);
+  });
+
   test("a failed turn stays on the branch", async () => {
     const model = new MockLanguageModelV4({
       doGenerate: async () => {
diff --git a/agent-service/src/agent/texera-agent.ts 
b/agent-service/src/agent/texera-agent.ts
index ccd0545919..9a640aaab6 100644
--- a/agent-service/src/agent/texera-agent.ts
+++ b/agent-service/src/agent/texera-agent.ts
@@ -657,7 +657,8 @@ export class TexeraAgent {
         stopped: false,
       };
     } catch (error: any) {
-      const isAborted = error.name === "AbortError" || 
this.abortController?.signal.aborted;
+      const errorMessage = error?.message || String(error);
+      const isAborted = error?.name === "AbortError" || 
this.abortController?.signal.aborted;
 
       if (isAborted) {
         stepIndex++;
@@ -693,7 +694,7 @@ export class TexeraAgent {
         stepId: stepIndex,
         timestamp: Date.now(),
         role: "agent",
-        content: `Error: ${error.message || String(error)}`,
+        content: `Error: ${errorMessage}`,
         isBegin: false,
         isEnd: true,
       };
@@ -705,7 +706,7 @@ export class TexeraAgent {
         messages: [],
         usage: { inputTokens: 0, outputTokens: 0, totalTokens: 0 },
         stopped: false,
-        error: error.message || String(error),
+        error: errorMessage,
       };
     } finally {
       this.abortController = null;

Reply via email to