Skip to content

agentserver-stub missing /api/agent/discovery/{agents,cards} + WS /api/tunnel — driver.inspect_capabilities 404s on stub #78

Description

@yzs15

Summary

tools/eval/agentserver-stub only serves 3 endpoints (register / whoami / heartbeat) but the agentsdk client used by driver-agent and slave-agent needs 3 additional endpoints to complete inspect_capabilities / dry_run_contract / peer proxy — a full-stack smoke run against the stub fails at the very first driver MCP tool call.

Base: paper/v3-integration HEAD 1185e990 (Phase 2 complete).

Repro

# 1) Build the four binaries
cd multi-agent
mkdir -p deploy/linux/bin
go build -o deploy/linux/bin/agentserver-stub ./tools/eval/agentserver-stub
go build -o deploy/linux/bin/observer-server  ./cmd/observer-server
go build -o deploy/linux/bin/slave-agent      ./cmd/slave-agent
go build -o deploy/linux/bin/driver-agent     ./cmd/driver-agent

# 2) Bring the stack up (deploy.sh handles the stub + observer + driver + one slave)
export LOOM_HOME=/tmp/loom-smoke LOOM_AGENT_KIND=codex
rm -rf "$LOOM_HOME"
bash deploy/linux/deploy.sh --stub --loom-home "$LOOM_HOME"
# → 4 processes spawn cleanly; 18080/18091/18092 all in LISTEN.

# 3) Attach the driver's stdio MCP server to Codex and ask for inspect_capabilities
codex mcp add smoke-driver -- "$PWD/deploy/linux/bin/driver-agent" \
    serve-mcp --config "$LOOM_HOME/driver/config.yaml"
codex exec --skip-git-repo-check --dangerously-bypass-approvals-and-sandbox \
    "Call MCP tool smoke-driver.inspect_capabilities with {}"

Observed

mcp: smoke-driver/inspect_capabilities (failed)
tool call error: tool call failed for `smoke-driver/inspect_capabilities`

Caused by:
    Mcp error: -32000: discover agents: discover agents failed (404): 404 page not found

Slave log ($LOOM_HOME/logs/slave.log) has the same shape from the tunnel side:

agentsdk: connecting to http://127.0.0.1:18080
agentsdk: tunnel disconnected: dial: failed to WebSocket dial: expected handshake response status code 101 but got 404
agentsdk: reconnecting in 2s...

Root cause — 3 missing endpoints

tools/eval/agentserver-stub/server.go:76 wires only:

Method Path
POST /api/{v1/agents,agent}/register
GET/POST /api/{v1/agents,agent}/whoami
POST /api/{v1/agents,agent}/heartbeat

But github.com/agentserver/agentserver@v0.69.9/pkg/agentsdk (the client that driver-agent and slave-agent both link against) also calls:

Method Path Caller Location
GET /api/agent/discovery/agents client.DiscoverAgents → driver-agent inspect_capabilities / dry_run_contract (internal/driver/capability_tools.go) agentsdk/agents.go:87
POST /api/agent/discovery/cards slave-agent tunnel.PublishCard (internal/tunnel/tunnel.go:180) internal/tunnel/tunnel.go:180
WS /api/tunnel/<sandbox_id>?token=<tunnel_token> slave-agent reverse tunnel connect agentsdk/client.go:144

All three return 404 from the stub. inspect_capabilities fails on the first call; PublishCard silently 404s (slave.log: publish card: publish card: status 404 (continuing)); the WebSocket tunnel loops forever in exponential-backoff reconnect.

Impact

Phase 0 WT-0-agentserver-stub's stated acceptance criterion (docs/final/todo_list.md L66) — "stub 起来后 driver/slave 用 stub 签发的五元组直接跑通 inspect_capabilitiessubmit_task;不触发任何 OAuth code path" — is not actually met. The stub signs the five-tuple credentials correctly, but every subsequent SDK call past register / whoami fails. The Phase 3 worktrees (p3-mini-case, p3-stub-fulltable, p3-prod-multidevice) all shipped as harness-only with an explicit "do not run 60 real runs" gate — this gap is likely the reason a real end-to-end run kept getting deferred.

Suggested fix (minimal)

Extend agentserver-stub/server.go with three handlers that don't need real fan-out or a real reverse tunnel — the stub only needs to be shape-compatible so smoke runs against a --stub deploy exercise the same code paths a prod agentserver would:

  1. POST /api/agent/discovery/cards — store the posted AgentCard in an in-memory map[sandbox_id]AgentCard, keyed by the tunnel_token bearer.
  2. GET /api/agent/discovery/agents — look up the caller's workspace_id from the bearer (already available via the existing byProxy/byTunnel maps), return every card in the same workspace as a []AgentCard JSON array.
  3. WS /api/tunnel/<sandbox_id> (with ?token=<tunnel_token> query) — hijack the connection, complete the WebSocket handshake, then read/discard frames in a loop until the peer closes. Peer-proxy data-plane isn't needed for inspect_capabilities / dry_run_contract smoke; if a future test needs real PeerProxy behavior, that can be a follow-up.

Once these land, the same smoke script above should reach capability_snapshots / route_reasons writes and let a real 4-workload smoke run against --stub succeed end-to-end — which is what Phase 3 real-run worktrees need.

Environment

  • Linux 6.18.33.1-microsoft-standard-WSL2, amd64, go 1.26.4
  • Real codex-cli 0.142.5 against code.ai.cs.ac.cn/v1 (modelserver provider)
  • All 4 stack processes verified live (ss -tlnp shows LISTEN on 18080/18091/18092; slave-agent PID 207921 alive)
  • Session id: 019f3711-b48f-7f01-a25a-f91fa8526354
  • Full finding memo: paper_writing repo docs/intermediate/15_smoke_e2e_2slave_finding.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions