mirror of
https://github.com/stablyai/orca.git
synced 2026-10-04 08:02:09 +00:00
* feat(source-control-ai): support OMP text generation Read prompts on stdin, retain OMP configured model by default, and reuse JSON model discovery. Co-authored-by: unknown <1784931579@qq.com> * test(source-control-ai): cover OMP large input and model overrides * fix(omp): keep configured model default out of discovered catalog * fix(omp): hide config default from model discovery catalog * fix(omp): separate terminal discovery from generation defaults * test(omp): keep model probe import compatible with CLI typecheck * test: align Source Control AI registry contracts with OMP --------- Co-authored-by: unknown <1784931579@qq.com>
67 lines
2.4 KiB
TypeScript
67 lines
2.4 KiB
TypeScript
import type { CommitMessageModel } from './commit-message-agent-spec'
|
|
import { labelFromModelId } from './model-id-label'
|
|
|
|
// Why: `omp models --json` is the one machine-readable listing OMP offers; the
|
|
// default table output groups rows per provider and would need a brittle parser.
|
|
export const OMP_MODEL_LIST_ARGS = ['models', '--json']
|
|
|
|
/** The outermost JSON value on stdout, or null when none parses. */
|
|
function parseJsonObject(stdout: string): unknown {
|
|
const trimmed = stdout.trim()
|
|
try {
|
|
return JSON.parse(trimmed)
|
|
} catch {
|
|
// Why: an update notice or extension warning can precede the JSON on stdout;
|
|
// the listing itself is the outermost object.
|
|
const start = trimmed.indexOf('{')
|
|
const end = trimmed.lastIndexOf('}')
|
|
if (start === -1 || end <= start) {
|
|
return null
|
|
}
|
|
try {
|
|
return JSON.parse(trimmed.slice(start, end + 1))
|
|
} catch {
|
|
return null
|
|
}
|
|
}
|
|
}
|
|
|
|
/** Parses `omp models --json`. Ids are OMP's `provider/model` selector — the form
|
|
* `--model` and `/model` resolve exactly, unlike a bare model id that several
|
|
* providers can share. */
|
|
export function parseOmpModelList(stdout: string): CommitMessageModel[] {
|
|
const parsed = parseJsonObject(stdout)
|
|
if (!parsed || typeof parsed !== 'object' || !('models' in parsed)) {
|
|
return []
|
|
}
|
|
const rows: unknown = parsed.models
|
|
if (!Array.isArray(rows)) {
|
|
return []
|
|
}
|
|
const byId = new Map<string, CommitMessageModel>()
|
|
for (const row of rows) {
|
|
const value: unknown = row
|
|
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
continue
|
|
}
|
|
const provider =
|
|
'provider' in value && typeof value.provider === 'string' ? value.provider.trim() : ''
|
|
const bareId = 'id' in value && typeof value.id === 'string' ? value.id.trim() : ''
|
|
const selector =
|
|
'selector' in value && typeof value.selector === 'string' ? value.selector.trim() : ''
|
|
const id = selector || (provider && bareId ? `${provider}/${bareId}` : '')
|
|
if (!id || byId.has(id)) {
|
|
continue
|
|
}
|
|
const name = 'name' in value && typeof value.name === 'string' ? value.name.trim() : ''
|
|
byId.set(id, {
|
|
id,
|
|
label: name || labelFromModelId(id),
|
|
// Why: the same model name ships under several providers; the provider is
|
|
// what tells two "DeepSeek V4 Pro" rows apart in the picker.
|
|
...(provider ? { description: provider } : {})
|
|
})
|
|
}
|
|
return [...byId.values()]
|
|
}
|