139: "Who can I ask?" — discover teammate agents by skill and engage them; publish cards for hosted personas - #178
Conversation
|
End-to-end merge gate: this PR is not production-ready yet. Validated locally at
Real integration blockers:
Unblock/merge criteria:
Marking draft so the passing mocked checks cannot be mistaken for full ecosystem proof. |
|
Addressed the branch-integration finding from the merge-gate review on the current PR head.
The PR remains draft. The external merge gates are still blocked exactly as identified: Relaycast #294 is not deployed, Workforce #296 has not published |
Stale-PR triage: REVIVE — the blocker that stalled this has since clearedTriage sweep of the 6 open PRs, evaluated against #139's closure is a false positive — this work is not done#139 shows Factory has no PR #2891 — its numbering is in the ~270s. PR #2891 is in Nothing on main implements thisNo The question that stalled it has been answered by eventsThis PR stopped on 2026-07-22 with an open human-input request:
That was never answered in-thread, but upstream resolved it two days later.
Rebase cost: moderate, mostly mechanicalTested in an isolated detached worktree (never the shared checkout, no force-push). 7 files conflict, one block each: The lockfile and CI. Still a draft — it would need the dependency bump, mapper deletion, and un-drafting before review. Recommendation only — I do not close or merge. Posted by an automated triage lane. |
Triage: REBASE-AND-FINISH — unlanded, blocker cleared, and the conflicts are mostly mechanicalStale-PR triage pass. Recommendation only; no ruling has been made yet. Evidence against This is the healthiest of the four stale Factory PRs and the one I'd revive first. 1. Is the work already on main by another route? — No.Checked
None of this PR's 300-line teammate directory or 298-line persona-card publisher exists on main. 2. Does the parent issue still describe something we want? — Yes. And #139 is wrongly closed; it should be reopened.
The second closure is not the same defect, and #278's fix would not have prevented it. #278 is a real merged PR in this repository, so repo-qualification passes. But #278's file list is exactly (I have not established whether the running Factory had picked up #278's build by 23:27 — merged is not released is not deployed — so this may be the old binary re-firing rather than a surviving hole in the new logic. Either way the closure is invalid and worth a separate look. Flagging, not filing, pending your ruling.) Recommendation: reopen #139. I have not done so — that is outside my brief. 3. Is the original blocker cleared? — Yes. Verified independently against the registry, not against upstream issue state.#139's open human-input request from 2026-07-22 was: "Which published @agentworkforce/persona-kit version containing I unpacked the published tarball rather than trusting a version claim:
4. How big is the conflict? — 7 files, 82 behind — but 4 of the 7 are mechanical.
Seven conflicts sounds worse than it is. Inspected individually:
So the substantive merge work is roughly 60 additive lines across two fleet clients. Rebase, don't redo — the 300-line RecommendationREBASE-AND-FINISH. Concretely, on a ruling:
Holding for a ruling — not rebasing, reopening, or closing anything on my own. |
d93aaa5 to
996b7bc
Compare
Rebase-and-finish updateRebased this PR onto current The July blocker in Workforce is resolved in code:
Verification at the rebased content:
The PR remains draft for one external reason that the rebase cannot fix: AgentWorkforce/relaycast#294 is still open and an unauthenticated probe of the required directory route still returns HTTP 404. Therefore the required real deployed discover → ask → reply → persona publish/directory proof is not available yet. The checked-in mock round trip is green, but I am not presenting it as production proof. No merge performed. |
|
Hosted CI is green at exact head The PR intentionally remains draft only for the live Relaycast directory proof recorded above. |
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()inFleetClient(src/ports/fleet.ts), implemented inRelayFleetClient(src/fleet/relay-fleet-client.ts) — query Relaycast'sGET /v1/a2a/directoryfiltered by skill/tag, returning{ name, skills[], url, kind }per candidate. Optionally cache via an in-package index likeRelayflowPolicyRegistry(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/rpcmessage/sendor 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-kitderiveAgentCard([workforce#296]) and publish it when the persona-backed node comes online —createFactoryNodeDefinition(src/node/factory-node.ts) already assembles capabilities/tags/metadata and callsdefineNode. Export the new surface fromsrc/index.ts.Acceptance
FleetClientmethod returns teammate agents matching a skill/tag from the Relaycast directory (with how to reach each).deriveAgentCard-derived card when their node comes online; they appear in the directory.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
The E2E (
test/e2e/ask-a-teammate.test.ts, runnable vianpm test) must:/v1/a2a/directoryHTTP response, or seed the in-process broker) with two agents whose cards declare distinct skills (e.g.["infra-watch"],["code-review"]).skill: "infra-watch"→ assert it returns only the infra agent, with an address to reach it.InternalFleetClient+ensureRelayBroker) that replies to an inbound question with a canned answer.createFactoryNodeDefinition, then assert itsderiveAgentCard-derived card was published/registered and shows up in the directory lookup from step 2.Observe (must pass)
[]for an unknown skill.Deliverable
test/e2e/ask-a-teammate.test.tsrunning the full discover→ask→reply round trip against the in-process broker + mock directory, one command (npm test).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.tssrc/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.mdFixes #139
Summary by cubic
Lets workers discover teammate agents by skill and ask them questions over Relaycast; factory-hosted personas publish A2A cards so they appear in the Relaycast directory. Previously there was no skill-based discovery or reply path.
Discovery:
FleetClient.discoverTeammates(TeammateQuery)via aRelaycastTeammateDirectory(GET /v1/a2a/directorywithskill/tag/q). Applies exact skill/tag filters client‑side, dedupes by kind+address, preserves server alias matches forq, and times out cleanly. Works inRelayFleetClient(workspace key or agent token; optionaldirectoryFetch/directoryTimeoutMs/teammateDirectory) andInternalFleetClient(inject aTeammateDirectoryor use a workspace key).Ask a teammate:
askTeammate(fleet, { from, question, ... })resolves a target, arms the listener before send, accepts only that agent’s reply addressed to the requester, useswaitForInjectedwhen available, and fails with a bounded timeout.Persona cards: derive with
@agentworkforce/persona-kit’s canonical mapper and validate with@relaycast/a2a; publish viaRelaycastAgentCardPublisher(POST /v1/a2a/register). On 409, verify an exact card match withGET /v1/a2a/agentsand returnalreadyPublished(andcertificationwhen present).createFactoryNodeDefinition(...)attachesagentCard;startFactoryNode(...)publishes on node-online and exposes acardPublishedpromise.Public API: exports discovery (
TeammateQuery,TeammateAgent,RelaycastTeammateDirectory,askTeammate), persona tooling (deriveFactoryPersonaCard,RelaycastAgentCardPublisher,startFactoryNode), and defaults (DEFAULT_RELAYCAST_BASE_URL,DEFAULT_TEAMMATE_DIRECTORY_TIMEOUT_MS,DEFAULT_ASK_TEAMMATE_TIMEOUT_MS). AddsA2aSkillto types. E2E covers discover→ask→reply and card publishing.Migration
fleet.discoverTeammates({ skill | tag | q })oraskTeammate(...)to consult a peer mid-task.RelayFleetClient, configure a workspace key or agent token; inInternalFleetClient, pass ateammateDirectoryor a workspace key.personatocreateFactoryNodeDefinition(...)and provide aRelaycastAgentCardPublishertostartFactoryNode(...)when anagentCardis present.Written for commit 996b7bc. Summary will update on new commits.