vibeman 0.0.5 → 0.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api.js +43 -0
- package/dist/index.js +227 -104
- package/dist/ui/assets/index-C_kQPI1m.js +9 -0
- package/dist/ui/index.html +12 -0
- package/package.json +13 -46
- package/README.md +0 -12
- package/dist/runtime/api/.tsbuildinfo +0 -1
- package/dist/runtime/api/agent/agent-service.d.ts +0 -229
- package/dist/runtime/api/agent/agent-service.js +0 -963
- package/dist/runtime/api/agent/ai-providers/amp-cli-provider.d.ts +0 -38
- package/dist/runtime/api/agent/ai-providers/amp-cli-provider.js +0 -268
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.d.ts +0 -61
- package/dist/runtime/api/agent/ai-providers/claude-code-adapter.js +0 -362
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +0 -36
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +0 -375
- package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.d.ts +0 -24
- package/dist/runtime/api/agent/ai-providers/gemini-cli-provider.js +0 -291
- package/dist/runtime/api/agent/ai-providers/index.d.ts +0 -9
- package/dist/runtime/api/agent/ai-providers/index.js +0 -9
- package/dist/runtime/api/agent/ai-providers/types.d.ts +0 -185
- package/dist/runtime/api/agent/ai-providers/types.js +0 -5
- package/dist/runtime/api/agent/amp-cli-provider.test.d.ts +0 -1
- package/dist/runtime/api/agent/amp-cli-provider.test.js +0 -99
- package/dist/runtime/api/agent/codex-cli-provider.test.d.ts +0 -1
- package/dist/runtime/api/agent/codex-cli-provider.test.js +0 -172
- package/dist/runtime/api/agent/core-agent-service.d.ts +0 -119
- package/dist/runtime/api/agent/core-agent-service.js +0 -267
- package/dist/runtime/api/agent/parsers.d.ts +0 -16
- package/dist/runtime/api/agent/parsers.js +0 -308
- package/dist/runtime/api/agent/prompt-service.d.ts +0 -30
- package/dist/runtime/api/agent/prompt-service.js +0 -452
- package/dist/runtime/api/agent/prompt-service.test.d.ts +0 -1
- package/dist/runtime/api/agent/prompt-service.test.js +0 -265
- package/dist/runtime/api/agent/routing-policy.d.ts +0 -171
- package/dist/runtime/api/agent/routing-policy.js +0 -196
- package/dist/runtime/api/agent/routing-policy.test.d.ts +0 -1
- package/dist/runtime/api/agent/routing-policy.test.js +0 -63
- package/dist/runtime/api/api/router-helpers.d.ts +0 -32
- package/dist/runtime/api/api/router-helpers.js +0 -31
- package/dist/runtime/api/api/routers/ai.d.ts +0 -200
- package/dist/runtime/api/api/routers/ai.js +0 -396
- package/dist/runtime/api/api/routers/executions.d.ts +0 -93
- package/dist/runtime/api/api/routers/executions.js +0 -94
- package/dist/runtime/api/api/routers/git.d.ts +0 -45
- package/dist/runtime/api/api/routers/git.js +0 -35
- package/dist/runtime/api/api/routers/provider-config.d.ts +0 -199
- package/dist/runtime/api/api/routers/provider-config.js +0 -252
- package/dist/runtime/api/api/routers/settings.d.ts +0 -158
- package/dist/runtime/api/api/routers/settings.js +0 -129
- package/dist/runtime/api/api/routers/tasks.d.ts +0 -141
- package/dist/runtime/api/api/routers/tasks.js +0 -238
- package/dist/runtime/api/api/routers/workflows.d.ts +0 -275
- package/dist/runtime/api/api/routers/workflows.js +0 -311
- package/dist/runtime/api/api/routers/worktrees.d.ts +0 -101
- package/dist/runtime/api/api/routers/worktrees.js +0 -80
- package/dist/runtime/api/api/trpc.d.ts +0 -118
- package/dist/runtime/api/api/trpc.js +0 -34
- package/dist/runtime/api/index.d.ts +0 -9
- package/dist/runtime/api/index.js +0 -117
- package/dist/runtime/api/lib/id-generator.d.ts +0 -70
- package/dist/runtime/api/lib/id-generator.js +0 -123
- package/dist/runtime/api/lib/local-config.d.ts +0 -335
- package/dist/runtime/api/lib/local-config.js +0 -304
- package/dist/runtime/api/lib/logger.d.ts +0 -11
- package/dist/runtime/api/lib/logger.js +0 -188
- package/dist/runtime/api/lib/provider-detection.d.ts +0 -61
- package/dist/runtime/api/lib/provider-detection.js +0 -326
- package/dist/runtime/api/lib/server/agent-service-singleton.d.ts +0 -6
- package/dist/runtime/api/lib/server/agent-service-singleton.js +0 -27
- package/dist/runtime/api/lib/server/bootstrap.d.ts +0 -38
- package/dist/runtime/api/lib/server/bootstrap.js +0 -197
- package/dist/runtime/api/lib/server/git-service-singleton.d.ts +0 -6
- package/dist/runtime/api/lib/server/git-service-singleton.js +0 -47
- package/dist/runtime/api/lib/server/project-root.d.ts +0 -2
- package/dist/runtime/api/lib/server/project-root.js +0 -61
- package/dist/runtime/api/lib/server/task-service-singleton.d.ts +0 -7
- package/dist/runtime/api/lib/server/task-service-singleton.js +0 -58
- package/dist/runtime/api/lib/server/vibeman-info.d.ts +0 -5
- package/dist/runtime/api/lib/server/vibeman-info.js +0 -85
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.d.ts +0 -7
- package/dist/runtime/api/lib/server/vibing-orchestrator-singleton.js +0 -57
- package/dist/runtime/api/lib/trpc/server.d.ts +0 -965
- package/dist/runtime/api/lib/trpc/server.js +0 -11
- package/dist/runtime/api/lib/trpc/ws-server.d.ts +0 -8
- package/dist/runtime/api/lib/trpc/ws-server.js +0 -33
- package/dist/runtime/api/persistence/database-service.d.ts +0 -14
- package/dist/runtime/api/persistence/database-service.js +0 -74
- package/dist/runtime/api/persistence/execution-log-persistence.d.ts +0 -90
- package/dist/runtime/api/persistence/execution-log-persistence.js +0 -426
- package/dist/runtime/api/persistence/execution-log-persistence.test.d.ts +0 -1
- package/dist/runtime/api/persistence/execution-log-persistence.test.js +0 -170
- package/dist/runtime/api/router.d.ts +0 -968
- package/dist/runtime/api/router.js +0 -34
- package/dist/runtime/api/settings-service.d.ts +0 -110
- package/dist/runtime/api/settings-service.js +0 -678
- package/dist/runtime/api/tasks/file-watcher.d.ts +0 -23
- package/dist/runtime/api/tasks/file-watcher.js +0 -88
- package/dist/runtime/api/tasks/task-file-parser.d.ts +0 -14
- package/dist/runtime/api/tasks/task-file-parser.js +0 -180
- package/dist/runtime/api/tasks/task-service.d.ts +0 -36
- package/dist/runtime/api/tasks/task-service.js +0 -173
- package/dist/runtime/api/tasks/task-updater.d.ts +0 -62
- package/dist/runtime/api/tasks/task-updater.js +0 -260
- package/dist/runtime/api/tasks/task-updater.test.d.ts +0 -1
- package/dist/runtime/api/tasks/task-updater.test.js +0 -303
- package/dist/runtime/api/types/index.d.ts +0 -186
- package/dist/runtime/api/types/index.js +0 -1
- package/dist/runtime/api/types/settings.d.ts +0 -105
- package/dist/runtime/api/types/settings.js +0 -2
- package/dist/runtime/api/types.d.ts +0 -2
- package/dist/runtime/api/types.js +0 -1
- package/dist/runtime/api/utils/env.d.ts +0 -6
- package/dist/runtime/api/utils/env.js +0 -12
- package/dist/runtime/api/utils/stripNextEnv.d.ts +0 -7
- package/dist/runtime/api/utils/stripNextEnv.js +0 -22
- package/dist/runtime/api/utils/title-slug.d.ts +0 -6
- package/dist/runtime/api/utils/title-slug.js +0 -77
- package/dist/runtime/api/utils/url.d.ts +0 -2
- package/dist/runtime/api/utils/url.js +0 -19
- package/dist/runtime/api/vcs/git-history-service.d.ts +0 -57
- package/dist/runtime/api/vcs/git-history-service.js +0 -228
- package/dist/runtime/api/vcs/git-service.d.ts +0 -136
- package/dist/runtime/api/vcs/git-service.js +0 -307
- package/dist/runtime/api/vcs/worktree-service.d.ts +0 -93
- package/dist/runtime/api/vcs/worktree-service.js +0 -518
- package/dist/runtime/api/vcs/worktree-service.test.d.ts +0 -1
- package/dist/runtime/api/vcs/worktree-service.test.js +0 -20
- package/dist/runtime/api/workflows/quality-pipeline.d.ts +0 -58
- package/dist/runtime/api/workflows/quality-pipeline.js +0 -401
- package/dist/runtime/api/workflows/vibing-orchestrator.d.ts +0 -406
- package/dist/runtime/api/workflows/vibing-orchestrator.js +0 -2462
- package/dist/runtime/api/workflows/workflow-effects.d.ts +0 -45
- package/dist/runtime/api/workflows/workflow-effects.js +0 -49
- package/dist/runtime/api/workflows/workflow-reconciler.d.ts +0 -65
- package/dist/runtime/api/workflows/workflow-reconciler.js +0 -226
- package/dist/runtime/api/workflows/workflow-reducer.d.ts +0 -26
- package/dist/runtime/api/workflows/workflow-reducer.js +0 -288
- package/dist/runtime/api/workflows/workflow-reducer.test.d.ts +0 -1
- package/dist/runtime/api/workflows/workflow-reducer.test.js +0 -247
- package/dist/runtime/api/workflows/workflow-schema.d.ts +0 -546
- package/dist/runtime/api/workflows/workflow-schema.js +0 -256
- package/dist/runtime/web/.next/BUILD_ID +0 -1
- package/dist/runtime/web/.next/app-build-manifest.json +0 -66
- package/dist/runtime/web/.next/app-path-routes-manifest.json +0 -8
- package/dist/runtime/web/.next/build-manifest.json +0 -33
- package/dist/runtime/web/.next/package.json +0 -1
- package/dist/runtime/web/.next/prerender-manifest.json +0 -61
- package/dist/runtime/web/.next/react-loadable-manifest.json +0 -8
- package/dist/runtime/web/.next/required-server-files.json +0 -334
- package/dist/runtime/web/.next/routes-manifest.json +0 -70
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js +0 -1
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/_not-found/page.js +0 -2
- package/dist/runtime/web/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/_not-found.html +0 -7
- package/dist/runtime/web/.next/server/app/_not-found.meta +0 -8
- package/dist/runtime/web/.next/server/app/_not-found.rsc +0 -22
- package/dist/runtime/web/.next/server/app/api/health/route.js +0 -1
- package/dist/runtime/web/.next/server/app/api/health/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +0 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/api/upload/route.js +0 -1
- package/dist/runtime/web/.next/server/app/api/upload/route.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app/index.html +0 -7
- package/dist/runtime/web/.next/server/app/index.meta +0 -7
- package/dist/runtime/web/.next/server/app/index.rsc +0 -27
- package/dist/runtime/web/.next/server/app/page.js +0 -112
- package/dist/runtime/web/.next/server/app/page.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/app-paths-manifest.json +0 -8
- package/dist/runtime/web/.next/server/chunks/210.js +0 -1
- package/dist/runtime/web/.next/server/chunks/291.js +0 -18
- package/dist/runtime/web/.next/server/chunks/552.js +0 -22
- package/dist/runtime/web/.next/server/chunks/780.js +0 -1
- package/dist/runtime/web/.next/server/chunks/905.js +0 -6
- package/dist/runtime/web/.next/server/chunks/98.js +0 -1
- package/dist/runtime/web/.next/server/functions-config-manifest.json +0 -4
- package/dist/runtime/web/.next/server/middleware-build-manifest.js +0 -1
- package/dist/runtime/web/.next/server/middleware-manifest.json +0 -6
- package/dist/runtime/web/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/dist/runtime/web/.next/server/next-font-manifest.js +0 -1
- package/dist/runtime/web/.next/server/next-font-manifest.json +0 -1
- package/dist/runtime/web/.next/server/pages/404.html +0 -7
- package/dist/runtime/web/.next/server/pages/500.html +0 -1
- package/dist/runtime/web/.next/server/pages/_app.js +0 -1
- package/dist/runtime/web/.next/server/pages/_app.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/pages/_document.js +0 -1
- package/dist/runtime/web/.next/server/pages/_document.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/pages/_error.js +0 -19
- package/dist/runtime/web/.next/server/pages/_error.js.nft.json +0 -1
- package/dist/runtime/web/.next/server/pages-manifest.json +0 -6
- package/dist/runtime/web/.next/server/server-reference-manifest.js +0 -1
- package/dist/runtime/web/.next/server/server-reference-manifest.json +0 -1
- package/dist/runtime/web/.next/server/webpack-runtime.js +0 -1
- package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_buildManifest.js +0 -1
- package/dist/runtime/web/.next/static/LJFZk_8tvKFN_Ee4HqUuM/_ssgManifest.js +0 -1
- package/dist/runtime/web/.next/static/chunks/05c91ade-7d09b2b280adffd1.js +0 -1
- package/dist/runtime/web/.next/static/chunks/201-51bef3fa8c832e2e.js +0 -1
- package/dist/runtime/web/.next/static/chunks/524-89747ed9b0294f8a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/554-8bec6e9cca6acc67.js +0 -1
- package/dist/runtime/web/.next/static/chunks/764.86e9503a69d45a85.js +0 -1
- package/dist/runtime/web/.next/static/chunks/7ab4dc20-239138e0ae7af24a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/905-342391e3d3a3678f.js +0 -20
- package/dist/runtime/web/.next/static/chunks/a8a5ce16-4edea7df2d9b544a.js +0 -79
- package/dist/runtime/web/.next/static/chunks/ad74d572-4c1b162e2c15acaa.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/.vibeman/assets/images/[...path]/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/_not-found/page-34e66b251c2b5044.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/health/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/upload/route-7b752a8641f96c1f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/layout-df9ac93cb02b2385.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/page-6610743f7de5f92a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/c25e0690-e9b798b8de667da1.js +0 -1
- package/dist/runtime/web/.next/static/chunks/framework-57157ec4d37f64aa.js +0 -1
- package/dist/runtime/web/.next/static/chunks/main-app-156cc0c60371bd78.js +0 -1
- package/dist/runtime/web/.next/static/chunks/main-df25d367c47b1fec.js +0 -1
- package/dist/runtime/web/.next/static/chunks/pages/_app-9f629a5e1131d19f.js +0 -1
- package/dist/runtime/web/.next/static/chunks/pages/_error-9238238274c7efcd.js +0 -1
- package/dist/runtime/web/.next/static/chunks/polyfills-42372ed130431b0a.js +0 -1
- package/dist/runtime/web/.next/static/chunks/webpack-cd50e39b423d1808.js +0 -1
- package/dist/runtime/web/.next/static/css/2728291c68f99cb1.css +0 -3
- package/dist/runtime/web/.next/static/css/4fbf378a264bd4ea.css +0 -1
- package/dist/runtime/web/.next/static/css/521bd69cc298cd1a.css +0 -1
- package/dist/runtime/web/.next/static/css/537e22821e101b87.css +0 -1
- package/dist/runtime/web/.next/static/media/19cfc7226ec3afaa-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/21350d82a1f187e9-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/8e9860b6e62d6359-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/ba9851c3c22cd980-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/c5fe6dc8356a8c31-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/df0a9ae256c0569c-s.woff2 +0 -0
- package/dist/runtime/web/.next/static/media/e4af272ccee01ff0-s.p.woff2 +0 -0
- package/dist/runtime/web/package.json +0 -65
- package/dist/runtime/web/server.js +0 -44
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -1,265 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
|
|
2
|
-
import { promises as fs } from 'fs';
|
|
3
|
-
import path from 'path';
|
|
4
|
-
import { PromptService } from './prompt-service.js';
|
|
5
|
-
const TEST_DATA_DIR = path.resolve(process.cwd(), '.test-prompt-service');
|
|
6
|
-
const TEST_TASKS_DIR = path.join(TEST_DATA_DIR, 'tasks');
|
|
7
|
-
// Mock getVibeDir to return test directory
|
|
8
|
-
vi.mock('../lib/server/project-root', () => ({
|
|
9
|
-
getVibeDir: () => TEST_DATA_DIR,
|
|
10
|
-
getProjectRoot: () => TEST_DATA_DIR,
|
|
11
|
-
}));
|
|
12
|
-
// Mock TaskService
|
|
13
|
-
const mockTaskService = {
|
|
14
|
-
getTask: vi.fn(),
|
|
15
|
-
getAllTasks: vi.fn(),
|
|
16
|
-
};
|
|
17
|
-
describe('PromptService Task File Path Integration', () => {
|
|
18
|
-
let promptService;
|
|
19
|
-
beforeEach(async () => {
|
|
20
|
-
promptService = new PromptService(TEST_DATA_DIR, mockTaskService);
|
|
21
|
-
// Create test directories
|
|
22
|
-
await fs.mkdir(TEST_TASKS_DIR, { recursive: true });
|
|
23
|
-
});
|
|
24
|
-
afterEach(async () => {
|
|
25
|
-
// Clean up test data
|
|
26
|
-
try {
|
|
27
|
-
await fs.rm(TEST_DATA_DIR, { recursive: true, force: true });
|
|
28
|
-
}
|
|
29
|
-
catch {
|
|
30
|
-
// Ignore cleanup errors
|
|
31
|
-
}
|
|
32
|
-
});
|
|
33
|
-
describe('generateTaskPrompt', () => {
|
|
34
|
-
it('should include absolute path when task file exists', async () => {
|
|
35
|
-
const mockTask = {
|
|
36
|
-
id: 'TEST-TASK-001',
|
|
37
|
-
title: 'Test Task',
|
|
38
|
-
type: 'feature',
|
|
39
|
-
status: 'in-progress',
|
|
40
|
-
priority: 'high',
|
|
41
|
-
tags: ['test'],
|
|
42
|
-
content: 'Test task content',
|
|
43
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
44
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
45
|
-
assignee: [],
|
|
46
|
-
comments: [],
|
|
47
|
-
};
|
|
48
|
-
// Create task file
|
|
49
|
-
const taskFilePath = path.join(TEST_TASKS_DIR, 'TEST-TASK-001.md');
|
|
50
|
-
const taskFileContent = `---
|
|
51
|
-
id: TEST-TASK-001
|
|
52
|
-
title: Test Task
|
|
53
|
-
type: feature
|
|
54
|
-
status: in-progress
|
|
55
|
-
priority: high
|
|
56
|
-
tags: test
|
|
57
|
-
---
|
|
58
|
-
|
|
59
|
-
Test task content`;
|
|
60
|
-
await fs.writeFile(taskFilePath, taskFileContent, 'utf-8');
|
|
61
|
-
const prompt = await promptService.generateTaskPrompt(mockTask);
|
|
62
|
-
expect(prompt).toContain('Current task file:');
|
|
63
|
-
expect(prompt).toContain(taskFilePath);
|
|
64
|
-
expect(prompt).toContain('TEST-TASK-001');
|
|
65
|
-
expect(prompt).toContain('Test Task');
|
|
66
|
-
expect(prompt).toContain('Test task content');
|
|
67
|
-
});
|
|
68
|
-
it('should handle missing task file gracefully', async () => {
|
|
69
|
-
const mockTask = {
|
|
70
|
-
id: 'NONEXISTENT-TASK',
|
|
71
|
-
title: 'Nonexistent Task',
|
|
72
|
-
type: 'bug',
|
|
73
|
-
status: 'backlog',
|
|
74
|
-
priority: 'medium',
|
|
75
|
-
tags: [],
|
|
76
|
-
content: 'This task file does not exist',
|
|
77
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
78
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
79
|
-
assignee: [],
|
|
80
|
-
comments: [],
|
|
81
|
-
};
|
|
82
|
-
const prompt = await promptService.generateTaskPrompt(mockTask);
|
|
83
|
-
expect(prompt).toContain('not accessible at expected path');
|
|
84
|
-
expect(prompt).toContain('NONEXISTENT-TASK.md');
|
|
85
|
-
expect(prompt).toContain('Nonexistent Task');
|
|
86
|
-
expect(prompt).toContain('This task file does not exist');
|
|
87
|
-
});
|
|
88
|
-
it('should handle path resolution errors', async () => {
|
|
89
|
-
// Mock generateTaskFilePath to return null (simulating path resolution error)
|
|
90
|
-
const originalGenerateTaskFilePath = promptService.generateTaskFilePath;
|
|
91
|
-
promptService.generateTaskFilePath = vi.fn().mockReturnValue(null);
|
|
92
|
-
const mockTask = {
|
|
93
|
-
id: 'ERROR-TASK',
|
|
94
|
-
title: 'Error Task',
|
|
95
|
-
type: 'chore',
|
|
96
|
-
status: 'review',
|
|
97
|
-
priority: 'low',
|
|
98
|
-
tags: ['error'],
|
|
99
|
-
content: 'Task with path resolution error',
|
|
100
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
101
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
102
|
-
assignee: [],
|
|
103
|
-
comments: [],
|
|
104
|
-
};
|
|
105
|
-
const prompt = await promptService.generateTaskPrompt(mockTask);
|
|
106
|
-
expect(prompt).toContain('path could not be resolved');
|
|
107
|
-
expect(prompt).toContain('ERROR-TASK');
|
|
108
|
-
expect(prompt).toContain('Task with path resolution error');
|
|
109
|
-
// Restore original method
|
|
110
|
-
promptService.generateTaskFilePath = originalGenerateTaskFilePath;
|
|
111
|
-
});
|
|
112
|
-
});
|
|
113
|
-
describe('generateImprovementPrompt', () => {
|
|
114
|
-
it('should include task file path in project context', async () => {
|
|
115
|
-
const mockTask = {
|
|
116
|
-
id: 'IMPROVE-TASK-001',
|
|
117
|
-
title: 'Improvement Task',
|
|
118
|
-
type: 'feature',
|
|
119
|
-
status: 'backlog',
|
|
120
|
-
priority: 'medium',
|
|
121
|
-
tags: [],
|
|
122
|
-
content: 'Original content',
|
|
123
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
124
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
125
|
-
assignee: [],
|
|
126
|
-
comments: [],
|
|
127
|
-
};
|
|
128
|
-
const taskData = {
|
|
129
|
-
title: 'Improved Task',
|
|
130
|
-
type: 'feature',
|
|
131
|
-
priority: 'high',
|
|
132
|
-
content: 'Improved content',
|
|
133
|
-
};
|
|
134
|
-
const productOverviewPath = path.join(TEST_DATA_DIR, 'product_overview.md');
|
|
135
|
-
const readmePath = path.join(TEST_DATA_DIR, 'README.md');
|
|
136
|
-
await fs.writeFile(productOverviewPath, 'Existing product overview content for context.', 'utf-8');
|
|
137
|
-
await fs.writeFile(readmePath, '# Workspace README\n', 'utf-8');
|
|
138
|
-
// Create task file
|
|
139
|
-
const taskFilePath = path.join(TEST_TASKS_DIR, 'IMPROVE-TASK-001.md');
|
|
140
|
-
await fs.writeFile(taskFilePath, 'Task file content', 'utf-8');
|
|
141
|
-
const prompt = await promptService.generateImprovementPrompt(mockTask, taskData);
|
|
142
|
-
expect(prompt).not.toContain('Existing product overview content for context.');
|
|
143
|
-
expect(prompt).toContain(`**Product overview file:** ${productOverviewPath}`);
|
|
144
|
-
expect(prompt).toContain('Reference this for additional product context.');
|
|
145
|
-
expect(prompt).toContain(`**Repository README:** ${readmePath}`);
|
|
146
|
-
expect(prompt).toContain('Review this if you need additional project context.');
|
|
147
|
-
expect(prompt).toContain('Current task file location:');
|
|
148
|
-
expect(prompt).toContain(taskFilePath);
|
|
149
|
-
expect(prompt).toContain('IMPROVE-TASK-001');
|
|
150
|
-
});
|
|
151
|
-
it('should include language preservation instructions in the prompt', async () => {
|
|
152
|
-
const mockTask = {
|
|
153
|
-
id: 'LANG-TEST-001',
|
|
154
|
-
title: 'Language Test Task',
|
|
155
|
-
type: 'feature',
|
|
156
|
-
status: 'backlog',
|
|
157
|
-
priority: 'medium',
|
|
158
|
-
tags: [],
|
|
159
|
-
content: 'Test content in any language',
|
|
160
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
161
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
162
|
-
assignee: [],
|
|
163
|
-
comments: [],
|
|
164
|
-
};
|
|
165
|
-
const taskData = {
|
|
166
|
-
title: 'Tarea de prueba de idioma',
|
|
167
|
-
type: 'feature',
|
|
168
|
-
priority: 'high',
|
|
169
|
-
content: 'Contenido de prueba en español',
|
|
170
|
-
};
|
|
171
|
-
const prompt = await promptService.generateImprovementPrompt(mockTask, taskData);
|
|
172
|
-
// Verify the prompt contains language preservation instructions
|
|
173
|
-
expect(prompt).toContain('Detect the language of the task content');
|
|
174
|
-
expect(prompt).toContain('respond in that SAME language');
|
|
175
|
-
expect(prompt).toContain('Keep enum fields (type, priority) in English');
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
describe('generateReviewPrompt', () => {
|
|
179
|
-
it('should include task file path in additional context', async () => {
|
|
180
|
-
const mockTask = {
|
|
181
|
-
id: 'REVIEW-TASK-001',
|
|
182
|
-
title: 'Review Task',
|
|
183
|
-
type: 'bug',
|
|
184
|
-
status: 'review',
|
|
185
|
-
priority: 'high',
|
|
186
|
-
tags: [],
|
|
187
|
-
content: 'Task under review',
|
|
188
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
189
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
190
|
-
assignee: [],
|
|
191
|
-
comments: [],
|
|
192
|
-
};
|
|
193
|
-
const mockWorktree = {
|
|
194
|
-
taskId: 'REVIEW-TASK-001',
|
|
195
|
-
path: '/test/worktree',
|
|
196
|
-
branchName: 'feature/review-task-001',
|
|
197
|
-
};
|
|
198
|
-
// Create task file
|
|
199
|
-
const taskFilePath = path.join(TEST_TASKS_DIR, 'REVIEW-TASK-001.md');
|
|
200
|
-
await fs.writeFile(taskFilePath, 'Review task content', 'utf-8');
|
|
201
|
-
const prompt = await promptService.generateReviewPrompt(mockTask, mockWorktree, 'Custom review context');
|
|
202
|
-
expect(prompt).toContain('Current task file:');
|
|
203
|
-
expect(prompt).toContain(taskFilePath);
|
|
204
|
-
expect(prompt).toContain('Custom review context');
|
|
205
|
-
expect(prompt).toContain('REVIEW-TASK-001');
|
|
206
|
-
});
|
|
207
|
-
});
|
|
208
|
-
describe('cross-platform path resolution', () => {
|
|
209
|
-
it('should generate valid absolute paths on different platforms', async () => {
|
|
210
|
-
const taskId = 'CROSS-PLATFORM-TEST';
|
|
211
|
-
// Test the private method through a task prompt generation
|
|
212
|
-
const mockTask = {
|
|
213
|
-
id: taskId,
|
|
214
|
-
title: 'Cross Platform Test',
|
|
215
|
-
type: 'test',
|
|
216
|
-
status: 'in-progress',
|
|
217
|
-
priority: 'medium',
|
|
218
|
-
tags: [],
|
|
219
|
-
content: 'Cross platform path test',
|
|
220
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
221
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
222
|
-
assignee: [],
|
|
223
|
-
comments: [],
|
|
224
|
-
};
|
|
225
|
-
// Create task file
|
|
226
|
-
const taskFilePath = path.join(TEST_TASKS_DIR, `${taskId}.md`);
|
|
227
|
-
await fs.writeFile(taskFilePath, 'Cross platform test content', 'utf-8');
|
|
228
|
-
const prompt = await promptService.generateTaskPrompt(mockTask);
|
|
229
|
-
// Verify the path is absolute and uses correct separators
|
|
230
|
-
const pathMatch = prompt.match(/- \*\*Current task file:\*\* (.+)/);
|
|
231
|
-
expect(pathMatch).toBeTruthy();
|
|
232
|
-
if (pathMatch) {
|
|
233
|
-
const extractedPath = pathMatch[1];
|
|
234
|
-
expect(path.isAbsolute(extractedPath)).toBe(true);
|
|
235
|
-
expect(extractedPath).toContain(taskId);
|
|
236
|
-
expect(extractedPath.endsWith('.md')).toBe(true);
|
|
237
|
-
}
|
|
238
|
-
});
|
|
239
|
-
});
|
|
240
|
-
describe('error handling', () => {
|
|
241
|
-
it('should handle file system permission errors gracefully', async () => {
|
|
242
|
-
const mockTask = {
|
|
243
|
-
id: 'PERMISSION-TEST',
|
|
244
|
-
title: 'Permission Test',
|
|
245
|
-
type: 'chore',
|
|
246
|
-
status: 'backlog',
|
|
247
|
-
priority: 'low',
|
|
248
|
-
tags: [],
|
|
249
|
-
content: 'Permission test content',
|
|
250
|
-
created_at: '2024-09-04T12:00:00.000Z',
|
|
251
|
-
updated_at: '2024-09-04T12:00:00.000Z',
|
|
252
|
-
assignee: [],
|
|
253
|
-
comments: [],
|
|
254
|
-
};
|
|
255
|
-
// Mock validateTaskFile to simulate permission error
|
|
256
|
-
const originalValidateTaskFile = promptService.validateTaskFile;
|
|
257
|
-
promptService.validateTaskFile = vi.fn().mockResolvedValueOnce(false);
|
|
258
|
-
const prompt = await promptService.generateTaskPrompt(mockTask);
|
|
259
|
-
expect(prompt).toContain('not accessible at expected path');
|
|
260
|
-
expect(prompt).toContain('PERMISSION-TEST');
|
|
261
|
-
// Restore original function
|
|
262
|
-
promptService.validateTaskFile = originalValidateTaskFile;
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
});
|
|
@@ -1,171 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AI Routing Policy Management
|
|
3
|
-
* Handles provider selection per operation with fallbacks and configuration
|
|
4
|
-
*/
|
|
5
|
-
import { z } from 'zod';
|
|
6
|
-
/**
|
|
7
|
-
* Operation types that support AI routing
|
|
8
|
-
*/
|
|
9
|
-
declare const ROUTABLE_OPERATIONS: readonly ["execute_task", "quality_checks", "ai_codereview", "ai_merge", "improve_task"];
|
|
10
|
-
export type RoutableOperation = (typeof ROUTABLE_OPERATIONS)[number];
|
|
11
|
-
/**
|
|
12
|
-
* Generation options for AI execution
|
|
13
|
-
*/
|
|
14
|
-
export declare const GenerationOptionsSchema: z.ZodObject<{
|
|
15
|
-
temperature: z.ZodOptional<z.ZodNumber>;
|
|
16
|
-
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
17
|
-
tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
18
|
-
}, "strip", z.ZodTypeAny, {
|
|
19
|
-
temperature?: number | undefined;
|
|
20
|
-
maxTokens?: number | undefined;
|
|
21
|
-
tools?: string[] | undefined;
|
|
22
|
-
}, {
|
|
23
|
-
temperature?: number | undefined;
|
|
24
|
-
maxTokens?: number | undefined;
|
|
25
|
-
tools?: string[] | undefined;
|
|
26
|
-
}>;
|
|
27
|
-
export type GenerationOptions = z.infer<typeof GenerationOptionsSchema>;
|
|
28
|
-
/**
|
|
29
|
-
* Per-operation routing configuration
|
|
30
|
-
*/
|
|
31
|
-
export declare const OperationConfigSchema: z.ZodObject<{
|
|
32
|
-
provider: z.ZodString;
|
|
33
|
-
model: z.ZodOptional<z.ZodString>;
|
|
34
|
-
options: z.ZodOptional<z.ZodObject<{
|
|
35
|
-
temperature: z.ZodOptional<z.ZodNumber>;
|
|
36
|
-
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
37
|
-
tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
38
|
-
}, "strip", z.ZodTypeAny, {
|
|
39
|
-
temperature?: number | undefined;
|
|
40
|
-
maxTokens?: number | undefined;
|
|
41
|
-
tools?: string[] | undefined;
|
|
42
|
-
}, {
|
|
43
|
-
temperature?: number | undefined;
|
|
44
|
-
maxTokens?: number | undefined;
|
|
45
|
-
tools?: string[] | undefined;
|
|
46
|
-
}>>;
|
|
47
|
-
fallback: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
48
|
-
}, "strip", z.ZodTypeAny, {
|
|
49
|
-
provider: string;
|
|
50
|
-
options?: {
|
|
51
|
-
temperature?: number | undefined;
|
|
52
|
-
maxTokens?: number | undefined;
|
|
53
|
-
tools?: string[] | undefined;
|
|
54
|
-
} | undefined;
|
|
55
|
-
model?: string | undefined;
|
|
56
|
-
fallback?: string[] | undefined;
|
|
57
|
-
}, {
|
|
58
|
-
provider: string;
|
|
59
|
-
options?: {
|
|
60
|
-
temperature?: number | undefined;
|
|
61
|
-
maxTokens?: number | undefined;
|
|
62
|
-
tools?: string[] | undefined;
|
|
63
|
-
} | undefined;
|
|
64
|
-
model?: string | undefined;
|
|
65
|
-
fallback?: string[] | undefined;
|
|
66
|
-
}>;
|
|
67
|
-
export type OperationConfig = z.infer<typeof OperationConfigSchema>;
|
|
68
|
-
/**
|
|
69
|
-
* Complete routing policy schema
|
|
70
|
-
*/
|
|
71
|
-
export declare const RoutingPolicySchema: z.ZodObject<{
|
|
72
|
-
defaultProvider: z.ZodString;
|
|
73
|
-
operations: z.ZodOptional<z.ZodRecord<z.ZodEnum<["execute_task", "quality_checks", "ai_codereview", "ai_merge", "improve_task"]>, z.ZodObject<{
|
|
74
|
-
provider: z.ZodString;
|
|
75
|
-
model: z.ZodOptional<z.ZodString>;
|
|
76
|
-
options: z.ZodOptional<z.ZodObject<{
|
|
77
|
-
temperature: z.ZodOptional<z.ZodNumber>;
|
|
78
|
-
maxTokens: z.ZodOptional<z.ZodNumber>;
|
|
79
|
-
tools: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
80
|
-
}, "strip", z.ZodTypeAny, {
|
|
81
|
-
temperature?: number | undefined;
|
|
82
|
-
maxTokens?: number | undefined;
|
|
83
|
-
tools?: string[] | undefined;
|
|
84
|
-
}, {
|
|
85
|
-
temperature?: number | undefined;
|
|
86
|
-
maxTokens?: number | undefined;
|
|
87
|
-
tools?: string[] | undefined;
|
|
88
|
-
}>>;
|
|
89
|
-
fallback: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
90
|
-
}, "strip", z.ZodTypeAny, {
|
|
91
|
-
provider: string;
|
|
92
|
-
options?: {
|
|
93
|
-
temperature?: number | undefined;
|
|
94
|
-
maxTokens?: number | undefined;
|
|
95
|
-
tools?: string[] | undefined;
|
|
96
|
-
} | undefined;
|
|
97
|
-
model?: string | undefined;
|
|
98
|
-
fallback?: string[] | undefined;
|
|
99
|
-
}, {
|
|
100
|
-
provider: string;
|
|
101
|
-
options?: {
|
|
102
|
-
temperature?: number | undefined;
|
|
103
|
-
maxTokens?: number | undefined;
|
|
104
|
-
tools?: string[] | undefined;
|
|
105
|
-
} | undefined;
|
|
106
|
-
model?: string | undefined;
|
|
107
|
-
fallback?: string[] | undefined;
|
|
108
|
-
}>>>;
|
|
109
|
-
}, "strip", z.ZodTypeAny, {
|
|
110
|
-
defaultProvider: string;
|
|
111
|
-
operations?: Partial<Record<"execute_task" | "quality_checks" | "ai_codereview" | "ai_merge" | "improve_task", {
|
|
112
|
-
provider: string;
|
|
113
|
-
options?: {
|
|
114
|
-
temperature?: number | undefined;
|
|
115
|
-
maxTokens?: number | undefined;
|
|
116
|
-
tools?: string[] | undefined;
|
|
117
|
-
} | undefined;
|
|
118
|
-
model?: string | undefined;
|
|
119
|
-
fallback?: string[] | undefined;
|
|
120
|
-
}>> | undefined;
|
|
121
|
-
}, {
|
|
122
|
-
defaultProvider: string;
|
|
123
|
-
operations?: Partial<Record<"execute_task" | "quality_checks" | "ai_codereview" | "ai_merge" | "improve_task", {
|
|
124
|
-
provider: string;
|
|
125
|
-
options?: {
|
|
126
|
-
temperature?: number | undefined;
|
|
127
|
-
maxTokens?: number | undefined;
|
|
128
|
-
tools?: string[] | undefined;
|
|
129
|
-
} | undefined;
|
|
130
|
-
model?: string | undefined;
|
|
131
|
-
fallback?: string[] | undefined;
|
|
132
|
-
}>> | undefined;
|
|
133
|
-
}>;
|
|
134
|
-
export type RoutingPolicy = z.infer<typeof RoutingPolicySchema>;
|
|
135
|
-
export declare const ROUTABLE_OPERATION_LIST: readonly ["execute_task", "quality_checks", "ai_codereview", "ai_merge", "improve_task"];
|
|
136
|
-
/**
|
|
137
|
-
* Resolved provider configuration for execution
|
|
138
|
-
*/
|
|
139
|
-
export interface ResolvedProvider {
|
|
140
|
-
provider: string;
|
|
141
|
-
model?: string;
|
|
142
|
-
options?: GenerationOptions;
|
|
143
|
-
fallbacks?: string[];
|
|
144
|
-
}
|
|
145
|
-
/**
|
|
146
|
-
* Routing Policy Manager
|
|
147
|
-
* Manages AI provider routing policies stored inside settings.json
|
|
148
|
-
*/
|
|
149
|
-
export declare class RoutingPolicyManager {
|
|
150
|
-
private policy;
|
|
151
|
-
private readonly settingsService;
|
|
152
|
-
constructor();
|
|
153
|
-
/**
|
|
154
|
-
* Get current effective policy (lazy loads from settings)
|
|
155
|
-
*/
|
|
156
|
-
getPolicy(): Promise<RoutingPolicy>;
|
|
157
|
-
/**
|
|
158
|
-
* Update routing policy and persist via settings service
|
|
159
|
-
*/
|
|
160
|
-
updatePolicy(updates: Partial<RoutingPolicy>): Promise<void>;
|
|
161
|
-
/**
|
|
162
|
-
* Resolve provider for a specific operation
|
|
163
|
-
*/
|
|
164
|
-
getEffectivePolicy(): Promise<RoutingPolicy>;
|
|
165
|
-
resolveProviderForOperation(operation: RoutableOperation, overrides?: Partial<ResolvedProvider>): Promise<ResolvedProvider>;
|
|
166
|
-
setDefaultProvider(provider: string): Promise<void>;
|
|
167
|
-
setOperationConfig(operation: RoutableOperation, config: OperationConfig): Promise<void>;
|
|
168
|
-
validatePolicy(policy: RoutingPolicy, availableProviders: Set<string>): string[];
|
|
169
|
-
private buildPolicyFromSettings;
|
|
170
|
-
}
|
|
171
|
-
export {};
|
|
@@ -1,196 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* AI Routing Policy Management
|
|
3
|
-
* Handles provider selection per operation with fallbacks and configuration
|
|
4
|
-
*/
|
|
5
|
-
import { z } from 'zod';
|
|
6
|
-
import { log } from '../lib/logger.js';
|
|
7
|
-
import { getSettingsService } from '../settings-service.js';
|
|
8
|
-
/**
|
|
9
|
-
* Operation types that support AI routing
|
|
10
|
-
*/
|
|
11
|
-
const ROUTABLE_OPERATIONS = [
|
|
12
|
-
'execute_task',
|
|
13
|
-
'quality_checks',
|
|
14
|
-
'ai_codereview',
|
|
15
|
-
'ai_merge',
|
|
16
|
-
'improve_task',
|
|
17
|
-
];
|
|
18
|
-
/**
|
|
19
|
-
* Generation options for AI execution
|
|
20
|
-
*/
|
|
21
|
-
export const GenerationOptionsSchema = z.object({
|
|
22
|
-
temperature: z.number().min(0).max(2).optional(),
|
|
23
|
-
maxTokens: z.number().positive().optional(),
|
|
24
|
-
tools: z.array(z.string()).optional(),
|
|
25
|
-
});
|
|
26
|
-
/**
|
|
27
|
-
* Per-operation routing configuration
|
|
28
|
-
*/
|
|
29
|
-
export const OperationConfigSchema = z.object({
|
|
30
|
-
provider: z.string(),
|
|
31
|
-
model: z.string().optional(),
|
|
32
|
-
options: GenerationOptionsSchema.optional(),
|
|
33
|
-
fallback: z.array(z.string()).optional(),
|
|
34
|
-
});
|
|
35
|
-
/**
|
|
36
|
-
* Complete routing policy schema
|
|
37
|
-
*/
|
|
38
|
-
export const RoutingPolicySchema = z.object({
|
|
39
|
-
defaultProvider: z.string(),
|
|
40
|
-
operations: z.record(z.enum(ROUTABLE_OPERATIONS), OperationConfigSchema).optional(),
|
|
41
|
-
});
|
|
42
|
-
export const ROUTABLE_OPERATION_LIST = ROUTABLE_OPERATIONS;
|
|
43
|
-
/**
|
|
44
|
-
* Routing Policy Manager
|
|
45
|
-
* Manages AI provider routing policies stored inside settings.json
|
|
46
|
-
*/
|
|
47
|
-
export class RoutingPolicyManager {
|
|
48
|
-
constructor() {
|
|
49
|
-
this.policy = null;
|
|
50
|
-
this.settingsService = getSettingsService();
|
|
51
|
-
// Invalidate cached policy when settings change
|
|
52
|
-
this.settingsService.on('settingsUpdated', () => {
|
|
53
|
-
this.policy = null;
|
|
54
|
-
});
|
|
55
|
-
}
|
|
56
|
-
/**
|
|
57
|
-
* Get current effective policy (lazy loads from settings)
|
|
58
|
-
*/
|
|
59
|
-
async getPolicy() {
|
|
60
|
-
if (!this.policy) {
|
|
61
|
-
this.policy = this.buildPolicyFromSettings();
|
|
62
|
-
}
|
|
63
|
-
return this.policy;
|
|
64
|
-
}
|
|
65
|
-
/**
|
|
66
|
-
* Update routing policy and persist via settings service
|
|
67
|
-
*/
|
|
68
|
-
async updatePolicy(updates) {
|
|
69
|
-
const currentPolicy = await this.getPolicy();
|
|
70
|
-
const mergedOperations = {
|
|
71
|
-
...(currentPolicy.operations ?? {}),
|
|
72
|
-
...(updates.operations ?? {}),
|
|
73
|
-
};
|
|
74
|
-
const operationsKeys = Object.keys(mergedOperations);
|
|
75
|
-
const nextPolicy = {
|
|
76
|
-
defaultProvider: updates.defaultProvider ?? currentPolicy.defaultProvider,
|
|
77
|
-
...(operationsKeys.length > 0 ? { operations: mergedOperations } : {}),
|
|
78
|
-
};
|
|
79
|
-
const validated = RoutingPolicySchema.parse(nextPolicy);
|
|
80
|
-
await this.settingsService.updateSettings([
|
|
81
|
-
{ path: ['agents', 'routingPolicy'], value: validated },
|
|
82
|
-
]);
|
|
83
|
-
this.policy = validated;
|
|
84
|
-
log.info('Updated AI routing policy', { policy: validated }, 'routing-policy');
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* Resolve provider for a specific operation
|
|
88
|
-
*/
|
|
89
|
-
async getEffectivePolicy() {
|
|
90
|
-
const base = await this.getPolicy();
|
|
91
|
-
const operations = {
|
|
92
|
-
...base.operations,
|
|
93
|
-
};
|
|
94
|
-
for (const op of ROUTABLE_OPERATIONS) {
|
|
95
|
-
if (!operations[op]) {
|
|
96
|
-
const resolved = await this.resolveProviderForOperation(op);
|
|
97
|
-
operations[op] = {
|
|
98
|
-
provider: resolved.provider,
|
|
99
|
-
...(resolved.model ? { model: resolved.model } : {}),
|
|
100
|
-
...(resolved.options ? { options: resolved.options } : {}),
|
|
101
|
-
...(resolved.fallbacks && resolved.fallbacks.length
|
|
102
|
-
? { fallback: resolved.fallbacks }
|
|
103
|
-
: {}),
|
|
104
|
-
};
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
return {
|
|
108
|
-
defaultProvider: base.defaultProvider,
|
|
109
|
-
operations,
|
|
110
|
-
};
|
|
111
|
-
}
|
|
112
|
-
async resolveProviderForOperation(operation, overrides) {
|
|
113
|
-
const policy = await this.getPolicy();
|
|
114
|
-
const operationConfig = policy.operations?.[operation];
|
|
115
|
-
// Pull provider/model defaults from settings per operation
|
|
116
|
-
const settings = this.settingsService.getSettings();
|
|
117
|
-
const coding = settings.agents?.codingAgent;
|
|
118
|
-
const judge = settings.agents?.judgeAgent;
|
|
119
|
-
const settingsProviderModel = (() => {
|
|
120
|
-
switch (operation) {
|
|
121
|
-
case 'ai_codereview':
|
|
122
|
-
return { provider: judge?.provider, model: judge?.model };
|
|
123
|
-
case 'execute_task':
|
|
124
|
-
case 'quality_checks':
|
|
125
|
-
case 'ai_merge':
|
|
126
|
-
case 'improve_task':
|
|
127
|
-
default:
|
|
128
|
-
return { provider: coding?.provider, model: coding?.model };
|
|
129
|
-
}
|
|
130
|
-
})();
|
|
131
|
-
// Start with operation-specific config or fall back to settings, then default policy
|
|
132
|
-
const baseProvider = operationConfig?.provider || settingsProviderModel.provider || policy.defaultProvider;
|
|
133
|
-
const baseModel = operationConfig?.model
|
|
134
|
-
? operationConfig.model
|
|
135
|
-
: operationConfig?.provider
|
|
136
|
-
? undefined
|
|
137
|
-
: settingsProviderModel.model;
|
|
138
|
-
const baseOptions = operationConfig?.options;
|
|
139
|
-
const baseFallbacks = operationConfig?.fallback || [];
|
|
140
|
-
// Apply overrides
|
|
141
|
-
const overrideProviderOnly = overrides?.provider && overrides.model === undefined;
|
|
142
|
-
const resolved = {
|
|
143
|
-
provider: overrides?.provider || baseProvider,
|
|
144
|
-
model: overrideProviderOnly ? undefined : overrides?.model || baseModel,
|
|
145
|
-
options: overrides?.options || baseOptions,
|
|
146
|
-
fallbacks: overrides?.fallbacks || baseFallbacks,
|
|
147
|
-
};
|
|
148
|
-
log.debug(`Resolved provider for ${operation}`, { operation, resolved }, 'routing-policy');
|
|
149
|
-
return resolved;
|
|
150
|
-
}
|
|
151
|
-
async setDefaultProvider(provider) {
|
|
152
|
-
await this.updatePolicy({ defaultProvider: provider });
|
|
153
|
-
}
|
|
154
|
-
async setOperationConfig(operation, config) {
|
|
155
|
-
const currentPolicy = await this.getPolicy();
|
|
156
|
-
const operations = {
|
|
157
|
-
...(currentPolicy.operations ?? {}),
|
|
158
|
-
[operation]: config,
|
|
159
|
-
};
|
|
160
|
-
await this.updatePolicy({ operations });
|
|
161
|
-
}
|
|
162
|
-
validatePolicy(policy, availableProviders) {
|
|
163
|
-
const errors = [];
|
|
164
|
-
if (!availableProviders.has(policy.defaultProvider)) {
|
|
165
|
-
errors.push(`Default provider '${policy.defaultProvider}' is not available`);
|
|
166
|
-
}
|
|
167
|
-
if (policy.operations) {
|
|
168
|
-
for (const [operation, config] of Object.entries(policy.operations)) {
|
|
169
|
-
if (!availableProviders.has(config.provider)) {
|
|
170
|
-
errors.push(`Provider '${config.provider}' for operation '${operation}' is not available`);
|
|
171
|
-
}
|
|
172
|
-
if (config.fallback) {
|
|
173
|
-
for (const fallbackProvider of config.fallback) {
|
|
174
|
-
if (!availableProviders.has(fallbackProvider)) {
|
|
175
|
-
errors.push(`Fallback provider '${fallbackProvider}' for operation '${operation}' is not available`);
|
|
176
|
-
}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
}
|
|
181
|
-
return errors;
|
|
182
|
-
}
|
|
183
|
-
buildPolicyFromSettings() {
|
|
184
|
-
const settings = this.settingsService.getSettings();
|
|
185
|
-
const settingsPolicy = settings.agents?.routingPolicy;
|
|
186
|
-
const defaultProvider = settingsPolicy?.defaultProvider || settings.agents.defaultProvider || 'claude-code';
|
|
187
|
-
const operations = settingsPolicy?.operations
|
|
188
|
-
? { ...settingsPolicy.operations }
|
|
189
|
-
: undefined;
|
|
190
|
-
const policy = {
|
|
191
|
-
defaultProvider,
|
|
192
|
-
...(operations ? { operations } : {}),
|
|
193
|
-
};
|
|
194
|
-
return RoutingPolicySchema.parse(policy);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|