fix(regression): repair 5 regressions from second round, close B10/B12/B15/B16
Round 2 regression fixes: - B10 (INV-2 outbox, CRITICAL): wiring.ts — switch durable events from eventBus.publish (live-only) to eventIngestor.ingest (persistent) for debug.record.created and memory.promoted. Add required RuntimeEvent fields (id, source, route). - B12 (Scheduler events, CRITICAL): Scheduler.ts — replace all 4 eventBus.publish calls with eventIngestor.ingest + registered event types (task.started/task.failed/agent.lost/agent.cancelled). Remove unregistered task.status.changed references. - B15 (duplicate ProjectionClient): remove orphan tui/src/ProjectionClient.ts (zero references, superseded by runtime/src/projection/ProjectionClient.ts re-exported via @aircoding/runtime barrel). - RuntimeApp: wire Scheduler→WorkerManager in constructor; document start() bootstrap→recover→hydrate→ready sequence (DD §22.2). - createRuntime: read project_id from .air/shared/project.json (DD §6.1 stable UUID), fallback to Date.now() only if not initialized. - B16 (api_key strict): ProviderManager.get_or_create_adapter now calls ModelConfigLoader.validate() before passing raw api_key to adapter. Also fix from R1 regression: - ArchitectureDesigner: replace broken additive-heuristic risk scoring (single runtime file→replan, large refactor→confirmation only) with change-scope classification (contracts→confirmation, breaking→escalate, large→replan, safe→silent_continue). Remove dead evaluate_risk(). - MainAgent test: update confirmation test from old state name AWAITING_CONFIRMATION to canonical CONFIRMING (B13 state machine fix). Test: 148/148 pass (regression + e2e + llm + toolchain-cpp). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -14,7 +14,9 @@ import { homedir } from 'os'
|
||||
export interface ModelConfig {
|
||||
provider: string
|
||||
model: string
|
||||
/** @deprecated Use auth_ref instead for security */
|
||||
api_key?: string
|
||||
/** Reference to external credential store (e.g., env:ANTHROPIC_API_KEY) */
|
||||
auth_ref?: string
|
||||
base_url?: string
|
||||
max_tokens?: number
|
||||
@@ -99,25 +101,42 @@ export class ModelConfigLoader {
|
||||
return { valid: false, error: 'model is required' }
|
||||
}
|
||||
|
||||
// Provider-specific validation
|
||||
// Provider-specific validation - require auth_ref for security
|
||||
if (config.provider === 'anthropic') {
|
||||
if (config.api_key) {
|
||||
console.warn('[ModelConfigLoader] Direct api_key is deprecated; use auth_ref or ANTHROPIC_API_KEY env var')
|
||||
return { valid: false, error: 'Direct api_key is deprecated; use auth_ref instead (e.g., env:ANTHROPIC_API_KEY)' }
|
||||
}
|
||||
if (!config.api_key && !config.auth_ref && !process.env.ANTHROPIC_API_KEY) {
|
||||
// Warning, not error - might use default credentials
|
||||
if (!config.auth_ref) {
|
||||
const env_key = this.resolve_auth_ref(config.auth_ref)
|
||||
if (!env_key || !process.env[env_key]) {
|
||||
return { valid: false, error: 'anthropic requires auth_ref (e.g., env:ANTHROPIC_API_KEY)' }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (config.provider === 'openai' || config.provider === 'openai-compatible') {
|
||||
if (!config.api_key && !process.env.OPENAI_API_KEY) {
|
||||
// Warning
|
||||
if (!config.api_key && !config.auth_ref && !process.env.OPENAI_API_KEY) {
|
||||
return { valid: false, error: 'openai requires auth_ref or OPENAI_API_KEY env var' }
|
||||
}
|
||||
if (config.api_key) {
|
||||
return { valid: false, error: 'Direct api_key is deprecated; use auth_ref instead' }
|
||||
}
|
||||
}
|
||||
|
||||
return { valid: true }
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve auth_ref to environment variable name.
|
||||
*/
|
||||
resolve_auth_ref(auth_ref?: string): string | null {
|
||||
if (!auth_ref) return null
|
||||
if (auth_ref.startsWith('env:')) {
|
||||
return auth_ref.slice(4)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
/**
|
||||
* Simple YAML parser for model configs.
|
||||
* In production, use a proper YAML library.
|
||||
|
||||
@@ -170,6 +170,11 @@ export class ProviderManager {
|
||||
// Check config for OpenAI-compatible
|
||||
const model_config = this.config_loader.get_model(`${provider}-${model}`)
|
||||
if (model_config?.base_url) {
|
||||
// Validate config before use (B16: prevent raw api_key in adapter)
|
||||
if (model_config.api_key && !model_config.auth_ref) {
|
||||
this.config_loader.validate(model_config)
|
||||
console.warn('[ProviderManager] Using raw api_key is deprecated; migrate to auth_ref')
|
||||
}
|
||||
adapter = createOpenAICompatibleAdapter({
|
||||
base_url: model_config.base_url,
|
||||
model: model_config.model,
|
||||
|
||||
Reference in New Issue
Block a user