Skip to content
Merged
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
13 changes: 13 additions & 0 deletions apps/code/src/main/services/agent/service.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -240,6 +240,19 @@ describe("AgentService", () => {
});

describe("MCP servers", () => {
it("marks desktop sessions as local even though they have a taskRunId", async () => {
await service.startSession({
...baseSessionParams,
adapter: "codex",
});

expect(mockNewSession).toHaveBeenCalledTimes(1);
expect(mockNewSession.mock.calls[0][0]._meta).toMatchObject({
taskRunId: "run-1",
environment: "local",
});
});

it("passes MCP servers to newSession for codex adapter", async () => {
await service.startSession({
...baseSessionParams,
Expand Down
2 changes: 2 additions & 0 deletions apps/code/src/main/services/agent/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,6 +789,7 @@ When creating pull requests, add the following footer at the end of the PR descr
persistence: { taskId, runId: taskRunId, logUrl },
}),
taskRunId,
environment: "local",
sessionId: existingSessionId,
systemPrompt,
mcpToolApprovals: toolApprovals,
Expand All @@ -814,6 +815,7 @@ When creating pull requests, add the following footer at the end of the PR descr
mcpServers,
_meta: {
taskRunId,
environment: "local",
systemPrompt,
mcpToolApprovals: toolApprovals,
...(permissionMode && { permissionMode }),
Expand Down
2 changes: 1 addition & 1 deletion packages/agent/src/adapters/claude/mcp/local-tools.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ describe("createLocalToolsMcpServer", () => {
it("exposes git_signed_commit over MCP in a cloud run with a token", async () => {
const server = createLocalToolsMcpServer(
{ cwd: "/repo", token: "ghs_x" },
{ taskRunId: "run-1" },
{ environment: "cloud" },
);
if (!server) {
throw new Error("expected the local-tools server to be registered");
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/adapters/claude/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ export type SDKMessageFilter = {
export type NewSessionMeta = {
taskRunId?: string;
taskId?: string;
environment?: "local" | "cloud";
disableBuiltInTools?: boolean;
systemPrompt?: unknown;
sessionId?: string;
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/adapters/codex/codex-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export {
interface NewSessionMeta {
taskRunId?: string;
taskId?: string;
environment?: "local" | "cloud";
systemPrompt?: string;
permissionMode?: string;
model?: string;
Expand Down
43 changes: 32 additions & 11 deletions packages/agent/src/adapters/local-tools/registry.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ describe("local-tools registry", () => {
const savedSandbox = process.env.IS_SANDBOX;

beforeEach(() => {
// isCloudRun also keys off IS_SANDBOX; clear it so meta.taskRunId is the
// isCloudRun also keys off IS_SANDBOX; clear it so meta.environment is the
// only cloud signal under test.
delete process.env.IS_SANDBOX;
});
Expand All @@ -35,23 +35,44 @@ describe("local-tools registry", () => {
});

it.each([
{ name: "cloud run with a token", taskRunId: "run-1", token: "ghs_x" },
{ name: "cloud run without a token", taskRunId: "run-1", token: undefined },
{ name: "desktop run with a token", taskRunId: undefined, token: "ghs_x" },
{
name: "cloud run with a token",
meta: { environment: "cloud" as const },
token: "ghs_x",
expected: true,
},
{
name: "cloud run without a token",
meta: { environment: "cloud" as const },
token: undefined,
expected: false,
},
{
name: "desktop run with a token",
meta: { environment: "local" as const },
token: "ghs_x",
expected: false,
},
{
name: "desktop run without a token",
taskRunId: undefined,
meta: { environment: "local" as const },
token: undefined,
expected: false,
},
])(
"exposes git_signed_commit only in $name when cloud+token",
({ taskRunId, token }) => {
const tools = enabledLocalTools(
{ cwd: "/repo", token },
taskRunId ? { taskRunId } : undefined,
);
({ meta, token, expected }) => {
const tools = enabledLocalTools({ cwd: "/repo", token }, meta);
const hasSignedCommit = tools.some((t) => t.name === "git_signed_commit");
expect(hasSignedCommit).toBe(Boolean(taskRunId) && Boolean(token));
expect(hasSignedCommit).toBe(expected);
},
);

it("does not treat legacy taskRunId-only metadata as cloud", () => {
const tools = enabledLocalTools({ cwd: "/repo", token: "ghs_x" }, {
taskRunId: "run-1",
} as unknown as { environment?: "local" | "cloud" });
const hasSignedCommit = tools.some((t) => t.name === "git_signed_commit");
expect(hasSignedCommit).toBe(false);
});
});
2 changes: 1 addition & 1 deletion packages/agent/src/adapters/local-tools/registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export interface LocalToolCtx {

/** Minimal session-meta shape needed to gate tools (e.g. cloud-only). */
export interface LocalToolGateMeta {
taskRunId?: string;
environment?: "local" | "cloud";
}
Comment thread
tatoalo marked this conversation as resolved.

/**
Expand Down
1 change: 1 addition & 0 deletions packages/agent/src/server/agent-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -976,6 +976,7 @@ export class AgentServer {
sessionId: payload.run_id,
taskRunId: payload.run_id,
taskId: payload.task_id,
environment: "cloud",
systemPrompt: sessionSystemPrompt,
...(this.config.model && { model: this.config.model }),
allowedDomains: this.config.allowedDomains,
Expand Down
13 changes: 9 additions & 4 deletions packages/agent/src/utils/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,16 @@ export const IS_ROOT =
export const ALLOW_BYPASS = !IS_ROOT || !!process.env.IS_SANDBOX;

/**
* A cloud sandbox run, as opposed to a local desktop session. Cloud sandboxes
* always set IS_SANDBOX and carry a taskRunId; desktop sessions have neither.
* A cloud sandbox run, as opposed to a local desktop session. `taskRunId` is
* used by both desktop and cloud for persistence, so it must not imply cloud.
*/
export function isCloudRun(meta: { taskRunId?: string } | undefined): boolean {
return !!process.env.IS_SANDBOX || !!meta?.taskRunId;
export function isCloudRun(
meta: { environment?: "local" | "cloud" } | undefined,
): boolean {
if (meta?.environment) {
return meta.environment === "cloud";
}
return !!process.env.IS_SANDBOX;
}

/** The GitHub token available to the sandbox, if any. */
Expand Down
Loading