Skip to content

[bug] The agent prescribes pags up when the runner is excluded by the pin — the chat prompt is a fourth "no runner" construction site and the only one never wired to diagnoseAttachment #530

Description

@serge-ivo

The agent tells the owner to run pags up when pags up is already running and the pin is the problem

Live, instance f8ddc272-0390-4826-8812-94989e3d2ebd, 2026-08-12:

07:44:05  chat.in   "Retry"
07:44:10  chat.out  "The runner is currently offline — I can't start new work until it's
                     connected. Run `pags up` in your terminal to bring it back online…"

No tool.call between them (agent_trace, and instance_activity shows chat.messagechat.response with no tool.called). The refusal came from the system prompt, not a tool.

The owner's pags up was running the whole time, on RLs-MacBook-Air (runner row created 03:07:22, live). The instance was pinned to Sergeys-Mac-mini.local. At 07:55:10 the same start_work succeeded — the only variable that changed was the pin.

Mechanism

workers/api/src/agent-think.ts:534-535:

const boundConn = await getBoundRunnerConn(env, state.agentId, userId).catch(() => null);
const runnerOnline = boundConn ? await relayConnected(env, state.agentId, boundConn.runnerNode ?? null) : false;
systemPrompt += runnerStatusPrompt(selfModel, runnerOnline);

getBoundRunnerConn is pin-authoritative and correctly returns null — the mini and the Air carry different machine_ids, so aliasNodesFor cannot rescue it (runner-client.ts:96-101). The routing verdict is right.

Then it is collapsed to a boolean, and lib/agent-style-prompt.ts:89-99 turns that boolean into a fixed remedy:

const remedy = model.hasRunner
  ? ` If the user wants to run, search, or fix code, tell them to start the runner first with \`pags up\`…`

grep -c diagnoseAttachment workers/api/src/agent-think.ts workers/api/src/lib/agent-style-prompt.ts0 and 0.

The correct sentence already exists and is deliberately remedy-free

lib/runtime-attachment.ts:69-79 produces: "This agent is pinned to Sergeys-Mac-mini.local, which isn't connected. RLs-MacBook-Air is connected — set 'Runs on' to RLs-MacBook-Air (or Automatic)" — and carries no remedy string, precisely because pags up is the wrong advice in this state.

The chat prompt is a fourth construction site for "why is there no runner", and the only one never wired to that diagnosis. 07ec7af (#461) and e6e330d (#468) fixed forwarding for the three adapters; this path was not in their scope, so those commits could not have reached it.

Same class as #271/#321/#524 — a message that cannot name the machine it means — in a file none of them touched.

Acceptance criteria

  1. When the runner is unavailable because of a pin, the agent says so and names both machines, instead of prescribing pags up.
  2. The chat prompt consumes diagnoseAttachment rather than re-deriving a boolean — one construction site, not four.
  3. Where the true remedy is "change Runs on", the agent does not offer a remedy the platform knows is wrong. Note runtime-attachment.ts returns remedy: null for this case on purpose; respect that rather than substituting one.
  4. A genuinely absent runner still gets the pags up advice — this must not become a generic softening.
  5. A test with pin=A, live=B asserting the reply names the pin.

Verified vs inferred

A second, separable gap this exposed: the repin is invisible — no agent_events row, no activity entry. A configuration change that silently decides whether every tool call routes anywhere should leave a record.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions