create-quorum-router 0.1.8 → 0.1.10
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 +11 -3
- package/bin/create-quorum-router.js +3 -3
- package/package.json +1 -1
- package/templates/basic/README.md +13 -9
- package/templates/basic/router.config.example.json +2 -2
- package/templates/basic/src/auth.ts +6 -4
- package/templates/basic/src/best_route.ts +7 -2
- package/templates/basic/src/calibration_route.ts +31 -0
- package/templates/basic/src/cli.ts +25 -2
- package/templates/basic/src/intake.ts +9 -6
- package/templates/basic/src/model_inventory.ts +4 -1
- package/templates/basic/src/provider_registry.ts +0 -15
- package/templates/basic/src/schema.ts +23 -2
- package/templates/basic/src/trace.ts +30 -0
package/README.md
CHANGED
|
@@ -17,7 +17,7 @@ deno task intake
|
|
|
17
17
|
deno task supabase:status
|
|
18
18
|
```
|
|
19
19
|
|
|
20
|
-
Current package version: `create-quorum-router@0.1.
|
|
20
|
+
Current package version: `create-quorum-router@0.1.10`. Releases are published
|
|
21
21
|
from an immutable Git tag through GitHub Actions OIDC Trusted Publishing.
|
|
22
22
|
|
|
23
23
|
## What the generated project supports
|
|
@@ -27,7 +27,9 @@ API.
|
|
|
27
27
|
|
|
28
28
|
`deno task calibration:demo` runs the bundled calibration-by-task API against
|
|
29
29
|
deterministic local observations. The report is advisory-only and is not
|
|
30
|
-
connected to routing weights, provider eligibility, or execution.
|
|
30
|
+
connected to routing weights, provider eligibility, or execution. The command
|
|
31
|
+
does not call provider APIs; on a new Deno installation, its first run resolves
|
|
32
|
+
the pinned Zod dependency before execution.
|
|
31
33
|
|
|
32
34
|
`deno task intake` is the first real setup command. It detects local provider
|
|
33
35
|
wrappers, checks OAuth/session status, runs safe list-only model inventory where
|
|
@@ -54,9 +56,15 @@ RUN_EXTERNAL_MODEL_DOGFOOD=1 deno task route:once --prompt "https://github.com/s
|
|
|
54
56
|
# GitHub URL prompts fetch bounded repository context before invoking the selected provider.
|
|
55
57
|
# Only use this with repositories you are allowed to send to that provider.
|
|
56
58
|
RUN_EXTERNAL_MODEL_DOGFOOD=1 deno task best-route --prompt "Choose the safest launch copy."
|
|
57
|
-
RUN_EXTERNAL_MODEL_DOGFOOD=1
|
|
59
|
+
RUN_EXTERNAL_MODEL_DOGFOOD=1 RUN_AGENT_CHAT=1 deno task agent-chat --prompt "Review this launch plan."
|
|
58
60
|
```
|
|
59
61
|
|
|
62
|
+
`route:once` and `best-route` also accept
|
|
63
|
+
`--calibration-evidence ./calibration-evidence.json`. The generated CLI
|
|
64
|
+
caller-attested outcomes before invoking providers and stores the advisory
|
|
65
|
+
metrics with hashed task/source identifiers in the route trace without changing
|
|
66
|
+
routing authority.
|
|
67
|
+
|
|
60
68
|
`auth:login` does not ask for API keys as the primary path. If OAuth/browser
|
|
61
69
|
login is not wired in the generated scaffold, it fails closed and tells the user
|
|
62
70
|
to use an installed provider CLI login, then rerun `deno task intake`.
|
|
@@ -3,7 +3,7 @@ const fs = require("fs");
|
|
|
3
3
|
const path = require("path");
|
|
4
4
|
const { spawnSync } = require("child_process");
|
|
5
5
|
|
|
6
|
-
const VERSION = "0.1.
|
|
6
|
+
const VERSION = "0.1.10";
|
|
7
7
|
const SUPPORTED_TEMPLATES = new Set(["basic"]);
|
|
8
8
|
|
|
9
9
|
function usage() {
|
|
@@ -150,7 +150,7 @@ function main() {
|
|
|
150
150
|
console.log("Then verify with: deno --version");
|
|
151
151
|
}
|
|
152
152
|
console.log(
|
|
153
|
-
" # Optional one-shot real provider dogfood after
|
|
153
|
+
" # Optional one-shot real provider dogfood after live probe verifies authentication:",
|
|
154
154
|
);
|
|
155
155
|
console.log(
|
|
156
156
|
' RUN_EXTERNAL_MODEL_DOGFOOD=1 deno task route:once --prompt "Review this README for risky claims."',
|
|
@@ -163,7 +163,7 @@ function main() {
|
|
|
163
163
|
" # Optional conversation-only Agent Chat stays explicit opt-in:",
|
|
164
164
|
);
|
|
165
165
|
console.log(
|
|
166
|
-
' RUN_EXTERNAL_MODEL_DOGFOOD=1
|
|
166
|
+
' RUN_EXTERNAL_MODEL_DOGFOOD=1 RUN_AGENT_CHAT=1 deno task agent-chat --prompt "Review this launch plan."',
|
|
167
167
|
);
|
|
168
168
|
console.log("");
|
|
169
169
|
console.log(
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# QuorumRouter generated workspace
|
|
2
2
|
|
|
3
3
|
This generated workspace contains the MIT-licensed QuorumRouter current release.
|
|
4
|
-
npm latest targets v0.1.
|
|
4
|
+
npm latest targets v0.1.10.
|
|
5
5
|
|
|
6
6
|
QuorumRouter is **MIT**. It is **open source**. Commercial and production use
|
|
7
7
|
are permitted under the MIT License.
|
|
@@ -51,7 +51,8 @@ deno task supabase:status
|
|
|
51
51
|
`calibration:demo` exercises the bundled calibration-by-task API with local
|
|
52
52
|
fixture observations. Calibration reports are advisory-only: the scaffold does
|
|
53
53
|
not use them to change routing weights, ranks, provider eligibility, quorum, or
|
|
54
|
-
execution.
|
|
54
|
+
execution. The command does not call provider APIs; on a new Deno installation,
|
|
55
|
+
its first run resolves the pinned Zod dependency before execution.
|
|
55
56
|
|
|
56
57
|
`intake` detects local provider wrappers, checks OAuth/session status, runs safe
|
|
57
58
|
model inventory/list-only probes where possible, writes local health traces
|
|
@@ -93,20 +94,24 @@ enabled by this audit integration.
|
|
|
93
94
|
|
|
94
95
|
## Real provider dogfood commands
|
|
95
96
|
|
|
96
|
-
Run only after
|
|
97
|
+
Run only after a live probe verifies provider authentication:
|
|
97
98
|
|
|
98
99
|
```bash
|
|
99
100
|
RUN_EXTERNAL_MODEL_DOGFOOD=1 deno task route:once --prompt "Review this README for risky claims."
|
|
100
101
|
RUN_EXTERNAL_MODEL_DOGFOOD=1 deno task best-route --prompt "Choose the safest launch copy."
|
|
101
|
-
RUN_EXTERNAL_MODEL_DOGFOOD=1
|
|
102
|
+
RUN_EXTERNAL_MODEL_DOGFOOD=1 RUN_AGENT_CHAT=1 deno task agent-chat --prompt "Review this launch plan."
|
|
102
103
|
```
|
|
103
104
|
|
|
104
105
|
Behavior:
|
|
105
106
|
|
|
106
107
|
- `route:once` requires `RUN_EXTERNAL_MODEL_DOGFOOD=1`.
|
|
107
108
|
- `best-route` requires `RUN_EXTERNAL_MODEL_DOGFOOD=1`.
|
|
109
|
+
- `route:once` and `best-route` accept
|
|
110
|
+
`--calibration-evidence ./calibration-evidence.json`; evidence is validated
|
|
111
|
+
before provider invocation. The trace stores advisory metrics with hashed task
|
|
112
|
+
and source identifiers, not raw labels.
|
|
108
113
|
- `agent-chat` requires both `RUN_EXTERNAL_MODEL_DOGFOOD=1` and
|
|
109
|
-
`
|
|
114
|
+
`RUN_AGENT_CHAT=1`.
|
|
110
115
|
- Live Agent Chat requires at least two distinct working provider/model
|
|
111
116
|
identities. It passes the bounded transcript to alternating models, prints
|
|
112
117
|
each response and `replying to` lineage as it arrives, and stores turns in
|
|
@@ -168,10 +173,9 @@ RUN_EXTERNAL_MODEL_DOGFOOD=1 \
|
|
|
168
173
|
```
|
|
169
174
|
|
|
170
175
|
Supported provider aliases include `grok-cli`, `grok`, `xai`, `xAI`, `OpenAI`,
|
|
171
|
-
`codex-cli`, `claude-code`, `gemini-cli`,
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
model answers.
|
|
176
|
+
`codex-cli`, `claude-code`, `gemini-cli`, and `devin-cli`. Wrapper invocations
|
|
177
|
+
use argv arrays, closed stdin, timeout guards, and sanitized stdout/stderr; CLI
|
|
178
|
+
banners or auth/runtime errors are not accepted as valid model answers.
|
|
175
179
|
|
|
176
180
|
## Auth and inventory
|
|
177
181
|
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
},
|
|
19
19
|
"runtime_boundaries": {
|
|
20
20
|
"best_route_direct": "production-ready best-answer routing",
|
|
21
|
-
"agent_chat": "
|
|
22
|
-
"
|
|
21
|
+
"agent_chat": "explicit opt-in conversation mode; no mutation authority",
|
|
22
|
+
"safeloop_execution": "production-capable only with explicit execution authority and approval",
|
|
23
23
|
"live_supabase_agent_bus_writes": false,
|
|
24
24
|
"service_role_runtime": false
|
|
25
25
|
}
|
|
@@ -18,9 +18,11 @@ export async function runAuthStatus(): Promise<void> {
|
|
|
18
18
|
console.log("Credential values printed: false");
|
|
19
19
|
console.log(`Env fallback configured: ${envFallbackConfigured()}`);
|
|
20
20
|
printInventoryTable(inventory);
|
|
21
|
-
const
|
|
22
|
-
if (
|
|
23
|
-
console.log(
|
|
21
|
+
const invokable = invokableEntries(inventory);
|
|
22
|
+
if (invokable.length === 0) {
|
|
23
|
+
console.log(
|
|
24
|
+
"Status: no invokable OAuth/session/wrapper provider discovered",
|
|
25
|
+
);
|
|
24
26
|
console.log("Next action: deno task auth:login");
|
|
25
27
|
} else if (authMode === "env") {
|
|
26
28
|
console.log("Status: explicit private env fallback is configured");
|
|
@@ -29,7 +31,7 @@ export async function runAuthStatus(): Promise<void> {
|
|
|
29
31
|
);
|
|
30
32
|
} else {
|
|
31
33
|
console.log(
|
|
32
|
-
"Status: at least one
|
|
34
|
+
"Status: at least one provider command is invokable; live authentication is not verified by auth:status",
|
|
33
35
|
);
|
|
34
36
|
console.log(
|
|
35
37
|
'Next action: RUN_EXTERNAL_MODEL_DOGFOOD=1 deno task route:once --prompt "Review this README for risky claims."',
|
|
@@ -22,6 +22,7 @@ import { buildTrace, score, writeTrace } from "./trace.ts";
|
|
|
22
22
|
import { callWrapper } from "./wrapper_client.ts";
|
|
23
23
|
import { preparePromptWithContext } from "./context.ts";
|
|
24
24
|
import { selectCandidatesWithinBudget } from "./cost_aware.ts";
|
|
25
|
+
import type { TaskCalibrationReport } from "./calibration.ts";
|
|
25
26
|
|
|
26
27
|
function hasExplicitSelection(request: ProviderSelectionRequest): boolean {
|
|
27
28
|
return Boolean(
|
|
@@ -180,6 +181,7 @@ async function discoverCandidates(authMode: ReturnType<typeof parseAuthMode>) {
|
|
|
180
181
|
|
|
181
182
|
export async function invokeSelected(
|
|
182
183
|
prompt: string,
|
|
184
|
+
calibration?: TaskCalibrationReport,
|
|
183
185
|
): Promise<
|
|
184
186
|
{ results: ProviderResult[]; tracePath: string; trace: DogfoodTrace }
|
|
185
187
|
> {
|
|
@@ -188,7 +190,7 @@ export async function invokeSelected(
|
|
|
188
190
|
const { request, candidates } = await discoverCandidates(authMode);
|
|
189
191
|
if (candidates.length === 0) {
|
|
190
192
|
throw new Error(
|
|
191
|
-
"OAuth/session-first provider unavailable. No
|
|
193
|
+
"OAuth/session-first provider unavailable. No discovered provider has passed live authentication yet. Next: deno task auth:login",
|
|
192
194
|
);
|
|
193
195
|
}
|
|
194
196
|
const prepared = await preparePromptWithContext(prompt);
|
|
@@ -250,6 +252,7 @@ export async function invokeSelected(
|
|
|
250
252
|
requestedModel: request.model,
|
|
251
253
|
providerSelectionHonored: selectionHonored(request, result),
|
|
252
254
|
fallbackUsed: selectedIndex > 0 || selected.source === "env_fallback",
|
|
255
|
+
calibration,
|
|
253
256
|
});
|
|
254
257
|
const tracePath = await writeTrace("route-once-trace", trace);
|
|
255
258
|
return { results: [result], tracePath, trace };
|
|
@@ -257,6 +260,7 @@ export async function invokeSelected(
|
|
|
257
260
|
|
|
258
261
|
export async function runBestRoute(
|
|
259
262
|
prompt: string,
|
|
263
|
+
calibration?: TaskCalibrationReport,
|
|
260
264
|
): Promise<
|
|
261
265
|
{ results: ProviderResult[]; tracePath: string; trace: DogfoodTrace }
|
|
262
266
|
> {
|
|
@@ -270,7 +274,7 @@ export async function runBestRoute(
|
|
|
270
274
|
const candidates = costAwareDecision.candidates;
|
|
271
275
|
if (candidates.length === 0) {
|
|
272
276
|
throw new Error(
|
|
273
|
-
"OAuth/session-first provider unavailable. best-route has no
|
|
277
|
+
"OAuth/session-first provider unavailable. best-route has no provider with verified live authentication yet. Next: deno task auth:login",
|
|
274
278
|
);
|
|
275
279
|
}
|
|
276
280
|
const prepared = await preparePromptWithContext(prompt);
|
|
@@ -325,6 +329,7 @@ export async function runBestRoute(
|
|
|
325
329
|
costAware: costAwareDecision.cost.enabled
|
|
326
330
|
? costAwareDecision.cost
|
|
327
331
|
: undefined,
|
|
332
|
+
calibration,
|
|
328
333
|
});
|
|
329
334
|
const tracePath = await writeTrace("best-route-trace", trace);
|
|
330
335
|
return { results, tracePath, trace };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import {
|
|
2
|
+
aggregateTaskCalibration,
|
|
3
|
+
type TaskCalibrationOptions,
|
|
4
|
+
type TaskCalibrationReport,
|
|
5
|
+
} from "./calibration.ts";
|
|
6
|
+
|
|
7
|
+
export async function loadCalibrationEvidence(
|
|
8
|
+
path: string | undefined,
|
|
9
|
+
): Promise<TaskCalibrationReport | undefined> {
|
|
10
|
+
if (path === undefined) return undefined;
|
|
11
|
+
const normalizedPath = path.trim();
|
|
12
|
+
if (!normalizedPath) {
|
|
13
|
+
throw new Error("--calibration-evidence requires a local JSON file path");
|
|
14
|
+
}
|
|
15
|
+
const parsed: unknown = JSON.parse(
|
|
16
|
+
await Deno.readTextFile(normalizedPath),
|
|
17
|
+
);
|
|
18
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
19
|
+
throw new Error(
|
|
20
|
+
"calibration evidence must be an object with observations and optional options",
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
const record = parsed as Record<string, unknown>;
|
|
24
|
+
if (!Array.isArray(record.observations)) {
|
|
25
|
+
throw new Error("calibration evidence observations must be an array");
|
|
26
|
+
}
|
|
27
|
+
return aggregateTaskCalibration(
|
|
28
|
+
record.observations,
|
|
29
|
+
record.options as TaskCalibrationOptions | undefined,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
runSupabaseStatus,
|
|
18
18
|
} from "./supabase.ts";
|
|
19
19
|
import { buildTrace, writeTrace } from "./trace.ts";
|
|
20
|
+
import { loadCalibrationEvidence } from "./calibration_route.ts";
|
|
20
21
|
|
|
21
22
|
const DEFAULT_PROMPT = "Review this README for risky claims.";
|
|
22
23
|
|
|
@@ -61,6 +62,21 @@ function promptFromArgs(): string {
|
|
|
61
62
|
return DEFAULT_PROMPT;
|
|
62
63
|
}
|
|
63
64
|
|
|
65
|
+
async function calibrationFromArgs() {
|
|
66
|
+
const indices = Deno.args.flatMap((arg, index) =>
|
|
67
|
+
arg === "--calibration-evidence" ? [index] : []
|
|
68
|
+
);
|
|
69
|
+
if (indices.length === 0) return await loadCalibrationEvidence(undefined);
|
|
70
|
+
if (indices.length !== 1) {
|
|
71
|
+
throw new Error("--calibration-evidence may be specified only once");
|
|
72
|
+
}
|
|
73
|
+
const path = Deno.args[indices[0] + 1];
|
|
74
|
+
if (path === undefined || path.startsWith("--")) {
|
|
75
|
+
throw new Error("--calibration-evidence requires a local JSON file path");
|
|
76
|
+
}
|
|
77
|
+
return await loadCalibrationEvidence(path);
|
|
78
|
+
}
|
|
79
|
+
|
|
64
80
|
async function runModelsList(): Promise<void> {
|
|
65
81
|
const inventory = await inventoryCommand();
|
|
66
82
|
console.log("QuorumRouter model inventory");
|
|
@@ -92,7 +108,8 @@ async function runHealth(): Promise<void> {
|
|
|
92
108
|
)}`,
|
|
93
109
|
);
|
|
94
110
|
console.log(`Model inventory entries: ${inventory.entries.length}`);
|
|
95
|
-
console.log(`
|
|
111
|
+
console.log(`Discovered invokable providers: ${invokable.length}`);
|
|
112
|
+
console.log("Live provider authentication verified: false");
|
|
96
113
|
console.log("Provider request sent: false");
|
|
97
114
|
console.log(`Trace: ${tracePath}`);
|
|
98
115
|
console.log(
|
|
@@ -110,9 +127,11 @@ try {
|
|
|
110
127
|
else if (command === "health") await runHealth();
|
|
111
128
|
else if (command === "supabase:status") await runSupabaseStatus();
|
|
112
129
|
else if (command === "route:once") {
|
|
130
|
+
const calibration = await calibrationFromArgs();
|
|
113
131
|
await preflightRequiredSupabaseAudit();
|
|
114
132
|
const { results, tracePath, trace } = await invokeSelected(
|
|
115
133
|
promptFromArgs(),
|
|
134
|
+
calibration,
|
|
116
135
|
);
|
|
117
136
|
await auditRouteOutcome(trace);
|
|
118
137
|
console.log("QuorumRouter route:once");
|
|
@@ -126,8 +145,12 @@ try {
|
|
|
126
145
|
console.log(`final: ${summarize(results[0].response_summary, 500)}`);
|
|
127
146
|
console.log(`trace: ${tracePath}`);
|
|
128
147
|
} else if (command === "best-route") {
|
|
148
|
+
const calibration = await calibrationFromArgs();
|
|
129
149
|
await preflightRequiredSupabaseAudit();
|
|
130
|
-
const { results, tracePath, trace } = await runBestRoute(
|
|
150
|
+
const { results, tracePath, trace } = await runBestRoute(
|
|
151
|
+
promptFromArgs(),
|
|
152
|
+
calibration,
|
|
153
|
+
);
|
|
131
154
|
await auditRouteOutcome(trace);
|
|
132
155
|
console.log("QuorumRouter best-route");
|
|
133
156
|
console.log(`models_called: ${results.length}`);
|
|
@@ -8,7 +8,7 @@ import { buildTrace, writeTrace } from "./trace.ts";
|
|
|
8
8
|
export async function runIntake(): Promise<void> {
|
|
9
9
|
const inventory = await discoverInventoryWithModelListing();
|
|
10
10
|
await writeInventory(inventory);
|
|
11
|
-
const
|
|
11
|
+
const invokable = invokableEntries(inventory);
|
|
12
12
|
console.log("QuorumRouter intake");
|
|
13
13
|
console.log("");
|
|
14
14
|
console.log("Step 1 — Detect local providers");
|
|
@@ -16,7 +16,10 @@ export async function runIntake(): Promise<void> {
|
|
|
16
16
|
printInventoryTable(inventory);
|
|
17
17
|
console.log("");
|
|
18
18
|
console.log("Step 2 — OAuth/session status");
|
|
19
|
-
console.log(
|
|
19
|
+
console.log(
|
|
20
|
+
`Discovered invokable OAuth/session/wrapper providers: ${invokable.length}`,
|
|
21
|
+
);
|
|
22
|
+
console.log("Live provider authentication verified: false");
|
|
20
23
|
console.log("Provider request sent: false");
|
|
21
24
|
console.log("Credential values printed: false");
|
|
22
25
|
console.log("");
|
|
@@ -35,8 +38,8 @@ export async function runIntake(): Promise<void> {
|
|
|
35
38
|
command: "intake-health",
|
|
36
39
|
mode: "health",
|
|
37
40
|
authMode: inventory.auth_mode,
|
|
38
|
-
errors:
|
|
39
|
-
? ["no
|
|
41
|
+
errors: invokable.length === 0
|
|
42
|
+
? ["no invokable OAuth/session/wrapper provider was discovered"]
|
|
40
43
|
: [],
|
|
41
44
|
});
|
|
42
45
|
const tracePath = await writeTrace("intake-health-trace", trace);
|
|
@@ -44,10 +47,10 @@ export async function runIntake(): Promise<void> {
|
|
|
44
47
|
console.log("");
|
|
45
48
|
console.log("Step 6 — Recommended next action");
|
|
46
49
|
console.log("");
|
|
47
|
-
if (
|
|
50
|
+
if (invokable.length === 0) {
|
|
48
51
|
console.log("QuorumRouter intake blocked");
|
|
49
52
|
console.log("");
|
|
50
|
-
console.log("No
|
|
53
|
+
console.log("No invokable OAuth/session/wrapper provider was discovered.");
|
|
51
54
|
console.log("");
|
|
52
55
|
console.log("Next:");
|
|
53
56
|
console.log(" deno task auth:login");
|
|
@@ -46,7 +46,7 @@ export async function inventoryCommand(): Promise<ModelInventory> {
|
|
|
46
46
|
export function printInventoryTable(inventory: ModelInventory): void {
|
|
47
47
|
console.log("Provider Status Auth Models");
|
|
48
48
|
for (const entry of inventory.entries) {
|
|
49
|
-
const status = entry.available ? "
|
|
49
|
+
const status = entry.available ? "discovered" : "blocked";
|
|
50
50
|
const models = entry.listed_models?.length
|
|
51
51
|
? entry.listed_models.join(", ")
|
|
52
52
|
: entry.model;
|
|
@@ -56,4 +56,7 @@ export function printInventoryTable(inventory: ModelInventory): void {
|
|
|
56
56
|
} ${models}`,
|
|
57
57
|
);
|
|
58
58
|
}
|
|
59
|
+
console.log(
|
|
60
|
+
"Status note: discovered means command/config present; live authentication is not verified.",
|
|
61
|
+
);
|
|
59
62
|
}
|
|
@@ -61,7 +61,6 @@ export function providerAliasesForCommand(
|
|
|
61
61
|
claude: ["anthropic", "claude", "claude-code"],
|
|
62
62
|
gemini: ["google", "gemini", "gemini-cli"],
|
|
63
63
|
devin: ["cognition", "devin", "devin-cli"],
|
|
64
|
-
qwen: ["alibaba", "qwen", "qwen-cli"],
|
|
65
64
|
};
|
|
66
65
|
const providerAliases: Record<string, string[]> = {
|
|
67
66
|
xai: ["grok", "grok-cli", "xai", "xai-cli"],
|
|
@@ -69,7 +68,6 @@ export function providerAliasesForCommand(
|
|
|
69
68
|
anthropic: ["anthropic", "claude", "claude-code"],
|
|
70
69
|
google: ["google", "gemini", "gemini-cli"],
|
|
71
70
|
cognition: ["cognition", "devin", "devin-cli"],
|
|
72
|
-
alibaba: ["alibaba", "qwen", "qwen-cli"],
|
|
73
71
|
};
|
|
74
72
|
const normalizedProvider = normalizeSelectionValue(provider);
|
|
75
73
|
return aliasSet([
|
|
@@ -220,19 +218,6 @@ export const LOCAL_PROVIDER_SPECS: ProviderSpec[] = [
|
|
|
220
218
|
"Devin CLI does not expose a models subcommand in this environment.",
|
|
221
219
|
notes: ["Uses existing Devin CLI session."],
|
|
222
220
|
},
|
|
223
|
-
{
|
|
224
|
-
provider: "Alibaba",
|
|
225
|
-
model: "qwen-cli",
|
|
226
|
-
model_id: "alibaba/qwen-cli",
|
|
227
|
-
auth_mode: "session",
|
|
228
|
-
source: "local_cli",
|
|
229
|
-
command: "qwen",
|
|
230
|
-
args_template: ["-p", ""],
|
|
231
|
-
prompt_transport: "stdin",
|
|
232
|
-
list_blocked_reason:
|
|
233
|
-
"Qwen CLI model listing path is stdin/API-key dependent in this environment.",
|
|
234
|
-
notes: ["Uses existing local Qwen CLI session."],
|
|
235
|
-
},
|
|
236
221
|
];
|
|
237
222
|
|
|
238
223
|
export function envFallbackEntry(configured: boolean): ModelInventoryEntry {
|
|
@@ -168,6 +168,23 @@ export type CostAwareTrace = {
|
|
|
168
168
|
}>;
|
|
169
169
|
};
|
|
170
170
|
|
|
171
|
+
export type CalibrationTraceSummary = {
|
|
172
|
+
schema_version: "quorum-router.calibration-trace.v1";
|
|
173
|
+
advisory_only: true;
|
|
174
|
+
minimum_sample_count: number;
|
|
175
|
+
group_count: number;
|
|
176
|
+
groups: Array<{
|
|
177
|
+
task_type_sha256: string;
|
|
178
|
+
source_sha256: string;
|
|
179
|
+
sample_count: number;
|
|
180
|
+
accuracy: number;
|
|
181
|
+
mean_confidence: number;
|
|
182
|
+
brier_score: number;
|
|
183
|
+
mean_calibration_bias: number;
|
|
184
|
+
sample_status: "insufficient" | "sufficient";
|
|
185
|
+
}>;
|
|
186
|
+
};
|
|
187
|
+
|
|
171
188
|
export type DogfoodTrace = {
|
|
172
189
|
run_id: string;
|
|
173
190
|
timestamp: string;
|
|
@@ -186,6 +203,7 @@ export type DogfoodTrace = {
|
|
|
186
203
|
prompt_summary?: string;
|
|
187
204
|
prompt_context?: PromptContextTrace;
|
|
188
205
|
cost_aware?: CostAwareTrace;
|
|
206
|
+
calibration?: CalibrationTraceSummary;
|
|
189
207
|
response_summary?: string;
|
|
190
208
|
schema_valid: boolean;
|
|
191
209
|
redaction_ok: boolean;
|
|
@@ -217,9 +235,12 @@ export function assertOptIn(): void {
|
|
|
217
235
|
}
|
|
218
236
|
|
|
219
237
|
export function assertAgentChatOptIn(): void {
|
|
220
|
-
if (
|
|
238
|
+
if (
|
|
239
|
+
Deno.env.get("RUN_AGENT_CHAT") !== "1" &&
|
|
240
|
+
Deno.env.get("RUN_EXPERIMENTAL_AGENT_CHAT") !== "1"
|
|
241
|
+
) {
|
|
221
242
|
throw new Error(
|
|
222
|
-
"agent_chat blocked: set
|
|
243
|
+
"agent_chat blocked: set RUN_AGENT_CHAT=1; live multi-model dialogue is explicit opt-in and has no mutation authority",
|
|
223
244
|
);
|
|
224
245
|
}
|
|
225
246
|
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AgentChatTurn,
|
|
3
3
|
AuthMode,
|
|
4
|
+
CalibrationTraceSummary,
|
|
4
5
|
CostAwareTrace,
|
|
5
6
|
DogfoodTrace,
|
|
6
7
|
PromptContextTrace,
|
|
7
8
|
ProviderResult,
|
|
8
9
|
ScoreRow,
|
|
9
10
|
} from "./schema.ts";
|
|
11
|
+
import type { TaskCalibrationReport } from "./calibration.ts";
|
|
10
12
|
import { redactionOk, summarize } from "./redact.ts";
|
|
11
13
|
|
|
12
14
|
export const OUT_DIR = "out";
|
|
@@ -35,6 +37,29 @@ export async function promptHash(prompt: string): Promise<string> {
|
|
|
35
37
|
).join("");
|
|
36
38
|
}
|
|
37
39
|
|
|
40
|
+
async function calibrationTraceSummary(
|
|
41
|
+
report: TaskCalibrationReport,
|
|
42
|
+
): Promise<CalibrationTraceSummary> {
|
|
43
|
+
return {
|
|
44
|
+
schema_version: "quorum-router.calibration-trace.v1",
|
|
45
|
+
advisory_only: true,
|
|
46
|
+
minimum_sample_count: report.minimum_sample_count,
|
|
47
|
+
group_count: report.groups.length,
|
|
48
|
+
groups: await Promise.all(report.groups.map(async (group) => ({
|
|
49
|
+
task_type_sha256: await promptHash(group.task_type),
|
|
50
|
+
source_sha256: await promptHash(
|
|
51
|
+
`${group.source.provider}\u0000${group.source.model}`,
|
|
52
|
+
),
|
|
53
|
+
sample_count: group.sample_count,
|
|
54
|
+
accuracy: group.accuracy,
|
|
55
|
+
mean_confidence: group.mean_confidence,
|
|
56
|
+
brier_score: group.brier_score,
|
|
57
|
+
mean_calibration_bias: group.mean_calibration_bias,
|
|
58
|
+
sample_status: group.sample_status,
|
|
59
|
+
}))),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
38
63
|
export function score(result: ProviderResult): ScoreRow {
|
|
39
64
|
const text = result.response_summary;
|
|
40
65
|
const clarity = text.length > 20 ? 4 : 2;
|
|
@@ -77,7 +102,11 @@ export async function buildTrace(args: {
|
|
|
77
102
|
fallbackUsed?: boolean;
|
|
78
103
|
costAware?: CostAwareTrace;
|
|
79
104
|
agentChatTurns?: AgentChatTurn[];
|
|
105
|
+
calibration?: TaskCalibrationReport;
|
|
80
106
|
}): Promise<DogfoodTrace> {
|
|
107
|
+
const calibration = args.calibration
|
|
108
|
+
? await calibrationTraceSummary(args.calibration)
|
|
109
|
+
: undefined;
|
|
81
110
|
const responseSummary = args.results?.map((r) =>
|
|
82
111
|
`[${r.provider}/${r.model}] ${r.response_summary}`
|
|
83
112
|
).join("\n");
|
|
@@ -96,6 +125,7 @@ export async function buildTrace(args: {
|
|
|
96
125
|
provider_selection_honored: args.providerSelectionHonored ?? true,
|
|
97
126
|
fallback_used: args.fallbackUsed ?? false,
|
|
98
127
|
cost_aware: args.costAware,
|
|
128
|
+
...(calibration ? { calibration } : {}),
|
|
99
129
|
prompt_hash: args.prompt ? await promptHash(args.prompt) : undefined,
|
|
100
130
|
prompt_summary: args.prompt ? summarize(args.prompt, 160) : undefined,
|
|
101
131
|
prompt_context: args.promptContext,
|