feat(local-agent): sync and report ClawPro model configs - #393
Conversation
Handle apply_model_config delivery into CodeBuddy/Claude, then report the local model inventory on POST /api/local-agent/report. --story=1020422209136345350 Fixes #294 Co-authored-by: Cursor <cursoragent@cursor.com>
Treat omitted, empty, or 0 (Go zero value) as the design-doc default so models like kimi-k2.5 are not ack-failed for a missing output cap. --story=1020422209136345350 Co-authored-by: Cursor <cursoragent@cursor.com>
jeff-r2026
left a comment
There was a problem hiding this comment.
Found three P1 issues that reproduce locally against this head with an isolated HOME. Inline comments include the reproduction and impact.
| ...(fullSnapshot ? {} : manifest.providers), | ||
| ...Object.fromEntries(models.map((model) => [model.model_id, model.provider])), | ||
| }; | ||
| await reconcileCodebuddyModels(models, fullSnapshot, manifest); |
There was a problem hiding this comment.
[P1] Apply model configs to the reporting agent before acknowledging success
applyModelConfig never receives context.tool and unconditionally reconciles only CodeBuddy and Claude. I reproduced a sync with tool: 'workbuddy' and a seeded ~/.workbuddy/models.json: that file remained byte-for-byte unchanged, while ~/.codebuddy/models.json and ~/.claude/settings.json were created and the command was acked as success. The backend therefore will not retry even though the reporting WorkBuddy instance cannot discover the candidate; scanModelsFromDisk also returns no inventory for WorkBuddy. Please route persistence/reporting to the actual agent (WorkBuddy uses its own ~/.workbuddy/models.json format), or fail unsupported agents instead of acknowledging an unapplied task.
| } | ||
| Object.assign(env, desired); | ||
| settings.env = env; | ||
| await writeJsonAtomic(settingsPath, settings); |
There was a problem hiding this comment.
[P1] Preserve symlinked user settings files
writeJsonAtomic replaces the destination via rename, and its own contract explicitly says it is not for dotfile paths that may be symlinks. With ~/.claude/settings.json symlinked to a dotfiles-managed file, I reproduced this call replacing the symlink with a regular file while leaving the real target unchanged; the task still receives a success ack. This silently disconnects the user's source-of-truth configuration. The CodeBuddy write at line 2144 has the same issue. Resolve/follow the symlink (or use a symlink-preserving writer) before modifying these user dotfiles.
| const env = { ...(rawEnv as Record<string, unknown>) }; | ||
|
|
||
| if (models.length === 0) { | ||
| for (const [key, hash] of Object.entries(previousHashes)) { |
There was a problem hiding this comment.
[P1] Treat Claude gateway ownership atomically when removing a snapshot
The non-empty path treats any conflicting field as ownership of the whole gateway, but this empty-snapshot path deletes each still-matching field independently. I reproduced: apply a managed model, let the user change only ANTHROPIC_BASE_URL, then deliver {"models":[]}. The code preserves that URL but deletes ANTHROPIC_AUTH_TOKEN, ANTHROPIC_CUSTOM_MODEL_OPTION, and its name, leaving a broken half-gateway and acknowledging success. If any field in the previously managed gateway diverges, preserve the whole gateway (or track a bundle-level ownership hash) rather than stripping the remaining fields.
The backend cannot resolve user-owned models, so user_level.models now includes only entries that still match an apply_model_config delivery. --story=1020422209136345350 Co-authored-by: Cursor <cursoragent@cursor.com>
Report a successfully applied model in the same sync run and use scoped manifest ownership so agent-normalized entries remain reportable. Also route model writes to the reporting agent, preserve symlinked config, and remove Claude gateway settings atomically. --story=1020422209136345350 Co-authored-by: Cursor <cursoragent@cursor.com>
|
修复已推送到 |
Summary
apply_model_configtasks from/api/local-agent/sync, persist the candidate set only into the reporting CodeBuddy or Claude agent, and ack withtype: "apply_model_config". Unsupported agents fail the task; user-owned models and symlinked config files are preserved; credential files are0600; sync responses are redacted.POST /api/local-agent/reportasuser_level.models. Only models recorded in TeamAI's per-agent manifest are reported; user-owned models andapi_keyare never sent. CodeBuddy-added capability metadata no longer suppresses a delivered model.--story=1020422209136345350.Test plan
npx tsc --noEmitnpx vitest run(183 files, 2580 tests; 21 focused model-config cases)npm run buildreport → sync(apply_model_config) → ack(success) → immediate report; Kimi is reported asenterprise, remains reportable after CodeBuddy adds metadata, and ProxyToken is absent from report/ack trafficuser_level.models=[{provider:"tencentcodingplan",model_id:"kimi-k2.5",source:"enterprise"}]accepted with HTTP 200 forlocal_agent_id=0123456789abcdef