Give a duplicated coworker the endpoint it was copied from - #328
Merged
davidmckayv merged 2 commits intoSep 3, 2026
Merged
Conversation
zopeVaibhav
requested review from
MikeRyanDev,
davidmckayv,
guidovizoso and
tylerslaton
as code owners
September 2, 2026 07:23
# Conflicts: # CHANGELOG.md
davidmckayv
approved these changes
Sep 3, 2026
davidmckayv
left a comment
Contributor
There was a problem hiding this comment.
Validated locally + CI verify green; CHANGELOG-only rebase.
9 tasks
davidmckayv
added a commit
that referenced
this pull request
Sep 4, 2026
…355) #328 fixed the half of duplicate that a coworker with its own endpoint saw. This is the other half. A coworker that runs on this deployment's own Bot has no endpoint. Its configuration is `{ systemPrompt }`, and that prompt is the whole of what makes it that coworker. Duplicate rebuilt every copy from `source.endpoint` alone and wrote `type: "remote_ag_ui"` flat, so for one of these the endpoint read came back null, the copy fell through to the managed Bot, and the prompt was dropped on the floor. What comes back is the failure this repository already has a paragraph about. The copy looks identical on every screen and its entire instruction becomes standingRoleMessage - see the note above that function in copilot.ts, which names the compliance Bot that answered a filing question with invented thresholds because one sentence of role description was all that reached it. The default tenant package ships two built_in coworkers, General Assistant and Knowledge, and Knowledge's prompt is a careful do-not-fabricate instruction with the reasoning written out beside it in the package. Duplicate it and you get a coworker with the name, the title, the avatar, and none of that. The type is carried now, not only the configuration. A copy written as remote_ag_ui also could not be granted handoff for the rest of its life: agentRunsHere and botsReachableFrom both key on agents.type == "built_in", so the original could hand work on and its copy silently could not. And a built_in source no longer needs a managed Bot to fall back to. On a deployment with none, copying one used to be refused with advice to give the coworker an AG-UI endpoint it was never supposed to have - the same wrong refusal #328 removed for a coworker that brought its own endpoint. The decision is a pure function so it can be tested without a database. The stored row is read inside the transaction and after the access check, rather than widening AgentProfile: the DTO every surface receives should not start carrying a Bot's instructions. `auth` is still deliberately not copied. Co-authored-by: kevin9327 <kevin9327@users.noreply.github.com> Co-authored-by: Claude Opus 5 <noreply@anthropic.com> Co-authored-by: David McKay <david@copilotkit.ai>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #327.
What this changes
Duplicating a coworker now gives back a copy that runs where the original ran.
duplicate()wrote the managed Bot's address into every copy without reading the source, so duplicating a coworker hosted at its own AG-UI endpoint produced one answering from a different process under the same name, title and role. The copy'sbuiltInflipped to true as a result, and the connection section hides the endpoint entirely once that is set, so the swap was invisible on the one screen somebody would check.The managed address is the fallback
create()already applies to a coworker given no endpoint. This makesduplicate()treat it the same way rather than as a rule, which fixes three things at once:The endpoint alone is inherited, never the rest of the configuration.
authis a reference into the vault, so copying it would leave two coworkers sharing one credential, where rotating either one's key silently changes the other's. A copy starts with no key and fails closed at its endpoint until somebody gives it one.Not changed here:
avatarSeedis copied from the source and is pinned by an existing test, so a copy still renders the source's avatar. That is worth deciding on its own rather than inside this change.Where it runs
INSERTgains a value read from the row being copied, inside the transaction that already reads it.duplicate()reads its source and writes its copy in one transaction, and the value it now writes comes from that transaction's own read rather than from process configuration. Two replicas duplicating the same source produce two copies with distinct minted ids, exactly as before.Boundary and audit
ManagedAgentUnavailableErrorstill fires, on a strictly smaller set of cases (no managed Bot and no endpoint on the source), and is mapped by the samemapStoreErrorpath as before.Changelog
Unreleased.Proof
Five tests added to
server/tests/agent-profile-store.integration.test.ts, which exercises the real store against Postgres.Run against the unfixed code first, two fail and three pass. The two that fail are the proof; the three that pass pin behaviour this change must not break.
After the change:
The three that passed both before and after:
hasAuthand onauthFromConfigurationover its stored row),Verified end to end against a running server as well, not only in tests. A coworker created at
http://localhost:4201/ag-uiduplicates to a copy athttp://localhost:4201/ag-uiwithbuiltIn: false; an endpoint-less coworker duplicates to the managed address withbuiltIn: true; and a second server started with bothMANAGED_AGENT_*variables unset returns201for the first case where it returned400before.Full server suite run with the local dev server and worker stopped, since they contend on the same database and make the lease tests flap. The set of failing tests is identical with and without this change (six, all pre-existing, in
routine-sweep.integration.test.tsandagent-handoff-*.integration.test.ts); compared by test name rather than by count.typecheck,lintandformatare clean.