mirror of
https://github.com/stablyai/orca.git
synced 2026-09-22 16:02:32 +00:00
* feat(agents): add Prime Agent as a supported TUI agent with session history Wire Prime Intellect's prime-agent CLI (a Pi fork) into the desktop and mobile agent catalogs following the Trae registration pattern, and into the Agent Session History browser following the OMP pattern: - types.ts, tui-agent-config.ts: register 'prime-agent' with argv prompt injection behind a `--` separator (its own help documents `--` as "treat all following arguments as messages"; without it, prompts starting with `help`/`agents`/`-…` dispatch as subcommands or flags), plus csi-u Shift+Enter encoding matching the Pi TUI it embeds. - agent-kind.ts, telemetry-events.ts, agent-status-types.ts, agent-type-label.ts, tui-agent-display-names.ts, tui-agent-selection.ts, skills-cli-agent-keys.ts: standard per-agent registrations. - agent-headless-command.ts: `-p/--print` one-shot runs share the print-mode matcher with Claude/Trae so they are not mistaken for live interactive panes. - agent-process-recognition: the npm shim launches a generic bundled cli.js, so only the exact package path is an authoritative identity (same as Pi and cursor-agent). The three per-agent regex branches are now one table in agent-node-entrypoint-identities.ts — the module was at its max-lines budget and a table makes the next agent one entry. - AI Vault: sessions are Pi's message-graph JSONL under ~/.prime/agent/sessions (override PRIME_AGENT_CODING_AGENT_DIR — Prime Agent brands Pi's env contract instead of sharing PI_CODING_AGENT_DIR); parsed by the shared message-graph parser with incremental append-resume; discovered locally, in WSL homes, and over remote SSH; resumes by absolute transcript path (`prime-agent --resume <path>`) like OMP, with session-id fallback. - skill-discovery-sources.ts: ~/.prime/agent/skills home source. - Catalog, i18n (en/es/ja/ko/zh), mobile registries, and a bundled 64x64 favicon (required by mobile's offline-icon invariant). Scanner-test fixtures for OMP and Prime Agent move into session-scanner-test-fixtures.ts and the incremental fixture into its own module, keeping every touched file inside its max-lines budget without ratchet bumps. * fix(ai-vault): map custom Prime Agent roots to their sessions child PRIME_AGENT_CODING_AGENT_DIR is consumed verbatim by the CLI as its agent config dir, with transcripts always in <agentDir>/sessions — unlike PI_CODING_AGENT_DIR's <home>/agent/sessions shape the shared normalizer models. A custom root with a non-special basename (or a `.prime` leaf) was therefore scanned as-is instead of its sessions child. Dedicated normalizePrimeAgentSessionsDir appends `sessions` to every configured root, taking only an explicit `.../sessions` path as-is; the shared Pi/OMP normalizer drops the `.prime` widening it no longer needs. Raised in review on #12935. * fix(ai-vault): guard degenerate Prime Agent roots and cover the remote source normalizePrimeAgentSessionsDir stripped a filesystem-root value ('/' or '//') to '', which then joined into the relative root 'sessions' and would walk the main-process cwd. session-scanner-roots.ts already carries this guard for the OMP variant; apply the same fallback here. The remote SSH source had no test: deleting jsonlSource('prime-agent', ...) left the suite green, unlike the local path which is pinned by the AI_VAULT_AGENTS exhaustiveness assertion in session-scanner.test.ts. Add a case that fixes the .prime/agent/sessions root segments, the .jsonl extension, and parser routing. Raised in review on #12935. * fix(ai-vault): honor Prime Agent's sessions-root env and non-interactive modes Verified against upstream PrimeIntellect-ai/prime-agent source rather than inferred from the CLI's help text. config.ts getSessionsDir() reads PRIME_AGENT_SESSION_DIR (and its legacy PRIME_AGENT_CODING_AGENT_SESSION_DIR alias) ahead of the agent dir and uses it verbatim; setting either left the vault silently empty. It also appends `sessions` to the agent dir unconditionally, with no basename escape hatch, so PRIME_AGENT_CODING_AGENT_DIR=/data/sessions writes to /data/sessions/sessions while Orca scanned /data/sessions. getAgentDir() and the session-dir override both run through expandTildePath, so a `~` value set outside a shell resolves. cli/args.ts also spells the non-interactive runs `--mode json|rpc|acp|daemon`, which the shared print-mode matcher does not know, so those panes were counted as live interactive agents and the paste-submit path would write user text into a JSON-RPC/ACP stream. Match upstream exactly: only the space-separated form, since `--mode=json` is not parsed by the CLI and does start the TUI. Raised in review on #12935. * fix(ai-vault): keep Prime Agent roots absolute and remote segments posix Two holes in the previous commit. The degenerate-root guard only rejected pure-separator values, so a relative env value still resolved against the main-process cwd: PRIME_AGENT_CODING_AGENT_DIR='.' scanned '<cwd>/sessions' and, worse, PRIME_AGENT_SESSION_DIR='.' scanned the cwd itself. Require an absolute path in both branches and fall back to the default otherwise. remotePrimeAgentSessionsSegments() built its segments with the local-platform join, so on a Windows client scanning a posix SSH host it produced '\.prime\agent\sessions' and split('/') collapsed it to one bogus segment — remote discovery would have found nothing. Remote roots are posix regardless of client platform, so keep them literal. Pi and OMP are unaffected: their normalizer returns a '.../sessions' input unchanged and never joins. Raised in review on #12935. * test(ai-vault): pin Windows drive roots to the Prime Agent default fallback 'C:\' and 'C:/' strip to the drive-relative 'C:', which isAbsolute rejects on every platform — assert they land in the default fallback so a looser truthiness check can't reintroduce a 'C:sessions' scan root. Raised in review on #12935. * test(ai-vault): pin the drive-relative root form and state what the posix runner can assert --------- Co-authored-by: Brennan Benson <79079362+brennanb2025@users.noreply.github.com>
76 lines
2.5 KiB
TypeScript
76 lines
2.5 KiB
TypeScript
// Mapping from the renderer's `TuiAgent` union (every agent Orca knows how
|
|
// to launch) to the closed `agentKindSchema` enum on telemetry events. Every
|
|
// shipped agent maps to a concrete telemetry value so dashboards can
|
|
// distinguish launch interest instead of collapsing the long tail to `other`.
|
|
//
|
|
// Lives in `src/shared/` (not the renderer) because main-side telemetry
|
|
// emission (`agent_started` from the `pty:spawn` IPC handler) needs the
|
|
// same mapping. Centralizing here means a new TuiAgent member is one edit,
|
|
// not a sweep across renderer + main.
|
|
|
|
import type { AgentKind } from './telemetry-events'
|
|
import type { TuiAgent } from './types'
|
|
|
|
type ConcreteAgentKind = Exclude<AgentKind, 'other'>
|
|
|
|
const TUI_AGENT_KIND_BY_AGENT = {
|
|
claude: 'claude-code',
|
|
'claude-agent-teams': 'claude-agent-teams',
|
|
openclaude: 'openclaude',
|
|
codex: 'codex',
|
|
autohand: 'autohand',
|
|
opencode: 'opencode',
|
|
'mimo-code': 'mimo-code',
|
|
pi: 'pi',
|
|
omp: 'omp',
|
|
'prime-agent': 'prime-agent',
|
|
gemini: 'gemini',
|
|
antigravity: 'antigravity',
|
|
aider: 'aider',
|
|
goose: 'goose',
|
|
amp: 'amp',
|
|
kilo: 'kilo',
|
|
kiro: 'kiro',
|
|
crush: 'crush',
|
|
aug: 'aug',
|
|
cline: 'cline',
|
|
codebuff: 'codebuff',
|
|
'command-code': 'command-code',
|
|
continue: 'continue',
|
|
cursor: 'cursor',
|
|
droid: 'droid',
|
|
kimi: 'kimi',
|
|
'mistral-vibe': 'mistral-vibe',
|
|
'qwen-code': 'qwen-code',
|
|
rovo: 'rovo',
|
|
hermes: 'hermes',
|
|
openclaw: 'openclaw',
|
|
copilot: 'copilot',
|
|
grok: 'grok',
|
|
devin: 'devin',
|
|
ante: 'ante',
|
|
trae: 'trae'
|
|
} satisfies Record<TuiAgent, ConcreteAgentKind>
|
|
|
|
// Why: `satisfies Record<TuiAgent, …>` makes the lookup exhaustive at compile
|
|
// time, but stale persisted settings or unsafe IPC casts can carry a string
|
|
// outside the union at runtime — fall back to `'other'` so the event still
|
|
// emits instead of failing validation and dropping silently.
|
|
export function tuiAgentToAgentKind(agent: TuiAgent): AgentKind {
|
|
return TUI_AGENT_KIND_BY_AGENT[agent] ?? 'other'
|
|
}
|
|
|
|
// Why: the worktree-initial-terminal launch path only carries the telemetry
|
|
// `agent_kind`, not the TuiAgent. Reverse the map so that path can stamp the
|
|
// tab's launch agent without threading TuiAgent through every startup builder.
|
|
const AGENT_BY_TUI_AGENT_KIND: Partial<Record<AgentKind, TuiAgent>> = Object.fromEntries(
|
|
Object.entries(TUI_AGENT_KIND_BY_AGENT).map(([agent, kind]) => [kind, agent as TuiAgent])
|
|
)
|
|
|
|
export function agentKindToTuiAgent(kind: AgentKind | null | undefined): TuiAgent | null {
|
|
if (!kind) {
|
|
return null
|
|
}
|
|
return AGENT_BY_TUI_AGENT_KIND[kind] ?? null
|
|
}
|