feat: appove and go
This commit is contained in:
@@ -48,6 +48,8 @@ export interface GoalJob {
|
||||
finished_at?: string;
|
||||
local_provider: string;
|
||||
local_model: string;
|
||||
effective_local_provider?: string;
|
||||
effective_local_model?: string;
|
||||
cloud_provider: string;
|
||||
cloud_model: string;
|
||||
stages: GoalStage[];
|
||||
@@ -182,9 +184,20 @@ export class GoalsService {
|
||||
// must not silently change provider/model after a direct OpenAI repair
|
||||
// fails. Gateways can have their own transport and model-specific output
|
||||
// contracts; an operator can explicitly opt in after validating one.
|
||||
const gatewayPatchRepairModels = process.env.CASAN_GOAL_ENABLE_GATEWAY_PATCH_REPAIR === '1' ? gatewayModels : [];
|
||||
const gatewayPatchRepairModels = process.env.CASAN_GOAL_ENABLE_GATEWAY_PATCH_REPAIR === '1' ? gatewayModels.slice(0, 1) : [];
|
||||
const preferredCloudModel = cloudCandidates[0]?.model || '';
|
||||
const preferredCloudProvider = preferredCloudModel.startsWith('openai:') ? 'openai' : preferredCloudModel.startsWith('anthropic:') ? 'anthropic' : (cloud?.id || 'unavailable');
|
||||
// Coding-worker order is based on observed capability, not advertised
|
||||
// discovery: direct cloud credentials first, then a logged-in account
|
||||
// bridge, and only then the small local model. The account remains H3 when
|
||||
// direct cloud is H2, preserving a distinct reviewer channel.
|
||||
const cloudWorker = cloudCandidates[0];
|
||||
const accountWorker = cloudWorker ? '' : account;
|
||||
const accountReviewer = cloudWorker ? account : '';
|
||||
const workerModel = cloudWorker?.model || (accountWorker ? `account:${accountWorker}` : String(localRuntime.CASAN_CHAT_SELECTED_MODEL || `ollama:${localModel}`));
|
||||
const workerProvider = cloudWorker
|
||||
? (workerModel.startsWith('openai:') ? 'openai' : workerModel.startsWith('anthropic:') ? 'anthropic' : 'cloud')
|
||||
: (accountWorker ? `${accountWorker}-account` : (local?.id || 'local-policy'));
|
||||
const cloudModel = preferredCloudModel || gateway?.defaultModel || gateway?.models[0] || '';
|
||||
const id = randomUUID();
|
||||
const timestamp = new Date().toISOString();
|
||||
@@ -199,13 +212,13 @@ export class GoalsService {
|
||||
workspace,
|
||||
created_at: timestamp,
|
||||
updated_at: timestamp,
|
||||
local_provider: local?.id || 'local-policy',
|
||||
local_model: String(localRuntime.CASAN_CHAT_SELECTED_MODEL || `ollama:${localModel}`),
|
||||
cloud_provider: account ? `${account}-account` : (preferredCloudProvider !== 'unavailable' ? preferredCloudProvider : (selectedReviewer?.id || 'unavailable')),
|
||||
cloud_model: account ? `${account}-account-default` : preferredCloudModel || String(cloudRuntime.CASAN_CHAT_SELECTED_MODEL || ''),
|
||||
local_provider: workerProvider,
|
||||
local_model: workerModel,
|
||||
cloud_provider: accountReviewer ? `${accountReviewer}-account` : (preferredCloudProvider !== 'unavailable' ? preferredCloudProvider : (selectedReviewer?.id || 'unavailable')),
|
||||
cloud_model: accountReviewer ? `${accountReviewer}-account-default` : preferredCloudModel || String(cloudRuntime.CASAN_CHAT_SELECTED_MODEL || ''),
|
||||
stages: [
|
||||
{ id: 'local-worker', status: 'queued', detail: 'Waiting for local worker', provider: local?.id || 'local-policy', model: localModel },
|
||||
{ id: 'cloud-reviewer', status: 'queued', detail: account || preferredCloudModel || selectedReviewer ? 'Waiting for independent reviewer' : 'Cloud unavailable; local reviewer will be used', provider: account ? `${account}-account` : (preferredCloudProvider !== 'unavailable' ? preferredCloudProvider : (selectedReviewer?.id || 'local-policy')), model: account ? `${account}-account-default` : cloudModel || localModel },
|
||||
{ id: 'local-worker', status: 'queued', detail: 'Waiting for primary coding worker', provider: workerProvider, model: workerModel },
|
||||
{ id: 'cloud-reviewer', status: 'queued', detail: accountReviewer || preferredCloudModel || selectedReviewer ? 'Waiting for independent reviewer' : 'Cloud unavailable; local reviewer will be used', provider: accountReviewer ? `${accountReviewer}-account` : (preferredCloudProvider !== 'unavailable' ? preferredCloudProvider : (selectedReviewer?.id || 'local-policy')), model: accountReviewer ? `${accountReviewer}-account-default` : cloudModel || localModel },
|
||||
],
|
||||
};
|
||||
const jobFile = this.jobPath(actor.tenant, id);
|
||||
@@ -226,7 +239,7 @@ export class GoalsService {
|
||||
CASAN_GOAL_CLOUD_MODEL: job.cloud_model,
|
||||
CASAN_GOAL_LOCAL_PROVIDER: job.local_provider,
|
||||
CASAN_GOAL_CLOUD_PROVIDER: job.cloud_provider,
|
||||
CASAN_GOAL_ACCOUNT_PROVIDER: account || '',
|
||||
CASAN_GOAL_ACCOUNT_PROVIDER: accountReviewer || '',
|
||||
CASAN_GOAL_CLOUD_FALLBACK_MODEL: String(cloudRuntime.CASAN_CHAT_SELECTED_MODEL || ''),
|
||||
CASAN_GOAL_CLOUD_MODELS: cloudCandidates.map(({ model }) => model).join(','),
|
||||
CASAN_GOAL_OMNIROUTE_MODELS: gatewayModels.join(','),
|
||||
@@ -234,6 +247,8 @@ export class GoalsService {
|
||||
// explicit opt-in because it must not disguise a Codex patch failure.
|
||||
CASAN_GOAL_PATCH_REPAIR_MODELS: [...cloudCandidates.map(({ model }) => model), ...gatewayPatchRepairModels, String(localRuntime.CASAN_CHAT_SELECTED_MODEL || `ollama:${localModel}`)].filter((model, index, rows) => rows.indexOf(model) === index).join(','),
|
||||
CASAN_GOAL_LOCAL_REVIEWER_MODEL: String(localRuntime.CASAN_CHAT_SELECTED_MODEL || `ollama:${localModel}`),
|
||||
CASAN_GOAL_LOCAL_REVIEWER_PROVIDER: local?.id || 'local-policy',
|
||||
CASAN_GOAL_ENABLE_LOCAL_REVIEWER: process.env.CASAN_GOAL_ENABLE_LOCAL_REVIEWER || (account || preferredCloudModel ? '0' : '1'),
|
||||
CASAN_GOAL_REVIEWER_MAX_ATTEMPTS: process.env.CASAN_GOAL_REVIEWER_MAX_ATTEMPTS || '8',
|
||||
CASAN_GOAL_REVIEWER_DEADLINE_SEC: process.env.CASAN_GOAL_REVIEWER_DEADLINE_SEC || '600',
|
||||
},
|
||||
@@ -393,7 +408,8 @@ export class GoalsService {
|
||||
|
||||
apply(id: string, actor: SettingsActor): GoalJob {
|
||||
const job = this.get(id, actor);
|
||||
if (!job.patch_artifact || job.status !== 'requires_approval') {
|
||||
const retryableRollback = job.status === 'failed' && job.error === 'GOAL_APPLY_VERIFICATION_FAILED_ROLLED_BACK';
|
||||
if (!job.patch_artifact || (job.status !== 'requires_approval' && !retryableRollback)) {
|
||||
throw new BadRequestException('GOAL_PATCH_NOT_READY');
|
||||
}
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user