Phase 1プロンプトにもステータスルールを注入(Phase 3との併用方式)
buildInstruction()にセクション7を追加し、タグベースのルールがある場合に 判定基準と出力フォーマットをPhase 1のプロンプトに注入する。 ai()/aggregate条件のみの場合はスキップ。
This commit is contained in:
parent
9c05b45e1e
commit
213e293c06
@ -362,8 +362,8 @@ describe('instruction-builder', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('buildInstruction with rules (Phase 1 — no status tags)', () => {
|
describe('buildInstruction with rules (Phase 1 — status rules injection)', () => {
|
||||||
it('should NOT include status rules even when rules exist (phase separation)', () => {
|
it('should include status rules when tag-based rules exist', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
step.name = 'plan';
|
step.name = 'plan';
|
||||||
step.rules = [
|
step.rules = [
|
||||||
@ -374,10 +374,9 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
// Phase 1 should NOT contain status header or criteria
|
expect(result).toContain('Decision Criteria');
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).toContain('[PLAN:1]');
|
||||||
expect(result).not.toContain('Decision Criteria');
|
expect(result).toContain('[PLAN:2]');
|
||||||
expect(result).not.toContain('[PLAN:');
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not add status rules when rules do not exist', () => {
|
it('should not add status rules when rules do not exist', () => {
|
||||||
@ -386,7 +385,6 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
|
||||||
expect(result).not.toContain('Decision Criteria');
|
expect(result).not.toContain('Decision Criteria');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -397,7 +395,6 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
|
||||||
expect(result).not.toContain('Decision Criteria');
|
expect(result).not.toContain('Decision Criteria');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -859,8 +856,8 @@ describe('instruction-builder', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('phase separation — buildInstruction never includes status rules', () => {
|
describe('status rules injection — skip when all rules are ai()/aggregate', () => {
|
||||||
it('should NOT include status rules even with ai() conditions', () => {
|
it('should NOT include status rules when all rules are ai() conditions', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
step.rules = [
|
step.rules = [
|
||||||
{ condition: 'ai("No issues")', next: 'COMPLETE', isAiCondition: true, aiConditionText: 'No issues' },
|
{ condition: 'ai("No issues")', next: 'COMPLETE', isAiCondition: true, aiConditionText: 'No issues' },
|
||||||
@ -870,12 +867,13 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).not.toContain('Decision Criteria');
|
||||||
expect(result).not.toContain('[TEST-STEP:');
|
expect(result).not.toContain('[TEST-STEP:');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT include status rules with mixed regular and ai() conditions', () => {
|
it('should include status rules with mixed regular and ai() conditions', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
|
step.name = 'review';
|
||||||
step.rules = [
|
step.rules = [
|
||||||
{ condition: 'Error occurred', next: 'ABORT' },
|
{ condition: 'Error occurred', next: 'ABORT' },
|
||||||
{ condition: 'ai("Issues found")', next: 'fix', isAiCondition: true, aiConditionText: 'Issues found' },
|
{ condition: 'ai("Issues found")', next: 'fix', isAiCondition: true, aiConditionText: 'Issues found' },
|
||||||
@ -884,11 +882,13 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).toContain('Decision Criteria');
|
||||||
|
expect(result).toContain('[REVIEW:1]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT include status rules with regular conditions only', () => {
|
it('should include status rules with regular conditions only', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
|
step.name = 'plan';
|
||||||
step.rules = [
|
step.rules = [
|
||||||
{ condition: 'Done', next: 'COMPLETE' },
|
{ condition: 'Done', next: 'COMPLETE' },
|
||||||
{ condition: 'Blocked', next: 'ABORT' },
|
{ condition: 'Blocked', next: 'ABORT' },
|
||||||
@ -897,10 +897,12 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).toContain('Decision Criteria');
|
||||||
|
expect(result).toContain('[PLAN:1]');
|
||||||
|
expect(result).toContain('[PLAN:2]');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT include status rules with aggregate conditions', () => {
|
it('should NOT include status rules when all rules are aggregate conditions', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
step.rules = [
|
step.rules = [
|
||||||
{ condition: 'all("approved")', next: 'COMPLETE', isAggregateCondition: true, aggregateType: 'all' as const, aggregateConditionText: 'approved' },
|
{ condition: 'all("approved")', next: 'COMPLETE', isAggregateCondition: true, aggregateType: 'all' as const, aggregateConditionText: 'approved' },
|
||||||
@ -910,10 +912,10 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).not.toContain('Decision Criteria');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT include status rules with mixed ai() and aggregate conditions', () => {
|
it('should NOT include status rules when all rules are ai() + aggregate', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
step.rules = [
|
step.rules = [
|
||||||
{ condition: 'all("approved")', next: 'COMPLETE', isAggregateCondition: true, aggregateType: 'all' as const, aggregateConditionText: 'approved' },
|
{ condition: 'all("approved")', next: 'COMPLETE', isAggregateCondition: true, aggregateType: 'all' as const, aggregateConditionText: 'approved' },
|
||||||
@ -924,11 +926,12 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).not.toContain('Decision Criteria');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should NOT include status rules with mixed aggregate and regular conditions', () => {
|
it('should include status rules with mixed aggregate and regular conditions', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
|
step.name = 'supervise';
|
||||||
step.rules = [
|
step.rules = [
|
||||||
{ condition: 'all("approved")', next: 'COMPLETE', isAggregateCondition: true, aggregateType: 'all' as const, aggregateConditionText: 'approved' },
|
{ condition: 'all("approved")', next: 'COMPLETE', isAggregateCondition: true, aggregateType: 'all' as const, aggregateConditionText: 'approved' },
|
||||||
{ condition: 'Error occurred', next: 'ABORT' },
|
{ condition: 'Error occurred', next: 'ABORT' },
|
||||||
@ -937,7 +940,8 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).not.toContain('Status Output Rules');
|
expect(result).toContain('Decision Criteria');
|
||||||
|
expect(result).toContain('[SUPERVISE:1]');
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -3,10 +3,12 @@
|
|||||||
*
|
*
|
||||||
* Builds the instruction string for agent execution by:
|
* Builds the instruction string for agent execution by:
|
||||||
* 1. Auto-injecting standard sections (Execution Context, Workflow Context,
|
* 1. Auto-injecting standard sections (Execution Context, Workflow Context,
|
||||||
* User Request, Previous Response, Additional User Inputs, Instructions header)
|
* User Request, Previous Response, Additional User Inputs, Instructions header,
|
||||||
|
* Status Output Rules)
|
||||||
* 2. Replacing template placeholders with actual values
|
* 2. Replacing template placeholders with actual values
|
||||||
*
|
*
|
||||||
* Status judgment is handled separately in Phase 3 (buildStatusJudgmentInstruction).
|
* Status rules are injected into Phase 1 for tag-based detection,
|
||||||
|
* and also used in Phase 3 (buildStatusJudgmentInstruction) as a dedicated follow-up.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { WorkflowStep, WorkflowRule, AgentResponse, Language, ReportConfig, ReportObjectConfig } from '../models/types.js';
|
import type { WorkflowStep, WorkflowRule, AgentResponse, Language, ReportConfig, ReportObjectConfig } from '../models/types.js';
|
||||||
@ -406,8 +408,7 @@ function replaceTemplatePlaceholders(
|
|||||||
* 4. Previous Response — if passPreviousResponse and has content, unless template contains {previous_response}
|
* 4. Previous Response — if passPreviousResponse and has content, unless template contains {previous_response}
|
||||||
* 5. Additional User Inputs — unless template contains {user_inputs}
|
* 5. Additional User Inputs — unless template contains {user_inputs}
|
||||||
* 6. Instructions header + instruction_template content — always
|
* 6. Instructions header + instruction_template content — always
|
||||||
*
|
* 7. Status Output Rules — when step has tag-based rules (not all ai()/aggregate)
|
||||||
* Status judgment is handled separately in Phase 3 (buildStatusJudgmentInstruction).
|
|
||||||
*
|
*
|
||||||
* Template placeholders ({task}, {previous_response}, etc.) are still replaced
|
* Template placeholders ({task}, {previous_response}, etc.) are still replaced
|
||||||
* within the instruction_template body for backward compatibility.
|
* within the instruction_template body for backward compatibility.
|
||||||
@ -462,6 +463,16 @@ export function buildInstruction(
|
|||||||
);
|
);
|
||||||
sections.push(`${s.instructions}\n${processedTemplate}`);
|
sections.push(`${s.instructions}\n${processedTemplate}`);
|
||||||
|
|
||||||
|
// 7. Status Output Rules (for tag-based detection in Phase 1)
|
||||||
|
// Skip if all rules are ai() or aggregate conditions (no tags needed)
|
||||||
|
if (step.rules && step.rules.length > 0) {
|
||||||
|
const allNonTagConditions = step.rules.every((r) => r.isAiCondition || r.isAggregateCondition);
|
||||||
|
if (!allNonTagConditions) {
|
||||||
|
const statusRulesPrompt = generateStatusRulesFromRules(step.name, step.rules, language);
|
||||||
|
sections.push(statusRulesPrompt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return sections.join('\n\n');
|
return sections.join('\n\n');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user