@aiwg/cli 2026.9.1 → 2026.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/agentic/code/providers/antigravity/provider-contract.v1.json +121 -0
- package/agentic/code/providers/capability-matrix.yaml +88 -2
- package/agentic/code/providers/model-capabilities.v1.json +42 -0
- package/agentic/code/providers/model-catalog.v1.json +37 -0
- package/agentic/code/providers/omp/README.md +58 -0
- package/agentic/code/providers/omp/aiwg-bridge.ts +52 -0
- package/agentic/code/providers/pi/aiwg-bridge.ts +26 -0
- package/dist/src/agents/agent-deployer.js +18 -0
- package/dist/src/agents/agent-packager.js +25 -0
- package/dist/src/artifacts/backends/sqlite-backend.js +18 -10
- package/dist/src/artifacts/query-engine.js +30 -0
- package/dist/src/auth/credential-store.js +6 -0
- package/dist/src/cli/agent-spawn.js +13 -2
- package/dist/src/cli/handlers/help.js +3 -1
- package/dist/src/cli/handlers/init.js +2 -0
- package/dist/src/cli/handlers/models.js +1 -1
- package/dist/src/cli/handlers/runtime-info.js +8 -1
- package/dist/src/cli/handlers/session.js +5 -4
- package/dist/src/cli/handlers/sessions.js +54 -19
- package/dist/src/cli/handlers/setup.js +9 -2
- package/dist/src/cli/handlers/steward.js +13 -2
- package/dist/src/cli/handlers/subcommands.js +11 -0
- package/dist/src/cli/handlers/team.js +68 -7
- package/dist/src/cli/handlers/use.js +121 -9
- package/dist/src/cli/scope-resolver.js +7 -0
- package/dist/src/config/aiwg-config.js +1 -0
- package/dist/src/dataset/fortemi-live-qualification.d.ts +53 -0
- package/dist/src/dataset/fortemi-live-qualification.js +297 -0
- package/dist/src/dataset/index.d.ts +1 -0
- package/dist/src/dataset/index.js +1 -0
- package/dist/src/mcp/cli.mjs +30 -1
- package/dist/src/mcp/omp-config.mjs +128 -0
- package/dist/src/mcp/registry.js +45 -5
- package/dist/src/mcp/registry.mjs +29 -6
- package/dist/src/models/model-capabilities.v1.json +42 -0
- package/dist/src/models/model-catalog.v1.json +37 -0
- package/dist/src/models/model-discovery.js +78 -5
- package/dist/src/models/provider-policy.js +6 -3
- package/dist/src/plugin/skill-command-translator.js +2 -0
- package/dist/src/providers/capability-matrix.yaml +88 -2
- package/dist/src/providers/omp-agent.mjs +40 -0
- package/dist/src/providers/omp-diagnostics.mjs +15 -0
- package/dist/src/providers/omp-paths.mjs +38 -0
- package/dist/src/providers/provider-definitions.js +83 -0
- package/dist/src/providers/provider-definitions.mjs +25 -1
- package/dist/src/providers/provider-inventory.js +2 -0
- package/dist/src/sessions/adapters/omp.js +203 -0
- package/dist/src/sessions/adapters/pi.js +141 -0
- package/dist/src/sessions/batch-import.js +7 -0
- package/dist/src/sessions/contracts.js +1 -1
- package/dist/src/sessions/importer.js +4 -3
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/readers.js +4 -3
- package/dist/src/sessions/workspace-discovery.js +22 -2
- package/dist/src/skills/deployer.js +21 -1
- package/dist/src/smiths/agentsmith/generator.js +1 -0
- package/dist/src/smiths/context-pipeline/parallelism-section.js +2 -0
- package/dist/src/smiths/context-pipeline/provider-policy.js +2 -2
- package/dist/src/smiths/context-pipeline/workspace-context.js +2 -2
- package/dist/src/storage/backends/fortemi.js +142 -17
- package/dist/src/storage/fortemi-qualification-receipt.js +206 -0
- package/dist/src/storage/fortemi-qualification.js +67 -6
- package/dist/src/storage/index.js +1 -0
- package/package.json +2 -1
- package/schemas/dataset/fortemi-live-qualification-receipt.v1.schema.json +132 -0
- package/tools/agents/deploy-agents.mjs +6 -3
- package/tools/agents/providers/antigravity.mjs +147 -0
- package/tools/agents/providers/omp.d.mts +4 -0
- package/tools/agents/providers/omp.mjs +256 -0
- package/tools/agents/providers/pi.mjs +13 -1
- package/tools/providers/antigravity-transport.mjs +124 -0
|
@@ -26,8 +26,8 @@ function requireModelResource(filename) {
|
|
|
26
26
|
const capabilityData = requireModelResource('model-capabilities.v1.json');
|
|
27
27
|
const catalogData = requireModelResource('model-catalog.v1.json');
|
|
28
28
|
const ProviderSchema = z.enum([
|
|
29
|
-
'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
|
|
30
|
-
'opencode', 'openclaw', 'openhuman', 'warp', 'windsurf',
|
|
29
|
+
'antigravity', 'claude', 'codex', 'copilot', 'cursor', 'factory', 'hermes',
|
|
30
|
+
'opencode', 'openclaw', 'openhuman', 'omp', 'pi', 'warp', 'windsurf',
|
|
31
31
|
]);
|
|
32
32
|
const OutcomeSchema = z.enum([
|
|
33
33
|
'native', 'compiled', 'inherited', 'global-only', 'informational', 'unsupported',
|
|
@@ -107,7 +107,7 @@ export function loadProviderModelCapabilities() {
|
|
|
107
107
|
const expected = new Set(ProviderSchema.options);
|
|
108
108
|
const actual = new Set(Object.keys(registryCache.providers));
|
|
109
109
|
if (actual.size !== expected.size || [...expected].some(id => !actual.has(id))) {
|
|
110
|
-
throw new Error('Provider model capability registry must cover all
|
|
110
|
+
throw new Error('Provider model capability registry must cover all registered providers');
|
|
111
111
|
}
|
|
112
112
|
}
|
|
113
113
|
return registryCache;
|
|
@@ -153,12 +153,15 @@ function catalogRole(policy) {
|
|
|
153
153
|
}
|
|
154
154
|
function fieldNames(provider) {
|
|
155
155
|
switch (provider) {
|
|
156
|
+
case 'antigravity': return { model: 'model', effort: 'effort' };
|
|
156
157
|
case 'codex': return { model: 'model', effort: 'model_reasoning_effort' };
|
|
157
158
|
case 'factory': return { model: 'model', effort: 'reasoningEffort' };
|
|
158
159
|
case 'claude': return { model: 'model', effort: 'effort' };
|
|
159
160
|
case 'copilot':
|
|
160
161
|
case 'cursor':
|
|
161
162
|
case 'opencode': return { model: 'model' };
|
|
163
|
+
case 'omp': return { model: 'model', effort: 'thinkingLevel' };
|
|
164
|
+
case 'pi': return { model: 'model', effort: 'thinking' };
|
|
162
165
|
case 'openhuman': return { model: 'model_hint' };
|
|
163
166
|
case 'openclaw': return { model: 'subagents.model' };
|
|
164
167
|
default: return {};
|
|
@@ -34,11 +34,13 @@ const PROVIDERS_NEEDING_COMMANDS = new Set([
|
|
|
34
34
|
* Providers where skills are deployed natively (no command generation needed).
|
|
35
35
|
*/
|
|
36
36
|
const SKILLS_ONLY_PROVIDERS = new Set([
|
|
37
|
+
'antigravity',
|
|
37
38
|
'claude',
|
|
38
39
|
'cursor',
|
|
39
40
|
'hermes',
|
|
40
41
|
'openhuman',
|
|
41
42
|
'pi',
|
|
43
|
+
'omp',
|
|
42
44
|
]);
|
|
43
45
|
/**
|
|
44
46
|
* Check if a provider needs command files generated from skills.
|
|
@@ -361,7 +361,7 @@ providers:
|
|
|
361
361
|
|
|
362
362
|
hermes:
|
|
363
363
|
display_name: Hermes
|
|
364
|
-
status:
|
|
364
|
+
status: stable
|
|
365
365
|
daemon_tier: unsupported
|
|
366
366
|
daemon_pty_adapter: false
|
|
367
367
|
artifact_paths:
|
|
@@ -470,6 +470,51 @@ providers:
|
|
|
470
470
|
deploy_target: mixed
|
|
471
471
|
aggregated_output: true
|
|
472
472
|
|
|
473
|
+
antigravity:
|
|
474
|
+
display_name: Google Antigravity CLI
|
|
475
|
+
aliases:
|
|
476
|
+
- agy
|
|
477
|
+
status: experimental
|
|
478
|
+
executable: agy
|
|
479
|
+
qualified_version: 1.1.26
|
|
480
|
+
qualification_evidence: agentic/code/providers/antigravity/provider-contract.v1.json
|
|
481
|
+
daemon_tier: unsupported
|
|
482
|
+
daemon_pty_adapter: false
|
|
483
|
+
artifact_paths:
|
|
484
|
+
agents: .agents/agents/
|
|
485
|
+
commands: "(not deployed; no qualified native command surface)"
|
|
486
|
+
skills: .agents/skills/
|
|
487
|
+
rules: AGENTS.md
|
|
488
|
+
behaviors: "(not supported)"
|
|
489
|
+
mcp_project: .agents/mcp_config.json
|
|
490
|
+
mcp_user: "~/.gemini/config/mcp_config.json"
|
|
491
|
+
native_features:
|
|
492
|
+
cron: false
|
|
493
|
+
agent_teams: false
|
|
494
|
+
tasks: false
|
|
495
|
+
mcp: true
|
|
496
|
+
behaviors: false
|
|
497
|
+
mission_control: false
|
|
498
|
+
daemon: false
|
|
499
|
+
emulation:
|
|
500
|
+
cron: external-trigger
|
|
501
|
+
agent_teams: aiwg-mc
|
|
502
|
+
tasks: aiwg-mc
|
|
503
|
+
mcp: native
|
|
504
|
+
behaviors: null
|
|
505
|
+
mission_control: aiwg-mc
|
|
506
|
+
daemon: null
|
|
507
|
+
hook_wiring:
|
|
508
|
+
at_link_support: false
|
|
509
|
+
fallback: full-inject
|
|
510
|
+
context_file: AGENTS.md
|
|
511
|
+
interaction:
|
|
512
|
+
structured_questions: none
|
|
513
|
+
fallback: markdown
|
|
514
|
+
notes: No stable structured-question tool contract was qualified for CLI 1.1.26.
|
|
515
|
+
deploy_target: project
|
|
516
|
+
aggregated_output: false
|
|
517
|
+
|
|
473
518
|
pi:
|
|
474
519
|
display_name: Pi Coding Agent
|
|
475
520
|
aliases:
|
|
@@ -489,7 +534,7 @@ providers:
|
|
|
489
534
|
agent_teams: false
|
|
490
535
|
tasks: false
|
|
491
536
|
mcp: false
|
|
492
|
-
behaviors:
|
|
537
|
+
behaviors: true
|
|
493
538
|
mission_control: false
|
|
494
539
|
daemon: false
|
|
495
540
|
emulation:
|
|
@@ -511,6 +556,47 @@ providers:
|
|
|
511
556
|
deploy_target: project
|
|
512
557
|
aggregated_output: false
|
|
513
558
|
|
|
559
|
+
omp:
|
|
560
|
+
display_name: Oh My Pi
|
|
561
|
+
aliases:
|
|
562
|
+
- oh-my-pi
|
|
563
|
+
status: experimental
|
|
564
|
+
daemon_tier: unsupported
|
|
565
|
+
daemon_pty_adapter: false
|
|
566
|
+
artifact_paths:
|
|
567
|
+
agents: .omp/agents/
|
|
568
|
+
commands: .omp/prompts/
|
|
569
|
+
skills: .agents/skills/
|
|
570
|
+
skills_cross_agent: .agents/skills/
|
|
571
|
+
rules: .omp/rules/
|
|
572
|
+
behaviors: .omp/extensions/
|
|
573
|
+
native_features:
|
|
574
|
+
cron: false
|
|
575
|
+
agent_teams: true
|
|
576
|
+
tasks: true
|
|
577
|
+
mcp: true
|
|
578
|
+
behaviors: true
|
|
579
|
+
mission_control: false
|
|
580
|
+
daemon: false
|
|
581
|
+
emulation:
|
|
582
|
+
cron: external-trigger
|
|
583
|
+
agent_teams: null
|
|
584
|
+
tasks: null
|
|
585
|
+
mcp: null
|
|
586
|
+
behaviors: null
|
|
587
|
+
mission_control: aiwg-mc
|
|
588
|
+
daemon: null
|
|
589
|
+
hook_wiring:
|
|
590
|
+
at_link_support: true
|
|
591
|
+
fallback: full-inject
|
|
592
|
+
context_file: .omp/AGENTS.md
|
|
593
|
+
interaction:
|
|
594
|
+
structured_questions: none
|
|
595
|
+
fallback: markdown
|
|
596
|
+
notes: OMP integration uses Markdown questions; native UI questions require an interactive runtime.
|
|
597
|
+
deploy_target: project
|
|
598
|
+
aggregated_output: false
|
|
599
|
+
|
|
514
600
|
# Feature definitions — documents what each feature key means and
|
|
515
601
|
# what emulation strategies are available when native support is absent.
|
|
516
602
|
features:
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import path from 'node:path';
|
|
2
|
+
import YAML from 'yaml';
|
|
3
|
+
function parse(content) {
|
|
4
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---\r?\n([\s\S]*)$/);
|
|
5
|
+
return match ? { metadata: YAML.parse(match[1]) || {}, body: match[2] } : { metadata: {}, body: content };
|
|
6
|
+
}
|
|
7
|
+
const render = (metadata, body) => `---\n${YAML.stringify(metadata)}---\n\n${body.trim()}\n`;
|
|
8
|
+
function diagnostic(opts, message) { opts.diagnostics?.push(message); if (!opts.quiet) console.warn(`OMP: ${message}`); }
|
|
9
|
+
export function mapModel(model, config = {}) {
|
|
10
|
+
if (!model || model === 'inherit') return undefined;
|
|
11
|
+
const mapped = config.omp?.[model]?.model || config.omp?.[model];
|
|
12
|
+
if (typeof mapped === 'string') return mapped;
|
|
13
|
+
if (['opus', 'sonnet', 'haiku', 'reasoning', 'coding', 'efficiency', 'heavy', 'medium', 'light'].includes(model)) return undefined;
|
|
14
|
+
return model;
|
|
15
|
+
}
|
|
16
|
+
const toolMap = { Read: 'read', Write: 'write', Edit: 'edit', MultiEdit: 'edit', Bash: 'bash', Grep: 'grep', Glob: 'glob', WebSearch: 'web_search', Task: 'task', TodoWrite: 'todo' };
|
|
17
|
+
const nativeTools = new Set(['read','security_scan','bash','edit','ast_grep','ast_edit','ask','debug','eval','github','glob','grep','lsp','checkpoint','rewind','task','hub','todo','web_search','write','memory_edit','retain','recall','reflect','learn','manage_skill','think','yield','goal']);
|
|
18
|
+
const array = value => Array.isArray(value) ? value : typeof value === 'string' ? value.split(',').map(s => s.trim()).filter(Boolean) : [];
|
|
19
|
+
export function transformAgent(src, content, opts = {}) {
|
|
20
|
+
const { metadata: m, body } = parse(content);
|
|
21
|
+
const agentName = m.name ?? path.basename(src, '.md');
|
|
22
|
+
if (typeof agentName !== 'string' || !agentName.trim()) throw new Error('OMP agent name must be a nonempty string');
|
|
23
|
+
const out = { name: agentName.trim(), description: String(m.description || `AIWG ${path.basename(src, '.md')} agent`) };
|
|
24
|
+
if (['main','sub'].includes(out.name.toLowerCase())) throw new Error(`OMP reserves agent name ${out.name}`);
|
|
25
|
+
const tools = array(m.tools).flatMap(tool => {
|
|
26
|
+
const mapped = toolMap[tool] || (nativeTools.has(tool) ? tool : undefined);
|
|
27
|
+
if (!mapped) diagnostic(opts, `${out.name}: unsupported tool ${tool}; omitted (degraded)`);
|
|
28
|
+
return mapped ? [mapped] : [];
|
|
29
|
+
});
|
|
30
|
+
// OMP treats empty spawns as undefined; remove task unless explicit delegation is configured.
|
|
31
|
+
out.spawns = m.spawns === '*' ? '*' : array(m.spawns);
|
|
32
|
+
out.tools = [...new Set(tools)].filter(tool => tool !== 'task' || out.spawns === '*' || out.spawns.length > 0);
|
|
33
|
+
if (m.model) {
|
|
34
|
+
const models = array(m.model).flatMap(model => { const mapped = mapModel(model, opts.modelsConfig || opts.modelConfig || {}); if (!mapped && model !== 'inherit') diagnostic(opts, `${out.name}: unmapped model role ${model}; inherits session model (degraded)`); return mapped ? [mapped] : []; });
|
|
35
|
+
if (models.length) out.model = models.length === 1 ? models[0] : models;
|
|
36
|
+
}
|
|
37
|
+
for (const key of ['thinkingLevel', 'blocking', 'output', 'autoloadSkills', 'readSummarize', 'prewalk', 'advisor']) if (m[key] !== undefined) out[key] = m[key];
|
|
38
|
+
if (!out.thinkingLevel && m.thinking) out.thinkingLevel = m.thinking;
|
|
39
|
+
return render(out, body);
|
|
40
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { execFile } from 'node:child_process';
|
|
2
|
+
import { promisify } from 'node:util';
|
|
3
|
+
import { resolveOmpPaths } from './omp-paths.mjs';
|
|
4
|
+
const execute = promisify(execFile);
|
|
5
|
+
/** Reports only parsed version and non-secret paths; never reflects runtime output. */
|
|
6
|
+
export async function diagnoseOmpRuntime({ cwd = process.cwd(), env = process.env, binary = env.AIWG_OMP_BIN || 'omp', runner = execute } = {}) {
|
|
7
|
+
const paths = resolveOmpPaths({ cwd, env });
|
|
8
|
+
const result = { executable: binary, available: false, version: null, paths, reason: 'OMP executable unavailable; install the supported binary or set AIWG_OMP_BIN.' };
|
|
9
|
+
try {
|
|
10
|
+
const output = await runner(binary, ['--version'], { cwd, env: { PATH: env.PATH || '', PI_CODING_AGENT_DIR: paths.agentDir, NO_COLOR: '1', ...(env.SystemRoot ? { SystemRoot: env.SystemRoot } : {}) }, timeout: 5000, maxBuffer: 16384, encoding: 'utf8' });
|
|
11
|
+
const version = output.stdout.trim().match(/^(?:omp\/)?(\d+\.\d+\.\d+(?:[-+][a-zA-Z0-9.-]+)?)$/)?.[1];
|
|
12
|
+
if (!version) { result.reason = 'OMP returned an unrecognized version; verify the selected executable.'; return result; }
|
|
13
|
+
return { ...result, available: true, version, reason: null };
|
|
14
|
+
} catch { return result; }
|
|
15
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { homedir } from 'node:os';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { existsSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
/** OMP 18.1.10 profile contract; independent of original Pi configuration. */
|
|
6
|
+
export function normalizeOmpProfile(value) {
|
|
7
|
+
const name = value?.trim();
|
|
8
|
+
if (!name || name === 'default') return undefined;
|
|
9
|
+
if (!/^[a-z0-9][a-z0-9._-]{0,63}$/.test(name) || name.endsWith('.')
|
|
10
|
+
|| /^(?:con|prn|aux|nul|com[0-9]|lpt[0-9])(?:\..*)?$/i.test(name)) {
|
|
11
|
+
throw new Error('Invalid OMP profile: use 1–64 lowercase letters, digits, dots, hyphens or underscores; reserved device names are forbidden');
|
|
12
|
+
}
|
|
13
|
+
return name;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/** Resolve without reading credentials or importing the OMP runtime. */
|
|
17
|
+
export function resolveOmpPaths({ env = process.env, home = homedir(), cwd = process.cwd(),
|
|
18
|
+
platform = process.platform, exists = existsSync } = {}) {
|
|
19
|
+
const profile = normalizeOmpProfile(env.OMP_PROFILE !== undefined ? env.OMP_PROFILE : env.PI_PROFILE);
|
|
20
|
+
const directory = env.PI_CONFIG_DIR || '.omp';
|
|
21
|
+
const base = path.join(home, directory);
|
|
22
|
+
const configRoot = profile ? path.join(base, 'profiles', profile) : base;
|
|
23
|
+
const defaultAgent = path.join(configRoot, 'agent');
|
|
24
|
+
const agentDir = !profile && env.PI_CODING_AGENT_DIR
|
|
25
|
+
? path.resolve(cwd, env.PI_CODING_AGENT_DIR) : defaultAgent;
|
|
26
|
+
const xdg = (variable) => {
|
|
27
|
+
if (!['linux', 'darwin'].includes(platform) || agentDir !== defaultAgent || !env[variable]) return undefined;
|
|
28
|
+
const root = path.join(env[variable], 'omp');
|
|
29
|
+
const candidate = profile ? path.join(root, 'profiles', profile) : root;
|
|
30
|
+
return exists(candidate) ? candidate : undefined;
|
|
31
|
+
};
|
|
32
|
+
const dataDir = xdg('XDG_DATA_HOME') || agentDir;
|
|
33
|
+
const stateDir = xdg('XDG_STATE_HOME') || agentDir;
|
|
34
|
+
const cacheDir = xdg('XDG_CACHE_HOME') || agentDir;
|
|
35
|
+
const resourceDirs = { agents: path.join(defaultAgent, 'agents'), skills: path.join(agentDir, 'skills'), commands: path.join(agentDir, 'prompts'), rules: path.join(agentDir, 'rules'), behaviors: path.join(agentDir, 'extensions') };
|
|
36
|
+
return { profile, configRoot, agentDir, resourceDirs, projectDir: path.join(cwd, '.omp'),
|
|
37
|
+
dataDir, stateDir, cacheDir, sessionsDir: path.join(dataDir, 'sessions') };
|
|
38
|
+
}
|
|
@@ -12,6 +12,7 @@ const ArtifactPathsSchema = z.object({
|
|
|
12
12
|
});
|
|
13
13
|
const ProviderDefinitionSchema = z.object({
|
|
14
14
|
id: z.enum([
|
|
15
|
+
'antigravity',
|
|
15
16
|
'claude',
|
|
16
17
|
'codex',
|
|
17
18
|
'copilot',
|
|
@@ -22,6 +23,7 @@ const ProviderDefinitionSchema = z.object({
|
|
|
22
23
|
'openclaw',
|
|
23
24
|
'openhuman',
|
|
24
25
|
'pi',
|
|
26
|
+
'omp',
|
|
25
27
|
'warp',
|
|
26
28
|
'windsurf',
|
|
27
29
|
'generic',
|
|
@@ -123,6 +125,7 @@ const ProviderDefinitionSchema = z.object({
|
|
|
123
125
|
}),
|
|
124
126
|
});
|
|
125
127
|
export const PROVIDER_IDS = [
|
|
128
|
+
'antigravity',
|
|
126
129
|
'claude',
|
|
127
130
|
'codex',
|
|
128
131
|
'copilot',
|
|
@@ -133,12 +136,24 @@ export const PROVIDER_IDS = [
|
|
|
133
136
|
'openclaw',
|
|
134
137
|
'openhuman',
|
|
135
138
|
'pi',
|
|
139
|
+
'omp',
|
|
136
140
|
'warp',
|
|
137
141
|
'windsurf',
|
|
138
142
|
'generic',
|
|
139
143
|
];
|
|
140
144
|
const VERIFIED_ON = '2026-07-21';
|
|
141
145
|
const CONTEXT_CONTRACTS = {
|
|
146
|
+
antigravity: {
|
|
147
|
+
startupFiles: ['AGENTS.md', 'GEMINI.md'],
|
|
148
|
+
precedence: ['provider/system', 'project AGENTS.md or GEMINI.md', 'nested project context when selected by the CLI'],
|
|
149
|
+
loadMode: 'prose-directive', includeSyntax: null, configRegistration: null,
|
|
150
|
+
bootstrapTargets: ['AGENTS.md'], maxContextBytes: null, recommendedMaxLines: null, nestedContext: true, support: 'supported',
|
|
151
|
+
verification: {
|
|
152
|
+
method: 'official Antigravity CLI documentation and sanitized 1.1.26 help evidence',
|
|
153
|
+
source: 'https://antigravity.google/docs/cli/overview/',
|
|
154
|
+
lastVerified: '2026-09-04',
|
|
155
|
+
},
|
|
156
|
+
},
|
|
142
157
|
claude: {
|
|
143
158
|
startupFiles: ['CLAUDE.md', '.claude/CLAUDE.md'], precedence: ['provider/system', 'nested CLAUDE.md', 'root CLAUDE.md'],
|
|
144
159
|
loadMode: 'native-include', includeSyntax: '@WORKSPACE.md\n@AIWG.md', configRegistration: null,
|
|
@@ -193,6 +208,17 @@ const CONTEXT_CONTRACTS = {
|
|
|
193
208
|
bootstrapTargets: ['AGENTS.md'], maxContextBytes: null, recommendedMaxLines: null, nestedContext: false, support: 'degraded',
|
|
194
209
|
verification: { method: 'AIWG mixed-scope adapter contract; host loading remains capability-dependent', source: 'agentic/code/providers/capability-matrix.yaml', lastVerified: VERIFIED_ON },
|
|
195
210
|
},
|
|
211
|
+
omp: {
|
|
212
|
+
startupFiles: ['.omp/AGENTS.md', 'AGENTS.md'],
|
|
213
|
+
precedence: ['provider/system', 'native nearest nonempty .omp', 'compatibility context ordered by depth; exact paragraph deduplication'],
|
|
214
|
+
loadMode: 'native-include', includeSyntax: '@<relative-path>', configRegistration: null,
|
|
215
|
+
bootstrapTargets: ['.omp/AGENTS.md'], maxContextBytes: null, recommendedMaxLines: null, nestedContext: true, support: 'supported',
|
|
216
|
+
verification: {
|
|
217
|
+
method: 'OMP 18.1.10 source and live context import smoke',
|
|
218
|
+
source: 'https://github.com/can1357/oh-my-pi/blob/5964a0f7649275bcde818f20073193fd032451f2/packages/coding-agent/src/system-prompt.ts#L451',
|
|
219
|
+
lastVerified: '2026-09-04',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
196
222
|
pi: {
|
|
197
223
|
startupFiles: ['AGENTS.override.md', 'AGENTS.md', 'CLAUDE.md'],
|
|
198
224
|
precedence: ['provider/system', 'root-to-cwd context chain', 'AGENTS.override.md supersedes same-directory AGENTS.md and CLAUDE.md'],
|
|
@@ -223,6 +249,42 @@ const CONTEXT_CONTRACTS = {
|
|
|
223
249
|
},
|
|
224
250
|
};
|
|
225
251
|
const BUILT_IN_SEEDS = [
|
|
252
|
+
{
|
|
253
|
+
id: 'antigravity',
|
|
254
|
+
displayName: 'Google Antigravity CLI',
|
|
255
|
+
aliases: ['agy'],
|
|
256
|
+
status: 'experimental',
|
|
257
|
+
builtIn: true,
|
|
258
|
+
surfaces: {
|
|
259
|
+
primary: 'antigravity',
|
|
260
|
+
compatibility: ['agy'],
|
|
261
|
+
precedence: ['AGENTS.md', 'GEMINI.md', '.agents/agents/', '.agents/skills/'],
|
|
262
|
+
related: [],
|
|
263
|
+
},
|
|
264
|
+
detection: { env: [], process: ['agy'], capabilityId: 'antigravity' },
|
|
265
|
+
paths: {
|
|
266
|
+
deployTarget: 'project',
|
|
267
|
+
artifacts: {
|
|
268
|
+
agents: '.agents/agents', commands: null, skills: '.agents/.aiwg/skills', rules: null, behaviors: null,
|
|
269
|
+
},
|
|
270
|
+
kernelSkills: '.agents/skills',
|
|
271
|
+
contextDiscovery: { agents: '.agents/agents', skills: '.agents/skills', rules: null, behaviors: null },
|
|
272
|
+
configFile: 'AGENTS.md',
|
|
273
|
+
contextFiles: { aiwgMd: true, agentsMd: true, claudeMdHook: false, hookFile: null, contextFile: 'AGENTS.md' },
|
|
274
|
+
},
|
|
275
|
+
smithPaths: {
|
|
276
|
+
agents: '.agents/agents', commands: null, skills: '.agents/skills', rules: null,
|
|
277
|
+
fileExtension: '.md', configFile: 'AGENTS.md', aggregated: false,
|
|
278
|
+
},
|
|
279
|
+
skillNamespace: {
|
|
280
|
+
deploymentGroup: 'deep-recursion', pathType: 'project', skillsBaseDir: '.agents/skills', subdirLayout: true,
|
|
281
|
+
},
|
|
282
|
+
adapters: {
|
|
283
|
+
agentFormat: 'antigravity-markdown', hookBridge: null, mcpInjection: 'antigravity',
|
|
284
|
+
contextAggregation: 'agents-md', ruleFormat: null,
|
|
285
|
+
},
|
|
286
|
+
matrixRef: 'antigravity',
|
|
287
|
+
},
|
|
226
288
|
{
|
|
227
289
|
id: 'claude',
|
|
228
290
|
displayName: 'Claude Code',
|
|
@@ -669,6 +731,27 @@ const BUILT_IN_SEEDS = [
|
|
|
669
731
|
},
|
|
670
732
|
matrixRef: 'openhuman',
|
|
671
733
|
},
|
|
734
|
+
{
|
|
735
|
+
id: 'omp',
|
|
736
|
+
aliases: ['oh-my-pi'],
|
|
737
|
+
builtIn: true,
|
|
738
|
+
surfaces: {
|
|
739
|
+
primary: 'omp', compatibility: ['oh-my-pi'],
|
|
740
|
+
precedence: ['.omp/AGENTS.md', 'AGENTS.md', '.agents/skills/', '.omp/skills/', '.omp/prompts/'], related: [],
|
|
741
|
+
},
|
|
742
|
+
detection: { env: [], process: ['omp', '@oh-my-pi/pi-coding-agent'], capabilityId: 'omp' },
|
|
743
|
+
paths: {
|
|
744
|
+
artifacts: { agents: '.omp/agents', commands: '.omp/prompts', skills: '.agents/skills', rules: '.omp/rules', behaviors: '.omp/extensions' },
|
|
745
|
+
kernelSkills: '.agents/skills',
|
|
746
|
+
contextDiscovery: { agents: '.omp/agents', skills: '.agents/skills', rules: '.omp/rules', behaviors: '.omp/extensions' },
|
|
747
|
+
configFile: '.omp/AGENTS.md',
|
|
748
|
+
contextFiles: { aiwgMd: true, agentsMd: false, claudeMdHook: false, hookFile: '.omp/AGENTS.md', contextFile: '.omp/AGENTS.md' },
|
|
749
|
+
},
|
|
750
|
+
smithPaths: { agents: '.omp/agents', commands: '.omp/prompts', skills: '.agents/skills', rules: '.omp/rules', fileExtension: '.md', configFile: '.omp/AGENTS.md', aggregated: false },
|
|
751
|
+
skillNamespace: { deploymentGroup: 'one-level', pathType: 'project', skillsBaseDir: '.omp/skills', subdirLayout: false },
|
|
752
|
+
adapters: { agentFormat: 'omp-markdown', hookBridge: 'omp', mcpInjection: 'omp', contextAggregation: 'agents-md', ruleFormat: 'omp-markdown' },
|
|
753
|
+
matrixRef: 'omp',
|
|
754
|
+
},
|
|
672
755
|
{
|
|
673
756
|
id: 'pi',
|
|
674
757
|
aliases: ['pi-coding-agent'],
|
|
@@ -1,7 +1,24 @@
|
|
|
1
|
+
import { resolveOmpPaths } from './omp-paths.mjs';
|
|
1
2
|
import { homedir } from 'os';
|
|
2
3
|
import { resolve } from 'path';
|
|
3
4
|
|
|
4
5
|
const MCP_INJECTION_DEFINITIONS = [
|
|
6
|
+
{
|
|
7
|
+
id: 'antigravity', aliases: ['agy'],
|
|
8
|
+
mcp: { providerId: 'antigravity', includeInSupportedProviders: true, configFormat: 'json',
|
|
9
|
+
serverConfigFormat: 'antigravity', serversKey: 'mcpServers',
|
|
10
|
+
configPath: { scope: 'project', path: '.agents/mcp_config.json' },
|
|
11
|
+
supportsEphemeral: false,
|
|
12
|
+
unsupportedReason: 'Antigravity uses project or user persistent MCP configuration; temporary injection is not qualified.' },
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
id: 'omp', aliases: ['oh-my-pi'],
|
|
16
|
+
mcp: { providerId: 'omp', includeInSupportedProviders: true, configFormat: 'json',
|
|
17
|
+
serverConfigFormat: 'standard', serversKey: 'mcpServers',
|
|
18
|
+
configPath: { scope: 'project', path: '.omp/mcp.json' },
|
|
19
|
+
supportsEphemeral: false,
|
|
20
|
+
unsupportedReason: 'OMP uses owned persistent MCP configuration; temporary injection is not supported.' },
|
|
21
|
+
},
|
|
5
22
|
{
|
|
6
23
|
id: 'claude',
|
|
7
24
|
aliases: ['claude-code'],
|
|
@@ -147,7 +164,14 @@ export function listMcpInjectProviderIds() {
|
|
|
147
164
|
.map((definition) => definition.providerId);
|
|
148
165
|
}
|
|
149
166
|
|
|
150
|
-
export function resolveMcpConfigPath(provider, projectDir = '.') {
|
|
167
|
+
export function resolveMcpConfigPath(provider, projectDir = '.', options = {}) {
|
|
168
|
+
if (normalizeRuntimeProviderId(provider) === 'antigravity' && options.scope === 'user') {
|
|
169
|
+
const home = process.env.HOME || process.env.USERPROFILE || homedir();
|
|
170
|
+
return resolve(home, '.gemini/config/mcp_config.json');
|
|
171
|
+
}
|
|
172
|
+
if (normalizeRuntimeProviderId(provider) === 'omp' && options.scope === 'user') {
|
|
173
|
+
return resolve(resolveOmpPaths(options).agentDir, 'mcp.json');
|
|
174
|
+
}
|
|
151
175
|
const definition = getMcpInjectionDefinition(provider);
|
|
152
176
|
if (!definition) return '';
|
|
153
177
|
|
|
@@ -5,6 +5,7 @@ import { readAiwgConfig } from '../config/aiwg-config.js';
|
|
|
5
5
|
import { resolveActiveProvider } from '../cli/provider-resolution.js';
|
|
6
6
|
import { listProviderDefinitions, normalizeProviderDefinitionId, resolveProviderPathValue, } from './provider-definitions.js';
|
|
7
7
|
const PROVIDER_EXECUTABLES = {
|
|
8
|
+
antigravity: ['agy'],
|
|
8
9
|
claude: ['claude'],
|
|
9
10
|
codex: ['codex'],
|
|
10
11
|
copilot: ['github-copilot-cli', 'copilot'],
|
|
@@ -15,6 +16,7 @@ const PROVIDER_EXECUTABLES = {
|
|
|
15
16
|
openclaw: ['openclaw'],
|
|
16
17
|
openhuman: ['openhuman'],
|
|
17
18
|
pi: ['pi'],
|
|
19
|
+
omp: ['omp'],
|
|
18
20
|
warp: ['warp'],
|
|
19
21
|
windsurf: ['windsurf'],
|
|
20
22
|
};
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { opendir } from 'node:fs/promises';
|
|
2
|
+
import { resolve } from 'node:path';
|
|
3
|
+
import { z } from 'zod';
|
|
4
|
+
import { SessionContractError, } from '../contracts.js';
|
|
5
|
+
import { readBoundedJsonLines, streamBoundedJsonLines } from '../readers.js';
|
|
6
|
+
export const OMP_ADAPTER_VERSION = '1.0.0';
|
|
7
|
+
export const OMP_SOURCE_SCHEMA_VERSION = '3.0.0';
|
|
8
|
+
const Title = z.object({ type: z.literal('title'), v: z.literal(1), title: z.string(), source: z.enum(['auto', 'user']).optional(), updatedAt: z.string(), pad: z.string() });
|
|
9
|
+
const Header = z.object({ type: z.literal('session'), version: z.number().int(), id: z.string().min(1),
|
|
10
|
+
timestamp: z.string().datetime({ offset: true }), cwd: z.string(), parentSession: z.string().optional() }).passthrough();
|
|
11
|
+
const Entry = z.object({ type: z.string().min(1), id: z.string().min(1),
|
|
12
|
+
parentId: z.string().nullable(), timestamp: z.string().datetime({ offset: true }) }).passthrough();
|
|
13
|
+
export class OmpSessionAdapter {
|
|
14
|
+
limits;
|
|
15
|
+
maxFiles;
|
|
16
|
+
provider = 'omp';
|
|
17
|
+
sourceSchemaMajor = 3;
|
|
18
|
+
adapterVersion = OMP_ADAPTER_VERSION;
|
|
19
|
+
disposition = 'implemented';
|
|
20
|
+
supportedOperations = ['discover', 'inspect', 'stream'];
|
|
21
|
+
acquisitionModes = ['jsonl'];
|
|
22
|
+
constructor(limits, maxFiles = 10_000) {
|
|
23
|
+
this.limits = limits;
|
|
24
|
+
this.maxFiles = maxFiles;
|
|
25
|
+
}
|
|
26
|
+
async *discover(scope) {
|
|
27
|
+
if (!scope.allowedRoots.length)
|
|
28
|
+
throw new SessionContractError('SOURCE_NOT_AUTHORIZED', 'OMP discovery requires an authorized sessions root');
|
|
29
|
+
let count = 0;
|
|
30
|
+
for (const root of [...scope.allowedRoots].sort()) {
|
|
31
|
+
for await (const locator of jsonlFiles(resolve(root))) {
|
|
32
|
+
if (++count > this.maxFiles)
|
|
33
|
+
throw new SessionContractError('RESOURCE_LIMIT_EXCEEDED', 'OMP discovery file limit exceeded');
|
|
34
|
+
yield { provider: 'omp', locator, locatorClass: 'omp-session-v3-jsonl' };
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
async inspect(source) {
|
|
39
|
+
let input;
|
|
40
|
+
try {
|
|
41
|
+
input = await readBoundedJsonLines({ selectedPath: source.locator,
|
|
42
|
+
allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
throw normalizeAuthorizationError(error);
|
|
46
|
+
}
|
|
47
|
+
const header = parseHeader(input.records[titleOffset(input.records[0]) ? 1 : 0]?.value);
|
|
48
|
+
if (input.incompleteTail)
|
|
49
|
+
throw new SessionContractError('TRUNCATED_SOURCE', 'OMP session has a truncated JSONL tail');
|
|
50
|
+
return { sourceSchemaVersion: `${header.version}.0.0`, consistency: 'complete', operationalState: 'available' };
|
|
51
|
+
}
|
|
52
|
+
async *stream(source, cursor) {
|
|
53
|
+
let input;
|
|
54
|
+
try {
|
|
55
|
+
input = await streamBoundedJsonLines({ selectedPath: source.locator,
|
|
56
|
+
allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
throw normalizeAuthorizationError(error);
|
|
60
|
+
}
|
|
61
|
+
let sessionId = '';
|
|
62
|
+
let header = {};
|
|
63
|
+
let prefix = true;
|
|
64
|
+
const start = cursor?.value.replace(/^byte:/, '') ?? '0';
|
|
65
|
+
if (!/^\d+$/.test(start))
|
|
66
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'invalid OMP cursor');
|
|
67
|
+
let end = 0;
|
|
68
|
+
const ids = new Set();
|
|
69
|
+
for await (const line of input) {
|
|
70
|
+
end = line.byteOffset + line.byteLength;
|
|
71
|
+
if (Number(start) > line.byteOffset && Number(start) < end) {
|
|
72
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'OMP cursor is not a record boundary');
|
|
73
|
+
}
|
|
74
|
+
if (prefix) {
|
|
75
|
+
prefix = false;
|
|
76
|
+
if (titleOffset(line))
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (!sessionId) {
|
|
80
|
+
header = parseHeader(line.value);
|
|
81
|
+
sessionId = String(header.id);
|
|
82
|
+
continue;
|
|
83
|
+
}
|
|
84
|
+
const parsed = Entry.safeParse(line.value);
|
|
85
|
+
if (!parsed.success)
|
|
86
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session entry is malformed');
|
|
87
|
+
const entry = parsed.data;
|
|
88
|
+
if (ids.has(entry.id))
|
|
89
|
+
throw new SessionContractError('DUPLICATE_NATIVE_ID', 'OMP session contains a duplicate entry id');
|
|
90
|
+
ids.add(entry.id);
|
|
91
|
+
if (end <= Number(start))
|
|
92
|
+
continue;
|
|
93
|
+
const message = object(entry.message);
|
|
94
|
+
const role = string(message.role) ?? roleFor(entry.type);
|
|
95
|
+
const sensitive = role === 'toolResult' || ['custom', 'custom_message', 'session_init', 'credential_pin'].includes(entry.type) || !KNOWN.has(entry.type);
|
|
96
|
+
const text = sensitive ? '[redacted provider content]' : entryText(entry, message);
|
|
97
|
+
yield { nativeSessionId: sessionId, nativeEventId: entry.id, sequence: line.sequence,
|
|
98
|
+
kind: kindFor(entry.type, role), role, toolName: sensitive ? string(message.toolName) : undefined,
|
|
99
|
+
toolCallId: sensitive ? string(message.toolCallId) : undefined,
|
|
100
|
+
occurredAt: entry.timestamp, text, model: string(entry.model) ?? string(message.model), sourceCursor: `byte:${end}`,
|
|
101
|
+
sourceBytes: line.byteLength, rawReference: { locatorClass: 'omp-session-v3-jsonl', offset: line.byteOffset },
|
|
102
|
+
activityBoundary: entry.type === 'compaction' ? 'continuation' : undefined,
|
|
103
|
+
activityBoundaryBasis: entry.type === 'compaction' ? 'pi-session:compaction' : undefined,
|
|
104
|
+
activityBoundaryConfidence: entry.type === 'compaction' ? 'high' : undefined,
|
|
105
|
+
extensions: { provenance: { acquisition: 'omp-session-v3', parentId: entry.parentId, parentSession: header.parentSession, previousSessionFiles: header.previousSessionFiles, cwd: header.cwd, additionalDirectories: header.additionalDirectories },
|
|
106
|
+
opaque: !KNOWN.has(entry.type), redacted: sensitive,
|
|
107
|
+
nativeType: entry.type, parentId: entry.parentId, ...metadata(entry, message) } };
|
|
108
|
+
}
|
|
109
|
+
if (!sessionId)
|
|
110
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session header is missing');
|
|
111
|
+
if (Number(start) > end)
|
|
112
|
+
throw new SessionContractError('SCHEMA_DRIFT', 'OMP cursor exceeds source size');
|
|
113
|
+
if (input.incompleteTail)
|
|
114
|
+
throw new SessionContractError('TRUNCATED_SOURCE', 'OMP session has a truncated JSONL tail');
|
|
115
|
+
}
|
|
116
|
+
async mutablePrefixBytes(source) {
|
|
117
|
+
const input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: this.limits });
|
|
118
|
+
for await (const line of input)
|
|
119
|
+
return titleOffset(line);
|
|
120
|
+
return 0;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
const KNOWN = new Set(['message', 'thinking_level_change', 'model_change', 'compaction',
|
|
124
|
+
'branch_summary', 'custom', 'label', 'session_info', 'custom_message', 'model_usage', 'title_change', 'service_tier_change', 'reset_boundary', 'ttsr_injection', 'credential_pin', 'session_init', 'mode_change']);
|
|
125
|
+
function parseHeader(value) {
|
|
126
|
+
const parsed = Header.safeParse(value);
|
|
127
|
+
if (!parsed.success)
|
|
128
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP session header is malformed');
|
|
129
|
+
if (parsed.data.version !== 3)
|
|
130
|
+
throw new SessionContractError('UNKNOWN_SCHEMA_MAJOR', `unsupported OMP session version: ${parsed.data.version}`);
|
|
131
|
+
return parsed.data;
|
|
132
|
+
}
|
|
133
|
+
function object(value) { return value && typeof value === 'object' ? value : {}; }
|
|
134
|
+
function string(value) { return typeof value === 'string' && value ? value : undefined; }
|
|
135
|
+
function roleFor(type) { return type === 'compaction' || type === 'branch_summary' ? 'system' : undefined; }
|
|
136
|
+
function kindFor(type, role) { return type === 'message' ? `message.${role ?? 'unknown'}` : `omp.${type}`; }
|
|
137
|
+
function entryText(entry, message) {
|
|
138
|
+
const value = entry.type === 'message' ? message.content : entry.summary ?? entry.title ?? entry.name ?? entry.label ?? '';
|
|
139
|
+
if (typeof value === 'string')
|
|
140
|
+
return value;
|
|
141
|
+
if (Array.isArray(value))
|
|
142
|
+
return value.flatMap(part => typeof part === 'string' ? part : string(object(part).text) ?? []).join('\n');
|
|
143
|
+
return '';
|
|
144
|
+
}
|
|
145
|
+
async function* jsonlFiles(root) {
|
|
146
|
+
let directory;
|
|
147
|
+
try {
|
|
148
|
+
directory = await opendir(root);
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
for await (const entry of directory) {
|
|
154
|
+
const path = resolve(root, entry.name);
|
|
155
|
+
if (entry.isDirectory())
|
|
156
|
+
yield* jsonlFiles(path);
|
|
157
|
+
else if (entry.isFile() && entry.name.endsWith('.jsonl'))
|
|
158
|
+
yield path;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function normalizeAuthorizationError(error) {
|
|
162
|
+
if (error instanceof SessionContractError && (error.code === 'SOURCE_OUTSIDE_ALLOWED_ROOT'
|
|
163
|
+
|| error.code === 'SOURCE_SYMLINK' || error.code === 'SOURCE_NOT_REGULAR_FILE')) {
|
|
164
|
+
return new SessionContractError('SOURCE_NOT_AUTHORIZED', 'OMP source is not an authorized regular file');
|
|
165
|
+
}
|
|
166
|
+
return error;
|
|
167
|
+
}
|
|
168
|
+
function titleOffset(line) {
|
|
169
|
+
if (object(line?.value).type !== 'title')
|
|
170
|
+
return 0;
|
|
171
|
+
if (!Title.safeParse(line?.value).success || line?.byteLength !== 256) {
|
|
172
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP title slot is malformed');
|
|
173
|
+
}
|
|
174
|
+
return 256;
|
|
175
|
+
}
|
|
176
|
+
function metadata(entry, message) {
|
|
177
|
+
const result = {};
|
|
178
|
+
for (const key of ['fromId', 'firstKeptEntryId', 'providerReplayThroughEntryId', 'tokensBefore', 'tokensAfter', 'method', 'role', 'resolvedModelIsFallback', 'purpose', 'provider', 'api', 'stopReason']) {
|
|
179
|
+
if (['string', 'number', 'boolean'].includes(typeof entry[key]))
|
|
180
|
+
result[key] = entry[key];
|
|
181
|
+
}
|
|
182
|
+
const usage = object(entry.usage ?? message.usage);
|
|
183
|
+
const numbers = Object.fromEntries(Object.entries(usage).filter(([, v]) => typeof v === 'number' && Number.isFinite(v)));
|
|
184
|
+
const cost = Object.fromEntries(Object.entries(object(usage.cost)).filter(([, v]) => typeof v === 'number' && Number.isFinite(v)));
|
|
185
|
+
if (Object.keys(numbers).length || Object.keys(cost).length)
|
|
186
|
+
result.usage = { ...numbers, cost };
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
/** Read only the bounded native preamble; never infer OMP from version alone. */
|
|
190
|
+
export async function readOmpSessionHeader(source) {
|
|
191
|
+
const input = await streamBoundedJsonLines({ selectedPath: source.locator, allowedRoots: source.authorizedScope.allowedRoots }, { consistency: 'provisional', limits: { maxRecords: 2, maxRecordBytes: 1024 * 1024 } });
|
|
192
|
+
let first = true;
|
|
193
|
+
for await (const line of input) {
|
|
194
|
+
if (first) {
|
|
195
|
+
first = false;
|
|
196
|
+
if (titleOffset(line))
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
return parseHeader(line.value);
|
|
200
|
+
}
|
|
201
|
+
throw new SessionContractError('MALFORMED_SOURCE', 'OMP header is missing');
|
|
202
|
+
}
|
|
203
|
+
//# sourceMappingURL=omp.js.map
|