feat(native): add OMP settings integration - #89
Conversation
…yml + agent.db) Reads modelRoles/defaultThinkingLevel/approvalMode/enabledModels and provider keys (masked sk-…last4) from the real OMP stores; writes round-trip unknown config.yml keys, upsert auth_credentials, and conflict on stale revisions. config.read/config.write now implemented on official hosts.
…ance)
T4SessionStore: replace settingsWrite(key:value:) with settingsWrite(patch:)
— sends a partial settings object with expectedRevision, gates on
config.write, captures the new revision from the {written, revision}
result, and re-reads so masked providerKeys stay authoritative. Request
config.write at pair time so the pane's writes are authorized.
T4SettingsPane: rewrite into five sections against the live contract.
MODELS: per-role (default/smol/slow/vision/plan/designer/commit/tiny/
task/advisor) model selector dropdown from the catalog; current value
from modelRoles or 'default'. BEHAVIOR: defaultThinkingLevel picker
(off/minimal/low/medium/high/xhigh/max/auto) + tools.approvalMode picker
(always-ask/write/yolo). PROVIDERS & KEYS: masked rows per providerKeys
entry + an add-key sheet (provider + write-only SecureField) saved as a
single-key providerKeys patch (never echoes masked values back).
CONNECTION: endpoint, host info, wss leaf-cert fingerprint row with
Forget (T4CertPinner), disconnect. APPEARANCE: theme picker.
All writes go through settingsWrite(patch:) with revision; the pane
keeps a local optimistic snapshot mirror, applies mutations in place,
and reverts from the store on failure (lastError surfaced).
… effective
boundedSettings rejects bare scalar settings values (they hit the JSON
literal parser), so the authority now emits {type, effective} leaves and the
app store unwraps them back to raw values for the panes.
…nt on controls The pane's insetGrouped List traded row hairlines for labeled cards (bg2, 12pt radius, faint border, padded rows). All pickers/buttons use t.interactiveAccent — the user's system accent on macOS — leaving brand color for meaning (status, roles, attention).
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: ab909d864c
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| const parent = dirname(sessionsRoot); | ||
| return basename(parent) === "agent" ? dirname(parent) : parent; |
There was a problem hiding this comment.
Derive settings paths from the selected OMP profile
In the checked official desktop launch, apps/desktop/src/lifecycle.ts:131 passes a T4-owned session path such as ~/.t4-code/host/official-sessions/default, while apps/desktop/src/local-profiles.ts:157-159 locates OMP profiles under ~/.omp/agent or ~/.omp/profiles/<id>/agent. Deriving the settings root from the unrelated session path therefore reads or creates config.yml and agent/agent.db under T4 host state instead of the selected OMP profile; settings appear empty, provider writes fail against a database without the OMP schema, and config edits never affect OMP. Pass the actual profile directory derived from profileId and the service's home instead.
AGENTS.md reference: AGENTS.md:L5-L5
Useful? React with 👍 / 👎.
| effective: Object.fromEntries( | ||
| Object.entries(keys).map(([provider, masked]) => [provider, { type: "string", effective: masked }]), | ||
| ), |
There was a problem hiding this comment.
Return provider-key leaves in the shape the client consumes
When an official host has provider credentials, this wraps each provider value as {type, effective} inside the outer providerKeys metadata object. The new client unwrapping in T4SessionStore.unwrapSettingsMetadata strips only the outer layer, while T4SettingsPane.providerKeys() accepts only direct string values, so every existing key—and a newly added key after the authoritative re-read—is omitted from the Providers & Keys section. Make the nested effective map contain masked strings directly or recursively unwrap these leaves on the client.
Useful? React with 👍 / 👎.
What changed
Why
The native settings pane previously exposed only a partial host-wire surface, while official OMP settings live across config.yml and agent.db. The client also treated settings metadata as bare values, could round-trip masked provider keys incorrectly, and kept connection failures in a global error slot indefinitely. This change makes the selected official OMP profile authoritative end to end and reconciles native connection state after recovery.
Impact
Verification