mirror of
https://github.com/getpaseo/paseo.git
synced 2026-07-29 12:01:31 +00:00
Fix E2E tests: gate on credentials and parse agentId robustly
This commit is contained in:
@@ -1133,7 +1133,7 @@ describe("CodexMcpAgentClient (MCP integration)", () => {
|
||||
model: CODEX_TEST_MODEL,
|
||||
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||
cwd,
|
||||
modeId: "auto",
|
||||
modeId: "read-only",
|
||||
approvalPolicy: "on-request",
|
||||
} satisfies AgentSessionConfig;
|
||||
const filePath = path.join(cwd, "permission.txt");
|
||||
|
||||
@@ -19,6 +19,17 @@ function tmpCwd(prefix: string): string {
|
||||
return realpathSync(mkdtempSync(path.join(tmpdir(), prefix)));
|
||||
}
|
||||
|
||||
function hasGitHubCliAuth(): boolean {
|
||||
try {
|
||||
execSync("gh auth status -h github.com", { stdio: "pipe" });
|
||||
return true;
|
||||
} catch {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
const testWithGitHubCliAuth = hasGitHubCliAuth() ? test : test.skip;
|
||||
|
||||
type McpToolResult = {
|
||||
structuredContent?: Record<string, unknown>;
|
||||
content?: Array<{ structuredContent?: Record<string, unknown> } | Record<string, unknown>>;
|
||||
@@ -137,7 +148,7 @@ describe("daemon checkout ship loop", () => {
|
||||
await ctx.cleanup();
|
||||
}, 60000);
|
||||
|
||||
test(
|
||||
testWithGitHubCliAuth(
|
||||
"runs the full checkout ship loop via checkout RPCs",
|
||||
async () => {
|
||||
const repoDir = tmpCwd("checkout-ship-");
|
||||
|
||||
@@ -120,11 +120,36 @@ describe("daemon E2E", () => {
|
||||
createAgentCall.type === "tool_call" &&
|
||||
createAgentCall.output
|
||||
) {
|
||||
// The output contains the agentId
|
||||
const output = createAgentCall.output as { agentId?: string };
|
||||
if (output.agentId) {
|
||||
childAgentId = output.agentId;
|
||||
}
|
||||
const output = createAgentCall.output as unknown;
|
||||
const tryExtract = (value: unknown): string | null => {
|
||||
if (!value) return null;
|
||||
if (typeof value === "string") {
|
||||
try {
|
||||
return tryExtract(JSON.parse(value));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
if (typeof value !== "object") return null;
|
||||
const asObj = value as Record<string, unknown>;
|
||||
const direct = asObj.agentId;
|
||||
if (typeof direct === "string") return direct;
|
||||
const structured = asObj.structuredContent;
|
||||
if (structured && typeof structured === "object") {
|
||||
const nested = (structured as Record<string, unknown>).agentId;
|
||||
if (typeof nested === "string") return nested;
|
||||
}
|
||||
if (typeof structured === "string") {
|
||||
try {
|
||||
return tryExtract(JSON.parse(structured));
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
childAgentId = tryExtract(output);
|
||||
}
|
||||
|
||||
// Verify we found the child agent ID
|
||||
|
||||
@@ -40,7 +40,7 @@ describe("daemon E2E", () => {
|
||||
provider: "codex", model: CODEX_TEST_MODEL, reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||
cwd,
|
||||
title: "Codex Permission Test",
|
||||
modeId: "auto",
|
||||
modeId: "read-only",
|
||||
});
|
||||
|
||||
expect(agent.id).toBeTruthy();
|
||||
@@ -105,7 +105,7 @@ describe("daemon E2E", () => {
|
||||
provider: "codex", model: CODEX_TEST_MODEL, reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||
cwd,
|
||||
title: "Codex Permission Deny Test",
|
||||
modeId: "auto",
|
||||
modeId: "read-only",
|
||||
});
|
||||
|
||||
expect(agent.id).toBeTruthy();
|
||||
|
||||
@@ -17,7 +17,12 @@ function tmpCwd(): string {
|
||||
const CODEX_TEST_MODEL = "gpt-5.1-codex-mini";
|
||||
const CODEX_TEST_REASONING_EFFORT = "low";
|
||||
|
||||
describe("daemon E2E", () => {
|
||||
const hasClaudeCredentials =
|
||||
!!process.env.CLAUDE_SESSION_TOKEN || !!process.env.ANTHROPIC_API_KEY;
|
||||
|
||||
const describeWithClaude = hasClaudeCredentials ? describe : describe.skip;
|
||||
|
||||
describeWithClaude("daemon E2E", () => {
|
||||
let ctx: DaemonTestContext;
|
||||
|
||||
beforeEach(async () => {
|
||||
@@ -389,43 +394,26 @@ describe("daemon E2E", () => {
|
||||
const queue = ctx.client.getMessageQueue();
|
||||
const assistantChunks: string[] = [];
|
||||
|
||||
// Debug: dump all events from queue
|
||||
|
||||
for (let i = 0; i < queue.length; i++) {
|
||||
const m = queue[i];
|
||||
if (m.type === "agent_stream" && m.payload.agentId === agent.id) {
|
||||
const event = m.payload.event;
|
||||
if (event.type === "timeline") {
|
||||
const item = event.item;
|
||||
|
||||
} else {
|
||||
|
||||
}
|
||||
} else if (m.type === "agent_state" && m.payload.id === agent.id) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// Find the user_message for message 2 to mark the boundary
|
||||
let foundMsg2UserMessage = false;
|
||||
// We only care about Turn 2 ("Hello world ..."), but event ordering can be noisy when
|
||||
// Turn 1 is still streaming. Anchor on the assistant response content itself.
|
||||
let startedCollecting = false;
|
||||
|
||||
for (let i = msg2StartPosition; i < queue.length; i++) {
|
||||
const m = queue[i];
|
||||
|
||||
// Look for our user message to mark the start of message 2 context
|
||||
if (
|
||||
m.type === "agent_stream" &&
|
||||
m.payload.agentId === agent.id &&
|
||||
m.payload.event.type === "timeline"
|
||||
) {
|
||||
const item = m.payload.event.item;
|
||||
if (item.type === "user_message" && (item.text as string)?.includes("Hello world")) {
|
||||
foundMsg2UserMessage = true;
|
||||
|
||||
}
|
||||
// Collect assistant messages after we found the user message
|
||||
if (foundMsg2UserMessage && item.type === "assistant_message" && item.text) {
|
||||
assistantChunks.push(item.text);
|
||||
if (item.type === "assistant_message" && item.text) {
|
||||
const text = String(item.text);
|
||||
if (!startedCollecting && text.includes("Hello")) {
|
||||
startedCollecting = true;
|
||||
}
|
||||
if (startedCollecting) {
|
||||
assistantChunks.push(text);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user