Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions apps/server/src/peer/PeerLinkRequests.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -985,6 +985,11 @@ it.live("naming a machine that is already linked returns the link at once, with
// Not both: the address could name another machine than the id.
const both = yield* a.call({ environmentId: box.environmentId, url: b.url });
expect(errorOf(both)).toMatchObject({ code: "invalid_request" });

// A mention can name the machine the agent runs on, which has nothing to link.
const own = yield* a.call({ environmentId: laptop.environmentId });
expect(errorOf(own)).toMatchObject({ code: "invalid_request" });
expect(yield* cardOf(a)).toBeUndefined();
}),
),
);
Expand Down
6 changes: 6 additions & 0 deletions apps/server/src/peer/PeerLinkRequests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,12 @@ const make = Effect.gen(function* () {
"Pass either environmentId or url, not both. Pass neither to let the user pick the machine.",
});
}
if (input.environmentId === scope.environmentId) {
return yield* new OrchestratorMcpFailure({
code: "invalid_request",
message: "That is the machine you run on. Work here: it needs no link.",
});
}
// A machine already linked needs no card: the agent can use it now.
if (input.environmentId !== undefined) {
const linked = yield* usableLink(input.environmentId).pipe(
Expand Down
13 changes: 11 additions & 2 deletions packages/client-runtime/src/composerThreadItems.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ describe("matchComposerEnvironmentItems", () => {
{ environmentId: EnvironmentId.make("env-mini"), label: "Mac mini", machine: "mac-mini" },
] as const;

it("offers the other machines matching the query, never the composer's own", () => {
it("offers the machines matching the query, naming the thread's own", () => {
expect(
matchComposerEnvironmentItems({
environments,
Expand All @@ -108,7 +108,16 @@ describe("matchComposerEnvironmentItems", () => {
environmentId: EnvironmentId.make("env-here"),
query: "lap",
}),
).toEqual([]);
).toEqual([
{
id: "environment:env-here",
type: "environment",
environmentId: "env-here",
machine: "laptop",
label: "Laptop",
description: "This thread's machine",
},
]);
expect(
matchComposerEnvironmentItems({
environments,
Expand Down
15 changes: 6 additions & 9 deletions packages/client-runtime/src/composerThreadItems.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ export interface ComposerEnvironmentItem {
}

/**
* The user's machines the `@` picker offers, so the agent can link or work there. The
* composer's own environment is left out. Like threads, they need a query: bare `@` stays a
* file picker.
* The user's machines the `@` picker offers, so the agent can link or work there. That includes
* the thread's own machine, which the user may still want to name. Like threads, they need a
* query: bare `@` stays a file picker.
*/
export function matchComposerEnvironmentItems(input: {
environments: ReadonlyArray<ComposerEnvironmentCandidate>;
Expand All @@ -99,17 +99,14 @@ export function matchComposerEnvironmentItems(input: {
const query = input.query.trim().toLowerCase();
if (query.length === 0) return [];
return input.environments
.filter(
(environment) =>
environment.environmentId !== input.environmentId &&
environment.label.toLowerCase().includes(query),
)
.filter((environment) => environment.label.toLowerCase().includes(query))
.map((environment) => ({
id: `environment:${environment.environmentId}`,
type: "environment",
environmentId: environment.environmentId,
machine: environment.machine,
label: environment.label,
description: "Machine",
description:
environment.environmentId === input.environmentId ? "This thread's machine" : "Machine",
}));
}
2 changes: 1 addition & 1 deletion packages/shared/src/composerContextReferences.ts
Original file line number Diff line number Diff line change
Expand Up @@ -353,7 +353,7 @@ function formatComposerContextProviderPayload(record: KnownComposerContextRecord
return [
`label: ${record.label}`,
`environmentId: ${record.environmentId}`,
"The user means this machine. Not linked here yet: call t3_environment_link with this environmentId. Linked: pass it as environmentId, or target.environmentId for delegate_task.",
"The user means this machine. Not linked here yet: call t3_environment_link with this environmentId, which says so if it is the machine you run on. Linked: pass it as environmentId, or target.environmentId for delegate_task.",
].join("\n");
}
}
Expand Down
Loading