Skip to content

feat(models): support OMP as a model agent - #990

Open
daoiqi wants to merge 1 commit into
Tencent:mainfrom
daoiqi:feat/models-omp-agent
Open

daoiqi wants to merge 1 commit into
Tencent:mainfrom
daoiqi:feat/models-omp-agent

Conversation

@daoiqi

@daoiqi daoiqi commented Oct 7, 2026

Copy link
Copy Markdown
Collaborator

What

Adds OMP (Oh My Pi) as a models target, so teamai models switch / restore / pull reach it like any other agent.

OMP is Pi's fork and keeps the same provider catalog, so the switch, restore and ownership paths are shared with Pi — piProvider, piSnapshot, piKeyOf and sameManaged are reused as-is. Only three things differ:

Pi OMP
File ~/.pi/agent/models.json ~/.omp/agent/models.yml (YAML)
Agent-dir override honors PI_CODING_AGENT_DIR not honored — default layout only
Env-backed apiKey $VAR, expanded by Pi !printenv VAR, run by OMP

Notes on the last two:

  • PI_CODING_AGENT_DIR relocates Pi's agent dir, so reading it here would send OMP's catalog into Pi's directory (or the reverse) on a machine that sets it for either tool. This is the position omp-hooks.ts already takes for OMP, and it means OMP's path is constant — no sameAgentSettingsPath case is needed.
  • OMP has no inline $VAR expansion, but it runs a !command apiKey through /bin/sh and uses its output. So an environment-backed key is written as !printenv VAR and stays out of the file, the same guarantee the other agents' forms give. A key stored locally with no environment reference (no variable to reference) is still written as-is. When the variable is unset, OMP fails at startup with a named error rather than sending an empty key.

OMP only reads models.yml; it never rewrites it, so TeamAI owns the bytes and the serialization is ours to choose.

Verification

npm run build, npx tsc --noEmit, npm run lint, npx vitest run (8087 passed), and the e2e suite are green. Real-CLI run against the built dist, in a scratch HOME, with the actual omp 18.6.1 binary consuming the file TeamAI wrote:

$ teamai models add tokenhub --name 'Tencent TokenHub' \
    --protocol anthropic,openai-chat-completions \
    --base-url https://api.model.haihub.cn --model deepseek-flash --from-env TEAMAI_E2E_KEY
✔ Added local model profile local:tokenhub.

$ teamai models switch local:tokenhub --agent omp
switched      omp switched to local:tokenhub

$ cat ~/.omp/agent/models.yml
providers:
  local:tokenhub:
    name: Tencent TokenHub
    baseUrl: https://api.model.haihub.cn/v1
    apiKey: "!printenv TEAMAI_E2E_KEY"
    api: openai-completions
    models:
      - id: deepseek-flash

$ omp -p "reply with the single word: ok" --model deepseek-flash
ok

$ omp models
local:tokenhub (1)
│ deepseek-flash │      1M │    384K │ low,high,max │ yes │

$ teamai models restore --agent omp
restored      omp model settings restored

restore returns the file to its prior bytes, including a member's own providers alongside TeamAI's. Also checked by hand: --dry-run writes nothing; an unparseable models.yml fails closed and is left untouched; a provider already owned by the member under the same key is refused rather than overwritten.

Docs

Bilingual, kept in sync: docs/designs/model-profiles.{md,zh-CN.md} (agent-writes table, key-reference sentence, path-pinning sentence), docs/product-overview.{md,zh-CN.md}, docs/usage-guide.{md,zh-CN.md}, and the Oh My Pi models column in all five READMEs.

Note for reviewers

writePi / piDoc gained an agent: 'pi' | 'omp' parameter, so Pi's call sites are touched even though their behavior is unchanged — Pi's four e2e tests and the full unit suite cover it. The rationale for keying on the agent rather than on a file-format capability object: the agent is one fact that determines both path and serialization, so the two cannot be mismatched.

OMP is Pi's fork and keeps the same provider catalog, so the switch,
restore and ownership paths are shared with it; only three things differ.

- The file is ~/.omp/agent/models.yml, in YAML rather than JSON. OMP only
  ever reads it, so TeamAI owns the bytes.
- PI_CODING_AGENT_DIR is not honored. It relocates Pi's agent dir, so
  reading it here would send OMP's catalog into Pi's directory on a
  machine that sets it for Pi. The default layout only, the position
  omp-hooks.ts already takes for OMP.
- apiKey has no inline expansion. An environment-backed key is written as
  `!printenv VAR`: OMP runs a `!command` value through /bin/sh and uses
  its output, so the key stays out of the file. A key stored locally with
  no environment reference is still written as-is.
@jeff-r2026 jeff-r2026 self-assigned this Oct 7, 2026
@github-actions

github-actions Bot commented Oct 7, 2026

Copy link
Copy Markdown

Findings

  • [P1 blocking] src/models/switch.ts:1089 skips collision detection whenever OMP already has managed state. If a member owns local:b, then switches OMP to local:a and later local:b, writePi overwrites their provider; restore subsequently deletes it because only local:a’s original snapshot was captured. Check collisions for a newly targeted key even during re-switches.
  • [P2 non-blocking] src/models/switch.ts:292 parses and re-stringifies the entire user-owned YAML document. The first switch permanently removes comments and original formatting, and restore cannot return the file to its prior bytes as claimed. Preserve the YAML document structure/comments or retain sufficient original content.
  • [P2 non-blocking] docs/designs/model-profiles.md:82, its Chinese counterpart, both usage guides, and skill-data/core/SKILL.md:198 still say only Codex/OpenCode/CodeBuddy/WorkBuddy lose alias models when switched. OMP now follows that path too; update all affected bilingual docs and the deployed skill as required by AGENTS.md.

Testing

  • The PR description documents sufficient testing, including a representative real-CLI run with OMP.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants