refactor: share owner prompts and tighten silent output guidance
This commit is contained in:
@@ -222,6 +222,14 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
||||
path.join(promptsDir, 'codex-review-paired-room.md'),
|
||||
'review paired prompt\n',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(promptsDir, 'owner-common-platform.md'),
|
||||
'owner common platform prompt\n',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(promptsDir, 'owner-common-paired-room.md'),
|
||||
'owner common paired prompt\n',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(promptsDir, 'codex-review-failover-platform.md'),
|
||||
'failover platform prompt\n',
|
||||
@@ -253,12 +261,59 @@ describe('prepareGroupEnvironment codex auth handling', () => {
|
||||
const segments = agents.trim().split('\n\n---\n\n');
|
||||
|
||||
expect(segments).toEqual([
|
||||
'owner common platform prompt',
|
||||
'failover platform prompt',
|
||||
'owner common paired prompt',
|
||||
'failover paired prompt',
|
||||
'memory briefing',
|
||||
]);
|
||||
});
|
||||
|
||||
it('adds the shared owner prompt fragments to Claude session prompts', () => {
|
||||
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
||||
mockReadEnvFile.mockReturnValue({});
|
||||
|
||||
const promptsDir = path.join(tempRoot, 'prompts');
|
||||
fs.mkdirSync(promptsDir, { recursive: true });
|
||||
fs.writeFileSync(
|
||||
path.join(promptsDir, 'owner-common-platform.md'),
|
||||
'owner common platform prompt\n',
|
||||
);
|
||||
fs.writeFileSync(
|
||||
path.join(promptsDir, 'owner-common-paired-room.md'),
|
||||
'owner common paired prompt\n',
|
||||
);
|
||||
|
||||
prepareGroupEnvironment(
|
||||
{ ...group, agentType: 'claude-code' },
|
||||
false,
|
||||
'dc:test',
|
||||
{
|
||||
memoryBriefing: 'memory briefing',
|
||||
},
|
||||
);
|
||||
|
||||
const claudePath = path.join(
|
||||
tempRoot,
|
||||
'sessions',
|
||||
group.folder,
|
||||
'services',
|
||||
'codex-main',
|
||||
'.claude',
|
||||
'CLAUDE.md',
|
||||
);
|
||||
const claude = fs.readFileSync(claudePath, 'utf-8');
|
||||
const segments = claude.trim().split('\n\n---\n\n');
|
||||
|
||||
expect(segments).toEqual([
|
||||
'owner common platform prompt',
|
||||
'platform prompt',
|
||||
'owner common paired prompt',
|
||||
'paired room prompt',
|
||||
'memory briefing',
|
||||
]);
|
||||
});
|
||||
|
||||
it('returns to the normal review prompt stack after failover is cleared', () => {
|
||||
vi.mocked(config.isReviewService).mockReturnValue(true);
|
||||
vi.mocked(db.isPairedRoomJid).mockReturnValue(true);
|
||||
|
||||
@@ -258,10 +258,17 @@ function prepareCodexSessionEnvironment(args: {
|
||||
const sessionAgents = (
|
||||
args.useFailoverPromptPack
|
||||
? [
|
||||
readOptionalPromptFile(args.projectRoot, 'owner-common-platform.md'),
|
||||
readOptionalPromptFile(
|
||||
args.projectRoot,
|
||||
'codex-review-failover-platform.md',
|
||||
),
|
||||
args.isPairedRoom
|
||||
? readOptionalPromptFile(
|
||||
args.projectRoot,
|
||||
'owner-common-paired-room.md',
|
||||
)
|
||||
: undefined,
|
||||
args.isPairedRoom
|
||||
? readOptionalPromptFile(
|
||||
args.projectRoot,
|
||||
@@ -427,7 +434,14 @@ export function prepareGroupEnvironment(
|
||||
effectiveLease.explicit &&
|
||||
effectiveLease.owner_service_id === CODEX_REVIEW_SERVICE_ID;
|
||||
|
||||
const ownerCommonPlatformPrompt = readOptionalPromptFile(
|
||||
projectRoot,
|
||||
'owner-common-platform.md',
|
||||
);
|
||||
const claudePlatformPrompt = readPlatformPrompt('claude-code', projectRoot);
|
||||
const ownerCommonPairedRoomPrompt = isPairedRoom
|
||||
? readOptionalPromptFile(projectRoot, 'owner-common-paired-room.md')
|
||||
: undefined;
|
||||
const claudePairedRoomPrompt = isPairedRoom
|
||||
? readPairedRoomPrompt('claude-code', projectRoot)
|
||||
: undefined;
|
||||
@@ -436,7 +450,9 @@ export function prepareGroupEnvironment(
|
||||
? fs.readFileSync(globalClaudeMdPath, 'utf-8').trim()
|
||||
: undefined;
|
||||
const sessionClaudeMd = [
|
||||
ownerCommonPlatformPrompt,
|
||||
claudePlatformPrompt,
|
||||
ownerCommonPairedRoomPrompt,
|
||||
claudePairedRoomPrompt,
|
||||
globalClaudeMemory,
|
||||
options?.memoryBriefing,
|
||||
|
||||
@@ -222,8 +222,8 @@ describe('runAgentForGroup room memory', () => {
|
||||
expect(agentRunner.runAgentProcess).toHaveBeenCalledWith(
|
||||
group,
|
||||
expect.objectContaining({
|
||||
prompt: expect.stringContaining(
|
||||
'If you have no user-visible content to send for this turn, output exactly this JSON and nothing else: {"ejclaw":{"visibility":"silent"}}',
|
||||
prompt: expect.stringMatching(
|
||||
/If you have no user-visible content to send for this turn, output exactly this JSON and nothing else: \{"ejclaw":\{"visibility":"silent"\}\}[\s\S]*If you have already emitted any visible progress, status update, or partial answer earlier in this turn, do not end with the JSON object\. Finish with a short visible final conclusion for the user instead\./,
|
||||
),
|
||||
}),
|
||||
expect.any(Function),
|
||||
@@ -253,8 +253,8 @@ describe('runAgentForGroup room memory', () => {
|
||||
expect(agentRunner.runAgentProcess).toHaveBeenCalledWith(
|
||||
group,
|
||||
expect.objectContaining({
|
||||
prompt: expect.stringContaining(
|
||||
'If you are only agreeing, mirroring, or restating without adding a concrete correction, risk, missing prerequisite, test gap, or code change, output only the JSON object.',
|
||||
prompt: expect.stringMatching(
|
||||
/If you have already emitted any visible progress, status update, or partial answer earlier in this turn, do not end with the JSON object\. Finish with a short visible final conclusion for the user instead\.[\s\S]*If you have not already emitted any visible progress, status update, or partial answer in this turn and you are only agreeing, mirroring, or restating without adding a concrete correction, risk, missing prerequisite, test gap, or code change, output only the JSON object\./,
|
||||
),
|
||||
}),
|
||||
expect.any(Function),
|
||||
|
||||
@@ -92,5 +92,16 @@ describe('buildStructuredOutputPrompt', () => {
|
||||
expect(buildStructuredOutputPrompt('hello')).toContain(
|
||||
'If you have no user-visible content to send for this turn, output exactly this JSON and nothing else: {"ejclaw":{"visibility":"silent"}}',
|
||||
);
|
||||
expect(buildStructuredOutputPrompt('hello')).toContain(
|
||||
'If you have already emitted any visible progress, status update, or partial answer earlier in this turn, do not end with the JSON object. Finish with a short visible final conclusion for the user instead.',
|
||||
);
|
||||
});
|
||||
|
||||
it('tightens the reviewer silent rule when reviewer mode is enabled', () => {
|
||||
expect(
|
||||
buildStructuredOutputPrompt('hello', { reviewerMode: true }),
|
||||
).toContain(
|
||||
'If you have not already emitted any visible progress, status update, or partial answer in this turn and you are only agreeing, mirroring, or restating without adding a concrete correction, risk, missing prerequisite, test gap, or code change, output only the JSON object.',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -92,11 +92,12 @@ export function buildStructuredOutputPrompt(
|
||||
`If you have no user-visible content to send for this turn, output exactly this JSON and nothing else: ${STRUCTURED_SILENT_OUTPUT_ENVELOPE}`,
|
||||
'Do not wrap the JSON in backticks or code fences.',
|
||||
'Do not combine the JSON with any other text.',
|
||||
'If you have already emitted any visible progress, status update, or partial answer earlier in this turn, do not end with the JSON object. Finish with a short visible final conclusion for the user instead.',
|
||||
];
|
||||
|
||||
if (options?.reviewerMode) {
|
||||
lines.push(
|
||||
'If you are only agreeing, mirroring, or restating without adding a concrete correction, risk, missing prerequisite, test gap, or code change, output only the JSON object.',
|
||||
'If you have not already emitted any visible progress, status update, or partial answer in this turn and you are only agreeing, mirroring, or restating without adding a concrete correction, risk, missing prerequisite, test gap, or code change, output only the JSON object.',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user