refactor: remove paseo prompt instructions and add real agent tests
This commit is contained in:
@@ -1,321 +1,148 @@
|
|||||||
import { describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeEach, describe, expect, test } from "vitest";
|
||||||
|
import { execSync } from "child_process";
|
||||||
|
import { mkdtempSync, rmSync, writeFileSync, realpathSync } from "fs";
|
||||||
|
import { tmpdir } from "os";
|
||||||
|
import path from "path";
|
||||||
|
import pino from "pino";
|
||||||
|
|
||||||
import { createTestLogger } from "../../test-utils/test-logger.js";
|
import { AgentManager } from "./agent-manager.js";
|
||||||
import type { AgentManager } from "./agent-manager.js";
|
import { AgentStorage } from "./agent-storage.js";
|
||||||
import {
|
import { createAllClients, shutdownProviders } from "./provider-registry.js";
|
||||||
determineAgentMetadataNeeds,
|
import { generateAndApplyAgentMetadata } from "./agent-metadata-generator.js";
|
||||||
generateAndApplyAgentMetadata,
|
import { createWorktree, validateBranchSlug } from "../../utils/worktree.js";
|
||||||
scheduleAgentMetadataGeneration,
|
|
||||||
} from "./agent-metadata-generator.js";
|
|
||||||
|
|
||||||
const logger = createTestLogger();
|
const CODEX_TEST_MODEL = "gpt-5.1-codex-mini";
|
||||||
|
const CODEX_TEST_REASONING_EFFORT = "low";
|
||||||
|
|
||||||
function createAgentManagerStub() {
|
function tmpCwd(prefix: string): string {
|
||||||
return {
|
return realpathSync(mkdtempSync(path.join(tmpdir(), prefix)));
|
||||||
setTitle: vi.fn().mockResolvedValue(undefined),
|
|
||||||
} as unknown as AgentManager;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function delayImmediate(): Promise<void> {
|
function initGitRepo(repoDir: string): void {
|
||||||
return new Promise((resolve) => setImmediate(resolve));
|
execSync("git init -b main", { cwd: repoDir, stdio: "pipe" });
|
||||||
|
execSync("git config user.email 'paseo-test@example.com'", {
|
||||||
|
cwd: repoDir,
|
||||||
|
stdio: "pipe",
|
||||||
|
});
|
||||||
|
execSync("git config user.name 'Paseo Test'", {
|
||||||
|
cwd: repoDir,
|
||||||
|
stdio: "pipe",
|
||||||
|
});
|
||||||
|
writeFileSync(path.join(repoDir, "README.md"), "init\n");
|
||||||
|
execSync("git add README.md", { cwd: repoDir, stdio: "pipe" });
|
||||||
|
execSync("git -c commit.gpgsign=false commit -m 'Initial commit'", {
|
||||||
|
cwd: repoDir,
|
||||||
|
stdio: "pipe",
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSchemaKeys(schema: unknown): string[] {
|
describe("agent metadata generation (real agents)", () => {
|
||||||
const shape =
|
const logger = pino({ level: "silent" });
|
||||||
(schema as { shape?: Record<string, unknown> }).shape ??
|
let repoDir: string;
|
||||||
(schema as { _def?: { shape?: () => Record<string, unknown> } })._def?.shape?.();
|
let paseoHome: string;
|
||||||
return shape ? Object.keys(shape).sort() : [];
|
let storagePath: string;
|
||||||
}
|
let manager: AgentManager;
|
||||||
|
let storage: AgentStorage;
|
||||||
|
let codexSessionDir: string;
|
||||||
|
let previousCodexSessionDir: string | undefined;
|
||||||
|
|
||||||
describe("agent metadata generation", () => {
|
beforeEach(() => {
|
||||||
it("skips generation when there is no initial prompt", async () => {
|
repoDir = tmpCwd("metadata-repo-");
|
||||||
const agentManager = createAgentManagerStub();
|
initGitRepo(repoDir);
|
||||||
const generator = vi.fn();
|
paseoHome = tmpCwd("metadata-paseo-home-");
|
||||||
|
storagePath = path.join(paseoHome, "agents");
|
||||||
await generateAndApplyAgentMetadata({
|
storage = new AgentStorage(storagePath, logger);
|
||||||
agentManager,
|
manager = new AgentManager({
|
||||||
agentId: "agent-1",
|
clients: createAllClients(logger),
|
||||||
cwd: "/tmp",
|
registry: storage,
|
||||||
initialPrompt: " ",
|
|
||||||
logger,
|
logger,
|
||||||
deps: { generateStructuredAgentResponse: generator },
|
|
||||||
});
|
});
|
||||||
|
codexSessionDir = tmpCwd("codex-sessions-");
|
||||||
expect(generator).not.toHaveBeenCalled();
|
previousCodexSessionDir = process.env.CODEX_SESSION_DIR;
|
||||||
|
process.env.CODEX_SESSION_DIR = codexSessionDir;
|
||||||
});
|
});
|
||||||
|
|
||||||
it("determines title needs when explicit title is missing", async () => {
|
afterEach(async () => {
|
||||||
const needs = await determineAgentMetadataNeeds({
|
process.env.CODEX_SESSION_DIR = previousCodexSessionDir;
|
||||||
cwd: "/tmp",
|
await shutdownProviders(logger);
|
||||||
initialPrompt: "Do the thing",
|
rmSync(repoDir, { recursive: true, force: true });
|
||||||
explicitTitle: null,
|
rmSync(paseoHome, { recursive: true, force: true });
|
||||||
deps: {
|
rmSync(codexSessionDir, { recursive: true, force: true });
|
||||||
getCheckoutStatus: async () => ({
|
}, 60000);
|
||||||
isGit: false,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(needs.needsTitle).toBe(true);
|
test(
|
||||||
expect(needs.needsBranch).toBe(false);
|
"generates a title using a real Codex agent",
|
||||||
});
|
async () => {
|
||||||
|
const agent = await manager.createAgent({
|
||||||
|
provider: "codex",
|
||||||
|
model: CODEX_TEST_MODEL,
|
||||||
|
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||||
|
modeId: "auto",
|
||||||
|
cwd: repoDir,
|
||||||
|
title: "Main Agent",
|
||||||
|
}, "metadata-title-agent");
|
||||||
|
|
||||||
it("schedules async title generation", async () => {
|
await generateAndApplyAgentMetadata({
|
||||||
const agentManager = createAgentManagerStub();
|
agentManager: manager,
|
||||||
const generator = vi.fn(async () => ({ title: "Generated Title" }));
|
agentId: agent.id,
|
||||||
|
cwd: repoDir,
|
||||||
|
initialPrompt: "Use the exact title 'Metadata Title E2E'.",
|
||||||
|
explicitTitle: null,
|
||||||
|
paseoHome,
|
||||||
|
logger,
|
||||||
|
});
|
||||||
|
|
||||||
scheduleAgentMetadataGeneration({
|
await storage.flush();
|
||||||
agentManager,
|
const record = await storage.get(agent.id);
|
||||||
agentId: "agent-2",
|
expect(record?.title).toBe("Metadata Title E2E");
|
||||||
cwd: "/tmp",
|
|
||||||
initialPrompt: "Create a report",
|
|
||||||
explicitTitle: null,
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: false,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(generator).not.toHaveBeenCalled();
|
await manager.closeAgent(agent.id);
|
||||||
|
},
|
||||||
|
180000
|
||||||
|
);
|
||||||
|
|
||||||
await delayImmediate();
|
test(
|
||||||
|
"renames the worktree branch using a real Codex agent",
|
||||||
|
async () => {
|
||||||
|
const worktreeSlug = "metadata-worktree";
|
||||||
|
const worktree = await createWorktree({
|
||||||
|
branchName: worktreeSlug,
|
||||||
|
cwd: repoDir,
|
||||||
|
baseBranch: "main",
|
||||||
|
worktreeSlug,
|
||||||
|
paseoHome,
|
||||||
|
});
|
||||||
|
|
||||||
expect(generator).toHaveBeenCalledTimes(1);
|
const agent = await manager.createAgent({
|
||||||
expect(agentManager.setTitle).toHaveBeenCalledWith(
|
provider: "codex",
|
||||||
"agent-2",
|
model: CODEX_TEST_MODEL,
|
||||||
"Generated Title"
|
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||||
);
|
modeId: "auto",
|
||||||
});
|
cwd: worktree.worktreePath,
|
||||||
|
title: "Worktree Agent",
|
||||||
|
}, "metadata-branch-agent");
|
||||||
|
|
||||||
it("selects title-only schema when branch is not eligible", async () => {
|
await generateAndApplyAgentMetadata({
|
||||||
const agentManager = createAgentManagerStub();
|
agentManager: manager,
|
||||||
let capturedSchema: unknown;
|
agentId: agent.id,
|
||||||
const generator = vi.fn(async (options: any) => {
|
cwd: worktree.worktreePath,
|
||||||
capturedSchema = options.schema;
|
initialPrompt: "Use the exact branch 'feat/metadata-worktree'.",
|
||||||
return { title: "Only Title" };
|
explicitTitle: "Explicit Title",
|
||||||
});
|
paseoHome,
|
||||||
|
logger,
|
||||||
|
});
|
||||||
|
|
||||||
await generateAndApplyAgentMetadata({
|
const currentBranch = execSync("git rev-parse --abbrev-ref HEAD", {
|
||||||
agentManager,
|
cwd: worktree.worktreePath,
|
||||||
agentId: "agent-title-only",
|
stdio: "pipe",
|
||||||
cwd: "/tmp",
|
}).toString().trim();
|
||||||
initialPrompt: "Do the thing",
|
|
||||||
explicitTitle: null,
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: false,
|
|
||||||
}),
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getSchemaKeys(capturedSchema)).toEqual(["title"]);
|
const validation = validateBranchSlug(currentBranch);
|
||||||
});
|
expect(validation.valid).toBe(true);
|
||||||
|
expect(currentBranch).toBe("feat/metadata-worktree");
|
||||||
|
|
||||||
it("selects branch-only schema when explicit title exists and branch is eligible", async () => {
|
await manager.closeAgent(agent.id);
|
||||||
const agentManager = createAgentManagerStub();
|
},
|
||||||
let capturedSchema: unknown;
|
180000
|
||||||
const generator = vi.fn(async (options: any) => {
|
);
|
||||||
capturedSchema = options.schema;
|
|
||||||
return { branch: "feat/branch-only" };
|
|
||||||
});
|
|
||||||
const renameCurrentBranch = vi.fn().mockResolvedValue({
|
|
||||||
previousBranch: "worktree-name",
|
|
||||||
currentBranch: "feat/branch-only",
|
|
||||||
});
|
|
||||||
|
|
||||||
await generateAndApplyAgentMetadata({
|
|
||||||
agentManager,
|
|
||||||
agentId: "agent-branch-only",
|
|
||||||
cwd: "/tmp/worktree",
|
|
||||||
initialPrompt: "Add feature",
|
|
||||||
explicitTitle: "Explicit Title",
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: true,
|
|
||||||
isPaseoOwnedWorktree: true,
|
|
||||||
repoRoot: "/tmp/worktree-name",
|
|
||||||
mainRepoRoot: "/tmp/main",
|
|
||||||
currentBranch: "worktree-name",
|
|
||||||
isDirty: false,
|
|
||||||
baseRef: "main",
|
|
||||||
aheadBehind: null,
|
|
||||||
aheadOfOrigin: null,
|
|
||||||
hasRemote: false,
|
|
||||||
remoteUrl: null,
|
|
||||||
}),
|
|
||||||
renameCurrentBranch,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getSchemaKeys(capturedSchema)).toEqual(["branch"]);
|
|
||||||
expect(agentManager.setTitle).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("selects title+branch schema when both are needed", async () => {
|
|
||||||
const agentManager = createAgentManagerStub();
|
|
||||||
let capturedSchema: unknown;
|
|
||||||
const generator = vi.fn(async (options: any) => {
|
|
||||||
capturedSchema = options.schema;
|
|
||||||
return { title: "Both", branch: "feat/both" };
|
|
||||||
});
|
|
||||||
const renameCurrentBranch = vi.fn().mockResolvedValue({
|
|
||||||
previousBranch: "worktree-name",
|
|
||||||
currentBranch: "feat/both",
|
|
||||||
});
|
|
||||||
|
|
||||||
await generateAndApplyAgentMetadata({
|
|
||||||
agentManager,
|
|
||||||
agentId: "agent-both",
|
|
||||||
cwd: "/tmp/worktree",
|
|
||||||
initialPrompt: "Add payment support",
|
|
||||||
explicitTitle: null,
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: true,
|
|
||||||
isPaseoOwnedWorktree: true,
|
|
||||||
repoRoot: "/tmp/worktree-name",
|
|
||||||
mainRepoRoot: "/tmp/main",
|
|
||||||
currentBranch: "worktree-name",
|
|
||||||
isDirty: false,
|
|
||||||
baseRef: "main",
|
|
||||||
aheadBehind: null,
|
|
||||||
aheadOfOrigin: null,
|
|
||||||
hasRemote: false,
|
|
||||||
remoteUrl: null,
|
|
||||||
}),
|
|
||||||
renameCurrentBranch,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(getSchemaKeys(capturedSchema)).toEqual(["branch", "title"]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("renames branch when eligible, even with explicit title", async () => {
|
|
||||||
const agentManager = createAgentManagerStub();
|
|
||||||
const generator = vi.fn(async () => ({ branch: "feat/auto-branch" }));
|
|
||||||
const renameCurrentBranch = vi.fn().mockResolvedValue({
|
|
||||||
previousBranch: "worktree-name",
|
|
||||||
currentBranch: "feat/auto-branch",
|
|
||||||
});
|
|
||||||
|
|
||||||
await generateAndApplyAgentMetadata({
|
|
||||||
agentManager,
|
|
||||||
agentId: "agent-3",
|
|
||||||
cwd: "/tmp/worktree",
|
|
||||||
initialPrompt: "Add payment support",
|
|
||||||
explicitTitle: "Payments",
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: true,
|
|
||||||
isPaseoOwnedWorktree: true,
|
|
||||||
repoRoot: "/tmp/worktree-name",
|
|
||||||
mainRepoRoot: "/tmp/main",
|
|
||||||
currentBranch: "worktree-name",
|
|
||||||
isDirty: false,
|
|
||||||
baseRef: "main",
|
|
||||||
aheadBehind: null,
|
|
||||||
aheadOfOrigin: null,
|
|
||||||
hasRemote: false,
|
|
||||||
remoteUrl: null,
|
|
||||||
}),
|
|
||||||
renameCurrentBranch,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(generator).toHaveBeenCalledTimes(1);
|
|
||||||
expect(renameCurrentBranch).toHaveBeenCalledWith(
|
|
||||||
"/tmp/worktree",
|
|
||||||
"feat/auto-branch"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("skips rename when generated branch is invalid", async () => {
|
|
||||||
const agentManager = createAgentManagerStub();
|
|
||||||
const generator = vi.fn(async () => ({ branch: "Invalid Branch" }));
|
|
||||||
const renameCurrentBranch = vi.fn();
|
|
||||||
|
|
||||||
await generateAndApplyAgentMetadata({
|
|
||||||
agentManager,
|
|
||||||
agentId: "agent-invalid-branch",
|
|
||||||
cwd: "/tmp/worktree",
|
|
||||||
initialPrompt: "Ship it",
|
|
||||||
explicitTitle: "Explicit",
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: true,
|
|
||||||
isPaseoOwnedWorktree: true,
|
|
||||||
repoRoot: "/tmp/worktree-name",
|
|
||||||
mainRepoRoot: "/tmp/main",
|
|
||||||
currentBranch: "worktree-name",
|
|
||||||
isDirty: false,
|
|
||||||
baseRef: "main",
|
|
||||||
aheadBehind: null,
|
|
||||||
aheadOfOrigin: null,
|
|
||||||
hasRemote: false,
|
|
||||||
remoteUrl: null,
|
|
||||||
}),
|
|
||||||
renameCurrentBranch,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(renameCurrentBranch).not.toHaveBeenCalled();
|
|
||||||
});
|
|
||||||
|
|
||||||
it("schedules async branch generation for worktree agents", async () => {
|
|
||||||
const agentManager = createAgentManagerStub();
|
|
||||||
const generator = vi.fn(async () => ({ branch: "feat/async-branch" }));
|
|
||||||
const renameCurrentBranch = vi.fn().mockResolvedValue({
|
|
||||||
previousBranch: "worktree-name",
|
|
||||||
currentBranch: "feat/async-branch",
|
|
||||||
});
|
|
||||||
|
|
||||||
scheduleAgentMetadataGeneration({
|
|
||||||
agentManager,
|
|
||||||
agentId: "agent-4",
|
|
||||||
cwd: "/tmp/worktree",
|
|
||||||
initialPrompt: "Ship the feature",
|
|
||||||
explicitTitle: "Explicit Title",
|
|
||||||
logger,
|
|
||||||
deps: {
|
|
||||||
generateStructuredAgentResponse: generator,
|
|
||||||
getCheckoutStatus: async () => ({
|
|
||||||
isGit: true,
|
|
||||||
isPaseoOwnedWorktree: true,
|
|
||||||
repoRoot: "/tmp/worktree-name",
|
|
||||||
mainRepoRoot: "/tmp/main",
|
|
||||||
currentBranch: "worktree-name",
|
|
||||||
isDirty: false,
|
|
||||||
baseRef: "main",
|
|
||||||
aheadBehind: null,
|
|
||||||
aheadOfOrigin: null,
|
|
||||||
hasRemote: false,
|
|
||||||
remoteUrl: null,
|
|
||||||
}),
|
|
||||||
renameCurrentBranch,
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
expect(generator).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
await delayImmediate();
|
|
||||||
|
|
||||||
expect(generator).toHaveBeenCalledTimes(1);
|
|
||||||
expect(renameCurrentBranch).toHaveBeenCalledWith(
|
|
||||||
"/tmp/worktree",
|
|
||||||
"feat/async-branch"
|
|
||||||
);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,7 +14,9 @@ import {
|
|||||||
type CheckoutStatusResult,
|
type CheckoutStatusResult,
|
||||||
} from "../../utils/checkout-git.js";
|
} from "../../utils/checkout-git.js";
|
||||||
|
|
||||||
const AUTO_GEN_MODEL = "haiku";
|
const AUTO_GEN_PROVIDER = "codex" as const;
|
||||||
|
const AUTO_GEN_MODEL = "gpt-5.1-codex-mini";
|
||||||
|
const AUTO_GEN_REASONING_EFFORT = "low";
|
||||||
|
|
||||||
export type AgentMetadataGeneratorDeps = {
|
export type AgentMetadataGeneratorDeps = {
|
||||||
generateStructuredAgentResponse?: typeof generateStructuredAgentResponse;
|
generateStructuredAgentResponse?: typeof generateStructuredAgentResponse;
|
||||||
@@ -156,8 +158,9 @@ export async function generateAndApplyAgentMetadata(
|
|||||||
result = await generator({
|
result = await generator({
|
||||||
manager: options.agentManager,
|
manager: options.agentManager,
|
||||||
agentConfig: {
|
agentConfig: {
|
||||||
provider: "claude",
|
provider: AUTO_GEN_PROVIDER,
|
||||||
model: AUTO_GEN_MODEL,
|
model: AUTO_GEN_MODEL,
|
||||||
|
reasoningEffort: AUTO_GEN_REASONING_EFFORT,
|
||||||
cwd: options.cwd,
|
cwd: options.cwd,
|
||||||
title: "Agent metadata generator",
|
title: "Agent metadata generator",
|
||||||
internal: true,
|
internal: true,
|
||||||
|
|||||||
@@ -147,8 +147,6 @@ describe("Codex app-server provider (integration)", () => {
|
|||||||
cwd,
|
cwd,
|
||||||
modeId: "auto",
|
modeId: "auto",
|
||||||
approvalPolicy: "on-request",
|
approvalPolicy: "on-request",
|
||||||
paseoPromptInstructions:
|
|
||||||
"You must use the shell tool for command execution tasks. Do not answer without running the command.",
|
|
||||||
model: CODEX_TEST_MODEL,
|
model: CODEX_TEST_MODEL,
|
||||||
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||||
});
|
});
|
||||||
@@ -229,8 +227,6 @@ describe("Codex app-server provider (integration)", () => {
|
|||||||
cwd,
|
cwd,
|
||||||
modeId: "full-access",
|
modeId: "full-access",
|
||||||
approvalPolicy: "on-request",
|
approvalPolicy: "on-request",
|
||||||
paseoPromptInstructions:
|
|
||||||
"You must use shell for commands and apply_patch for file edits. Do not skip tool usage.",
|
|
||||||
model: CODEX_TEST_MODEL,
|
model: CODEX_TEST_MODEL,
|
||||||
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||||
});
|
});
|
||||||
@@ -552,8 +548,6 @@ describe("Codex app-server provider (integration)", () => {
|
|||||||
cwd,
|
cwd,
|
||||||
modeId: "full-access",
|
modeId: "full-access",
|
||||||
approvalPolicy: "on-request",
|
approvalPolicy: "on-request",
|
||||||
paseoPromptInstructions:
|
|
||||||
"You must use the apply_patch tool for file edits. Do not use the shell tool for file changes.",
|
|
||||||
model: CODEX_TEST_MODEL,
|
model: CODEX_TEST_MODEL,
|
||||||
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
reasoningEffort: CODEX_TEST_REASONING_EFFORT,
|
||||||
});
|
});
|
||||||
@@ -616,9 +610,6 @@ describe("Codex app-server provider (integration)", () => {
|
|||||||
expect(sawPermissionResolved).toBe(true);
|
expect(sawPermissionResolved).toBe(true);
|
||||||
}
|
}
|
||||||
expect(sawPermission || timelineItems.length > 0).toBe(true);
|
expect(sawPermission || timelineItems.length > 0).toBe(true);
|
||||||
expect(
|
|
||||||
timelineItems.some((item) => item.type === "tool_call" && item.name === "apply_patch")
|
|
||||||
).toBe(true);
|
|
||||||
expect(readFileSync(targetPath, "utf8").trim()).toBe("ok");
|
expect(readFileSync(targetPath, "utf8").trim()).toBe("ok");
|
||||||
} finally {
|
} finally {
|
||||||
cleanup();
|
cleanup();
|
||||||
|
|||||||
@@ -33,7 +33,6 @@ import os from "node:os";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import readline from "node:readline";
|
import readline from "node:readline";
|
||||||
|
|
||||||
import { injectLeadingPaseoInstructionTag } from "../paseo-instructions-tag.js";
|
|
||||||
|
|
||||||
const DEFAULT_TIMEOUT_MS = 14 * 24 * 60 * 60 * 1000;
|
const DEFAULT_TIMEOUT_MS = 14 * 24 * 60 * 60 * 1000;
|
||||||
const CODEX_PROVIDER = "codex" as const;
|
const CODEX_PROVIDER = "codex" as const;
|
||||||
@@ -1335,37 +1334,15 @@ class CodexAppServerAgentSession implements AgentSession {
|
|||||||
|
|
||||||
private buildUserInput(prompt: AgentPromptInput): unknown[] {
|
private buildUserInput(prompt: AgentPromptInput): unknown[] {
|
||||||
if (typeof prompt === "string") {
|
if (typeof prompt === "string") {
|
||||||
const text = this.paseoInstructionsInjected
|
|
||||||
? prompt
|
|
||||||
: injectLeadingPaseoInstructionTag(prompt, this.config.paseoPromptInstructions);
|
|
||||||
this.paseoInstructionsInjected = true;
|
this.paseoInstructionsInjected = true;
|
||||||
return [{ type: "text", text }];
|
return [{ type: "text", text: prompt }];
|
||||||
}
|
}
|
||||||
const blocks = prompt as AgentPromptContentBlock[];
|
const blocks = prompt as AgentPromptContentBlock[];
|
||||||
if (this.paseoInstructionsInjected) {
|
if (this.paseoInstructionsInjected) {
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
this.paseoInstructionsInjected = true;
|
this.paseoInstructionsInjected = true;
|
||||||
if (blocks.length === 0) {
|
return blocks;
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
const first = blocks[0];
|
|
||||||
if (first && typeof first === "object" && (first as { type?: string }).type === "text") {
|
|
||||||
const textBlock = first as { type: "text"; text: string };
|
|
||||||
const text = injectLeadingPaseoInstructionTag(
|
|
||||||
textBlock.text ?? "",
|
|
||||||
this.config.paseoPromptInstructions
|
|
||||||
);
|
|
||||||
return [{ ...textBlock, text }, ...blocks.slice(1)];
|
|
||||||
}
|
|
||||||
const injected = injectLeadingPaseoInstructionTag(
|
|
||||||
"",
|
|
||||||
this.config.paseoPromptInstructions
|
|
||||||
);
|
|
||||||
if (injected.trim().length === 0) {
|
|
||||||
return blocks;
|
|
||||||
}
|
|
||||||
return [{ type: "text", text: injected }, ...blocks];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private emitEvent(event: AgentStreamEvent): void {
|
private emitEvent(event: AgentStreamEvent): void {
|
||||||
|
|||||||
Reference in New Issue
Block a user