Skip to content

"Who can I ask?" — discover teammate agents by skill and engage them; publish cards for hosted personas #139

Description

@khaliqgant

Part of the cross-repo epic #2785. This is the consumer issue — the one that makes the ecosystem come alive. Depends on the directory from relaycast#294 and the shared card contract from workforce#296.

Why

The Factory turns issues into reviewed PRs by spawning worker agents. Today, when a worker hits a question it can't answer, it has nowhere to turn — Factory only discovers fleet nodes/capabilities for placement (FleetClient.roster()), not agents by skill, and there's no path to actually ask another agent. Once every proactive agent publishes an A2A card and registers with the Relaycast directory, a Factory worker should be able to: "who can answer X?" → pick an agent by its card skills → send it the question and get a reply.

What

1. Directory-backed peer discovery

Add a card-aware lookup alongside roster() in FleetClient (src/ports/fleet.ts), implemented in RelayFleetClient (src/fleet/relay-fleet-client.ts) — query Relaycast's GET /v1/a2a/directory filtered by skill/tag, returning { name, skills[], url, kind } per candidate. Optionally cache via an in-package index like RelayflowPolicyRegistry (src/dispatch/relayflow-registry.ts).

2. "Ask a teammate" capability

Give a running worker a way to engage a discovered peer: resolve target via #1, then send over Relaycast — A2A POST /a2a/rpc message/send or the broker seam (FleetClient.sendMessage/waitForInjected/onAgentMessage). Reuse the existing DM/relay path; don't invent a new transport. Surface it as a discrete capability/tool the worker invokes mid-task, with a bounded wait for the reply.

3. Publish cards for factory-hosted personas

Generate an A2A card for factory-hosted personas (e.g. .agentworkforce/agents/factory-feature-guardian/persona.json) via @agentworkforce/persona-kit deriveAgentCard ([workforce#296]) and publish it when the persona-backed node comes online — createFactoryNodeDefinition (src/node/factory-node.ts) already assembles capabilities/tags/metadata and calls defineNode. Export the new surface from src/index.ts.

Acceptance

  • A FleetClient method returns teammate agents matching a skill/tag from the Relaycast directory (with how to reach each).
  • A worker can, mid-task, ask a discovered teammate a question and receive a reply (bounded wait).
  • Factory-hosted personas publish a deriveAgentCard-derived card when their node comes online; they appear in the directory.
  • New surface exported from src/index.ts; card schema consumed from @relaycast/a2a (no hand-rolled shape).

✅ End-to-end verification — Factory success criteria (REQUIRED)

This issue IS the "does the ecosystem come alive?" proof. "Compiles" is nowhere near done — the Factory must run a real discover → ask → reply round trip and observe the reply arrive, then check the harness in. Use agent-relay's in-process broker so this runs locally with no external services (src/fleet/internal-fleet-client.ts, src/fleet/ensure-relay-broker.ts).

Run it

npm run build
npm test                                   # vitest run (add the E2E below)

The E2E (test/e2e/ask-a-teammate.test.ts, runnable via npm test) must:

  1. Stand up a local directory (mock the Relaycast /v1/a2a/directory HTTP response, or seed the in-process broker) with two agents whose cards declare distinct skills (e.g. ["infra-watch"], ["code-review"]).
  2. Call the new Factory discovery method with skill: "infra-watch" → assert it returns only the infra agent, with an address to reach it.
  3. Stand up a stub teammate agent on the in-process broker (InternalFleetClient + ensureRelayBroker) that replies to an inbound question with a canned answer.
  4. From a simulated worker, invoke the new "ask a teammate" capability against the discovered agent → assert the question is delivered and the canned reply is received within the bounded wait.
  5. For persona cards: bring a factory-hosted persona node online via createFactoryNodeDefinition, then assert its deriveAgentCard-derived card was published/registered and shows up in the directory lookup from step 2.

Observe (must pass)

  • Discovery returns the right agent for a skill and [] for an unknown skill.
  • The worker actually receives the teammate's reply over the relay path (the round trip completes, not just "message sent").
  • A factory-hosted persona is discoverable by its skill after its node comes online.

Deliverable

  • test/e2e/ask-a-teammate.test.ts running the full discover→ask→reply round trip against the in-process broker + mock directory, one command (npm test).
  • The E2E fails if discovery returns everything unfiltered, if the reply never arrives, or if persona-card publishing is removed (no false green).

Anchor files

  • src/ports/fleet.ts (FleetClient, RosterEntry, sendMessage/waitForInjected/onAgentMessage)
  • src/fleet/relay-fleet-client.ts, src/fleet/internal-fleet-client.ts, src/fleet/ensure-relay-broker.ts
  • src/dispatch/relayflow-registry.ts (in-package registry precedent)
  • src/node/factory-node.ts (createFactoryNodeDefinition), src/index.ts (public barrel)
  • .agentworkforce/agents/factory-feature-guardian/persona.json (proto card / template)
  • planning/linear-issue-cloud-proactive-runtime-fleet-unification.md, planning/factory-unified-node-architecture-linear-issue.md

Metadata

Metadata

Assignees

No one assigned

    Labels

    factory-readyApproved for the Factory to pick up and implementfactory:in-progressFactory agents are working on this issue.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions