@qvac/harness 1.0.0-rc.2 → 1.0.0-rc.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.
Files changed (58) hide show
  1. package/README.md +12 -12
  2. package/bench/README.md +94 -0
  3. package/bench/bfcl/checker.ts +313 -0
  4. package/bench/bfcl/data.ts +93 -0
  5. package/bench/bfcl/observe.ts +93 -0
  6. package/bench/bfcl/run.ts +213 -0
  7. package/bench/bfcl/tools.ts +72 -0
  8. package/bench/bridge/bridge.ts +392 -0
  9. package/bench/bridge/openai.ts +150 -0
  10. package/bench/bridge/python/qvac_bench/__init__.py +3 -0
  11. package/bench/bridge/python/qvac_bench/airline.py +42 -0
  12. package/bench/bridge/python/qvac_bench/approval.py +26 -0
  13. package/bench/bridge/python/qvac_bench/bfcl_multi_turn.py +152 -0
  14. package/bench/bridge/python/qvac_bench/client.py +88 -0
  15. package/bench/bridge/python/qvac_bench/harbor_agent.py +85 -0
  16. package/bench/bridge/python/qvac_bench/session.py +107 -0
  17. package/bench/bridge/python/qvac_bench/speed.py +30 -0
  18. package/bench/bridge/python/qvac_bench/tau2_agent.py +106 -0
  19. package/bench/bridge/python/qvac_bench/tools.py +11 -0
  20. package/bench/bridge/python/run_bfcl_multi_turn.py +95 -0
  21. package/bench/bridge/python/run_tau2.py +150 -0
  22. package/bench/bridge/python/smoke.py +47 -0
  23. package/bench/bridge/python/test_airline.py +28 -0
  24. package/bench/bridge/python/test_approval.py +57 -0
  25. package/bench/bridge/python/test_bfcl_multi_turn.py +185 -0
  26. package/bench/bridge/python/test_harbor_agent.py +107 -0
  27. package/bench/bridge/serve.ts +52 -0
  28. package/bench/bridge/transcript.ts +52 -0
  29. package/bench/bun-tsconfig.json +15 -0
  30. package/bench/cpu-main.mjs +216 -0
  31. package/bench/cpu.ts +457 -0
  32. package/bench/evidence/2026-09-28-review15.md +225 -0
  33. package/bench/evidence/redact-bun1.3.14.json +92 -0
  34. package/bench/evidence/redact-node24.11.json +92 -0
  35. package/bench/graph-metrics.ts +43 -0
  36. package/bench/harness.ts +73 -0
  37. package/bench/issue129-matrix.mjs +722 -0
  38. package/bench/redact-adversarial.ts +256 -0
  39. package/bench/repeat-cpu.mjs +281 -0
  40. package/bench/report.ts +1075 -0
  41. package/bench/skill-eval/harness.ts +30 -0
  42. package/bench/skill-eval/laws.ts +37 -0
  43. package/bench/skill-eval/mermaid/client.ts +132 -0
  44. package/bench/skill-eval/mermaid/validate.mjs +115 -0
  45. package/bench/skill-eval/pack.ts +61 -0
  46. package/bench/skill-eval/packs/diagrams/cases.ts +281 -0
  47. package/bench/skill-eval/packs/diagrams/index.ts +50 -0
  48. package/bench/skill-eval/packs/diagrams/score.ts +74 -0
  49. package/bench/skill-eval/packs/index.ts +5 -0
  50. package/bench/skill-eval/packs/weather/cases.ts +279 -0
  51. package/bench/skill-eval/packs/weather/fixtures/wttr.json +566 -0
  52. package/bench/skill-eval/packs/weather/fixtures.ts +84 -0
  53. package/bench/skill-eval/packs/weather/index.ts +55 -0
  54. package/bench/skill-eval/packs/weather/score.ts +92 -0
  55. package/bench/skill-eval/report.ts +194 -0
  56. package/bench/skill-eval/run.ts +316 -0
  57. package/bench/speed.ts +80 -0
  58. package/package.json +4 -13
@@ -0,0 +1,92 @@
1
+ {
2
+ "runtime": "bun",
3
+ "version": "1.3.14",
4
+ "adapter": "completion() production redactor + schema registration + awaited host onStep",
5
+ "warmups": 1,
6
+ "results": [
7
+ {
8
+ "pattern": "prose",
9
+ "bytes": 100000,
10
+ "samples": 3,
11
+ "medianCpuMs": 40.991,
12
+ "maxCpuMs": 50.851
13
+ },
14
+ {
15
+ "pattern": "prose",
16
+ "bytes": 500000,
17
+ "samples": 3,
18
+ "medianCpuMs": 92.336,
19
+ "maxCpuMs": 95.606
20
+ },
21
+ {
22
+ "pattern": "prose",
23
+ "bytes": 1000000,
24
+ "samples": 3,
25
+ "medianCpuMs": 178.887,
26
+ "maxCpuMs": 179.778
27
+ },
28
+ {
29
+ "pattern": "jwtPrefix",
30
+ "bytes": 100000,
31
+ "samples": 3,
32
+ "medianCpuMs": 26.832,
33
+ "maxCpuMs": 29.781
34
+ },
35
+ {
36
+ "pattern": "jwtPrefix",
37
+ "bytes": 500000,
38
+ "samples": 3,
39
+ "medianCpuMs": 100.205,
40
+ "maxCpuMs": 103.24
41
+ },
42
+ {
43
+ "pattern": "jwtPrefix",
44
+ "bytes": 1000000,
45
+ "samples": 3,
46
+ "medianCpuMs": 171.772,
47
+ "maxCpuMs": 194.774
48
+ },
49
+ {
50
+ "pattern": "markup",
51
+ "bytes": 100000,
52
+ "samples": 3,
53
+ "medianCpuMs": 28.644,
54
+ "maxCpuMs": 28.959
55
+ },
56
+ {
57
+ "pattern": "markup",
58
+ "bytes": 500000,
59
+ "samples": 3,
60
+ "medianCpuMs": 107.861,
61
+ "maxCpuMs": 110.075
62
+ },
63
+ {
64
+ "pattern": "markup",
65
+ "bytes": 1000000,
66
+ "samples": 3,
67
+ "medianCpuMs": 196.109,
68
+ "maxCpuMs": 204.343
69
+ },
70
+ {
71
+ "pattern": "punctuation",
72
+ "bytes": 100000,
73
+ "samples": 3,
74
+ "medianCpuMs": 54.76,
75
+ "maxCpuMs": 56.285
76
+ },
77
+ {
78
+ "pattern": "punctuation",
79
+ "bytes": 500000,
80
+ "samples": 3,
81
+ "medianCpuMs": 223.607,
82
+ "maxCpuMs": 224.801
83
+ },
84
+ {
85
+ "pattern": "punctuation",
86
+ "bytes": 1000000,
87
+ "samples": 3,
88
+ "medianCpuMs": 438.701,
89
+ "maxCpuMs": 447.244
90
+ }
91
+ ]
92
+ }
@@ -0,0 +1,92 @@
1
+ {
2
+ "runtime": "node",
3
+ "version": "v24.11.0",
4
+ "adapter": "completion() production redactor + schema registration + awaited host onStep",
5
+ "warmups": 1,
6
+ "results": [
7
+ {
8
+ "pattern": "prose",
9
+ "bytes": 100000,
10
+ "samples": 3,
11
+ "medianCpuMs": 36.119,
12
+ "maxCpuMs": 37.424
13
+ },
14
+ {
15
+ "pattern": "prose",
16
+ "bytes": 500000,
17
+ "samples": 3,
18
+ "medianCpuMs": 113.27,
19
+ "maxCpuMs": 124.599
20
+ },
21
+ {
22
+ "pattern": "prose",
23
+ "bytes": 1000000,
24
+ "samples": 3,
25
+ "medianCpuMs": 223.539,
26
+ "maxCpuMs": 248.6
27
+ },
28
+ {
29
+ "pattern": "jwtPrefix",
30
+ "bytes": 100000,
31
+ "samples": 3,
32
+ "medianCpuMs": 32.039,
33
+ "maxCpuMs": 36.487
34
+ },
35
+ {
36
+ "pattern": "jwtPrefix",
37
+ "bytes": 500000,
38
+ "samples": 3,
39
+ "medianCpuMs": 116.359,
40
+ "maxCpuMs": 128.674
41
+ },
42
+ {
43
+ "pattern": "jwtPrefix",
44
+ "bytes": 1000000,
45
+ "samples": 3,
46
+ "medianCpuMs": 218.697,
47
+ "maxCpuMs": 220.754
48
+ },
49
+ {
50
+ "pattern": "markup",
51
+ "bytes": 100000,
52
+ "samples": 3,
53
+ "medianCpuMs": 31.789,
54
+ "maxCpuMs": 38.346
55
+ },
56
+ {
57
+ "pattern": "markup",
58
+ "bytes": 500000,
59
+ "samples": 3,
60
+ "medianCpuMs": 125.848,
61
+ "maxCpuMs": 148.413
62
+ },
63
+ {
64
+ "pattern": "markup",
65
+ "bytes": 1000000,
66
+ "samples": 3,
67
+ "medianCpuMs": 250.558,
68
+ "maxCpuMs": 256.972
69
+ },
70
+ {
71
+ "pattern": "punctuation",
72
+ "bytes": 100000,
73
+ "samples": 3,
74
+ "medianCpuMs": 33.315,
75
+ "maxCpuMs": 37.608
76
+ },
77
+ {
78
+ "pattern": "punctuation",
79
+ "bytes": 500000,
80
+ "samples": 3,
81
+ "medianCpuMs": 141.881,
82
+ "maxCpuMs": 154.584
83
+ },
84
+ {
85
+ "pattern": "punctuation",
86
+ "bytes": 1000000,
87
+ "samples": 3,
88
+ "medianCpuMs": 282.219,
89
+ "maxCpuMs": 282.905
90
+ }
91
+ ]
92
+ }
@@ -0,0 +1,43 @@
1
+ import { CompletionMachine } from '../lib/machine/index.ts'
2
+
3
+ interface Transition {
4
+ target?: string[]
5
+ }
6
+ interface Node {
7
+ type: string
8
+ states?: Record<string, Node>
9
+ on?: Record<string, Transition[]>
10
+ onDone?: Transition[]
11
+ onError?: Transition[]
12
+ always?: Transition[]
13
+ after?: Record<string, Transition[]> | Transition[]
14
+ }
15
+
16
+ interface Metrics {
17
+ states: number
18
+ transitions: number
19
+ }
20
+ interface CountOptions {
21
+ root?: boolean
22
+ }
23
+
24
+ function count(node: Node, { root = true }: CountOptions = {}): Metrics {
25
+ const transitions = [
26
+ ...Object.values(node.on ?? {}).flat(),
27
+ ...(node.onDone ?? []),
28
+ ...(node.onError ?? []),
29
+ ...(node.always ?? []),
30
+ ...(Array.isArray(node.after) ? node.after : Object.values(node.after ?? {}).flat())
31
+ ]
32
+ const nested = Object.values(node.states ?? {}).map((child) => count(child, { root: false }))
33
+
34
+ return {
35
+ states: (root || node.type === 'history' ? 0 : 1) + nested.reduce((n, x) => n + x.states, 0),
36
+ transitions: transitions.length + nested.reduce((n, x) => n + x.transitions, 0)
37
+ }
38
+ }
39
+
40
+ // lunte-disable-next-line qvac/no-as-cast -- xstate root nodes are untyped.
41
+ const metrics = count(CompletionMachine.create().root as Node)
42
+ console.log(`states: ${metrics.states}`)
43
+ console.log(`transitions: ${metrics.transitions}`)
@@ -0,0 +1,73 @@
1
+ import process from 'process'
2
+ import { Harness, loadSkillCatalog } from '../index.ts'
3
+ import { ObsidianRoute } from '../plugins/obsidian/index.ts'
4
+ import { Python } from '../plugins/python/index.ts'
5
+ import { TranslationPlugin } from '../plugins/translation/index.ts'
6
+ import { configureSdkStorage } from '../lib/sdk-storage.ts'
7
+ import { MODEL_CACHE_PATH_ENV, resolveStorage } from '../lib/storage.ts'
8
+ import { Tools } from '../lib/tools/index.ts'
9
+ import { Weather } from '../plugins/weather/index.ts'
10
+ import { WebSearchPlugin } from '../plugins/web-search/index.ts'
11
+ import { McpPlugin } from '../plugins/mcp/index.ts'
12
+ import { CodeMode } from '../plugins/code-mode/index.ts'
13
+ import { QuickJs } from '../plugins/quickjs/index.ts'
14
+ import type { HarnessPlugin } from '../lib/plugins/index.ts'
15
+ import type { CredentialStoreFn } from '../lib/tools/skills/index.ts'
16
+
17
+ export interface BenchHarnessOptions {
18
+ readonly root: string
19
+ readonly skillsDir: string
20
+ readonly contextSize?: number | undefined
21
+ }
22
+
23
+ export async function openBenchHarness(options: BenchHarnessOptions): Promise<Harness> {
24
+ const storage = resolveStorage('dev', {
25
+ root: options.root,
26
+ models: process.env[MODEL_CACHE_PATH_ENV]
27
+ })
28
+ configureSdkStorage(storage.sdk)
29
+ process.env.QVAC_PYODIDE_CACHE_DIR ??= `${storage.sdk.home}/pyodide-cache`
30
+
31
+ const { skillsDir } = options
32
+ let harness: Harness | null = null
33
+ const skillCatalog = await loadSkillCatalog(skillsDir)
34
+ const credentialStore: CredentialStoreFn = (key, ctx) =>
35
+ harness?.resolveCredential(key, ctx) ?? null
36
+ const tools = Tools.product({
37
+ sdkHome: storage.sdk.home,
38
+ skillsDir,
39
+ skillCatalog,
40
+ credentialStore
41
+ })
42
+ harness = new Harness({
43
+ tools,
44
+ exec: true,
45
+ skillsDir,
46
+ sdkHome: storage.sdk.home,
47
+ modelsDir: storage.sdk.models,
48
+ contextSize: options.contextSize,
49
+ plugins: [
50
+ new Python(),
51
+ new ObsidianRoute({ credentialStore }),
52
+ new Weather({ read: ['weather_lookup'] }),
53
+ new TranslationPlugin(),
54
+ new WebSearchPlugin({ read: ['web_search'] }),
55
+ new McpPlugin({ generic: true, skillCatalog, credentialStore, read: ['mcp_call'] }),
56
+ ...codeModePlugins()
57
+ ]
58
+ })
59
+ await harness.ready()
60
+
61
+ return harness
62
+ }
63
+
64
+ // QVAC_BENCH_CODE_MODE=1 adds run_code, which the sidecar does not compose
65
+ function codeModePlugins(): HarnessPlugin[] {
66
+ if (process.env.QVAC_BENCH_CODE_MODE !== '1') {
67
+ return []
68
+ }
69
+
70
+ const quickjs = new QuickJs()
71
+
72
+ return [quickjs, new CodeMode({ quickjs, read: ['run_code'] })]
73
+ }