vibeman 0.0.2 → 0.0.3
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/runtime/api/.tsbuildinfo +1 -1
- package/dist/runtime/api/agent/agent-service.d.ts +7 -6
- package/dist/runtime/api/agent/agent-service.js +36 -27
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.d.ts +2 -0
- package/dist/runtime/api/agent/ai-providers/codex-cli-provider.js +62 -30
- package/dist/runtime/api/agent/codex-cli-provider.test.js +47 -2
- package/dist/runtime/api/agent/routing-policy.d.ts +13 -30
- package/dist/runtime/api/agent/routing-policy.js +82 -132
- package/dist/runtime/api/agent/routing-policy.test.js +63 -0
- package/dist/runtime/api/api/routers/ai.d.ts +15 -3
- package/dist/runtime/api/api/routers/ai.js +7 -6
- package/dist/runtime/api/api/routers/executions.d.ts +1 -1
- package/dist/runtime/api/api/routers/tasks.d.ts +3 -3
- package/dist/runtime/api/api/routers/workflows.d.ts +8 -0
- package/dist/runtime/api/api/routers/workflows.js +2 -1
- package/dist/runtime/api/api/trpc.d.ts +6 -6
- package/dist/runtime/api/lib/trpc/server.d.ts +27 -7
- package/dist/runtime/api/router.d.ts +27 -7
- package/dist/runtime/api/settings-service.js +49 -1
- package/dist/runtime/api/types/index.d.ts +8 -1
- package/dist/runtime/api/types/settings.d.ts +15 -2
- package/dist/runtime/api/workflows/vibing-orchestrator.js +32 -1
- package/dist/runtime/web/.next/BUILD_ID +1 -1
- package/dist/runtime/web/.next/app-build-manifest.json +18 -11
- package/dist/runtime/web/.next/app-path-routes-manifest.json +2 -1
- package/dist/runtime/web/.next/build-manifest.json +2 -2
- package/dist/runtime/web/.next/prerender-manifest.json +10 -10
- package/dist/runtime/web/.next/routes-manifest.json +8 -0
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js +1 -0
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route.js.nft.json +1 -0
- package/dist/runtime/web/.next/server/app/.vibeman/assets/images/[...path]/route_client-reference-manifest.js +1 -0
- package/dist/runtime/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/_not-found.html +2 -2
- package/dist/runtime/web/.next/server/app/_not-found.rsc +1 -1
- package/dist/runtime/web/.next/server/app/api/health/route_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route.js +1 -1
- package/dist/runtime/web/.next/server/app/api/images/[...path]/route_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/api/upload/route.js +1 -1
- package/dist/runtime/web/.next/server/app/api/upload/route_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app/index.html +2 -2
- package/dist/runtime/web/.next/server/app/index.rsc +2 -2
- package/dist/runtime/web/.next/server/app/page.js +21 -21
- package/dist/runtime/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/dist/runtime/web/.next/server/app-paths-manifest.json +2 -1
- package/dist/runtime/web/.next/server/pages/404.html +2 -2
- package/dist/runtime/web/.next/server/pages/500.html +1 -1
- package/dist/runtime/web/.next/server/server-reference-manifest.json +1 -1
- package/dist/runtime/web/.next/static/5_15u1WQCxN1_eHZpldCv/_buildManifest.js +1 -0
- package/dist/runtime/web/.next/static/chunks/{277-0142a939f08738c3.js → 823-6f371a6e829adbba.js} +1 -1
- package/dist/runtime/web/.next/static/chunks/app/.vibeman/assets/images/[...path]/route-751c9265a65409e5.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/health/route-751c9265a65409e5.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-751c9265a65409e5.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/api/upload/route-751c9265a65409e5.js +1 -0
- package/dist/runtime/web/.next/static/chunks/app/page-9fe7d75095b4ccec.js +1 -0
- package/package.json +1 -1
- package/dist/runtime/api/lib/image-paste-drop-extension.d.ts +0 -26
- package/dist/runtime/api/lib/image-paste-drop-extension.js +0 -125
- package/dist/runtime/api/lib/markdown-utils.d.ts +0 -8
- package/dist/runtime/api/lib/markdown-utils.js +0 -282
- package/dist/runtime/api/lib/markdown-utils.test.js +0 -348
- package/dist/runtime/api/lib/tiptap-utils.clamp-selection.test.d.ts +0 -1
- package/dist/runtime/api/lib/tiptap-utils.clamp-selection.test.js +0 -27
- package/dist/runtime/api/lib/tiptap-utils.d.ts +0 -130
- package/dist/runtime/api/lib/tiptap-utils.js +0 -327
- package/dist/runtime/web/.next/static/chunks/app/api/health/route-105a61ae865ba536.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/images/[...path]/route-105a61ae865ba536.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/api/upload/route-105a61ae865ba536.js +0 -1
- package/dist/runtime/web/.next/static/chunks/app/page-8c3ba579efc6f918.js +0 -1
- package/dist/runtime/web/.next/static/mRpNgPfbYR_0wrODzlg_4/_buildManifest.js +0 -1
- /package/dist/runtime/api/{lib/markdown-utils.test.d.ts → agent/routing-policy.test.d.ts} +0 -0
- /package/dist/runtime/web/.next/static/{mRpNgPfbYR_0wrODzlg_4 → 5_15u1WQCxN1_eHZpldCv}/_ssgManifest.js +0 -0
|
@@ -2,7 +2,7 @@ import { EventEmitter } from 'events';
|
|
|
2
2
|
import { Task, WorktreeInfo, AgentExecution, VibingPhase, QualityResults } from '../types/index.js';
|
|
3
3
|
import { TaskService } from '../tasks/task-service.js';
|
|
4
4
|
import { WorktreeService } from '../vcs/worktree-service.js';
|
|
5
|
-
import { RoutingPolicyManager, type ResolvedProvider } from './routing-policy.js';
|
|
5
|
+
import { RoutingPolicyManager, type RoutableOperation, type ResolvedProvider } from './routing-policy.js';
|
|
6
6
|
export interface AgentExecutionUpdate {
|
|
7
7
|
executionId: string;
|
|
8
8
|
status: AgentExecution['status'];
|
|
@@ -38,11 +38,6 @@ export declare class AgentService extends EventEmitter {
|
|
|
38
38
|
private getAgentConfig;
|
|
39
39
|
private initialize;
|
|
40
40
|
private setupEventForwarding;
|
|
41
|
-
/**
|
|
42
|
-
* Map core agent update to legacy format
|
|
43
|
-
* TODO: remove this later in a separate task, need to migrate the UI to handle raw message streaming
|
|
44
|
-
*/
|
|
45
|
-
private mapToLegacyUpdate;
|
|
46
41
|
/**
|
|
47
42
|
* Create a concise, human-readable line from a structured execution message
|
|
48
43
|
*/
|
|
@@ -62,6 +57,11 @@ export declare class AgentService extends EventEmitter {
|
|
|
62
57
|
qualityResults?: QualityResults;
|
|
63
58
|
lastLogs?: string[];
|
|
64
59
|
attempt?: number;
|
|
60
|
+
aiReview?: {
|
|
61
|
+
summary?: string;
|
|
62
|
+
recommendations?: string[];
|
|
63
|
+
score?: number;
|
|
64
|
+
};
|
|
65
65
|
};
|
|
66
66
|
providerOverride?: Partial<ResolvedProvider>;
|
|
67
67
|
workflowConfig?: import('../types/index.js').VibingConfig;
|
|
@@ -213,6 +213,7 @@ export declare class AgentService extends EventEmitter {
|
|
|
213
213
|
* Resolve provider for specific operation with failover support
|
|
214
214
|
*/
|
|
215
215
|
private resolveProviderForOperation;
|
|
216
|
+
previewProviderForOperation(operation: RoutableOperation, overrides?: Partial<ResolvedProvider>): Promise<ResolvedProvider>;
|
|
216
217
|
/**
|
|
217
218
|
* Execute with provider resolution and failover
|
|
218
219
|
*/
|
|
@@ -40,6 +40,7 @@ export class AgentService extends EventEmitter {
|
|
|
40
40
|
// TODO: need to be more granular, based on the task type and the toolset available for the AI provider
|
|
41
41
|
this.defaultTools = {
|
|
42
42
|
execute_task: fullTools,
|
|
43
|
+
quality_checks: fullTools,
|
|
43
44
|
improve_task: fullTools,
|
|
44
45
|
code_review: fullTools,
|
|
45
46
|
ai_merge: fullTools,
|
|
@@ -154,16 +155,6 @@ export class AgentService extends EventEmitter {
|
|
|
154
155
|
this.promptService = new PromptService(this.projectRoot, this.taskService);
|
|
155
156
|
// Initialize routing policy manager
|
|
156
157
|
this.routingPolicyManager = new RoutingPolicyManager();
|
|
157
|
-
// Create example policy file if needed (guarded for mocked environments)
|
|
158
|
-
try {
|
|
159
|
-
const maybePromise = this.routingPolicyManager.createExamplePolicy?.();
|
|
160
|
-
if (maybePromise && typeof maybePromise.catch === 'function') {
|
|
161
|
-
maybePromise.catch((err) => log.warn('Failed to create example policy', err, 'agent-service'));
|
|
162
|
-
}
|
|
163
|
-
}
|
|
164
|
-
catch (err) {
|
|
165
|
-
log.warn('Failed to trigger example policy creation', err, 'agent-service');
|
|
166
|
-
}
|
|
167
158
|
// Set up event forwarding
|
|
168
159
|
this.setupEventForwarding();
|
|
169
160
|
this.initialized = true;
|
|
@@ -219,23 +210,6 @@ export class AgentService extends EventEmitter {
|
|
|
219
210
|
});
|
|
220
211
|
});
|
|
221
212
|
}
|
|
222
|
-
/**
|
|
223
|
-
* Map core agent update to legacy format
|
|
224
|
-
* TODO: remove this later in a separate task, need to migrate the UI to handle raw message streaming
|
|
225
|
-
*/
|
|
226
|
-
mapToLegacyUpdate(data) {
|
|
227
|
-
const messages = this.coreAgentService
|
|
228
|
-
.getExecutionMessages(data.executionId)
|
|
229
|
-
.map((m) => this.summarizeMessage(m));
|
|
230
|
-
return {
|
|
231
|
-
executionId: data.executionId,
|
|
232
|
-
status: data.status ||
|
|
233
|
-
this.coreAgentService.getExecutionStatus(data.executionId)?.status ||
|
|
234
|
-
'running',
|
|
235
|
-
logs: messages,
|
|
236
|
-
error: data.error,
|
|
237
|
-
};
|
|
238
|
-
}
|
|
239
213
|
/**
|
|
240
214
|
* Create a concise, human-readable line from a structured execution message
|
|
241
215
|
*/
|
|
@@ -404,6 +378,28 @@ export class AgentService extends EventEmitter {
|
|
|
404
378
|
}
|
|
405
379
|
}
|
|
406
380
|
}
|
|
381
|
+
const review = rerun.aiReview;
|
|
382
|
+
if (review) {
|
|
383
|
+
parts.push('AI code review feedback from previous attempt:');
|
|
384
|
+
if (typeof review.score === 'number') {
|
|
385
|
+
parts.push(`- Quality score: ${review.score}`);
|
|
386
|
+
}
|
|
387
|
+
if (review.summary) {
|
|
388
|
+
parts.push(`- Summary: ${review.summary}`);
|
|
389
|
+
}
|
|
390
|
+
const recs = Array.isArray(review.recommendations)
|
|
391
|
+
? review.recommendations.filter((r) => typeof r === 'string' && r.trim().length)
|
|
392
|
+
: [];
|
|
393
|
+
if (recs.length) {
|
|
394
|
+
parts.push('Recommendations:');
|
|
395
|
+
for (const item of recs.slice(0, 5)) {
|
|
396
|
+
parts.push(` * ${item}`);
|
|
397
|
+
}
|
|
398
|
+
if (recs.length > 5) {
|
|
399
|
+
parts.push(` * ...and ${recs.length - 5} more recommendations`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
}
|
|
407
403
|
parts.push('Instruction: Address the reasons above. Avoid repeating prior mistakes. Keep changes scoped and test thoroughly. ');
|
|
408
404
|
return parts.join('\n');
|
|
409
405
|
}
|
|
@@ -801,6 +797,9 @@ export class AgentService extends EventEmitter {
|
|
|
801
797
|
async resolveProviderForOperation(operation, overrides) {
|
|
802
798
|
return await this.routingPolicyManager.resolveProviderForOperation(operation, overrides);
|
|
803
799
|
}
|
|
800
|
+
async previewProviderForOperation(operation, overrides) {
|
|
801
|
+
return await this.resolveProviderForOperation(operation, overrides);
|
|
802
|
+
}
|
|
804
803
|
/**
|
|
805
804
|
* Execute with provider resolution and failover
|
|
806
805
|
*/
|
|
@@ -815,6 +814,16 @@ export class AgentService extends EventEmitter {
|
|
|
815
814
|
workingDirectory: options.workingDirectory,
|
|
816
815
|
timeout: options.timeout,
|
|
817
816
|
};
|
|
817
|
+
// Persist a clear log line indicating chosen provider/model for this operation
|
|
818
|
+
try {
|
|
819
|
+
const execId = options?.executionId;
|
|
820
|
+
if (execId) {
|
|
821
|
+
await this.logPersistence.logMessage(execId, `Using provider: ${resolved.provider}${resolved.model ? ` (model: ${resolved.model})` : ''}`, 'info', { operation, resolved });
|
|
822
|
+
}
|
|
823
|
+
}
|
|
824
|
+
catch {
|
|
825
|
+
// best-effort logging; ignore
|
|
826
|
+
}
|
|
818
827
|
// Default maxTokens from settings when not provided (unlimited if omitted)
|
|
819
828
|
try {
|
|
820
829
|
if (executionOptions.maxTokens === undefined) {
|
|
@@ -15,6 +15,8 @@ export declare class CodexCliProvider implements AIProvider {
|
|
|
15
15
|
readonly displayName = "Codex CLI";
|
|
16
16
|
constructor(config?: CodexCliConfig);
|
|
17
17
|
private resolveExecutable;
|
|
18
|
+
private normalizeReasoningEffort;
|
|
19
|
+
private resolveModelSpec;
|
|
18
20
|
execute(prompt: string, options?: ExecutionOptions): AsyncIterableIterator<ExecutionMessage>;
|
|
19
21
|
executeSync(prompt: string, options?: ExecutionOptions): Promise<{
|
|
20
22
|
id: string;
|
|
@@ -37,26 +37,47 @@ export class CodexCliProvider {
|
|
|
37
37
|
// Default to binary name (resolve via PATH)
|
|
38
38
|
return 'codex';
|
|
39
39
|
}
|
|
40
|
+
normalizeReasoningEffort(value) {
|
|
41
|
+
if (!value)
|
|
42
|
+
return undefined;
|
|
43
|
+
const normalized = value.toLowerCase();
|
|
44
|
+
if (normalized === 'minimal')
|
|
45
|
+
return 'low';
|
|
46
|
+
const allowed = ['low', 'medium', 'high'];
|
|
47
|
+
return allowed.includes(normalized)
|
|
48
|
+
? normalized
|
|
49
|
+
: undefined;
|
|
50
|
+
}
|
|
51
|
+
resolveModelSpec(model, fallbackEffort) {
|
|
52
|
+
const fallback = this.normalizeReasoningEffort(fallbackEffort);
|
|
53
|
+
if (!model) {
|
|
54
|
+
return { reasoning: fallback };
|
|
55
|
+
}
|
|
56
|
+
const trimmed = model.trim();
|
|
57
|
+
const normalized = trimmed.toLowerCase();
|
|
58
|
+
const match = normalized.match(/^(gpt-5(?:-codex)?)(?:-(minimal|low|medium|high))?$/);
|
|
59
|
+
if (!match) {
|
|
60
|
+
return {
|
|
61
|
+
cliModel: trimmed,
|
|
62
|
+
requestedModel: trimmed,
|
|
63
|
+
reasoning: fallback,
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const baseModel = match[1];
|
|
67
|
+
const reasoning = this.normalizeReasoningEffort(match[2]);
|
|
68
|
+
return {
|
|
69
|
+
cliModel: baseModel,
|
|
70
|
+
requestedModel: trimmed,
|
|
71
|
+
reasoning: reasoning ?? fallback,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
40
74
|
async *execute(prompt, options) {
|
|
41
75
|
// Effective options
|
|
42
76
|
const cwd = options?.workingDirectory || this.config.defaultWorkingDirectory || process.cwd();
|
|
43
|
-
const
|
|
44
|
-
|
|
45
|
-
return m;
|
|
46
|
-
// Normalize reasoning-effort variants to the canonical model id
|
|
47
|
-
// Users reported only `gpt-5` is selectable; variants are effort levels in the TUI.
|
|
48
|
-
const lower = m.toLowerCase();
|
|
49
|
-
if (lower === 'gpt-5-minimal' ||
|
|
50
|
-
lower === 'gpt-5-low' ||
|
|
51
|
-
lower === 'gpt-5-medium' ||
|
|
52
|
-
lower === 'gpt-5-high') {
|
|
53
|
-
return 'gpt-5';
|
|
54
|
-
}
|
|
55
|
-
return m;
|
|
56
|
-
};
|
|
57
|
-
const model = mapModel(options?.model || this.config.defaultModel);
|
|
77
|
+
const resolvedModel = this.resolveModelSpec(options?.model || this.config.defaultModel, options?.effort);
|
|
78
|
+
const model = resolvedModel.cliModel;
|
|
58
79
|
const images = (options?.images || []).filter(Boolean);
|
|
59
|
-
const
|
|
80
|
+
const reasoningEffort = resolvedModel.reasoning;
|
|
60
81
|
const timeoutMs = options?.timeout ?? this.config.defaultTimeoutMs ?? 10 * 60 * 1000; // 10m
|
|
61
82
|
const systemPrompt = options?.systemPrompt?.trim();
|
|
62
83
|
const appendSystemPrompt = options?.appendSystemPrompt?.trim();
|
|
@@ -74,6 +95,9 @@ export class CodexCliProvider {
|
|
|
74
95
|
if (model) {
|
|
75
96
|
argv.push('--model', model);
|
|
76
97
|
}
|
|
98
|
+
if (reasoningEffort) {
|
|
99
|
+
argv.push('-c', `model_reasoning_effort=${reasoningEffort}`);
|
|
100
|
+
}
|
|
77
101
|
// Prefer spawning with cwd, but also set --cd to make Codex aware of root
|
|
78
102
|
if (cwd) {
|
|
79
103
|
argv.push('--cd', cwd);
|
|
@@ -95,7 +119,7 @@ export class CodexCliProvider {
|
|
|
95
119
|
type: 'init',
|
|
96
120
|
timestamp: new Date().toISOString(),
|
|
97
121
|
sessionId: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
98
|
-
model: model || 'default',
|
|
122
|
+
model: resolvedModel.requestedModel || model || 'default',
|
|
99
123
|
provider: this.name,
|
|
100
124
|
};
|
|
101
125
|
yield init;
|
|
@@ -108,7 +132,7 @@ export class CodexCliProvider {
|
|
|
108
132
|
metadata: {
|
|
109
133
|
provider: this.name,
|
|
110
134
|
images,
|
|
111
|
-
effort,
|
|
135
|
+
effort: reasoningEffort || options?.effort,
|
|
112
136
|
systemPrompt,
|
|
113
137
|
appendSystemPrompt,
|
|
114
138
|
dangerouslyBypassApprovalsAndSandbox: !!options?.dangerouslyBypassApprovalsAndSandbox,
|
|
@@ -242,6 +266,7 @@ export class CodexCliProvider {
|
|
|
242
266
|
// Convenience: collect from execute()
|
|
243
267
|
let content = '';
|
|
244
268
|
const start = Date.now();
|
|
269
|
+
const resolvedModel = this.resolveModelSpec(options?.model || this.config.defaultModel, options?.effort);
|
|
245
270
|
for await (const msg of this.execute(prompt, options)) {
|
|
246
271
|
if (msg.type === 'assistant' && typeof msg.content === 'string') {
|
|
247
272
|
content += (content ? '\n' : '') + msg.content;
|
|
@@ -250,25 +275,32 @@ export class CodexCliProvider {
|
|
|
250
275
|
return {
|
|
251
276
|
id: `${Date.now()}-${Math.random().toString(36).slice(2, 8)}`,
|
|
252
277
|
provider: this.name,
|
|
253
|
-
model:
|
|
278
|
+
model: resolvedModel.requestedModel || resolvedModel.cliModel || 'default',
|
|
254
279
|
content,
|
|
255
280
|
usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
|
|
256
281
|
duration: Date.now() - start,
|
|
257
282
|
};
|
|
258
283
|
}
|
|
259
284
|
async detectAvailableModels() {
|
|
260
|
-
|
|
285
|
+
const capabilities = ['code', 'analysis', 'tools', 'vision', 'image', 'reasoning'];
|
|
286
|
+
const makeModel = (id, displayName) => ({
|
|
287
|
+
id,
|
|
288
|
+
name: id,
|
|
289
|
+
displayName,
|
|
290
|
+
provider: this.name,
|
|
291
|
+
contextWindow: 256000,
|
|
292
|
+
maxOutputTokens: 16384,
|
|
293
|
+
capabilities,
|
|
294
|
+
});
|
|
261
295
|
return [
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
capabilities: ['code', 'analysis', 'tools', 'vision', 'image', 'reasoning'],
|
|
271
|
-
},
|
|
296
|
+
makeModel('gpt-5', 'gpt‑5'),
|
|
297
|
+
makeModel('gpt-5-low', 'gpt‑5 · low reasoning'),
|
|
298
|
+
makeModel('gpt-5-medium', 'gpt‑5 · medium reasoning'),
|
|
299
|
+
makeModel('gpt-5-high', 'gpt‑5 · high reasoning'),
|
|
300
|
+
makeModel('gpt-5-codex', 'gpt‑5 Codex'),
|
|
301
|
+
makeModel('gpt-5-codex-low', 'gpt‑5 Codex · low reasoning'),
|
|
302
|
+
makeModel('gpt-5-codex-medium', 'gpt‑5 Codex · medium reasoning'),
|
|
303
|
+
makeModel('gpt-5-codex-high', 'gpt‑5 Codex · high reasoning'),
|
|
272
304
|
];
|
|
273
305
|
}
|
|
274
306
|
async validateSetup() {
|
|
@@ -24,10 +24,12 @@ describe('CodexCliProvider (mocked)', () => {
|
|
|
24
24
|
setTimeout(() => proc.emit('exit', 0, null), 20);
|
|
25
25
|
return proc;
|
|
26
26
|
},
|
|
27
|
+
exec: vi.fn(),
|
|
28
|
+
execFile: vi.fn(),
|
|
27
29
|
};
|
|
28
30
|
});
|
|
29
31
|
const { CodexCliProvider } = await import('./ai-providers/codex-cli-provider.js');
|
|
30
|
-
const provider = new CodexCliProvider({ defaultTimeoutMs: 1000 });
|
|
32
|
+
const provider = new CodexCliProvider({ defaultTimeoutMs: 1000, codexBinPath: 'codex' });
|
|
31
33
|
const messages = [];
|
|
32
34
|
const iter = provider.execute('What is this project about?', {
|
|
33
35
|
workingDirectory: process.cwd(),
|
|
@@ -54,6 +56,47 @@ describe('CodexCliProvider (mocked)', () => {
|
|
|
54
56
|
const modelIdx = captured[1].indexOf('--model');
|
|
55
57
|
expect(modelIdx).toBeGreaterThan(-1);
|
|
56
58
|
expect(captured[1][modelIdx + 1]).toBe('gpt-5');
|
|
59
|
+
const configIdx = captured[1].indexOf('-c');
|
|
60
|
+
expect(configIdx).toBeGreaterThan(-1);
|
|
61
|
+
expect(captured[1][configIdx + 1]).toBe('model_reasoning_effort=low');
|
|
62
|
+
});
|
|
63
|
+
it('maps reasoning level encoded in model name to CLI flags', async () => {
|
|
64
|
+
vi.resetModules();
|
|
65
|
+
vi.doMock('child_process', () => {
|
|
66
|
+
let captured = [];
|
|
67
|
+
return {
|
|
68
|
+
__captured: () => captured,
|
|
69
|
+
spawn: (cmd, args, opts) => {
|
|
70
|
+
captured = [cmd, args, opts];
|
|
71
|
+
const { EventEmitter } = require('events');
|
|
72
|
+
const stdout = new EventEmitter();
|
|
73
|
+
const proc = new EventEmitter();
|
|
74
|
+
proc.stdout = stdout;
|
|
75
|
+
setTimeout(() => stdout.emit('data', Buffer.from('Reasoned\n')), 10);
|
|
76
|
+
setTimeout(() => proc.emit('exit', 0, null), 20);
|
|
77
|
+
return proc;
|
|
78
|
+
},
|
|
79
|
+
exec: vi.fn(),
|
|
80
|
+
execFile: vi.fn(),
|
|
81
|
+
};
|
|
82
|
+
});
|
|
83
|
+
const { CodexCliProvider } = await import('./ai-providers/codex-cli-provider.js');
|
|
84
|
+
const provider = new CodexCliProvider({ codexBinPath: 'codex' });
|
|
85
|
+
const messages = [];
|
|
86
|
+
const iter = provider.execute('Solve with depth', {
|
|
87
|
+
workingDirectory: process.cwd(),
|
|
88
|
+
model: 'gpt-5-codex-high',
|
|
89
|
+
});
|
|
90
|
+
for await (const m of iter)
|
|
91
|
+
messages.push(m);
|
|
92
|
+
const mockSpawn = await import('child_process');
|
|
93
|
+
const captured = mockSpawn.__captured();
|
|
94
|
+
const modelIdx = captured[1].indexOf('--model');
|
|
95
|
+
expect(modelIdx).toBeGreaterThan(-1);
|
|
96
|
+
expect(captured[1][modelIdx + 1]).toBe('gpt-5-codex');
|
|
97
|
+
const configIdx = captured[1].indexOf('-c');
|
|
98
|
+
expect(configIdx).toBeGreaterThan(-1);
|
|
99
|
+
expect(captured[1][configIdx + 1]).toBe('model_reasoning_effort=high');
|
|
57
100
|
});
|
|
58
101
|
it('prepends system prompts and toggles sandbox bypass flag', async () => {
|
|
59
102
|
vi.resetModules();
|
|
@@ -71,10 +114,12 @@ describe('CodexCliProvider (mocked)', () => {
|
|
|
71
114
|
setTimeout(() => proc.emit('exit', 0, null), 10);
|
|
72
115
|
return proc;
|
|
73
116
|
},
|
|
117
|
+
exec: vi.fn(),
|
|
118
|
+
execFile: vi.fn(),
|
|
74
119
|
};
|
|
75
120
|
});
|
|
76
121
|
const { CodexCliProvider } = await import('./ai-providers/codex-cli-provider.js');
|
|
77
|
-
const provider = new CodexCliProvider();
|
|
122
|
+
const provider = new CodexCliProvider({ codexBinPath: 'codex' });
|
|
78
123
|
const iter = provider.execute('Implement feature', {
|
|
79
124
|
workingDirectory: '/tmp/project',
|
|
80
125
|
systemPrompt: 'Base system prompt',
|
|
@@ -6,7 +6,8 @@ import { z } from 'zod';
|
|
|
6
6
|
/**
|
|
7
7
|
* Operation types that support AI routing
|
|
8
8
|
*/
|
|
9
|
-
|
|
9
|
+
declare const ROUTABLE_OPERATIONS: readonly ["execute_task", "quality_checks", "ai_codereview", "ai_merge", "improve_task"];
|
|
10
|
+
export type RoutableOperation = (typeof ROUTABLE_OPERATIONS)[number];
|
|
10
11
|
/**
|
|
11
12
|
* Generation options for AI execution
|
|
12
13
|
*/
|
|
@@ -69,7 +70,7 @@ export type OperationConfig = z.infer<typeof OperationConfigSchema>;
|
|
|
69
70
|
*/
|
|
70
71
|
export declare const RoutingPolicySchema: z.ZodObject<{
|
|
71
72
|
defaultProvider: z.ZodString;
|
|
72
|
-
operations: z.ZodOptional<z.ZodRecord<z.ZodEnum<["execute_task", "
|
|
73
|
+
operations: z.ZodOptional<z.ZodRecord<z.ZodEnum<["execute_task", "quality_checks", "ai_codereview", "ai_merge", "improve_task"]>, z.ZodObject<{
|
|
73
74
|
provider: z.ZodString;
|
|
74
75
|
model: z.ZodOptional<z.ZodString>;
|
|
75
76
|
options: z.ZodOptional<z.ZodObject<{
|
|
@@ -107,7 +108,7 @@ export declare const RoutingPolicySchema: z.ZodObject<{
|
|
|
107
108
|
}>>>;
|
|
108
109
|
}, "strip", z.ZodTypeAny, {
|
|
109
110
|
defaultProvider: string;
|
|
110
|
-
operations?: Partial<Record<"execute_task" | "improve_task" | "ai_merge" | "ai_codereview", {
|
|
111
|
+
operations?: Partial<Record<"execute_task" | "quality_checks" | "improve_task" | "ai_merge" | "ai_codereview", {
|
|
111
112
|
provider: string;
|
|
112
113
|
options?: {
|
|
113
114
|
temperature?: number | undefined;
|
|
@@ -119,7 +120,7 @@ export declare const RoutingPolicySchema: z.ZodObject<{
|
|
|
119
120
|
}>> | undefined;
|
|
120
121
|
}, {
|
|
121
122
|
defaultProvider: string;
|
|
122
|
-
operations?: Partial<Record<"execute_task" | "improve_task" | "ai_merge" | "ai_codereview", {
|
|
123
|
+
operations?: Partial<Record<"execute_task" | "quality_checks" | "improve_task" | "ai_merge" | "ai_codereview", {
|
|
123
124
|
provider: string;
|
|
124
125
|
options?: {
|
|
125
126
|
temperature?: number | undefined;
|
|
@@ -131,6 +132,7 @@ export declare const RoutingPolicySchema: z.ZodObject<{
|
|
|
131
132
|
}>> | undefined;
|
|
132
133
|
}>;
|
|
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"];
|
|
134
136
|
/**
|
|
135
137
|
* Resolved provider configuration for execution
|
|
136
138
|
*/
|
|
@@ -142,47 +144,28 @@ export interface ResolvedProvider {
|
|
|
142
144
|
}
|
|
143
145
|
/**
|
|
144
146
|
* Routing Policy Manager
|
|
145
|
-
* Manages AI provider routing policies
|
|
147
|
+
* Manages AI provider routing policies stored inside settings.json
|
|
146
148
|
*/
|
|
147
149
|
export declare class RoutingPolicyManager {
|
|
148
150
|
private policy;
|
|
149
|
-
private
|
|
150
|
-
private lastModified;
|
|
151
|
+
private readonly settingsService;
|
|
151
152
|
constructor();
|
|
152
153
|
/**
|
|
153
|
-
* Get current effective policy
|
|
154
|
+
* Get current effective policy (lazy loads from settings)
|
|
154
155
|
*/
|
|
155
156
|
getPolicy(): Promise<RoutingPolicy>;
|
|
156
157
|
/**
|
|
157
|
-
* Update routing policy and persist
|
|
158
|
+
* Update routing policy and persist via settings service
|
|
158
159
|
*/
|
|
159
160
|
updatePolicy(updates: Partial<RoutingPolicy>): Promise<void>;
|
|
160
161
|
/**
|
|
161
162
|
* Resolve provider for a specific operation
|
|
162
163
|
*/
|
|
164
|
+
getEffectivePolicy(): Promise<RoutingPolicy>;
|
|
163
165
|
resolveProviderForOperation(operation: RoutableOperation, overrides?: Partial<ResolvedProvider>): Promise<ResolvedProvider>;
|
|
164
|
-
/**
|
|
165
|
-
* Set default provider
|
|
166
|
-
*/
|
|
167
166
|
setDefaultProvider(provider: string): Promise<void>;
|
|
168
|
-
/**
|
|
169
|
-
* Set operation-specific routing
|
|
170
|
-
*/
|
|
171
167
|
setOperationConfig(operation: RoutableOperation, config: OperationConfig): Promise<void>;
|
|
172
|
-
/**
|
|
173
|
-
* Validate policy against available providers
|
|
174
|
-
*/
|
|
175
168
|
validatePolicy(policy: RoutingPolicy, availableProviders: Set<string>): string[];
|
|
176
|
-
|
|
177
|
-
* Load policy from file if it has changed
|
|
178
|
-
*/
|
|
179
|
-
private loadPolicyIfChanged;
|
|
180
|
-
/**
|
|
181
|
-
* Create example policy file if it doesn't exist
|
|
182
|
-
*/
|
|
183
|
-
createExamplePolicy(): Promise<void>;
|
|
184
|
-
/**
|
|
185
|
-
* Get policy file path for external access
|
|
186
|
-
*/
|
|
187
|
-
getPolicyFilePath(): string;
|
|
169
|
+
private buildPolicyFromSettings;
|
|
188
170
|
}
|
|
171
|
+
export {};
|