mirror of
https://github.com/davidkaya/aryx.git
synced 2026-08-03 18:38:35 +02:00
feat: add phase 3 prompt customization backend
- parse prompt model and argument-hint metadata and persist model on prompt invocations - expand markdown-linked file context in scanned prompt and instruction bodies - discover .claude/rules instructions and support Claude-style paths metadata - discover customization roots up to the nearest parent repository and watch them for changes - apply per-turn prompt model overrides before sidecar execution Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { describe, expect, mock, test } from 'bun:test';
|
||||
|
||||
import type { RunTurnCommand } from '@shared/contracts/sidecar';
|
||||
import { buildAvailableModelCatalog } from '@shared/domain/models';
|
||||
import type { PatternDefinition } from '@shared/domain/pattern';
|
||||
import type { ProjectRecord } from '@shared/domain/project';
|
||||
import type { SessionRecord } from '@shared/domain/session';
|
||||
@@ -76,6 +77,7 @@ function createService(
|
||||
internals.loadWorkspace = async () => workspace;
|
||||
internals.persistAndBroadcast = async (nextWorkspace: WorkspaceState) => nextWorkspace;
|
||||
internals.buildEffectivePattern = async () => pattern;
|
||||
internals.loadAvailableModelCatalog = async () => buildAvailableModelCatalog();
|
||||
internals.awaitFinalResponseApproval = async () => undefined;
|
||||
internals.finalizeTurn = () => undefined;
|
||||
internals.emitSessionEvent = () => undefined;
|
||||
@@ -344,6 +346,84 @@ describe('AryxAppService project customization', () => {
|
||||
expect(command?.messages.at(-1)?.content).toBe('Run prompt file: doc-review');
|
||||
});
|
||||
|
||||
test('sendSessionMessage hydrates prompt model metadata and overrides the turn pattern model', async () => {
|
||||
const workspace = createWorkspaceSeed();
|
||||
const basePattern = workspace.patterns.find((candidate) => candidate.mode === 'single');
|
||||
if (!basePattern) {
|
||||
throw new Error('Expected a single-agent pattern in the workspace seed.');
|
||||
}
|
||||
|
||||
const pattern: PatternDefinition = {
|
||||
...basePattern,
|
||||
agents: [
|
||||
{
|
||||
...basePattern.agents[0]!,
|
||||
model: 'gpt-5.4',
|
||||
reasoningEffort: 'high',
|
||||
},
|
||||
],
|
||||
};
|
||||
|
||||
const project = createProject({
|
||||
customization: {
|
||||
instructions: [],
|
||||
agentProfiles: [],
|
||||
promptFiles: [
|
||||
{
|
||||
id: 'project_customization_prompt_rest_review',
|
||||
name: 'rest-review',
|
||||
description: 'Review the REST API surface',
|
||||
model: 'Claude Sonnet 4.5',
|
||||
template: 'Review the REST API for security gaps.',
|
||||
variables: [],
|
||||
sourcePath: '.github\\prompts\\rest-review.prompt.md',
|
||||
},
|
||||
],
|
||||
lastScannedAt: TIMESTAMP,
|
||||
},
|
||||
});
|
||||
const session = createSession(project.id, pattern.id);
|
||||
|
||||
workspace.projects = [project];
|
||||
workspace.sessions = [session];
|
||||
workspace.selectedProjectId = project.id;
|
||||
workspace.selectedPatternId = pattern.id;
|
||||
workspace.selectedSessionId = session.id;
|
||||
|
||||
let command: RunTurnCommand | undefined;
|
||||
const service = createService(workspace, pattern, {
|
||||
captureRunTurn: (capturedCommand) => {
|
||||
command = capturedCommand;
|
||||
},
|
||||
});
|
||||
|
||||
await service.sendSessionMessage(session.id, '', undefined, undefined, {
|
||||
id: 'project_customization_prompt_rest_review',
|
||||
name: 'rest-review',
|
||||
sourcePath: '.github\\prompts\\rest-review.prompt.md',
|
||||
resolvedPrompt: 'Review the REST API for security gaps.',
|
||||
});
|
||||
|
||||
expect(session.messages.at(-1)?.promptInvocation).toEqual({
|
||||
id: 'project_customization_prompt_rest_review',
|
||||
name: 'rest-review',
|
||||
sourcePath: '.github\\prompts\\rest-review.prompt.md',
|
||||
description: 'Review the REST API surface',
|
||||
model: 'Claude Sonnet 4.5',
|
||||
resolvedPrompt: 'Review the REST API for security gaps.',
|
||||
});
|
||||
expect(command?.pattern.agents[0]?.model).toBe('claude-sonnet-4.5');
|
||||
expect(command?.pattern.agents[0]?.reasoningEffort).toBeUndefined();
|
||||
expect(command?.promptInvocation).toEqual({
|
||||
id: 'project_customization_prompt_rest_review',
|
||||
name: 'rest-review',
|
||||
sourcePath: '.github\\prompts\\rest-review.prompt.md',
|
||||
description: 'Review the REST API surface',
|
||||
model: 'Claude Sonnet 4.5',
|
||||
resolvedPrompt: 'Review the REST API for security gaps.',
|
||||
});
|
||||
});
|
||||
|
||||
test('setProjectAgentProfileEnabled persists the updated enabled state', async () => {
|
||||
const workspace = createWorkspaceSeed();
|
||||
const pattern = workspace.patterns.find((candidate) => candidate.mode === 'single');
|
||||
|
||||
Reference in New Issue
Block a user