@qadanm/opencode-smart-router 0.0.0-stage → 0.4.0
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/CHANGELOG.md +118 -0
- package/CONTRIBUTING.md +96 -0
- package/LICENSE +21 -0
- package/README.md +341 -2
- package/SECURITY.md +174 -0
- package/config.example.json +108 -0
- package/dist/allowance.js +487 -0
- package/dist/gui-experimental.cjs +1 -0
- package/dist/index.js +11111 -0
- package/dist/npm/index.js +40 -0
- package/dist/tui.js +587 -0
- package/docs/ARCHITECTURE.md +104 -0
- package/docs/DEBUGGING-GUI.md +70 -0
- package/docs/INSTALL.md +120 -0
- package/docs/LIMITATIONS.md +213 -0
- package/docs/MODELS.md +124 -0
- package/docs/OPENDESIGN-INTEGRATION.md +635 -0
- package/docs/QA.md +142 -0
- package/docs/SHARED-CORE.md +72 -0
- package/install +75 -0
- package/package.json +92 -4
- package/scripts/install.sh +324 -0
- package/scripts/uninstall.sh +91 -0
- package/src/allowance.ts +135 -0
- package/src/core/classify/classifier.ts +305 -0
- package/src/core/config-writer.ts +167 -0
- package/src/core/config.ts +1030 -0
- package/src/core/context/strategy.ts +188 -0
- package/src/core/context-health.ts +39 -0
- package/src/core/failures.ts +398 -0
- package/src/core/history/opencode.ts +173 -0
- package/src/core/models/protocol.ts +22 -0
- package/src/core/models/registry.ts +203 -0
- package/src/core/models/seed.ts +771 -0
- package/src/core/offline/mode.ts +321 -0
- package/src/core/plan-page.ts +390 -0
- package/src/core/plans/catalog.ts +481 -0
- package/src/core/policy/calibration.ts +259 -0
- package/src/core/policy/eligibility.ts +578 -0
- package/src/core/providers/enablement.ts +143 -0
- package/src/core/providers/opendesign-credits.ts +206 -0
- package/src/core/providers/opendesign-models.ts +628 -0
- package/src/core/providers/opendesign.ts +474 -0
- package/src/core/quota/calibration.ts +166 -0
- package/src/core/quota/commandcode.ts +471 -0
- package/src/core/quota/credentials.ts +490 -0
- package/src/core/quota/ledger.ts +1273 -0
- package/src/core/quota/opencode-go.ts +148 -0
- package/src/core/quota/opendesign.ts +1043 -0
- package/src/core/quota/reconcile.ts +155 -0
- package/src/core/quota/report.ts +261 -0
- package/src/core/quota/service.ts +273 -0
- package/src/core/reprompt.ts +48 -0
- package/src/core/routing/engine.ts +919 -0
- package/src/core/types.ts +825 -0
- package/src/core/ui.ts +236 -0
- package/src/core/util.ts +114 -0
- package/src/gui/index.tsx +1670 -0
- package/src/gui/viewmodel.ts +456 -0
- package/src/index.ts +48 -0
- package/src/rpc.ts +204 -0
- package/src/server/controller.ts +3281 -0
- package/src/server/route-tracker.ts +60 -0
- package/src/server/shared-core.ts +671 -0
- package/src/tui/index.tsx +168 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import type { RoutingDecision, TaskClass } from "../core/types.js"
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* What the router chose for the current prompt of a session, kept so the
|
|
5
|
+
* retry hook can re-route the same task when a provider deterministically
|
|
6
|
+
* rejects the request. The retry event carries no prompt linkage of its own,
|
|
7
|
+
* so the prompt hook records the pairing here.
|
|
8
|
+
*
|
|
9
|
+
* Sized like the other per-session caches (the `expectedSwitch` pattern):
|
|
10
|
+
* bounded, oldest entries evicted, never persisted to disk.
|
|
11
|
+
*/
|
|
12
|
+
export interface PromptRouteEntry {
|
|
13
|
+
/** The user prompt the routing belongs to (when the host reports one). */
|
|
14
|
+
readonly messageID?: string
|
|
15
|
+
readonly task: TaskClass
|
|
16
|
+
readonly decision: RoutingDecision
|
|
17
|
+
readonly at: number
|
|
18
|
+
/** Set once a prompt-rejection failover for this prompt has run. */
|
|
19
|
+
healedAt?: number
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const LIMIT = 500
|
|
23
|
+
|
|
24
|
+
export class PromptRouteTracker {
|
|
25
|
+
private readonly entries = new Map<string, PromptRouteEntry>()
|
|
26
|
+
|
|
27
|
+
set(sessionID: string, entry: PromptRouteEntry): void {
|
|
28
|
+
if (this.entries.size >= LIMIT && !this.entries.has(sessionID)) {
|
|
29
|
+
this.evict()
|
|
30
|
+
}
|
|
31
|
+
this.entries.set(sessionID, entry)
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
get(sessionID: string): PromptRouteEntry | undefined {
|
|
35
|
+
return this.entries.get(sessionID)
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
clear(sessionID: string): void {
|
|
39
|
+
this.entries.delete(sessionID)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
clearAll(): void {
|
|
43
|
+
this.entries.clear()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
size(): number {
|
|
47
|
+
return this.entries.size
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
private evict(): void {
|
|
51
|
+
const cutoff = Date.now() - 60_000
|
|
52
|
+
for (const [sessionID, entry] of this.entries) {
|
|
53
|
+
if (entry.at < cutoff) this.entries.delete(sessionID)
|
|
54
|
+
}
|
|
55
|
+
if (this.entries.size >= LIMIT) {
|
|
56
|
+
const oldest = [...this.entries.entries()].sort((a, b) => a[1].at - b[1].at)[0]
|
|
57
|
+
if (oldest) this.entries.delete(oldest[0])
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|