Skip to content

[aw] Daily Rig Sample Report failed #352

Description

@github-actions

Workflow Failure

Workflow: Daily Rig Sample Report
Branch: main
Run: https://github.com/githubnext/rig/actions/runs/30912003849

Warning

Engine Failure: The copilot engine terminated unexpectedly.

Last agent output:

{"type":"assistant.message","timestamp":"2026-08-04T13:15:35.205Z","data":{"content":"`tool_choice: \"required\"` works. The issue is that with `auto`, the model chose to respond with text. I need to use `required` when the agent has tools that need to be called. But this is tricky - after tool calls, the model should respond with text. Let me update the engine to be smarter:\n\nThe real approach: when there are tools defined for this agent and we haven't seen a tool call yet in the first turn, force `tool_choice: \"required\"` for the first API call. After the tool runs and returns, subsequent calls should use `auto`.\n\nActually a simpler fix: my engine should keep looping if it gets a non-JSON response. But the issue is the model itself decided not to call the tool. The prompt says \"Call run_random_samples exactly once with an empty object\" - but the model said \"I'll call it\" without actually calling it.\n\nThe cleanest solution is: when there are tools and no tool has been called yet, use `tool_choice: \"required\"`:"}}
{"type":"tool.execution_start","timestamp":"2026-08-04T13:15:35.206Z","data":{"toolName":"view","mcpServerName":""}}
{"type":"tool.execution_complete","timestamp":"2026-08-04T13:15:35.257Z","data":{"toolName":"view","mcpServerName":"","success":true,"result":{"content":"37.           max_tokens: 8192,\n38.         };\n39.         if (toolDefs.length > 0) {\n40.           body[\"tools\"] = toolDefs;\n41.           body[\"tool_choice\"] = \"auto\";\n42.         }\n43. \n44.         const response = await fetch(\"http://api-proxy:10002/chat/completions\", {\n45.           method: \"POST\",\n46.           headers: {\n47.             \"Content-Type\": \"application/json\",\n48.             \"Authorization\": `******\n49.           },\n50.           body: JSON.stringify(body),\n51.           signal: askOptions.signal,\n52.         });\n53. \n54.         if (!response.ok) {\n55.           throw new Error(`API error: ${response.status} ${await response.text()}`);\n56.         }\n57. \n58.         const data = await response.json() as any;\n59.         const choice = data.choices?.[0];\n60.         const message = choice?.message;","detailedContent":"\ndiff --git a/home/runner/work/rig/rig/.tmp/run_samples4.ts b/home/runner/work/rig/rig/.tmp/run_samples4.ts\nindex 0000000..0000000 100644\n--- a/home/runner/work/rig/rig/.tmp/run_samples4.ts\n+++ b/home/runner/work/rig/rig/.tmp/run_samples4.ts\n@@ -37,24 +37,24 @@\n           max_tokens: 8192,\n         };\n         if (toolDefs.length > 0) {\n           body[\"tools\"] = toolDefs;\n           body[\"tool_choice\"] = \"auto\";\n         }\n \n         const response = await fetch(\"http://api-proxy:10002/chat/completions\", {\n           method: \"POST\",\n           headers: {\n             \"Content-Type\": \"application/json\",\n             \"Authorization\": `******\n           },\n           body: JSON.stringify(body),\n           signal: askOptions.signal,\n         });\n \n         if (!response.ok) {\n           throw new Error(`API error: ${response.status} ${await response.text()}`);\n         }\n \n         const data = await response.json() as any;\n         const choice = data.choices?.[0];\n         const message = choice?.message;\n"}}}
{"type":"assistant.message","timestamp":"2026-08-04T13:16:04.968Z","data":{"content":""}}
{"type":"tool.execution_start","timestamp":"2026-08-04T13:16:04.970Z","data":{"toolName":"bash","mcpServerName":"","command":"cd /home/runner/work/rig/rig && cat > .tmp/run_samples5.ts << 'PROGRAM_EOF'\nimport { agent, configureAgent, defineTool, p, s } from \"rig\";\nimport type { AgentFactory } from \"rig\";\n\nconst simpleEngine: AgentFactory = async (agentOptions) => {\n  const messages: Array<{ role: string; content: string | null; tool_calls?: any[] }> = [];\n  const tools = agentOptions.tools ?? [];\n  const systemMessage = typeof agentOptions.systemMessage === \"string\" ? agentOptions.systemMessage : undefined;\n\n  const toolDefs = tools.map((tool) => ({\n    type: \"function\",\n    function: {\n      name: tool.name,\n      description: tool.description ?? \"\",\n      parameters: tool.inputSchema ?? { type: \"object\", properties: {} },\n    },\n  }));\n\n  return {\n    async ask(prompt, askOptions = {}) {\n      const requestMessages: any[] = [\n        ...(systemMessage ? [{ role: \"system\", content: systemMessage }] : []),\n        ...messages,\n        { role: \"user\", content: prompt },\n      ];\n\n      let currentMessages: any[] = [...requestMessages];\n      let iterations = 0;\n      const maxIterations = 30;\n      let toolCalledThisTurn = false;\n\n      while (iterations < maxIterations) {\n        iterations++;\n        const body: Record<string, unknown> = {\n          model: \"claude-sonnet-4.6\",\n          messages: currentMessages,\n          max_tokens: 8192,\n        };\n        if (toolDefs.length > 0) {\n          body[\"tools\"] = toolDefs;\n          // Force tool call on first iteration if tools haven't been called yet\n          body[\"tool_choice\"] = (!toolCalledThisTurn && iterations === 1) ? \"required\" : \"auto\";\n        }\n\n        const response = await fetch(\"http://api-proxy:10002/chat/completions\", {\n          method: \"POST\",\n          headers: {\n            \"Content-Type\": \"application/json\",\n            \"Authorization\": `Bearer ${process.env.COPILOT_DUMMY_BYOK}`,\n          },\n          body: JSON.stringify(body),\n          signal: askOptions.signal,\n        });\n\n        if (!response.ok) {\n          throw new Error(`API error: ${response.status} ${await response.text()}`);\n        }\n\n        const data = await response.json() as any;\n        const choice = data.choices?.[0];\n        const message = choice?.message;\n\n        if (!message) {\n          throw new Error(\"No message in response\");\n        }\n\n        currentMessages = [...currentMessages, message];\n\n        if (message.tool_calls && message.tool_calls.length > 0) {\n          toolCalledThisTurn = true;\n          const toolResults = [];\n          for (const toolCall of message.tool_calls) {\n            const tool = tools.find((t) => t.name === toolCall.function.name);\n            if (!tool || !tool.handler) {\n              toolResults.push({\n                role: \"tool\",\n                tool_call_id: toolCall.id,\n                content: `Error: unknown tool ${toolCall.function.name}`,\n              });\n              continue;\n            }\n            let args: unknown;\n            try {\n              args = JSON.parse(toolCall.function.arguments);\n            } catch {\n              args = {};\n            }\n            let result: unknown;\n            try {\n              result = await tool.handler(args as any);\n            } catch (e: any) {\n              result = { error: e.message };\n            }\n            toolResults.push({\n              role: \"tool\",\n              tool_call_id: toolCall.id,\n              content: JSON.stringify(result),\n            });\n          }\n          currentMessages = [...currentMessages, ...toolResults];\n          continue;\n        }\n\n        const text = message.content ?? \"\";\n        messages.push({ role: \"user\", content: prompt }, { role: \"assistant\", content: text });\n        return text;\n      }\n      throw new Error(\"Max iterations exceeded\");\n    },\n    async close() {},\n  };\n};\n\nconfigureAgent(simpleEngine);\n\nconst SampleRun = s.object({\n  path: s.path,\n  status: s.enum(\"succeeded\", \"failed\"),\n  output: s.string,\n  logs: s.array(s.string),\n});\n\nconst runRigSample = defineTool(\"run_rig_sample\", {\n  description: \"Execute one Rig sample and capture its stdout and stderr logs.\",\n  parameters: s.object({ path: s.path }),\n  async handler({ path }) {\n    const { spawn } = await import(\"node:child_process\");\n    const { readFile } = await import(\"node:fs/promises\");\n    const { resolve, sep } = await import(\"node:path\");\n\n    const samplesDirectory = resolve(\"skills/rig/samples\");\n    const samplePath = resolve(path);\n    if (!samplePath.startsWith(`${samplesDirectory}${sep}`) || !samplePath.endsWith(\".md\")) {\n      throw new Error(`Sample path is outside skills/rig/samples: ${path}`);\n    }\n\n    const markdown = await readFile(samplePath, \"utf8\");\n    const program = markdown.match(/^```rig[ \\t]*\\r?\\n([\\s\\S]*?)^```[ \\t]*\\r?$/m)?.[1];\n    if (!program) {\n      return { path, status: \"failed\", output: \"\", logs: [\"No rig fenced block found.\"] };\n    }\n\n    return await new Promise((resolveRun, rejectRun) => {\n      const child = spawn(process.execPath, [\"skills/rig/rig.ts\", \"--server\"], {\n        cwd: process.cwd(),\n        env: {\n          ...process.env,\n          RIG_DEBUG: \"agent:invoke,agent:retry,agent:error,agent:failure,agent:close,engine:copilot:create,engine:copilot:close\",\n        },\n        stdio: [\"pipe\", \"pipe\", \"pipe\"],\n      });\n      let stdout = \"\";\n      let stderr = \"\";\n      child.stdout.on(\"data\", (chunk: Buffer) => { stdout += String(chunk); });\n      child.stderr.on(\"data\", (chunk: Buffer) => { stderr += String(chunk); });\n      child.on(\"error\", rejectRun);\n      child.on(\"close\", (code: number | null) => {\n        resolveRun({\n          path,\n          status: code === 0 ? \"succeeded\" : \"failed\",\n          output: stdout.trim(),\n          logs: stderr.split(\"\\n\").filter(Boolean),\n        });\n      });\n      child.stdin.end(program);\n    });\n  },\n});\n\nconst runSample = agent({\n  name: \"sample-runner\",\n  model: \"small\",\n  input: s.object({ path: s.path }),\n  tools: [runRigSample],\n  instructions: p`Call run_rig_sample exactly once with ${p.inputField(\"path\")}.\nReturn the tool result unchanged. Do not run any other sample.`,\n  output: SampleRun,\n});\n\nconst runRandomSamples = defineTool(\"run_random_samples\", {\n  description: \"Randomly select five Rig samples and delegate each to sample-runner.\",\n  parameters: s.object({}),\n  async handler() {\n    const { randomInt } = await import(\"node:crypto\");\n    const { readdir } = await import(\"node:fs/promises\");\n    const names = (await readdir(\"skills/rig/samples\"))\n      .filter((name: string) => name.endsWith(\".md\"));\n    if (names.length < 5) {\n      throw new Error(`Expected at least 5 Rig samples, found ${names.length}.`);\n    }\n    for (let index = names.length - 1; index > 0; index -= 1) {\n      const other = randomInt(index + 1);\n      [names[index], names[other]] = [names[other]!, names[index]!];\n    }\n    const runs = [];\n    for (const name of names.slice(0, 5)) {\n      runs.push(await runSample({ path: `skills/rig/samples/${name}` }));\n    }\n    return { runs };\n  },\n});\n\n// Agent role: randomly select five Rig samples, delegate every run, and aggregate the results.\nconst sampleCoordinator = agent({\n  name: \"sample-coordinator\",\n  model: \"small\",\n  agents: { runSample },\n  tools: [runRandomSamples],\n  instructions: \"Call run_random_samples exactly once with an empty object and return its result unchanged.\",\n  output: s.object({\n    runs: s.array(SampleRun),\n  }),\n});\n\nexport default sampleCoordinator;\nPROGRAM_EOF\necho \"done\""}}
{"type":"tool.execution_complete","timestamp":"2026-08-04T13:16:04.995Z","data":{"toolName":"bash","mcpServerName":"","success":true,"result":{"content":"done\n<shellId: 63 completed with exit code 0>","detailedContent":"done\n<shellId: 63 completed with exit code 0>"}}}
{"type":"assistant.message","timestamp":"2026-08-04T13:16:10.857Z","data":{"content":""}}
{"type":"tool.execution_start","timestamp":"2026-08-04T13:16:10.859Z","data":{"toolName":"bash","mcpServerName":"","command":"cd /home/runner/work/rig/rig && echo \"run\" | RIG_DEBUG=\"agent:invoke,agent:retry,agent:error,agent:failure,agent:close\" node skills/rig/rig.ts .tmp/run_samples5.ts 2>/tmp/gh-aw/agent/stderr7.log | tee /tmp/gh-aw/agent/stdout7.log; echo \"EXIT:$?\""}}
{"type":"tool.execution_complete","timestamp":"2026-08-04T13:16:29.685Z","data":{"toolName":"bash","mcpServerName":"","success":true,"result":{"content":"EXIT:0\n<shellId: run8 completed with exit code 0>","detailedContent":"EXIT:0\n<shellId: run8 completed with exit code 0>"}}}
[copilot-sdk-driver] [sdk-driver] error: Authorization error, you may need to run /login (Request ID: 74d55ceb-2e8d-405b-9b1d-85397a271f65)

Action Required

Assign this issue to an agent to debug and fix the issue.

Debug with any coding agent

Use this prompt with any coding agent (GitHub Copilot, Claude, Gemini, etc.):

Debug the agentic workflow failure using https://raw.githubusercontent.com/github/gh-aw/main/debug.md

The failed workflow run is at https://github.com/githubnext/rig/actions/runs/30912003849
Manually invoke the agent

Debug this workflow failure using your favorite Agent CLI and the agentic-workflows prompt.

Tip

Stop reporting this workflow as a failure

To stop a workflow from creating failure issues, set report-failure-as-issue: false in its frontmatter:

safe-outputs:
  report-failure-as-issue: false

Generated from Daily Rig Sample Report · 151.3 AIC ·

  • expires on Aug 11, 2026, 1:17 PM UTC

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions