dsh-omni-router 2.2.0 → 2.2.1

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/README.md CHANGED
@@ -155,7 +155,7 @@ Then restart DSH and select **Omni Router** in a new session.
155
155
  - `/omni direct` — enter direct mode.
156
156
  - `/omni mode spec|react|balanced` — set thinking mode.
157
157
  - `/omni reroute plan|direct` — adaptively reroute current task.
158
- - Model tools: `omni_status`, `omni_plan`, `omni_direct`, `omni_mode`, `omni_reroute`, `omni_delegate`, `omni_memory`, `omni_benchmark`, `omni_mission_run`, `omni_mission_resume`, `omni_capability_audit`, `omni_capability_provision`, `omni_capability_probe`, `omni_visual_check`.
158
+ - Model tools: `omni_status`, `omni_plan`, `omni_direct`, `omni_mode`, `omni_reroute`, `omni_delegate`, `omni_memory`, `omni_benchmark`, `omni_mission_run`, `omni_mission_resume`, `omni_capability_audit`, `omni_capability_provision`, `omni_capability_probe`, `omni_capability_performance`, `omni_visual_check`.
159
159
 
160
160
  ## Configuration
161
161
 
package/README.zh-CN.md CHANGED
@@ -155,7 +155,7 @@ node scripts/install-preset.mjs
155
155
  - `/omni direct` — 进入直接执行模式。
156
156
  - `/omni mode spec|react|balanced` — 设置思维模式。
157
157
  - `/omni reroute plan|direct` — 动态切换当前任务路由。
158
- - 模型工具:`omni_status` / `omni_plan` / `omni_direct` / `omni_mode` / `omni_reroute` / `omni_delegate` / `omni_memory` / `omni_benchmark` / `omni_mission_run` / `omni_mission_resume` / `omni_capability_audit` / `omni_capability_provision` / `omni_capability_probe` / `omni_visual_check`。
158
+ - 模型工具:`omni_status` / `omni_plan` / `omni_direct` / `omni_mode` / `omni_reroute` / `omni_delegate` / `omni_memory` / `omni_benchmark` / `omni_mission_run` / `omni_mission_resume` / `omni_capability_audit` / `omni_capability_provision` / `omni_capability_probe` / `omni_capability_performance` / `omni_visual_check`。
159
159
 
160
160
  ## 配置
161
161
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dsh-omni-router",
3
- "version": "2.2.0",
3
+ "version": "2.2.1",
4
4
  "description": "Omni - a reliability and orchestration control plane for DeepSeek Harness, designed to turn fast models into dependable long-horizon software-engineering agents.",
5
5
  "type": "module",
6
6
  "main": "./lib/index.js",
@@ -6,12 +6,36 @@
6
6
  * demotion/removal decisions and benchmark plugin-contribution analysis.
7
7
  */
8
8
 
9
+ import fs from 'node:fs'
10
+ import path from 'node:path'
11
+
9
12
  export function createPerformanceRegistry(initial = {}) {
10
13
  return {
11
14
  providers: { ...(initial.providers || {}) },
12
15
  }
13
16
  }
14
17
 
18
+ export function performanceRegistryPath(cwd) {
19
+ return path.join(cwd, '.omni', 'capability-performance.json')
20
+ }
21
+
22
+ export function loadPerformanceRegistry(cwd) {
23
+ const file = performanceRegistryPath(cwd)
24
+ if (!fs.existsSync(file)) return createPerformanceRegistry()
25
+ try {
26
+ return createPerformanceRegistry(JSON.parse(fs.readFileSync(file, 'utf8')))
27
+ } catch {
28
+ return createPerformanceRegistry()
29
+ }
30
+ }
31
+
32
+ export function savePerformanceRegistry(cwd, registry) {
33
+ const file = performanceRegistryPath(cwd)
34
+ fs.mkdirSync(path.dirname(file), { recursive: true })
35
+ fs.writeFileSync(file, JSON.stringify(registry, null, 2), 'utf8')
36
+ return file
37
+ }
38
+
15
39
  export function recordProvisionOutcome(registry, providerId, outcome = {}) {
16
40
  const previous = registry.providers[providerId] || {
17
41
  runs: 0,
@@ -37,6 +37,7 @@ import { loadCapabilityManifests } from './capability-manifest.mjs'
37
37
  import { capabilityToolFilter } from './capability-sandbox.mjs'
38
38
  import { baselineAudit, formatCapabilityAudit, taskTimeAudit } from './capability-auditor.mjs'
39
39
  import { createStaticRegistryAdapter, discoverCandidates, evaluateProvisionPlan, formatProvisionResult, probeCapability, provisionCapabilities } from './capability-provisioner.mjs'
40
+ import { evaluateProviderValue, formatPerformanceRegistry, loadPerformanceRegistry, recommendDemotion, recordProvisionOutcome, savePerformanceRegistry } from './capability-performance.mjs'
40
41
  import { buildProgressiveContext } from './context-expansion.mjs'
41
42
  import { buildDynamicContext } from './dynamic-context.mjs'
42
43
  import { classifyFailure } from './failure-taxonomy.mjs'
@@ -1600,6 +1601,63 @@ export function apply(ctx, config = {}) {
1600
1601
  },
1601
1602
  })
1602
1603
 
1604
+ registerTool({
1605
+ name: 'omni_capability_performance',
1606
+ description: 'Track and inspect whether provisioned plugins/skills measurably improve task success, false completion, tokens, or tool errors.',
1607
+ parameters: {
1608
+ type: 'object',
1609
+ properties: {
1610
+ action: { type: 'string', enum: ['list', 'record', 'recommend'], description: 'Action (default list)' },
1611
+ provider: { type: 'string', description: 'Provider id' },
1612
+ successBefore: { type: 'number', description: 'Task success before provisioning' },
1613
+ successAfter: { type: 'number', description: 'Task success after provisioning' },
1614
+ falseCompletionBefore: { type: 'number', description: 'False completion rate before' },
1615
+ falseCompletionAfter: { type: 'number', description: 'False completion rate after' },
1616
+ tokensBefore: { type: 'number', description: 'Token usage before' },
1617
+ tokensAfter: { type: 'number', description: 'Token usage after' },
1618
+ toolErrorsBefore: { type: 'number', description: 'Tool errors before' },
1619
+ toolErrorsAfter: { type: 'number', description: 'Tool errors after' },
1620
+ usageDays: { type: 'number', description: 'Days since last use (for recommend)' },
1621
+ uniqueCapabilities: { type: 'number', description: 'Number of unique capabilities (for recommend)' },
1622
+ coveredBy: { type: 'array', items: { type: 'string' }, description: 'Other providers covering the same capabilities (for recommend)' },
1623
+ },
1624
+ required: [],
1625
+ },
1626
+ async execute(args) {
1627
+ const session = currentSession()
1628
+ const cwd = session?.meta?.cwd || session?.header?.cwd
1629
+ if (!cwd) return 'No workspace cwd found.'
1630
+ const action = args?.action || 'list'
1631
+ let registry = loadPerformanceRegistry(cwd)
1632
+ if (action === 'record') {
1633
+ if (!args?.provider) return 'provider is required for record.'
1634
+ registry = recordProvisionOutcome(registry, args.provider, {
1635
+ successBefore: args.successBefore,
1636
+ successAfter: args.successAfter,
1637
+ falseCompletionBefore: args.falseCompletionBefore,
1638
+ falseCompletionAfter: args.falseCompletionAfter,
1639
+ tokensBefore: args.tokensBefore,
1640
+ tokensAfter: args.tokensAfter,
1641
+ toolErrorsBefore: args.toolErrorsBefore,
1642
+ toolErrorsAfter: args.toolErrorsAfter,
1643
+ })
1644
+ const file = savePerformanceRegistry(cwd, registry)
1645
+ const value = evaluateProviderValue(registry.providers[args.provider])
1646
+ return `Recorded ${args.provider}: ${value.label} (${value.value})\nSaved: ${file}`
1647
+ }
1648
+ if (action === 'recommend') {
1649
+ if (!args?.provider) return 'provider is required for recommend.'
1650
+ const rec = recommendDemotion(registry, args.provider, {
1651
+ usageDays: Number(args.usageDays) || 0,
1652
+ uniqueCapabilities: Number(args.uniqueCapabilities) || 0,
1653
+ coveredBy: Array.isArray(args.coveredBy) ? args.coveredBy : [],
1654
+ })
1655
+ return `${rec.providerId}: ${rec.recommendation} — ${rec.reason}`
1656
+ }
1657
+ return formatPerformanceRegistry(registry)
1658
+ },
1659
+ })
1660
+
1603
1661
  registerTool({
1604
1662
  name: 'omni_mission_run',
1605
1663
  description: 'Run a Mission Planner loop with real subagents: Observe → Think → Act → Replan until completed or maxSteps.',
@@ -1,12 +1,17 @@
1
1
  import test from 'node:test'
2
2
  import assert from 'node:assert/strict'
3
+ import fs from 'node:fs'
4
+ import os from 'node:os'
5
+ import path from 'node:path'
3
6
 
4
7
  import {
5
8
  createPerformanceRegistry,
6
9
  evaluateProviderValue,
7
10
  formatPerformanceRegistry,
11
+ loadPerformanceRegistry,
8
12
  recommendDemotion,
9
13
  recordProvisionOutcome,
14
+ savePerformanceRegistry,
10
15
  } from '../src/capability-performance.mjs'
11
16
 
12
17
  test('recordProvisionOutcome stores before/after metrics', () => {
@@ -62,3 +67,18 @@ test('formatPerformanceRegistry renders entries', () => {
62
67
  registry = recordProvisionOutcome(registry, 'p', { successBefore: 0.5, successAfter: 0.9 })
63
68
  assert.match(formatPerformanceRegistry(registry), /p/)
64
69
  })
70
+
71
+ test('loadPerformanceRegistry and savePerformanceRegistry persist outcomes', () => {
72
+ const cwd = fs.mkdtempSync(path.join(os.tmpdir(), 'cap-perf-'))
73
+ try {
74
+ let registry = createPerformanceRegistry()
75
+ registry = recordProvisionOutcome(registry, 'plugin-x', { successBefore: 0.7, successAfter: 0.9 })
76
+ const file = savePerformanceRegistry(cwd, registry)
77
+ assert.ok(fs.existsSync(file))
78
+ const loaded = loadPerformanceRegistry(cwd)
79
+ assert.ok(loaded.providers['plugin-x'])
80
+ assert.equal(evaluateProviderValue(loaded.providers['plugin-x']).label, 'high')
81
+ } finally {
82
+ fs.rmSync(cwd, { recursive: true, force: true })
83
+ }
84
+ })