@agentdeck/bridge 0.2.1 → 0.2.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/assets/fonts/IBMPlexSans-Bold.ttf +0 -0
- package/assets/fonts/IBMPlexSans-Regular.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Bold.ttf +0 -0
- package/assets/fonts/JetBrainsMono-Regular.ttf +0 -0
- package/assets/fonts/LICENSES.md +22 -0
- package/dist/adapters/claude-code.d.ts +6 -0
- package/dist/adapters/claude-code.d.ts.map +1 -1
- package/dist/adapters/claude-code.js +8 -0
- package/dist/adapters/claude-code.js.map +1 -1
- package/dist/adapters/openclaw.d.ts +24 -0
- package/dist/adapters/openclaw.d.ts.map +1 -1
- package/dist/adapters/openclaw.js +291 -35
- package/dist/adapters/openclaw.js.map +1 -1
- package/dist/adapters/opencode-adapter.d.ts +59 -0
- package/dist/adapters/opencode-adapter.d.ts.map +1 -1
- package/dist/adapters/opencode-adapter.js +297 -35
- package/dist/adapters/opencode-adapter.js.map +1 -1
- package/dist/adb-reverse.d.ts +1 -1
- package/dist/adb-reverse.js +1 -1
- package/dist/antigravity-local.d.ts +1 -0
- package/dist/antigravity-local.d.ts.map +1 -1
- package/dist/antigravity-local.js +33 -0
- package/dist/antigravity-local.js.map +1 -1
- package/dist/apme/adapters/claude-hook.d.ts.map +1 -1
- package/dist/apme/adapters/claude-hook.js +5 -0
- package/dist/apme/adapters/claude-hook.js.map +1 -1
- package/dist/apme/adapters/codex-hook.d.ts +17 -0
- package/dist/apme/adapters/codex-hook.d.ts.map +1 -0
- package/dist/apme/adapters/codex-hook.js +95 -0
- package/dist/apme/adapters/codex-hook.js.map +1 -0
- package/dist/apme/adapters/codex-turn-manager.d.ts +86 -0
- package/dist/apme/adapters/codex-turn-manager.d.ts.map +1 -0
- package/dist/apme/adapters/codex-turn-manager.js +496 -0
- package/dist/apme/adapters/codex-turn-manager.js.map +1 -0
- package/dist/apme/adapters/openclaw-hook.d.ts +99 -0
- package/dist/apme/adapters/openclaw-hook.d.ts.map +1 -0
- package/dist/apme/adapters/openclaw-hook.js +234 -0
- package/dist/apme/adapters/openclaw-hook.js.map +1 -0
- package/dist/apme/adapters/opencode-hook.d.ts +56 -0
- package/dist/apme/adapters/opencode-hook.d.ts.map +1 -0
- package/dist/apme/adapters/opencode-hook.js +182 -0
- package/dist/apme/adapters/opencode-hook.js.map +1 -0
- package/dist/apme/adapters/timeline.d.ts.map +1 -1
- package/dist/apme/adapters/timeline.js +6 -1
- package/dist/apme/adapters/timeline.js.map +1 -1
- package/dist/apme/antigravity-transcript.d.ts +18 -0
- package/dist/apme/antigravity-transcript.d.ts.map +1 -0
- package/dist/apme/antigravity-transcript.js +94 -0
- package/dist/apme/antigravity-transcript.js.map +1 -0
- package/dist/apme/classify-turn.d.ts +13 -0
- package/dist/apme/classify-turn.d.ts.map +1 -0
- package/dist/apme/classify-turn.js +49 -0
- package/dist/apme/classify-turn.js.map +1 -0
- package/dist/apme/claude-transcript-reader.d.ts +10 -0
- package/dist/apme/claude-transcript-reader.d.ts.map +1 -1
- package/dist/apme/claude-transcript-reader.js +35 -0
- package/dist/apme/claude-transcript-reader.js.map +1 -1
- package/dist/apme/collector.d.ts +129 -6
- package/dist/apme/collector.d.ts.map +1 -1
- package/dist/apme/collector.js +470 -23
- package/dist/apme/collector.js.map +1 -1
- package/dist/apme/dashboard-html.d.ts.map +1 -1
- package/dist/apme/dashboard-html.js +87 -11
- package/dist/apme/dashboard-html.js.map +1 -1
- package/dist/apme/http.d.ts.map +1 -1
- package/dist/apme/http.js +43 -6
- package/dist/apme/http.js.map +1 -1
- package/dist/apme/index.d.ts +26 -5
- package/dist/apme/index.d.ts.map +1 -1
- package/dist/apme/index.js +135 -9
- package/dist/apme/index.js.map +1 -1
- package/dist/apme/pareto.d.ts +39 -0
- package/dist/apme/pareto.d.ts.map +1 -0
- package/dist/apme/pareto.js +59 -0
- package/dist/apme/pareto.js.map +1 -0
- package/dist/apme/recommend.d.ts +3 -0
- package/dist/apme/recommend.d.ts.map +1 -1
- package/dist/apme/recommend.js +43 -1
- package/dist/apme/recommend.js.map +1 -1
- package/dist/apme/runner.d.ts +92 -4
- package/dist/apme/runner.d.ts.map +1 -1
- package/dist/apme/runner.js +586 -70
- package/dist/apme/runner.js.map +1 -1
- package/dist/apme/sample-to-timeline.d.ts +26 -0
- package/dist/apme/sample-to-timeline.d.ts.map +1 -0
- package/dist/apme/sample-to-timeline.js +95 -0
- package/dist/apme/sample-to-timeline.js.map +1 -0
- package/dist/apme/scorers/index.d.ts +47 -0
- package/dist/apme/scorers/index.d.ts.map +1 -0
- package/dist/apme/scorers/index.js +96 -0
- package/dist/apme/scorers/index.js.map +1 -0
- package/dist/apme/settings.d.ts +14 -10
- package/dist/apme/settings.d.ts.map +1 -1
- package/dist/apme/settings.js +34 -8
- package/dist/apme/settings.js.map +1 -1
- package/dist/apme/store.d.ts +33 -1
- package/dist/apme/store.d.ts.map +1 -1
- package/dist/apme/store.js +334 -25
- package/dist/apme/store.js.map +1 -1
- package/dist/awaiting-overlay.d.ts +99 -0
- package/dist/awaiting-overlay.d.ts.map +1 -0
- package/dist/awaiting-overlay.js +148 -0
- package/dist/awaiting-overlay.js.map +1 -0
- package/dist/ble-sync-spawn.d.ts +63 -0
- package/dist/ble-sync-spawn.d.ts.map +1 -0
- package/dist/ble-sync-spawn.js +196 -0
- package/dist/ble-sync-spawn.js.map +1 -0
- package/dist/bridge-core.d.ts +24 -1
- package/dist/bridge-core.d.ts.map +1 -1
- package/dist/bridge-core.js +157 -24
- package/dist/bridge-core.js.map +1 -1
- package/dist/broadcast.d.ts +3 -0
- package/dist/broadcast.d.ts.map +1 -0
- package/dist/broadcast.js +122 -0
- package/dist/broadcast.js.map +1 -0
- package/dist/check-deps.d.ts.map +1 -1
- package/dist/check-deps.js +25 -9
- package/dist/check-deps.js.map +1 -1
- package/dist/cli.d.ts +15 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +1025 -94
- package/dist/cli.js.map +1 -1
- package/dist/codex-auth.d.ts +21 -0
- package/dist/codex-auth.d.ts.map +1 -1
- package/dist/codex-auth.js +52 -1
- package/dist/codex-auth.js.map +1 -1
- package/dist/codex-output-parser.d.ts +8 -0
- package/dist/codex-output-parser.d.ts.map +1 -1
- package/dist/codex-output-parser.js +110 -25
- package/dist/codex-output-parser.js.map +1 -1
- package/dist/codex-rate-limits.d.ts +16 -0
- package/dist/codex-rate-limits.d.ts.map +1 -0
- package/dist/codex-rate-limits.js +197 -0
- package/dist/codex-rate-limits.js.map +1 -0
- package/dist/codex-rollout-response.d.ts +31 -0
- package/dist/codex-rollout-response.d.ts.map +1 -0
- package/dist/codex-rollout-response.js +135 -0
- package/dist/codex-rollout-response.js.map +1 -0
- package/dist/daemon-server.d.ts +85 -0
- package/dist/daemon-server.d.ts.map +1 -1
- package/dist/daemon-server.js +1627 -159
- package/dist/daemon-server.js.map +1 -1
- package/dist/daemon.js +15 -6
- package/dist/daemon.js.map +1 -1
- package/dist/display-dim.d.ts +9 -0
- package/dist/display-dim.d.ts.map +1 -0
- package/dist/display-dim.js +53 -0
- package/dist/display-dim.js.map +1 -0
- package/dist/display-monitor.d.ts +15 -2
- package/dist/display-monitor.d.ts.map +1 -1
- package/dist/display-monitor.js +104 -26
- package/dist/display-monitor.js.map +1 -1
- package/dist/esp32-serial.d.ts +160 -1
- package/dist/esp32-serial.d.ts.map +1 -1
- package/dist/esp32-serial.js +950 -153
- package/dist/esp32-serial.js.map +1 -1
- package/dist/fallback-task-timeline.d.ts +42 -0
- package/dist/fallback-task-timeline.d.ts.map +1 -0
- package/dist/fallback-task-timeline.js +112 -0
- package/dist/fallback-task-timeline.js.map +1 -0
- package/dist/foundation-models-helper.d.ts +11 -0
- package/dist/foundation-models-helper.d.ts.map +1 -0
- package/dist/foundation-models-helper.js +241 -0
- package/dist/foundation-models-helper.js.map +1 -0
- package/dist/hook-migration.js +1 -1
- package/dist/hook-migration.js.map +1 -1
- package/dist/hook-server.d.ts +2 -3
- package/dist/hook-server.d.ts.map +1 -1
- package/dist/hook-server.js +22 -10
- package/dist/hook-server.js.map +1 -1
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts +33 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.js +164 -0
- package/dist/idotmatrix/idotmatrix-daemon-sync.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts +18 -0
- package/dist/idotmatrix/idotmatrix-discover.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-discover.js +85 -0
- package/dist/idotmatrix/idotmatrix-discover.js.map +1 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts +20 -0
- package/dist/idotmatrix/idotmatrix-settings.d.ts.map +1 -0
- package/dist/idotmatrix/idotmatrix-settings.js +57 -0
- package/dist/idotmatrix/idotmatrix-settings.js.map +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +215 -179
- package/dist/index.js.map +1 -1
- package/dist/log-stream.d.ts +15 -16
- package/dist/log-stream.d.ts.map +1 -1
- package/dist/log-stream.js +18 -96
- package/dist/log-stream.js.map +1 -1
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +12 -3
- package/dist/logger.js.map +1 -1
- package/dist/mdns.d.ts +17 -0
- package/dist/mdns.d.ts.map +1 -1
- package/dist/mdns.js +52 -18
- package/dist/mdns.js.map +1 -1
- package/dist/modules/adb-module.d.ts +1 -1
- package/dist/modules/adb-module.d.ts.map +1 -1
- package/dist/modules/adb-module.js +4 -3
- package/dist/modules/adb-module.js.map +1 -1
- package/dist/modules/broadcast-module.d.ts +17 -0
- package/dist/modules/broadcast-module.d.ts.map +1 -0
- package/dist/modules/broadcast-module.js +26 -0
- package/dist/modules/broadcast-module.js.map +1 -0
- package/dist/modules/idotmatrix-module.d.ts +9 -0
- package/dist/modules/idotmatrix-module.d.ts.map +1 -0
- package/dist/modules/idotmatrix-module.js +46 -0
- package/dist/modules/idotmatrix-module.js.map +1 -0
- package/dist/modules/index.d.ts +3 -1
- package/dist/modules/index.d.ts.map +1 -1
- package/dist/modules/index.js +9 -3
- package/dist/modules/index.js.map +1 -1
- package/dist/modules/pixoo-module.d.ts.map +1 -1
- package/dist/modules/pixoo-module.js +14 -4
- package/dist/modules/pixoo-module.js.map +1 -1
- package/dist/modules/serial-module.d.ts +4 -0
- package/dist/modules/serial-module.d.ts.map +1 -1
- package/dist/modules/serial-module.js +14 -12
- package/dist/modules/serial-module.js.map +1 -1
- package/dist/modules/timebox-module.d.ts +9 -0
- package/dist/modules/timebox-module.d.ts.map +1 -0
- package/dist/modules/timebox-module.js +46 -0
- package/dist/modules/timebox-module.js.map +1 -0
- package/dist/modules/types.d.ts +4 -2
- package/dist/modules/types.d.ts.map +1 -1
- package/dist/openclaw-session.d.ts +18 -0
- package/dist/openclaw-session.d.ts.map +1 -0
- package/dist/openclaw-session.js +34 -0
- package/dist/openclaw-session.js.map +1 -0
- package/dist/output-parser.d.ts +30 -0
- package/dist/output-parser.d.ts.map +1 -1
- package/dist/output-parser.js +125 -9
- package/dist/output-parser.js.map +1 -1
- package/dist/passive-observer.d.ts +26 -0
- package/dist/passive-observer.d.ts.map +1 -1
- package/dist/passive-observer.js +258 -49
- package/dist/passive-observer.js.map +1 -1
- package/dist/permission-resolver.d.ts +47 -0
- package/dist/permission-resolver.d.ts.map +1 -0
- package/dist/permission-resolver.js +103 -0
- package/dist/permission-resolver.js.map +1 -0
- package/dist/pixoo/micro-glyphs.d.ts +49 -0
- package/dist/pixoo/micro-glyphs.d.ts.map +1 -0
- package/dist/pixoo/micro-glyphs.js +276 -0
- package/dist/pixoo/micro-glyphs.js.map +1 -0
- package/dist/pixoo/pixoo-bridge.d.ts +2 -2
- package/dist/pixoo/pixoo-bridge.d.ts.map +1 -1
- package/dist/pixoo/pixoo-bridge.js +93 -25
- package/dist/pixoo/pixoo-bridge.js.map +1 -1
- package/dist/pixoo/pixoo-camera.d.ts +19 -3
- package/dist/pixoo/pixoo-camera.d.ts.map +1 -1
- package/dist/pixoo/pixoo-camera.js +62 -27
- package/dist/pixoo/pixoo-camera.js.map +1 -1
- package/dist/pixoo/pixoo-client.d.ts +13 -3
- package/dist/pixoo/pixoo-client.d.ts.map +1 -1
- package/dist/pixoo/pixoo-client.js +51 -22
- package/dist/pixoo/pixoo-client.js.map +1 -1
- package/dist/pixoo/pixoo-discover.d.ts +37 -0
- package/dist/pixoo/pixoo-discover.d.ts.map +1 -0
- package/dist/pixoo/pixoo-discover.js +105 -0
- package/dist/pixoo/pixoo-discover.js.map +1 -0
- package/dist/pixoo/pixoo-renderer.d.ts +8 -3
- package/dist/pixoo/pixoo-renderer.d.ts.map +1 -1
- package/dist/pixoo/pixoo-renderer.js +189 -60
- package/dist/pixoo/pixoo-renderer.js.map +1 -1
- package/dist/pixoo/pixoo-settings.d.ts +6 -0
- package/dist/pixoo/pixoo-settings.d.ts.map +1 -1
- package/dist/pixoo/pixoo-settings.js +9 -0
- package/dist/pixoo/pixoo-settings.js.map +1 -1
- package/dist/pixoo/pixoo-sprites.d.ts +60 -11
- package/dist/pixoo/pixoo-sprites.d.ts.map +1 -1
- package/dist/pixoo/pixoo-sprites.js +512 -209
- package/dist/pixoo/pixoo-sprites.js.map +1 -1
- package/dist/pty-manager.d.ts.map +1 -1
- package/dist/pty-manager.js +8 -2
- package/dist/pty-manager.js.map +1 -1
- package/dist/session-activity.d.ts +14 -0
- package/dist/session-activity.d.ts.map +1 -0
- package/dist/session-activity.js +160 -0
- package/dist/session-activity.js.map +1 -0
- package/dist/session-aggregator.d.ts +17 -0
- package/dist/session-aggregator.d.ts.map +1 -1
- package/dist/session-aggregator.js +48 -9
- package/dist/session-aggregator.js.map +1 -1
- package/dist/session-registry.d.ts +71 -3
- package/dist/session-registry.d.ts.map +1 -1
- package/dist/session-registry.js +137 -8
- package/dist/session-registry.js.map +1 -1
- package/dist/session-timeline-relay.d.ts.map +1 -1
- package/dist/session-timeline-relay.js +13 -4
- package/dist/session-timeline-relay.js.map +1 -1
- package/dist/session-transcript-timeline.d.ts +49 -0
- package/dist/session-transcript-timeline.d.ts.map +1 -0
- package/dist/session-transcript-timeline.js +276 -0
- package/dist/session-transcript-timeline.js.map +1 -0
- package/dist/state-machine.d.ts +6 -1
- package/dist/state-machine.d.ts.map +1 -1
- package/dist/state-machine.js +86 -28
- package/dist/state-machine.js.map +1 -1
- package/dist/timebox/timebox-daemon-sync.d.ts +19 -0
- package/dist/timebox/timebox-daemon-sync.d.ts.map +1 -0
- package/dist/timebox/timebox-daemon-sync.js +135 -0
- package/dist/timebox/timebox-daemon-sync.js.map +1 -0
- package/dist/timebox/timebox-discover.d.ts +19 -0
- package/dist/timebox/timebox-discover.d.ts.map +1 -0
- package/dist/timebox/timebox-discover.js +87 -0
- package/dist/timebox/timebox-discover.js.map +1 -0
- package/dist/timebox/timebox-settings.d.ts +32 -0
- package/dist/timebox/timebox-settings.d.ts.map +1 -0
- package/dist/timebox/timebox-settings.js +80 -0
- package/dist/timebox/timebox-settings.js.map +1 -0
- package/dist/timeline-store.d.ts +63 -3
- package/dist/timeline-store.d.ts.map +1 -1
- package/dist/timeline-store.js +292 -14
- package/dist/timeline-store.js.map +1 -1
- package/dist/timeline-summarizer.d.ts.map +1 -1
- package/dist/timeline-summarizer.js +29 -5
- package/dist/timeline-summarizer.js.map +1 -1
- package/dist/tui/ansi.d.ts +0 -4
- package/dist/tui/ansi.d.ts.map +1 -1
- package/dist/tui/ansi.js +14 -7
- package/dist/tui/ansi.js.map +1 -1
- package/dist/tui/dashboard.d.ts +1 -0
- package/dist/tui/dashboard.d.ts.map +1 -1
- package/dist/tui/dashboard.js +24 -7
- package/dist/tui/dashboard.js.map +1 -1
- package/dist/tui/renderer.d.ts +36 -0
- package/dist/tui/renderer.d.ts.map +1 -1
- package/dist/tui/renderer.js +303 -119
- package/dist/tui/renderer.js.map +1 -1
- package/dist/tui/terrarium.d.ts.map +1 -1
- package/dist/tui/terrarium.js +37 -49
- package/dist/tui/terrarium.js.map +1 -1
- package/dist/types.d.ts +2 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +2 -2
- package/dist/types.js.map +1 -1
- package/dist/usage-api.d.ts.map +1 -1
- package/dist/usage-api.js +7 -1
- package/dist/usage-api.js.map +1 -1
- package/dist/usage-event.d.ts +10 -3
- package/dist/usage-event.d.ts.map +1 -1
- package/dist/usage-event.js +74 -12
- package/dist/usage-event.js.map +1 -1
- package/dist/utility-proxy.d.ts.map +1 -1
- package/dist/utility-proxy.js +8 -0
- package/dist/utility-proxy.js.map +1 -1
- package/dist/utils/project-name.d.ts +3 -0
- package/dist/utils/project-name.d.ts.map +1 -1
- package/dist/utils/project-name.js +44 -2
- package/dist/utils/project-name.js.map +1 -1
- package/dist/windows-service.d.ts +26 -0
- package/dist/windows-service.d.ts.map +1 -0
- package/dist/windows-service.js +145 -0
- package/dist/windows-service.js.map +1 -0
- package/dist/ws-server.d.ts +22 -1
- package/dist/ws-server.d.ts.map +1 -1
- package/dist/ws-server.js +89 -4
- package/dist/ws-server.js.map +1 -1
- package/fm-helper/AgentDeckFMHelper.swift +112 -0
- package/package.json +9 -3
- package/scripts/build-fm-helper.mjs +26 -0
- package/LICENSE +0 -21
- package/dist/apme/tuner.d.ts +0 -64
- package/dist/apme/tuner.d.ts.map +0 -1
- package/dist/apme/tuner.js +0 -297
- package/dist/apme/tuner.js.map +0 -1
- package/dist/d200h/hid-protocol.d.ts +0 -62
- package/dist/d200h/hid-protocol.d.ts.map +0 -1
- package/dist/d200h/hid-protocol.js +0 -124
- package/dist/d200h/hid-protocol.js.map +0 -1
- package/dist/d200h/image-renderer.d.ts +0 -36
- package/dist/d200h/image-renderer.d.ts.map +0 -1
- package/dist/d200h/image-renderer.js +0 -487
- package/dist/d200h/image-renderer.js.map +0 -1
- package/dist/modules/d200h-module.d.ts +0 -43
- package/dist/modules/d200h-module.d.ts.map +0 -1
- package/dist/modules/d200h-module.js +0 -360
- package/dist/modules/d200h-module.js.map +0 -1
- package/dist/modules/d200h-renderer.d.ts +0 -7
- package/dist/modules/d200h-renderer.d.ts.map +0 -1
- package/dist/modules/d200h-renderer.js +0 -321
- package/dist/modules/d200h-renderer.js.map +0 -1
package/dist/apme/index.js
CHANGED
|
@@ -13,43 +13,164 @@
|
|
|
13
13
|
import { writeFileSync } from 'fs';
|
|
14
14
|
import { join } from 'path';
|
|
15
15
|
import { homedir } from 'os';
|
|
16
|
-
import {
|
|
16
|
+
import { logError } from '../logger.js';
|
|
17
17
|
import { ApmeStore } from './store.js';
|
|
18
18
|
import { apmeDashboardHtml } from './dashboard-html.js';
|
|
19
19
|
import { ApmeCollector } from './collector.js';
|
|
20
20
|
import { ApmeRunner } from './runner.js';
|
|
21
|
-
import { ApmeTuner } from './tuner.js';
|
|
22
21
|
import { ApmeHwSampler } from './hw-sampler.js';
|
|
23
22
|
import { ApmeRecommender } from './recommend.js';
|
|
23
|
+
import { sampleEventToTimeline } from './sample-to-timeline.js';
|
|
24
24
|
let singleton = null;
|
|
25
|
-
/** Initialize the APME subsystem. Returns null if the SQLite store can't open.
|
|
26
|
-
|
|
25
|
+
/** Initialize the APME subsystem. Returns null if the SQLite store can't open.
|
|
26
|
+
* When null, the failure reason is logged at ERROR level — silent disable was
|
|
27
|
+
* the dominant cause of multi-day data outages observed in user telemetry. */
|
|
28
|
+
export async function initApme(dbPath, opts = {}) {
|
|
27
29
|
if (singleton)
|
|
28
30
|
return singleton;
|
|
29
31
|
const store = new ApmeStore(dbPath);
|
|
30
32
|
const ok = await store.init();
|
|
31
33
|
if (!ok) {
|
|
32
|
-
|
|
34
|
+
logError(`APME disabled — ${store.lastInitError ?? 'unknown init failure'}. Agent runs will not be measured.`);
|
|
33
35
|
return null;
|
|
34
36
|
}
|
|
35
37
|
const hwSampler = new ApmeHwSampler();
|
|
36
38
|
const collector = new ApmeCollector(store, hwSampler);
|
|
37
39
|
const runner = new ApmeRunner(store);
|
|
38
|
-
const tuner = new ApmeTuner(store);
|
|
39
40
|
const recommender = new ApmeRecommender(store);
|
|
40
|
-
singleton = { store, collector, runner,
|
|
41
|
+
singleton = { store, collector, runner, hwSampler, recommender };
|
|
42
|
+
const emitTimeline = opts.emitTimeline;
|
|
43
|
+
// Task headers are DEFERRED (collector emits `task_start` only once a task
|
|
44
|
+
// proves itself multi-turn). Track which task ids actually reached the
|
|
45
|
+
// timeline so the async judge re-emit (`onTaskEvaluated`, below) can skip
|
|
46
|
+
// unpromoted single-turn tasks — otherwise it would insert an orphan
|
|
47
|
+
// `task_end` with a score badge under no header. `onTaskOpened` fires at the
|
|
48
|
+
// deferred promotion moment, so membership here == "header is on the timeline".
|
|
49
|
+
const promotedTaskIds = new Set();
|
|
41
50
|
// Wire task-level judge: whenever the collector closes a task (TodoWrite
|
|
42
51
|
// all-completed / /clear / session_end), enqueue a task_rollup judge call.
|
|
43
52
|
// Kept here — not in the collector constructor — so the collector has no
|
|
44
53
|
// hard dependency on the runner.
|
|
45
|
-
collector.onTaskClosed = ({ taskId, runId, boundarySignal, taskCategory }) => {
|
|
54
|
+
collector.onTaskClosed = ({ taskId, runId, sessionId, agentType, projectName, startedAt, endedAt, boundarySignal, taskCategory, timelineEmitted, }) => {
|
|
46
55
|
runner.enqueueTask({
|
|
47
56
|
runId,
|
|
48
57
|
taskId,
|
|
49
58
|
category: taskCategory ?? undefined,
|
|
50
59
|
boundarySignal,
|
|
51
60
|
});
|
|
61
|
+
// Gate the `task_end` row on the header having been emitted — an
|
|
62
|
+
// unpromoted single-turn task shows only its chat rows, never a bare
|
|
63
|
+
// "Task end" marker. The eval enqueue above runs regardless.
|
|
64
|
+
if (emitTimeline && timelineEmitted) {
|
|
65
|
+
const durationSec = Math.max(0, Math.round((endedAt - startedAt) / 1000));
|
|
66
|
+
const signalLabel = boundarySignal === 'todo_complete' ? 'TODO done'
|
|
67
|
+
: boundarySignal === 'clear' ? '/clear'
|
|
68
|
+
: boundarySignal === 'session_end' ? 'Session end'
|
|
69
|
+
: 'Task end';
|
|
70
|
+
emitTimeline({
|
|
71
|
+
ts: endedAt,
|
|
72
|
+
type: 'task_end',
|
|
73
|
+
raw: `${signalLabel} · ${durationSec}s`,
|
|
74
|
+
agentType: agentType ?? undefined,
|
|
75
|
+
projectName: projectName ?? undefined,
|
|
76
|
+
sessionId,
|
|
77
|
+
runId,
|
|
78
|
+
taskId,
|
|
79
|
+
boundarySignal,
|
|
80
|
+
startedAt,
|
|
81
|
+
endedAt,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
52
84
|
};
|
|
85
|
+
// Wire the SessionSample → Timeline projection. When enabled, the timeline
|
|
86
|
+
// is a projection of the canonical sample (one row per typed trajectory
|
|
87
|
+
// event), replacing display-time grouping + the race-sensitive dedup window.
|
|
88
|
+
if (emitTimeline && opts.projectSampleTimeline) {
|
|
89
|
+
const emitProjected = opts.emitProjectedTimeline ?? emitTimeline;
|
|
90
|
+
collector.onSampleEvent = ({ event, sessionId, runId, taskId, agentType, projectName }) => {
|
|
91
|
+
const entry = sampleEventToTimeline(event, { sessionId, runId, taskId, agentType, projectName });
|
|
92
|
+
if (entry)
|
|
93
|
+
emitProjected(entry);
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
// Wire task-start emission. The runner has no opinion on opens — only the
|
|
97
|
+
// dashboard does — so we keep this strictly local to the timeline path.
|
|
98
|
+
if (emitTimeline) {
|
|
99
|
+
collector.onTaskOpened = ({ taskId, runId, sessionId, agentType, projectName, taskIndex, startedAt, }) => {
|
|
100
|
+
promotedTaskIds.add(taskId);
|
|
101
|
+
emitTimeline({
|
|
102
|
+
ts: startedAt,
|
|
103
|
+
type: 'task_start',
|
|
104
|
+
raw: `Task ${taskIndex + 1}`,
|
|
105
|
+
agentType: agentType ?? undefined,
|
|
106
|
+
projectName: projectName ?? undefined,
|
|
107
|
+
sessionId,
|
|
108
|
+
runId,
|
|
109
|
+
taskId,
|
|
110
|
+
startedAt,
|
|
111
|
+
});
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
// Wire the mid-task completion milestone. TodoWrite-all-completed is a
|
|
115
|
+
// non-segmenting soft hint (fires ~18% of the time on Claude Code v2.1), so
|
|
116
|
+
// it must not split the task — but when it DOES fire it is a strong "the
|
|
117
|
+
// agent declared this chunk done" signal, and long sessions otherwise show
|
|
118
|
+
// no completion marks until /clear or session_end.
|
|
119
|
+
if (emitTimeline) {
|
|
120
|
+
collector.onTaskMilestone = ({ taskId, runId, sessionId, agentType, projectName, todoCount, at, }) => {
|
|
121
|
+
emitTimeline({
|
|
122
|
+
ts: at,
|
|
123
|
+
type: 'task_milestone',
|
|
124
|
+
raw: todoCount ? `Todos done (${todoCount})` : 'Todos done',
|
|
125
|
+
agentType: agentType ?? undefined,
|
|
126
|
+
projectName: projectName ?? undefined,
|
|
127
|
+
sessionId,
|
|
128
|
+
runId,
|
|
129
|
+
taskId,
|
|
130
|
+
});
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
// Wire task-eval completion → re-emit `task_end` with score + outcome.
|
|
134
|
+
// The original `task_end` (above) fires synchronously on closeTask so the
|
|
135
|
+
// boundary is visible immediately; the judge runs async and may take
|
|
136
|
+
// 5-30 s. When it resolves, this listener emits a second `task_end` with
|
|
137
|
+
// the same `taskId`. Timeline stores upsert by (type='task_end', taskId)
|
|
138
|
+
// and merge the new score fields onto the existing row, so dashboard task
|
|
139
|
+
// headers get the score badge as soon as the judge returns.
|
|
140
|
+
if (emitTimeline) {
|
|
141
|
+
runner.onTaskEvaluated((e) => {
|
|
142
|
+
// Skip the score re-emit for tasks whose header never reached the
|
|
143
|
+
// timeline (single-turn Q&A). Without this the merge-or-insert
|
|
144
|
+
// timeline store would insert a fresh orphan `task_end` here. Consume
|
|
145
|
+
// the id so the set doesn't grow unbounded across a long-lived daemon.
|
|
146
|
+
if (!promotedTaskIds.delete(e.taskId))
|
|
147
|
+
return;
|
|
148
|
+
const durationSec = Math.max(0, Math.round((e.endedAt - e.startedAt) / 1000));
|
|
149
|
+
const signalLabel = e.boundarySignal === 'todo_complete' ? 'TODO done'
|
|
150
|
+
: e.boundarySignal === 'clear' ? '/clear'
|
|
151
|
+
: e.boundarySignal === 'session_end' ? 'Session end'
|
|
152
|
+
: e.boundarySignal === 'manual' ? 'Manual'
|
|
153
|
+
: e.boundarySignal === 'idle_gap' ? 'Idle gap'
|
|
154
|
+
: 'Task end';
|
|
155
|
+
emitTimeline({
|
|
156
|
+
ts: e.endedAt,
|
|
157
|
+
type: 'task_end',
|
|
158
|
+
raw: `${signalLabel} · ${durationSec}s`,
|
|
159
|
+
agentType: e.agentType,
|
|
160
|
+
projectName: e.projectName,
|
|
161
|
+
sessionId: e.sessionId,
|
|
162
|
+
runId: e.runId,
|
|
163
|
+
taskId: e.taskId,
|
|
164
|
+
boundarySignal: e.boundarySignal,
|
|
165
|
+
startedAt: e.startedAt,
|
|
166
|
+
endedAt: e.endedAt,
|
|
167
|
+
taskScore: e.compositeScore ?? undefined,
|
|
168
|
+
taskOutcome: e.outcome,
|
|
169
|
+
taskCategory: e.taskCategory,
|
|
170
|
+
taskSummary: e.summary,
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
}
|
|
53
174
|
// Write dashboard HTML for Swift daemon to pick up.
|
|
54
175
|
try {
|
|
55
176
|
const dataDir = process.env.AGENTDECK_DATA_DIR || join(homedir(), '.agentdeck');
|
|
@@ -63,11 +184,16 @@ export async function initApme(dbPath) {
|
|
|
63
184
|
export function getApme() {
|
|
64
185
|
return singleton;
|
|
65
186
|
}
|
|
187
|
+
/** Phase 6 cutover switch (default OFF). Set `AGENTDECK_TIMELINE_PROJECTION=1`
|
|
188
|
+
* to make the timeline a projection of the canonical SessionSample. Read at
|
|
189
|
+
* daemon/session-bridge startup so it can be flipped without a recompile. */
|
|
190
|
+
export function isTimelineProjectionEnabled() {
|
|
191
|
+
return process.env.AGENTDECK_TIMELINE_PROJECTION === '1';
|
|
192
|
+
}
|
|
66
193
|
export { loadApmeConfig, shouldJudge, DEFAULT_APME_CONFIG } from './settings.js';
|
|
67
194
|
export { ApmeStore } from './store.js';
|
|
68
195
|
export { ApmeCollector } from './collector.js';
|
|
69
196
|
export { ApmeRunner } from './runner.js';
|
|
70
|
-
export { ApmeTuner } from './tuner.js';
|
|
71
197
|
export { ApmeHwSampler } from './hw-sampler.js';
|
|
72
198
|
export { ApmeRecommender } from './recommend.js';
|
|
73
199
|
export { classifyRun, classifyRunSmart, classifyWithLlm, classify, computeSignals, TASK_CATEGORIES } from './classifier.js';
|
package/dist/apme/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apme/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,IAAI,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAC5B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAC;AAC7B,OAAO,EAAE,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/apme/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pareto frontier over (quality, cost) for model orchestration.
|
|
3
|
+
*
|
|
4
|
+
* A model is on the frontier if no other model dominates it — i.e. no other
|
|
5
|
+
* model is BOTH higher quality AND lower (or equal) cost per sample. Dominated
|
|
6
|
+
* models are strictly worse on both axes and should never be recommended; the
|
|
7
|
+
* frontier is the real menu of quality/cost tradeoffs.
|
|
8
|
+
*
|
|
9
|
+
* "Same quality, 40% cheaper" decisions fall straight out of this: walk the
|
|
10
|
+
* frontier from cheapest to best and pick the knee that fits the budget.
|
|
11
|
+
*
|
|
12
|
+
* Pure + synchronous + unit-testable. Input is the sample-granularity
|
|
13
|
+
* scorecard; output partitions candidates into frontier vs dominated.
|
|
14
|
+
*/
|
|
15
|
+
import type { ApmeSampleScorecardRow } from '@agentdeck/shared';
|
|
16
|
+
export interface ParetoPoint {
|
|
17
|
+
agentType: string;
|
|
18
|
+
modelId: string;
|
|
19
|
+
taskCategory: string | null;
|
|
20
|
+
/** Quality axis (avg composite, [0,1]). Higher is better. */
|
|
21
|
+
quality: number;
|
|
22
|
+
/** Cost axis: average USD per sample. Lower is better. */
|
|
23
|
+
costPerSample: number;
|
|
24
|
+
avgLatencyMs: number | null;
|
|
25
|
+
samples: number;
|
|
26
|
+
}
|
|
27
|
+
export interface ParetoResult {
|
|
28
|
+
frontier: ParetoPoint[];
|
|
29
|
+
dominated: ParetoPoint[];
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Partition scorecard rows into the Pareto frontier and the dominated set.
|
|
33
|
+
* @param rows sample scorecard rows (optionally pre-filtered by category)
|
|
34
|
+
* @param minSamples ignore models with too little data to trust
|
|
35
|
+
*/
|
|
36
|
+
export declare function computePareto(rows: ApmeSampleScorecardRow[], minSamples?: number): ParetoResult;
|
|
37
|
+
/** Convenience: filter scorecard to a category before computing the frontier. */
|
|
38
|
+
export declare function paretoForCategory(rows: ApmeSampleScorecardRow[], category: string | null | undefined, minSamples?: number): ParetoResult;
|
|
39
|
+
//# sourceMappingURL=pareto.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pareto.d.ts","sourceRoot":"","sources":["../../src/apme/pareto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mBAAmB,CAAC;AAEhE,MAAM,WAAW,WAAW;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,6DAA6D;IAC7D,OAAO,EAAE,MAAM,CAAC;IAChB,0DAA0D;IAC1D,aAAa,EAAE,MAAM,CAAC;IACtB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,SAAS,EAAE,WAAW,EAAE,CAAC;CAC1B;AAsBD;;;;GAIG;AACH,wBAAgB,aAAa,CAC3B,IAAI,EAAE,sBAAsB,EAAE,EAC9B,UAAU,SAAI,GACb,YAAY,CAcd;AAED,iFAAiF;AACjF,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,sBAAsB,EAAE,EAC9B,QAAQ,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,EACnC,UAAU,SAAI,GACb,YAAY,CAGd"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pareto frontier over (quality, cost) for model orchestration.
|
|
3
|
+
*
|
|
4
|
+
* A model is on the frontier if no other model dominates it — i.e. no other
|
|
5
|
+
* model is BOTH higher quality AND lower (or equal) cost per sample. Dominated
|
|
6
|
+
* models are strictly worse on both axes and should never be recommended; the
|
|
7
|
+
* frontier is the real menu of quality/cost tradeoffs.
|
|
8
|
+
*
|
|
9
|
+
* "Same quality, 40% cheaper" decisions fall straight out of this: walk the
|
|
10
|
+
* frontier from cheapest to best and pick the knee that fits the budget.
|
|
11
|
+
*
|
|
12
|
+
* Pure + synchronous + unit-testable. Input is the sample-granularity
|
|
13
|
+
* scorecard; output partitions candidates into frontier vs dominated.
|
|
14
|
+
*/
|
|
15
|
+
function toPoint(r) {
|
|
16
|
+
return {
|
|
17
|
+
agentType: r.agentType,
|
|
18
|
+
modelId: r.modelId,
|
|
19
|
+
taskCategory: r.taskCategory,
|
|
20
|
+
quality: r.avgQuality ?? 0,
|
|
21
|
+
costPerSample: r.samples > 0 ? (r.totalCost ?? 0) / r.samples : 0,
|
|
22
|
+
avgLatencyMs: r.avgLatencyMs,
|
|
23
|
+
samples: r.samples,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
/** True when `b` dominates `a`: at least as good on both axes and strictly
|
|
27
|
+
* better on at least one (higher quality, lower cost). */
|
|
28
|
+
function dominates(b, a) {
|
|
29
|
+
const betterOrEqual = b.quality >= a.quality && b.costPerSample <= a.costPerSample;
|
|
30
|
+
const strictlyBetter = b.quality > a.quality || b.costPerSample < a.costPerSample;
|
|
31
|
+
return betterOrEqual && strictlyBetter;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Partition scorecard rows into the Pareto frontier and the dominated set.
|
|
35
|
+
* @param rows sample scorecard rows (optionally pre-filtered by category)
|
|
36
|
+
* @param minSamples ignore models with too little data to trust
|
|
37
|
+
*/
|
|
38
|
+
export function computePareto(rows, minSamples = 3) {
|
|
39
|
+
const points = rows
|
|
40
|
+
.filter((r) => r.samples >= minSamples && (r.avgQuality ?? 0) > 0)
|
|
41
|
+
.map(toPoint);
|
|
42
|
+
const frontier = [];
|
|
43
|
+
const dominated = [];
|
|
44
|
+
for (const a of points) {
|
|
45
|
+
if (points.some((b) => b !== a && dominates(b, a)))
|
|
46
|
+
dominated.push(a);
|
|
47
|
+
else
|
|
48
|
+
frontier.push(a);
|
|
49
|
+
}
|
|
50
|
+
// Frontier sorted cheapest → most expensive (the natural tradeoff curve).
|
|
51
|
+
frontier.sort((x, y) => x.costPerSample - y.costPerSample || y.quality - x.quality);
|
|
52
|
+
return { frontier, dominated };
|
|
53
|
+
}
|
|
54
|
+
/** Convenience: filter scorecard to a category before computing the frontier. */
|
|
55
|
+
export function paretoForCategory(rows, category, minSamples = 3) {
|
|
56
|
+
const scoped = category ? rows.filter((r) => r.taskCategory === category) : rows;
|
|
57
|
+
return computePareto(scoped, minSamples);
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=pareto.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pareto.js","sourceRoot":"","sources":["../../src/apme/pareto.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAqBH,SAAS,OAAO,CAAC,CAAyB;IACxC,OAAO;QACL,SAAS,EAAE,CAAC,CAAC,SAAS;QACtB,OAAO,EAAE,CAAC,CAAC,OAAO;QAClB,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,OAAO,EAAE,CAAC,CAAC,UAAU,IAAI,CAAC;QAC1B,aAAa,EAAE,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QACjE,YAAY,EAAE,CAAC,CAAC,YAAY;QAC5B,OAAO,EAAE,CAAC,CAAC,OAAO;KACnB,CAAC;AACJ,CAAC;AAED;2DAC2D;AAC3D,SAAS,SAAS,CAAC,CAAc,EAAE,CAAc;IAC/C,MAAM,aAAa,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,aAAa,CAAC;IACnF,MAAM,cAAc,GAAG,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,CAAC;IAClF,OAAO,aAAa,IAAI,cAAc,CAAC;AACzC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,IAA8B,EAC9B,UAAU,GAAG,CAAC;IAEd,MAAM,MAAM,GAAG,IAAI;SAChB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,OAAO,IAAI,UAAU,IAAI,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC;SACjE,GAAG,CAAC,OAAO,CAAC,CAAC;IAEhB,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,MAAM,SAAS,GAAkB,EAAE,CAAC;IACpC,KAAK,MAAM,CAAC,IAAI,MAAM,EAAE,CAAC;QACvB,IAAI,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,IAAI,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YAAE,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;;YACjE,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,0EAA0E;IAC1E,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,aAAa,GAAG,CAAC,CAAC,aAAa,IAAI,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,OAAO,CAAC,CAAC;IACpF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,CAAC;AACjC,CAAC;AAED,iFAAiF;AACjF,MAAM,UAAU,iBAAiB,CAC/B,IAA8B,EAC9B,QAAmC,EACnC,UAAU,GAAG,CAAC;IAEd,MAAM,MAAM,GAAG,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;IACjF,OAAO,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC3C,CAAC"}
|
package/dist/apme/recommend.d.ts
CHANGED
|
@@ -28,5 +28,8 @@ export declare class ApmeRecommender {
|
|
|
28
28
|
private readonly store;
|
|
29
29
|
constructor(store: ApmeStore);
|
|
30
30
|
recommend(input: RecommendInput): RecommendCandidate[];
|
|
31
|
+
/** Legacy run-level recommendation (v_model_scorecard). Used when no
|
|
32
|
+
* sample-granularity composite scores exist yet. */
|
|
33
|
+
private recommendFromRuns;
|
|
31
34
|
}
|
|
32
35
|
//# sourceMappingURL=recommend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../src/apme/recommend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"recommend.d.ts","sourceRoot":"","sources":["../../src/apme/recommend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AACnD,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAG5C,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,mFAAmF;IACnF,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,SAAS,CAAC;IACrB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,KAAK;gBAAL,KAAK,EAAE,SAAS;IAE7C,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,kBAAkB,EAAE;IAgDtD;yDACqD;IACrD,OAAO,CAAC,iBAAiB;CAyB1B"}
|
package/dist/apme/recommend.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* confidence. v1 uses the v_model_scorecard view; v2 (stretch) layers in
|
|
7
7
|
* task-similarity via local embeddings.
|
|
8
8
|
*/
|
|
9
|
+
import { paretoForCategory } from './pareto.js';
|
|
9
10
|
export class ApmeRecommender {
|
|
10
11
|
store;
|
|
11
12
|
constructor(store) {
|
|
@@ -14,6 +15,48 @@ export class ApmeRecommender {
|
|
|
14
15
|
recommend(input) {
|
|
15
16
|
if (!this.store.enabled)
|
|
16
17
|
return [];
|
|
18
|
+
// Work at sample granularity (the canonical eval unit) and restrict to the
|
|
19
|
+
// Pareto frontier — dominated models (strictly worse on quality AND cost)
|
|
20
|
+
// are never worth recommending. This is the model-orchestration payoff:
|
|
21
|
+
// the menu is the quality/cost tradeoff curve, not a flat ranking.
|
|
22
|
+
const scorecard = this.store.sampleScorecard();
|
|
23
|
+
let { frontier } = paretoForCategory(scorecard, input.taskKind);
|
|
24
|
+
// Fall back to the whole frontier if the category has too little data.
|
|
25
|
+
if (frontier.length === 0)
|
|
26
|
+
frontier = paretoForCategory(scorecard, undefined).frontier;
|
|
27
|
+
// Fall back to the run-level scorecard when no sample-granularity data has
|
|
28
|
+
// accumulated yet (legacy runs, or before the first task judge resolves).
|
|
29
|
+
if (frontier.length === 0)
|
|
30
|
+
return this.recommendFromRuns(input);
|
|
31
|
+
let candidates = frontier;
|
|
32
|
+
if (input.availableModels) {
|
|
33
|
+
candidates = candidates.filter((p) => input.availableModels.includes(p.modelId));
|
|
34
|
+
}
|
|
35
|
+
if (input.budgetUsd !== undefined) {
|
|
36
|
+
candidates = candidates.filter((p) => p.costPerSample <= input.budgetUsd);
|
|
37
|
+
}
|
|
38
|
+
if (input.latencyBudgetMs !== undefined) {
|
|
39
|
+
candidates = candidates.filter((p) => p.avgLatencyMs == null || p.avgLatencyMs <= input.latencyBudgetMs);
|
|
40
|
+
}
|
|
41
|
+
candidates = [...candidates].sort((a, b) => {
|
|
42
|
+
// Budget-conscious or local-preferring → cheapest first; else best quality.
|
|
43
|
+
if (input.preferLocal || (input.budgetUsd !== undefined && input.budgetUsd < 5)) {
|
|
44
|
+
return a.costPerSample - b.costPerSample || b.quality - a.quality;
|
|
45
|
+
}
|
|
46
|
+
return b.quality - a.quality || a.costPerSample - b.costPerSample;
|
|
47
|
+
});
|
|
48
|
+
return candidates.slice(0, 3).map((p) => ({
|
|
49
|
+
modelId: p.modelId,
|
|
50
|
+
agentType: p.agentType,
|
|
51
|
+
expectedScore: p.quality,
|
|
52
|
+
expectedCostUsd: p.costPerSample,
|
|
53
|
+
confidence: Math.min(1, p.samples / 20),
|
|
54
|
+
rationale: `${p.samples} samples, avg ${(p.quality * 100).toFixed(0)}%, $${p.costPerSample.toFixed(4)}/sample${p.avgLatencyMs != null ? `, ${Math.round(p.avgLatencyMs)}ms` : ''} — on the cost/quality frontier`,
|
|
55
|
+
}));
|
|
56
|
+
}
|
|
57
|
+
/** Legacy run-level recommendation (v_model_scorecard). Used when no
|
|
58
|
+
* sample-granularity composite scores exist yet. */
|
|
59
|
+
recommendFromRuns(input) {
|
|
17
60
|
const rows = this.store.scorecard();
|
|
18
61
|
const filtered = input.availableModels
|
|
19
62
|
? rows.filter((r) => input.availableModels.includes(r.modelId))
|
|
@@ -21,7 +64,6 @@ export class ApmeRecommender {
|
|
|
21
64
|
return filtered
|
|
22
65
|
.filter((r) => r.runs >= 3 && (r.avgOverall ?? 0) > 0)
|
|
23
66
|
.sort((a, b) => {
|
|
24
|
-
// Prefer cost-per-quality if budget is tight, otherwise raw quality.
|
|
25
67
|
if (input.budgetUsd !== undefined && input.budgetUsd < 5) {
|
|
26
68
|
return (a.costPerQuality ?? Infinity) - (b.costPerQuality ?? Infinity);
|
|
27
69
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"recommend.js","sourceRoot":"","sources":["../../src/apme/recommend.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;
|
|
1
|
+
{"version":3,"file":"recommend.js","sourceRoot":"","sources":["../../src/apme/recommend.ts"],"names":[],"mappings":"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"}
|
package/dist/apme/runner.d.ts
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
* 0/1 in `evals` (metrics: lint_clean, build_ok, tests_pass).
|
|
7
7
|
*
|
|
8
8
|
* Layer 2 (llm_judge): G-Eval style rubric against the latest `rubrics` row.
|
|
9
|
-
* Backend is pluggable — default is
|
|
10
|
-
*
|
|
11
|
-
* common "clear pass" case skips layer 2 entirely.
|
|
9
|
+
* Backend is pluggable — default is Foundation Models via the Swift daemon or
|
|
10
|
+
* bundled CLI Swift helper, with local MLX fallback for CLI-only runs. Gated
|
|
11
|
+
* by `shouldJudge()` so the common "clear pass" case skips layer 2 entirely.
|
|
12
12
|
*/
|
|
13
13
|
import type { ApmeStore } from './store.js';
|
|
14
|
-
import type { ApmeConfig, ApmeJudgeConfig } from './settings.js';
|
|
14
|
+
import type { ApmeConfig, ApmeJudgeConfig, ApmeJudgeBackend } from './settings.js';
|
|
15
|
+
import type { SessionSample } from '@agentdeck/shared';
|
|
15
16
|
import type { ApmeRunRow, ParsedJudge } from './types.js';
|
|
16
17
|
export interface EvalJob {
|
|
17
18
|
runId: string;
|
|
@@ -26,6 +27,37 @@ export interface EvalJobResult {
|
|
|
26
27
|
layer2Ran: boolean;
|
|
27
28
|
overall?: number;
|
|
28
29
|
}
|
|
30
|
+
/**
|
|
31
|
+
* Emitted after `runTaskEval` writes the task_judge axis scores + summary +
|
|
32
|
+
* compositeScore. Carries enough context for the timeline layer to upsert the
|
|
33
|
+
* existing `task_end` row with the verdict (score + outcome class + category +
|
|
34
|
+
* summary) so dashboard task headers can render the score badge.
|
|
35
|
+
*/
|
|
36
|
+
export interface TaskEvaluatedEvent {
|
|
37
|
+
runId: string;
|
|
38
|
+
taskId: string;
|
|
39
|
+
sessionId: string;
|
|
40
|
+
agentType?: string;
|
|
41
|
+
projectName?: string;
|
|
42
|
+
startedAt: number;
|
|
43
|
+
endedAt: number;
|
|
44
|
+
compositeScore: number | null;
|
|
45
|
+
/** Coarse outcome class. Normally derived from `compositeScore`:
|
|
46
|
+
* - `'success'` (≥0.75)
|
|
47
|
+
* - `'partial'` (≥0.50)
|
|
48
|
+
* - `'fail'` (<0.50)
|
|
49
|
+
* - `'pending'` (judge produced no score)
|
|
50
|
+
* May also be `'abandoned'` when the user manually closed the task
|
|
51
|
+
* via `agentdeck task cancel` (or the macOS detail-pane button) — that
|
|
52
|
+
* outcome takes priority and is never overwritten by the judge.
|
|
53
|
+
* Distinct from the run-level git outcome (`committed | abandoned |
|
|
54
|
+
* iterated`) which lives on the parent `runs` row.
|
|
55
|
+
*/
|
|
56
|
+
outcome: 'success' | 'partial' | 'fail' | 'pending' | 'abandoned';
|
|
57
|
+
taskCategory?: string;
|
|
58
|
+
summary?: string;
|
|
59
|
+
boundarySignal: string;
|
|
60
|
+
}
|
|
29
61
|
type Lang = 'typescript' | 'swift' | 'kotlin';
|
|
30
62
|
interface DetStepResult {
|
|
31
63
|
metric: 'lint_clean' | 'build_ok' | 'tests_pass';
|
|
@@ -39,15 +71,32 @@ export declare class ApmeRunner {
|
|
|
39
71
|
private readonly store;
|
|
40
72
|
private queue;
|
|
41
73
|
private drainPromise;
|
|
74
|
+
private readonly queuedRunIds;
|
|
75
|
+
private readonly runningRunIds;
|
|
76
|
+
private readonly runningTurnIds;
|
|
77
|
+
private readonly runningTaskIds;
|
|
42
78
|
private readonly listeners;
|
|
79
|
+
private readonly taskListeners;
|
|
43
80
|
private configOverride;
|
|
44
81
|
private judgeOverride;
|
|
45
82
|
private detOverride;
|
|
83
|
+
/** Cached startup judge readiness probe. Populated by `refreshBackendProbe`,
|
|
84
|
+
* surfaced on /health. Null until the first probe completes. */
|
|
85
|
+
lastBackendProbe: JudgeBackendStatus | null;
|
|
46
86
|
constructor(store: ApmeStore);
|
|
87
|
+
/** Probe the configured judge backend and cache the result. Safe to call
|
|
88
|
+
* fire-and-forget at daemon startup — failures don't throw. */
|
|
89
|
+
refreshBackendProbe(cfg: ApmeJudgeConfig): Promise<JudgeBackendStatus>;
|
|
47
90
|
_setConfig(cfg: ApmeConfig): void;
|
|
48
91
|
_setJudgeFn(fn: ((prompt: string, judgeCfg: ApmeJudgeConfig) => Promise<string>) | null): void;
|
|
49
92
|
_setDeterministicFn(fn: ((runRow: ApmeRunRow, cfg: ApmeConfig) => Promise<DetStepResult[]>) | null): void;
|
|
50
93
|
onResult(fn: (r: EvalJobResult) => void): () => void;
|
|
94
|
+
/** Subscribe to per-task judge completions. The event fires AFTER the
|
|
95
|
+
* task_judge axis scores and summary are persisted, so listeners can read
|
|
96
|
+
* the final state directly from the event payload without re-querying.
|
|
97
|
+
* Used by the timeline emitter to upsert the corresponding `task_end` row
|
|
98
|
+
* with score + outcome metadata. */
|
|
99
|
+
onTaskEvaluated(fn: (e: TaskEvaluatedEvent) => void): () => void;
|
|
51
100
|
enqueue(job: EvalJob): void;
|
|
52
101
|
/** Immediately judge a single completed turn (mid-session eval).
|
|
53
102
|
* Used for non-code categories where turn prompt+response is the eval unit.
|
|
@@ -75,6 +124,9 @@ export declare class ApmeRunner {
|
|
|
75
124
|
}
|
|
76
125
|
export declare function detectLanguage(projectPath: string | null | undefined): Lang | null;
|
|
77
126
|
export declare function runDeterministic(run: ApmeRunRow, cfg: ApmeConfig): Promise<DetStepResult[]>;
|
|
127
|
+
/** Render a SessionSample's typed trajectory as compact judge-prompt lines.
|
|
128
|
+
* Gives the judge tool-call sequences + model usage the turn rows omit. */
|
|
129
|
+
export declare function buildTrajectoryLines(sample: SessionSample, cap?: number): string[];
|
|
78
130
|
export declare function buildJudgePrompt(run: ApmeRunRow, rubricPrompt: string, layer1Passed: boolean | null, store?: import('./store.js').ApmeStore): string;
|
|
79
131
|
/** Response classification stored by ApmeCollector under turns.efficiency_json.response_kind.
|
|
80
132
|
* Drives which turns make it to the LLM judge — `tool_only` / `empty` are silence
|
|
@@ -88,7 +140,43 @@ export declare function readResponseKind(turn: Record<string, unknown>): Respons
|
|
|
88
140
|
* "qwen3-30b" placeholder). Non-MLX backends use cfg.judge.model verbatim.
|
|
89
141
|
*/
|
|
90
142
|
export declare function effectiveJudgeModelTag(cfg: ApmeJudgeConfig): string;
|
|
143
|
+
/** Strip backend-specific fields when forcing a cfg through a different
|
|
144
|
+
* adapter. Without this, a FM cfg (`endpoint:"http://.../apme/judge/foundation-models"`,
|
|
145
|
+
* `model:"apple-intelligence"`) handed to `callMlx` would POST to the FM URL
|
|
146
|
+
* and request a model the MLX server has never heard of — silent failure.
|
|
147
|
+
* Mirrors the `resetBackendCoupledFields` path inside `loadApmeConfig`. */
|
|
148
|
+
export declare function sanitizeForMlx(judgeCfg: ApmeJudgeConfig): ApmeJudgeConfig;
|
|
149
|
+
/** Result of a judge call that knows which backend ACTUALLY produced the
|
|
150
|
+
* text — important when the FM→MLX fallback path runs, because the caller
|
|
151
|
+
* needs the effective label (not the original cfg.backend) for the
|
|
152
|
+
* `evals.judge_model` column. Otherwise eval rows are misattributed to FM
|
|
153
|
+
* even though MLX produced them. */
|
|
154
|
+
export interface JudgeResult {
|
|
155
|
+
text: string;
|
|
156
|
+
/** Backend that actually generated `text` (after any fallback). */
|
|
157
|
+
effectiveBackend: ApmeJudgeBackend;
|
|
158
|
+
/** `judge_model` column value derived from the effective backend + cfg.
|
|
159
|
+
* Use this verbatim when writing to the DB. */
|
|
160
|
+
effectiveLabel: string;
|
|
161
|
+
}
|
|
162
|
+
/** Test hook for cache-sensitive runner tests. Production code should not call this. */
|
|
163
|
+
export declare function clearFoundationModelsAutoCacheForTests(): void;
|
|
164
|
+
/** Like `callJudge`, but returns the effective backend + label so callers
|
|
165
|
+
* can record `judge_model` correctly across fallback paths. */
|
|
166
|
+
export declare function callJudgeWithMeta(prompt: string, judgeCfg: ApmeJudgeConfig): Promise<JudgeResult>;
|
|
167
|
+
/** Backwards-compatible thin wrapper. Internal callers that need the actual
|
|
168
|
+
* effective backend (for DB labelling) should call `callJudgeWithMeta`. */
|
|
91
169
|
export declare function callJudge(prompt: string, judgeCfg: ApmeJudgeConfig): Promise<string>;
|
|
170
|
+
export interface JudgeBackendStatus {
|
|
171
|
+
backend: ApmeJudgeBackend;
|
|
172
|
+
status: 'ready' | 'unavailable' | 'unknown';
|
|
173
|
+
latencyMs?: number;
|
|
174
|
+
model?: string;
|
|
175
|
+
endpoint?: string;
|
|
176
|
+
reason?: string;
|
|
177
|
+
checkedAt: number;
|
|
178
|
+
}
|
|
179
|
+
export declare function probeJudgeBackend(cfg: ApmeJudgeConfig): Promise<JudgeBackendStatus>;
|
|
92
180
|
export declare function parseJudgeJson(text: string): ParsedJudge | null;
|
|
93
181
|
export {};
|
|
94
182
|
//# sourceMappingURL=runner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/apme/runner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/apme/runner.ts"],"names":[],"mappings":"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"}
|