takt: update-report-path-variable
This commit is contained in:
parent
f7181fc00c
commit
79227dffd1
4
package-lock.json
generated
4
package-lock.json
generated
@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "takt",
|
"name": "takt",
|
||||||
"version": "0.2.5",
|
"version": "0.2.3",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "takt",
|
"name": "takt",
|
||||||
"version": "0.2.5",
|
"version": "0.2.3",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.2.19",
|
"@anthropic-ai/claude-agent-sdk": "^0.2.19",
|
||||||
|
|||||||
@ -374,8 +374,8 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).toContain('- Report Directory: .takt/reports/20260129-test/');
|
expect(result).toContain('- Report Directory: 20260129-test/');
|
||||||
expect(result).toContain('- Report File: .takt/reports/20260129-test/00-plan.md');
|
expect(result).toContain('- Report File: 20260129-test/00-plan.md');
|
||||||
expect(result).not.toContain('Report Files:');
|
expect(result).not.toContain('Report Files:');
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -393,13 +393,29 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
const result = buildInstruction(step, context);
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
expect(result).toContain('- Report Directory: .takt/reports/20260129-test/');
|
expect(result).toContain('- Report Directory: 20260129-test/');
|
||||||
expect(result).toContain('- Report Files:');
|
expect(result).toContain('- Report Files:');
|
||||||
expect(result).toContain(' - Scope: .takt/reports/20260129-test/01-scope.md');
|
expect(result).toContain(' - Scope: 20260129-test/01-scope.md');
|
||||||
expect(result).toContain(' - Decisions: .takt/reports/20260129-test/02-decisions.md');
|
expect(result).toContain(' - Decisions: 20260129-test/02-decisions.md');
|
||||||
expect(result).not.toContain('Report File:');
|
expect(result).not.toContain('Report File:');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should include report file when report is ReportObjectConfig', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.name = 'plan';
|
||||||
|
step.report = { name: '00-plan.md' };
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
expect(result).toContain('- Report Directory: 20260129-test/');
|
||||||
|
expect(result).toContain('- Report File: 20260129-test/00-plan.md');
|
||||||
|
expect(result).not.toContain('Report Files:');
|
||||||
|
});
|
||||||
|
|
||||||
it('should NOT include report info when reportDir is undefined', () => {
|
it('should NOT include report info when reportDir is undefined', () => {
|
||||||
const step = createMinimalStep('Do work');
|
const step = createMinimalStep('Do work');
|
||||||
step.report = '00-plan.md';
|
step.report = '00-plan.md';
|
||||||
@ -437,6 +453,164 @@ describe('instruction-builder', () => {
|
|||||||
|
|
||||||
expect(result).toContain('- Step Iteration: 3(このステップの実行回数)');
|
expect(result).toContain('- Step Iteration: 3(このステップの実行回数)');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should NOT include .takt/reports/ prefix in report paths', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = '00-plan.md';
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
expect(result).not.toContain('.takt/reports/');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ReportObjectConfig order/format injection', () => {
|
||||||
|
it('should inject order before instruction_template', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = {
|
||||||
|
name: '00-plan.md',
|
||||||
|
order: '**Output:** Write to {report:00-plan.md}',
|
||||||
|
};
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
const orderIdx = result.indexOf('**Output:** Write to 20260129-test/00-plan.md');
|
||||||
|
const instructionsIdx = result.indexOf('## Instructions');
|
||||||
|
expect(orderIdx).toBeGreaterThan(-1);
|
||||||
|
expect(instructionsIdx).toBeGreaterThan(orderIdx);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should inject format after instruction_template', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = {
|
||||||
|
name: '00-plan.md',
|
||||||
|
format: '**Format:**\n```markdown\n# Plan\n```',
|
||||||
|
};
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
const instructionsIdx = result.indexOf('## Instructions');
|
||||||
|
const formatIdx = result.indexOf('**Format:**');
|
||||||
|
expect(formatIdx).toBeGreaterThan(instructionsIdx);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should inject both order before and format after instruction_template', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = {
|
||||||
|
name: '00-plan.md',
|
||||||
|
order: '**Output:** Write to {report:00-plan.md}',
|
||||||
|
format: '**Format:**\n```markdown\n# Plan\n```',
|
||||||
|
};
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
const orderIdx = result.indexOf('**Output:** Write to 20260129-test/00-plan.md');
|
||||||
|
const instructionsIdx = result.indexOf('## Instructions');
|
||||||
|
const formatIdx = result.indexOf('**Format:**');
|
||||||
|
expect(orderIdx).toBeGreaterThan(-1);
|
||||||
|
expect(instructionsIdx).toBeGreaterThan(orderIdx);
|
||||||
|
expect(formatIdx).toBeGreaterThan(instructionsIdx);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace {report:filename} in order text', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = {
|
||||||
|
name: '00-plan.md',
|
||||||
|
order: 'Output to {report:00-plan.md} file.',
|
||||||
|
};
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
expect(result).toContain('Output to 20260129-test/00-plan.md file.');
|
||||||
|
expect(result).not.toContain('{report:00-plan.md}');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not inject order/format when report is a simple string', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = '00-plan.md';
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
// Should contain instructions normally
|
||||||
|
expect(result).toContain('## Instructions');
|
||||||
|
expect(result).toContain('Do work');
|
||||||
|
// The instruction should appear right after Additional User Inputs, not after any order section
|
||||||
|
const additionalIdx = result.indexOf('## Additional User Inputs');
|
||||||
|
const instructionsIdx = result.indexOf('## Instructions');
|
||||||
|
expect(additionalIdx).toBeGreaterThan(-1);
|
||||||
|
expect(instructionsIdx).toBeGreaterThan(additionalIdx);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should not inject order/format when report is ReportConfig[]', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = [
|
||||||
|
{ label: 'Scope', path: '01-scope.md' },
|
||||||
|
];
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
// Just verify normal behavior without extra sections
|
||||||
|
expect(result).toContain('## Instructions');
|
||||||
|
expect(result).toContain('Do work');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace {report:filename} in instruction_template too', () => {
|
||||||
|
const step = createMinimalStep('Write to {report:00-plan.md}');
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
expect(result).toContain('Write to 20260129-test/00-plan.md');
|
||||||
|
expect(result).not.toContain('{report:00-plan.md}');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should replace {step_iteration} in order/format text', () => {
|
||||||
|
const step = createMinimalStep('Do work');
|
||||||
|
step.report = {
|
||||||
|
name: '00-plan.md',
|
||||||
|
order: 'Append ## Iteration {step_iteration} section',
|
||||||
|
};
|
||||||
|
const context = createMinimalContext({
|
||||||
|
reportDir: '20260129-test',
|
||||||
|
stepIteration: 3,
|
||||||
|
language: 'en',
|
||||||
|
});
|
||||||
|
|
||||||
|
const result = buildInstruction(step, context);
|
||||||
|
|
||||||
|
expect(result).toContain('Append ## Iteration 3 section');
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('auto-injected User Request and Additional User Inputs sections', () => {
|
describe('auto-injected User Request and Additional User Inputs sections', () => {
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { readFileSync, existsSync, readdirSync, statSync } from 'node:fs';
|
|||||||
import { join, dirname, basename } from 'node:path';
|
import { join, dirname, basename } from 'node:path';
|
||||||
import { parse as parseYaml } from 'yaml';
|
import { parse as parseYaml } from 'yaml';
|
||||||
import { WorkflowConfigRawSchema } from '../models/schemas.js';
|
import { WorkflowConfigRawSchema } from '../models/schemas.js';
|
||||||
import type { WorkflowConfig, WorkflowStep, WorkflowRule, ReportConfig } from '../models/types.js';
|
import type { WorkflowConfig, WorkflowStep, WorkflowRule, ReportConfig, ReportObjectConfig } from '../models/types.js';
|
||||||
import { getGlobalWorkflowsDir } from './paths.js';
|
import { getGlobalWorkflowsDir } from './paths.js';
|
||||||
|
|
||||||
/** Get builtin workflow by name */
|
/** Get builtin workflow by name */
|
||||||
@ -54,6 +54,13 @@ function extractAgentDisplayName(agentPath: string): string {
|
|||||||
return filename;
|
return filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a raw report value is the object form (has 'name' property).
|
||||||
|
*/
|
||||||
|
function isReportObject(raw: unknown): raw is { name: string; order?: string; format?: string } {
|
||||||
|
return typeof raw === 'object' && raw !== null && !Array.isArray(raw) && 'name' in raw;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Normalize the raw report field from YAML into internal format.
|
* Normalize the raw report field from YAML into internal format.
|
||||||
*
|
*
|
||||||
@ -62,16 +69,23 @@ function extractAgentDisplayName(agentPath: string): string {
|
|||||||
* report: → ReportConfig[] (multiple files)
|
* report: → ReportConfig[] (multiple files)
|
||||||
* - Scope: 01-scope.md
|
* - Scope: 01-scope.md
|
||||||
* - Decisions: 02-decisions.md
|
* - Decisions: 02-decisions.md
|
||||||
|
* report: → ReportObjectConfig (object form)
|
||||||
|
* name: 00-plan.md
|
||||||
|
* order: ...
|
||||||
|
* format: ...
|
||||||
*
|
*
|
||||||
* Array items are parsed as single-key objects: [{Scope: "01-scope.md"}, ...]
|
* Array items are parsed as single-key objects: [{Scope: "01-scope.md"}, ...]
|
||||||
*/
|
*/
|
||||||
function normalizeReport(
|
function normalizeReport(
|
||||||
raw: string | Record<string, string>[] | undefined,
|
raw: string | Record<string, string>[] | { name: string; order?: string; format?: string } | undefined,
|
||||||
): string | ReportConfig[] | undefined {
|
): string | ReportConfig[] | ReportObjectConfig | undefined {
|
||||||
if (raw == null) return undefined;
|
if (raw == null) return undefined;
|
||||||
if (typeof raw === 'string') return raw;
|
if (typeof raw === 'string') return raw;
|
||||||
|
if (isReportObject(raw)) {
|
||||||
|
return { name: raw.name, order: raw.order, format: raw.format };
|
||||||
|
}
|
||||||
// Convert [{Scope: "01-scope.md"}, ...] to [{label: "Scope", path: "01-scope.md"}, ...]
|
// Convert [{Scope: "01-scope.md"}, ...] to [{label: "Scope", path: "01-scope.md"}, ...]
|
||||||
return raw.flatMap((entry) =>
|
return (raw as Record<string, string>[]).flatMap((entry) =>
|
||||||
Object.entries(entry).map(([label, path]) => ({ label, path })),
|
Object.entries(entry).map(([label, path]) => ({ label, path })),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,6 +3,7 @@ export type {
|
|||||||
AgentType,
|
AgentType,
|
||||||
Status,
|
Status,
|
||||||
ReportConfig,
|
ReportConfig,
|
||||||
|
ReportObjectConfig,
|
||||||
AgentResponse,
|
AgentResponse,
|
||||||
SessionState,
|
SessionState,
|
||||||
WorkflowStep,
|
WorkflowStep,
|
||||||
|
|||||||
@ -27,20 +27,48 @@ export const StatusSchema = z.enum([
|
|||||||
/** Permission mode schema for tool execution */
|
/** Permission mode schema for tool execution */
|
||||||
export const PermissionModeSchema = z.enum(['default', 'acceptEdits', 'bypassPermissions']);
|
export const PermissionModeSchema = z.enum(['default', 'acceptEdits', 'bypassPermissions']);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Report object schema (new structured format).
|
||||||
|
*
|
||||||
|
* YAML format:
|
||||||
|
* report:
|
||||||
|
* name: 00-plan.md
|
||||||
|
* order: |
|
||||||
|
* **レポート出力:** {report:00-plan.md} に出力してください。
|
||||||
|
* format: |
|
||||||
|
* **レポートフォーマット:**
|
||||||
|
* ```markdown
|
||||||
|
* ...
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
export const ReportObjectSchema = z.object({
|
||||||
|
/** Report file name */
|
||||||
|
name: z.string().min(1),
|
||||||
|
/** Instruction prepended before instruction_template (e.g., output destination) */
|
||||||
|
order: z.string().optional(),
|
||||||
|
/** Instruction appended after instruction_template (e.g., output format) */
|
||||||
|
format: z.string().optional(),
|
||||||
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Report field schema.
|
* Report field schema.
|
||||||
*
|
*
|
||||||
* YAML formats:
|
* YAML formats:
|
||||||
* report: 00-plan.md # single file
|
* report: 00-plan.md # single file (string)
|
||||||
* report: # multiple files (label: path map entries)
|
* report: # multiple files (label: path map entries)
|
||||||
* - Scope: 01-scope.md
|
* - Scope: 01-scope.md
|
||||||
* - Decisions: 02-decisions.md
|
* - Decisions: 02-decisions.md
|
||||||
|
* report: # object form (name + order + format)
|
||||||
|
* name: 00-plan.md
|
||||||
|
* order: ...
|
||||||
|
* format: ...
|
||||||
*
|
*
|
||||||
* Array items are parsed as single-key objects: [{Scope: "01-scope.md"}, ...]
|
* Array items are parsed as single-key objects: [{Scope: "01-scope.md"}, ...]
|
||||||
*/
|
*/
|
||||||
export const ReportFieldSchema = z.union([
|
export const ReportFieldSchema = z.union([
|
||||||
z.string().min(1),
|
z.string().min(1),
|
||||||
z.array(z.record(z.string(), z.string())).min(1),
|
z.array(z.record(z.string(), z.string())).min(1),
|
||||||
|
ReportObjectSchema,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
/** Rule-based transition schema (new unified format) */
|
/** Rule-based transition schema (new unified format) */
|
||||||
|
|||||||
@ -50,7 +50,7 @@ export interface WorkflowRule {
|
|||||||
appendix?: string;
|
appendix?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Report file configuration for a workflow step */
|
/** Report file configuration for a workflow step (label: path pair) */
|
||||||
export interface ReportConfig {
|
export interface ReportConfig {
|
||||||
/** Display label (e.g., "Scope", "Decisions") */
|
/** Display label (e.g., "Scope", "Decisions") */
|
||||||
label: string;
|
label: string;
|
||||||
@ -58,6 +58,16 @@ export interface ReportConfig {
|
|||||||
path: string;
|
path: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Report object configuration with order/format instructions */
|
||||||
|
export interface ReportObjectConfig {
|
||||||
|
/** Report file name (e.g., "00-plan.md") */
|
||||||
|
name: string;
|
||||||
|
/** Instruction prepended before instruction_template (e.g., output destination) */
|
||||||
|
order?: string;
|
||||||
|
/** Instruction appended after instruction_template (e.g., output format) */
|
||||||
|
format?: string;
|
||||||
|
}
|
||||||
|
|
||||||
/** Permission mode for tool execution */
|
/** Permission mode for tool execution */
|
||||||
export type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions';
|
export type PermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions';
|
||||||
|
|
||||||
@ -81,8 +91,8 @@ export interface WorkflowStep {
|
|||||||
instructionTemplate: string;
|
instructionTemplate: string;
|
||||||
/** Rules for step routing */
|
/** Rules for step routing */
|
||||||
rules?: WorkflowRule[];
|
rules?: WorkflowRule[];
|
||||||
/** Report file configuration. Single string for one file, array for multiple. */
|
/** Report file configuration. Single string, array of label:path, or object with order/format. */
|
||||||
report?: string | ReportConfig[];
|
report?: string | ReportConfig[] | ReportObjectConfig;
|
||||||
passPreviousResponse: boolean;
|
passPreviousResponse: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
* 3. Appending auto-generated status rules from workflow rules
|
* 3. Appending auto-generated status rules from workflow rules
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { WorkflowStep, WorkflowRule, AgentResponse, Language, ReportConfig } from '../models/types.js';
|
import type { WorkflowStep, WorkflowRule, AgentResponse, Language, ReportConfig, ReportObjectConfig } from '../models/types.js';
|
||||||
import { getGitDiff } from '../agents/runner.js';
|
import { getGitDiff } from '../agents/runner.js';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -216,6 +216,13 @@ function escapeTemplateChars(str: string): string {
|
|||||||
return str.replace(/\{/g, '{').replace(/\}/g, '}');
|
return str.replace(/\{/g, '{').replace(/\}/g, '}');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if a report config is the object form (ReportObjectConfig).
|
||||||
|
*/
|
||||||
|
function isReportObjectConfig(report: string | ReportConfig[] | ReportObjectConfig): report is ReportObjectConfig {
|
||||||
|
return typeof report === 'object' && !Array.isArray(report) && 'name' in report;
|
||||||
|
}
|
||||||
|
|
||||||
/** Localized strings for auto-injected sections */
|
/** Localized strings for auto-injected sections */
|
||||||
const SECTION_STRINGS = {
|
const SECTION_STRINGS = {
|
||||||
en: {
|
en: {
|
||||||
@ -268,16 +275,19 @@ function renderWorkflowContext(
|
|||||||
|
|
||||||
// Report info (only if step has report config AND reportDir is available)
|
// Report info (only if step has report config AND reportDir is available)
|
||||||
if (step.report && context.reportDir) {
|
if (step.report && context.reportDir) {
|
||||||
lines.push(`- ${s.reportDirectory}: .takt/reports/${context.reportDir}/`);
|
lines.push(`- ${s.reportDirectory}: ${context.reportDir}/`);
|
||||||
|
|
||||||
if (typeof step.report === 'string') {
|
if (typeof step.report === 'string') {
|
||||||
// Single file
|
// Single file (string form)
|
||||||
lines.push(`- ${s.reportFile}: .takt/reports/${context.reportDir}/${step.report}`);
|
lines.push(`- ${s.reportFile}: ${context.reportDir}/${step.report}`);
|
||||||
|
} else if (isReportObjectConfig(step.report)) {
|
||||||
|
// Object form (name + order + format)
|
||||||
|
lines.push(`- ${s.reportFile}: ${context.reportDir}/${step.report.name}`);
|
||||||
} else {
|
} else {
|
||||||
// Multiple files
|
// Multiple files (ReportConfig[] form)
|
||||||
lines.push(`- ${s.reportFiles}:`);
|
lines.push(`- ${s.reportFiles}:`);
|
||||||
for (const file of step.report as ReportConfig[]) {
|
for (const file of step.report as ReportConfig[]) {
|
||||||
lines.push(` - ${file.label}: .takt/reports/${context.reportDir}/${file.path}`);
|
lines.push(` - ${file.label}: ${context.reportDir}/${file.path}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -341,6 +351,13 @@ function replaceTemplatePlaceholders(
|
|||||||
result = result.replace(/\{report_dir\}/g, context.reportDir);
|
result = result.replace(/\{report_dir\}/g, context.reportDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Replace {report:filename} with reportDir/filename
|
||||||
|
if (context.reportDir) {
|
||||||
|
result = result.replace(/\{report:([^}]+)\}/g, (_match, filename: string) => {
|
||||||
|
return `${context.reportDir}/${filename}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -403,7 +420,13 @@ export function buildInstruction(
|
|||||||
sections.push(`${s.additionalUserInputs}\n${escapeTemplateChars(userInputsStr)}`);
|
sections.push(`${s.additionalUserInputs}\n${escapeTemplateChars(userInputsStr)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 6. Instructions header + instruction_template content
|
// 6a. Report order (prepended before instruction_template, from ReportObjectConfig)
|
||||||
|
if (step.report && isReportObjectConfig(step.report) && step.report.order) {
|
||||||
|
const processedOrder = replaceTemplatePlaceholders(step.report.order.trimEnd(), step, context);
|
||||||
|
sections.push(processedOrder);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 6b. Instructions header + instruction_template content
|
||||||
const processedTemplate = replaceTemplatePlaceholders(
|
const processedTemplate = replaceTemplatePlaceholders(
|
||||||
step.instructionTemplate,
|
step.instructionTemplate,
|
||||||
step,
|
step,
|
||||||
@ -411,6 +434,12 @@ export function buildInstruction(
|
|||||||
);
|
);
|
||||||
sections.push(`${s.instructions}\n${processedTemplate}`);
|
sections.push(`${s.instructions}\n${processedTemplate}`);
|
||||||
|
|
||||||
|
// 6c. Report format (appended after instruction_template, from ReportObjectConfig)
|
||||||
|
if (step.report && isReportObjectConfig(step.report) && step.report.format) {
|
||||||
|
const processedFormat = replaceTemplatePlaceholders(step.report.format.trimEnd(), step, context);
|
||||||
|
sections.push(processedFormat);
|
||||||
|
}
|
||||||
|
|
||||||
// 7. Status rules (auto-generated from rules)
|
// 7. Status rules (auto-generated from rules)
|
||||||
if (step.rules && step.rules.length > 0) {
|
if (step.rules && step.rules.length > 0) {
|
||||||
const statusHeader = renderStatusRulesHeader(language);
|
const statusHeader = renderStatusRulesHeader(language);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user