bitfab-cli 0.2.399 → 0.2.401
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/dist/index.js +45 -24
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23449,6 +23449,7 @@ var MAX_ASSIGNEE_EMAIL_LENGTH = 320;
|
|
|
23449
23449
|
var GET_GRADER_LABELS_MAX_IDS = 100;
|
|
23450
23450
|
var DEFAULT_GRADER_LABEL_LIMIT = 50;
|
|
23451
23451
|
var MAX_GRADER_LABEL_LIMIT = 200;
|
|
23452
|
+
var SAVE_GRADER_LABELS_MAX_ENTRIES = 200;
|
|
23452
23453
|
function parseJsonString(val) {
|
|
23453
23454
|
if (typeof val !== "string") {
|
|
23454
23455
|
return val;
|
|
@@ -23752,7 +23753,7 @@ var archiveTraceAssertions = {
|
|
|
23752
23753
|
var saveGrader = {
|
|
23753
23754
|
name: "save_grader",
|
|
23754
23755
|
title: "Save Grader",
|
|
23755
|
-
description: `Create or edit
|
|
23756
|
+
description: `Create or edit a grader: a pass/fail check that describes what must hold for a traced function (e.g. 'The reply never invents order numbers'). Call when the user asks to add, define, update, rename, archive, or restore a grader or check for a traced function. By default the grader is an LLM-as-judge that Bitfab runs; pass external: true when the user evaluates traces themselves. To create, pass traceFunctionKey + name + evaluationFocus. To edit, pass graderId (from list_graders) plus only the fields to change; saving with the name of an existing grader on the same function updates that grader instead of creating a duplicate. Set status to "archived" to retire a grader; any later save that omits status (or sets "active") restores it. On edit, pass an empty string for passCriteria/failCriteria to clear them. After a successful create or update, present the returned grader definition to the user, including its evaluation focus and any pass/fail criteria; do not respond with only a generic success confirmation. Graders are definitions only for now: nothing auto-evaluates them on new traces yet, so do not promise live grading. Call list_graders first to find ids and avoid duplicates. An external grader is one the user runs themselves (their own eval harness, CI, a human review queue): Bitfab never runs it, and its verdicts are posted with save_grader_labels. A grader's external setting is fixed at creation and cannot be changed on edit, and external graders take no model.`,
|
|
23756
23757
|
inputSchema: {
|
|
23757
23758
|
graderId: external_exports.uuid().optional().describe("Id of an existing grader to edit (from list_graders or a previous save). Omit to create a new grader (or update-by-name)."),
|
|
23758
23759
|
traceFunctionKey: external_exports.string().min(1).optional().describe("The traced function the grader applies to. Required when graderId is omitted; ignored when it is set."),
|
|
@@ -23765,13 +23766,14 @@ var saveGrader = {
|
|
|
23765
23766
|
status: external_exports.enum(["active", "archived"]).optional().describe(`The grader's status: "active" (the default for a create or edit) or "archived" to retire it (hidden from list_graders by default). Omit on edit to keep it active / restore an archived grader.`),
|
|
23766
23767
|
// Keep the enum in sync with bitfab-web's save_grader route schema
|
|
23767
23768
|
// (GRADER_MODEL_SLUGS in graderModels.ts).
|
|
23768
|
-
model: external_exports.enum(["gemini-2-5-flash", "sol", "terra", "opus-4-8", "gemini-3-1-pro"]).optional().describe("Optional: the judge model this grader runs on. One of: gemini-2-5-flash, sol, terra, opus-4-8, gemini-3-1-pro. Omit to keep the current value (defaults to gemini-2-5-flash).")
|
|
23769
|
+
model: external_exports.enum(["gemini-2-5-flash", "sol", "terra", "opus-4-8", "gemini-3-1-pro"]).optional().describe("Optional: the judge model this grader runs on. One of: gemini-2-5-flash, sol, terra, opus-4-8, gemini-3-1-pro. Omit to keep the current value (defaults to gemini-2-5-flash)."),
|
|
23770
|
+
external: external_exports.boolean().optional().describe("Create an external grader: Bitfab never runs it, and its verdicts arrive through save_grader_labels. Only honored when creating; on edit it must match the grader or be omitted.")
|
|
23769
23771
|
}
|
|
23770
23772
|
};
|
|
23771
23773
|
var listGraders = {
|
|
23772
23774
|
name: "list_graders",
|
|
23773
23775
|
title: "List Graders",
|
|
23774
|
-
description: "List the
|
|
23776
|
+
description: "List the graders for a traced function: LLM-as-judge graders Bitfab runs, and external graders (marked 'Runs: externally') whose verdicts the user posts with save_grader_labels. Each comes with id, name, status, evaluation focus, and pass/fail criteria. Call before save_grader to find the grader to edit or to avoid creating a duplicate. Results are newest-first and paginated. Archived graders are hidden unless includeArchived is true.",
|
|
23775
23777
|
inputSchema: {
|
|
23776
23778
|
traceFunctionKey: external_exports.string().min(1).describe("The trace function key to list graders for"),
|
|
23777
23779
|
includeArchived: external_exports.preprocess(parseJsonString, external_exports.boolean()).optional().describe("Include archived graders (default false)"),
|
|
@@ -23992,13 +23994,28 @@ var getExperiment = {
|
|
|
23992
23994
|
var getGraderLabels = {
|
|
23993
23995
|
name: "get_grader_labels",
|
|
23994
23996
|
title: "Get Grader Labels",
|
|
23995
|
-
description: `Read the INDIVIDUAL verdicts each
|
|
23997
|
+
description: `Read the INDIVIDUAL verdicts each grader recorded, one row per grader per trace, with the grader's reason, its failure diagnostic, the confidence, and whether the verdict came from a human, a grader Bitfab ran, or an external grader whose verdict was posted from outside Bitfab with save_grader_labels. This is the per-grader breakdown that get_trace_labels does not show: that tool returns one grader-agnostic verdict per trace, so use it for a dataset's overall pass/fail and use this one to see WHICH check failed and why. Pass traceIds to see every grader's verdict on those traces, graderId to see that grader's most recent verdicts across traces (newest first, use it to diagnose a grader that is misfiring), or both to narrow to one grader on specific traces. Call list_graders first if you need grader ids.`,
|
|
23996
23998
|
inputSchema: {
|
|
23997
23999
|
traceIds: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.uuid()).min(1).max(GET_GRADER_LABELS_MAX_IDS)).optional().describe(`Trace IDs to read grader verdicts for (1-${GET_GRADER_LABELS_MAX_IDS}). Omit to read by grader instead.`),
|
|
23998
24000
|
graderId: external_exports.uuid().optional().describe("Restrict to one grader (from list_graders). On its own, returns that grader's most recent verdicts across all traces."),
|
|
23999
24001
|
limit: external_exports.preprocess(parseJsonString, external_exports.number().int().min(1).max(MAX_GRADER_LABEL_LIMIT)).optional().describe(`Max labels to return when reading by grader alone (default ${DEFAULT_GRADER_LABEL_LIMIT}, max ${MAX_GRADER_LABEL_LIMIT}). Ignored when traceIds is given.`)
|
|
24000
24002
|
}
|
|
24001
24003
|
};
|
|
24004
|
+
var saveGraderLabels = {
|
|
24005
|
+
name: "save_grader_labels",
|
|
24006
|
+
title: "Save Grader Labels",
|
|
24007
|
+
description: `Record verdicts for EXTERNAL graders: graders created with save_grader external: true, which Bitfab never runs because the user evaluates traces somewhere else (their own eval harness, CI, a review queue). Each entry is one grader's pass/fail on one trace, written as that grader's own verdict, so it shows up everywhere Bitfab-run grader verdicts do: get_grader_labels, dataset and experiment pass rates, and the trace's grader panel. Saving again for the same grader and trace replaces the earlier verdict. Rejects every grader that is not external: Bitfab runs its own graders, and a human's verdict on a trace belongs in save_human_labels. Up to ${SAVE_GRADER_LABELS_MAX_ENTRIES} entries per call; the whole call is rejected if any entry is invalid.`,
|
|
24008
|
+
inputSchema: {
|
|
24009
|
+
labels: external_exports.preprocess(parseJsonString, external_exports.array(external_exports.object({
|
|
24010
|
+
graderId: external_exports.uuid().describe("The external grader that produced this verdict (from list_graders or save_grader)."),
|
|
24011
|
+
traceId: external_exports.uuid().describe("The trace the verdict is about."),
|
|
24012
|
+
label: external_exports.boolean().describe("true for PASS, false for FAIL. Required."),
|
|
24013
|
+
reason: external_exports.string().min(1).optional().describe("Why the grader reached this verdict. Optional."),
|
|
24014
|
+
failureDiagnostic: external_exports.string().min(1).optional().describe("For a FAIL: what went wrong in the trace, in a form someone fixing it can act on. Optional."),
|
|
24015
|
+
confidence: external_exports.enum(["VeryLow", "Low", "Medium", "High", "VeryHigh"]).optional().describe("How confident the grader is: VeryLow / Low / Medium / High / VeryHigh. Optional.")
|
|
24016
|
+
})).min(1).max(SAVE_GRADER_LABELS_MAX_ENTRIES)).describe(`One entry per grader per trace (1-${SAVE_GRADER_LABELS_MAX_ENTRIES}).`)
|
|
24017
|
+
}
|
|
24018
|
+
};
|
|
24002
24019
|
var getSimPlan = {
|
|
24003
24020
|
name: "get_sim_plan",
|
|
24004
24021
|
title: "Get Sim Plan",
|
|
@@ -24022,6 +24039,7 @@ var saveSimPlan = {
|
|
|
24022
24039
|
};
|
|
24023
24040
|
var ALL_TOOL_CONTRACTS = [
|
|
24024
24041
|
getGraderLabels,
|
|
24042
|
+
saveGraderLabels,
|
|
24025
24043
|
getExperiment,
|
|
24026
24044
|
getExperimentGroup,
|
|
24027
24045
|
saveExperiment,
|
|
@@ -24679,10 +24697,10 @@ var semver3 = __toESM(require_semver2(), 1);
|
|
|
24679
24697
|
|
|
24680
24698
|
// ../bitfab-plugin-lib/dist/bakedSdkVersions.js
|
|
24681
24699
|
var BAKED_SDK_VERSIONS = {
|
|
24682
|
-
typescript: "0.62.
|
|
24683
|
-
python: "0.62.
|
|
24684
|
-
ruby: "0.62.
|
|
24685
|
-
go: "0.62.
|
|
24700
|
+
typescript: "0.62.3",
|
|
24701
|
+
python: "0.62.2",
|
|
24702
|
+
ruby: "0.62.2",
|
|
24703
|
+
go: "0.62.2"
|
|
24686
24704
|
};
|
|
24687
24705
|
|
|
24688
24706
|
// ../bitfab-plugin-lib/dist/installedSdk.js
|
|
@@ -26022,14 +26040,17 @@ Run ${platform2.loginHint} to re-authenticate.`);
|
|
|
26022
26040
|
}
|
|
26023
26041
|
|
|
26024
26042
|
// ../bitfab-plugin-lib/dist/commands/switchOrg.js
|
|
26025
|
-
async function requestSwitch(serviceUrl, apiKey,
|
|
26043
|
+
async function requestSwitch(serviceUrl, apiKey, authOrganizationId) {
|
|
26026
26044
|
const res = await fetch(`${serviceUrl}/api/plugin/organizations/switch`, {
|
|
26027
26045
|
method: "POST",
|
|
26028
26046
|
headers: {
|
|
26029
26047
|
Authorization: `Bearer ${apiKey}`,
|
|
26030
26048
|
"Content-Type": "application/json"
|
|
26031
26049
|
},
|
|
26032
|
-
body: JSON.stringify({
|
|
26050
|
+
body: JSON.stringify({
|
|
26051
|
+
authOrganizationId,
|
|
26052
|
+
clerkOrganizationId: authOrganizationId
|
|
26053
|
+
})
|
|
26033
26054
|
});
|
|
26034
26055
|
if (!res.ok) {
|
|
26035
26056
|
throw new Error(`Failed to switch organization (HTTP ${res.status})`);
|
|
@@ -26038,9 +26059,9 @@ async function requestSwitch(serviceUrl, apiKey, clerkOrganizationId) {
|
|
|
26038
26059
|
}
|
|
26039
26060
|
var ARGS = [
|
|
26040
26061
|
{
|
|
26041
|
-
name: "
|
|
26062
|
+
name: "authOrganizationId",
|
|
26042
26063
|
required: false,
|
|
26043
|
-
description: "
|
|
26064
|
+
description: "Organization ID to make active. Discover IDs with the list_organizations MCP tool."
|
|
26044
26065
|
}
|
|
26045
26066
|
];
|
|
26046
26067
|
async function runSwitchOrg(platform2) {
|
|
@@ -26049,21 +26070,21 @@ async function runSwitchOrg(platform2) {
|
|
|
26049
26070
|
})[0] ?? null;
|
|
26050
26071
|
const { apiKey, serviceUrl } = requireAuth(platform2.loginHint);
|
|
26051
26072
|
if (!target) {
|
|
26052
|
-
console.error("Usage: switchOrg <
|
|
26073
|
+
console.error("Usage: switchOrg <authOrganizationId>");
|
|
26053
26074
|
console.error("Discover org ids with the list_organizations MCP tool, then pass one here.");
|
|
26054
26075
|
process.exit(1);
|
|
26055
26076
|
}
|
|
26056
26077
|
try {
|
|
26057
26078
|
const result = await requestSwitch(serviceUrl, apiKey, target);
|
|
26058
26079
|
if (result.status === "not-member") {
|
|
26059
|
-
emitJson({ event: "not-member",
|
|
26080
|
+
emitJson({ event: "not-member", authOrganizationId: target });
|
|
26060
26081
|
return;
|
|
26061
26082
|
}
|
|
26062
26083
|
saveCredentials(result.apiKey);
|
|
26063
26084
|
emitJson({
|
|
26064
26085
|
event: "switched",
|
|
26065
26086
|
status: result.status,
|
|
26066
|
-
|
|
26087
|
+
authOrganizationId: result.authOrganizationId ?? result.clerkOrganizationId ?? target,
|
|
26067
26088
|
organizationName: result.organizationName,
|
|
26068
26089
|
apiKey: result.apiKey
|
|
26069
26090
|
});
|
|
@@ -31220,8 +31241,8 @@ var setupFlow = Flow.parse({
|
|
|
31220
31241
|
description: "Open a sign-in window and wait for authentication. Relay the printed sign-in link as a fallback."
|
|
31221
31242
|
},
|
|
31222
31243
|
switchOrg: {
|
|
31223
|
-
description: "List the user's Bitfab orgs (no args), or switch the plugin's active org and replace the local API key (with a <
|
|
31224
|
-
args: "[<
|
|
31244
|
+
description: "List the user's Bitfab orgs (no args), or switch the plugin's active org and replace the local API key (with a <authOrganizationId> arg)",
|
|
31245
|
+
args: "[<authOrganizationId>]"
|
|
31225
31246
|
},
|
|
31226
31247
|
startTemplatePreview: {
|
|
31227
31248
|
description: "Print a template preview link and exit.",
|
|
@@ -32230,7 +32251,7 @@ Then, for anything not healthy, name the most likely cause and the fix:
|
|
|
32230
32251
|
- **Root not replayable**, two failure modes, with the fix matched to each: **(a) the root takes unserializable inputs** (live SDK/DB clients, HTTP req/res, streams, opaque contexts), with or without a replay registry module: move the trace boundary inward to a serializable-input function or refactor to introduce one; **(b) a bare trace-processor-only key** ({{traceProcessorNames}}) whose root is the processor's empty-input span: add a \`withTrace\`/\`trace\` root that wraps the run and takes its input in a supported subtree runtime, or route the run through the run wrapper ({{traceProcessorRootWrappers}}). Use a manual \`withSpan\`/\`@span\` root only when opt-out is technically unavailable. Either way, re-instrument via \`{{cmd}}setup modify\` (or \`{{cmd}}setup instrument\` for a fresh boundary). This is a code change, recommended here, not applied blanket.
|
|
32231
32252
|
- **Opt-out roots without subtree capture**: every trace is the root alone, so tracing looks healthy and the traces are useless for per-step diagnosis, replay mocking, and prompt iteration. For TypeScript, use the installed SDK and wire the matching adapter into the build behind the server entrypoint, preserving existing config wrappers such as Sentry. For Python, this is a runtime upgrade to 3.12+; report it rather than attempting it.
|
|
32232
32253
|
- **Instrumented but no traces**: the app hasn't run with tracing enabled, or \`BITFAB_API_KEY\` isn't set in the run environment. Run the app with the key loaded.
|
|
32233
|
-
- **Key set but traces aren't visible in the browser**: the API key
|
|
32254
|
+
- **Key set but traces aren't visible in the browser**: the API key belongs to a different organization than the one the browser is showing. A key is bound to one organization when it is created, and the browser shows the signed-in user's active organization. Have the user pick the key's organization in the in-app org switcher; if it isn't listed, the signed-in user isn't a member of it.
|
|
32234
32255
|
- **Nothing instrumented**: run \`{{cmd}}setup instrument\`.
|
|
32235
32256
|
- **Want to change what's captured**: run \`{{cmd}}setup modify\`.
|
|
32236
32257
|
|
|
@@ -32294,7 +32315,7 @@ For unusual monorepos or private registries, defer to \`{{cmd}}update\`. Report
|
|
|
32294
32315
|
stepStyle: "list",
|
|
32295
32316
|
intro: `Switch which Bitfab organization the plugin reads and writes. Triggered explicitly by \`{{cmd}}setup switch-org\` (or natural-language asks like "switch org" / "change org" / "switch to the <name> org" / "I'm in the wrong org"). The plugin's org is set by the API key in \`~/.config/bitfab/credentials.json\`; this lists the user's orgs, switches to the chosen one, and replaces that local key. Requires authentication. Does **not** open Bitfab.
|
|
32296
32317
|
|
|
32297
|
-
**The live browser does not follow on its own.** Switching persists the new active org server-side (so future sign-ins default to it) and replaces the plugin's key, but a browser tab that's already signed in keeps showing the old org until its session is re-minted. The org actually flips in the browser on the **next** Bitfab open (a fresh session whose org check
|
|
32318
|
+
**The live browser does not follow on its own.** Switching persists the new active org server-side (so future sign-ins default to it) and replaces the plugin's key, but a browser tab that's already signed in keeps showing the old org until its session is re-minted. The org actually flips in the browser on the **next** Bitfab open (a fresh session whose org check sets the active organization in the browser) or when the user picks the org from the in-app org switcher.
|
|
32298
32319
|
|
|
32299
32320
|
**The plugin key and the app's runtime key are separate.** Switching replaces only the plugin's credential in \`~/.config/bitfab/credentials.json\`. The \`BITFAB_API_KEY\` your application reads at runtime (from a \`.env\`-style file) is untouched, so traces your code sends keep landing in the **old** org until that key is updated too. The last step offers to do that.`,
|
|
32300
32321
|
steps: [
|
|
@@ -32327,7 +32348,7 @@ If **already authenticated**, continue to step {{step:switch-org/pick-org}}. If
|
|
|
32327
32348
|
kind: "branch",
|
|
32328
32349
|
toolCalls: ["listOrganizations", "ask"],
|
|
32329
32350
|
title: "List the orgs and choose a target",
|
|
32330
|
-
body: `Call {{tool:listOrganizations}} to list the organizations the signed-in user belongs to. Each entry has a name, the user's role, an \`id:\` (the \`
|
|
32351
|
+
body: `Call {{tool:listOrganizations}} to list the organizations the signed-in user belongs to. Each entry has a name, the user's role, an \`id:\` (the \`authOrganizationId\`), and the org the plugin uses now is marked \`[current]\`.
|
|
32331
32352
|
|
|
32332
32353
|
Choose the target org:
|
|
32333
32354
|
- **If the user already named an org** (in their request), match it case-insensitively by name against the list and use that org's \`id\`. If the name matches none, or matches more than one, fall through to asking.
|
|
@@ -32352,15 +32373,15 @@ Only ever use an \`id\` value returned by {{tool:listOrganizations}}; never inve
|
|
|
32352
32373
|
toolCalls: ["bash"],
|
|
32353
32374
|
commandCalls: ["switchOrg"],
|
|
32354
32375
|
title: "Switch and confirm",
|
|
32355
|
-
body: `Switch to the chosen org by passing its \`
|
|
32376
|
+
body: `Switch to the chosen org by passing its \`authOrganizationId\`:
|
|
32356
32377
|
|
|
32357
32378
|
\`\`\`bash
|
|
32358
|
-
{{command:switchOrg}} <
|
|
32379
|
+
{{command:switchOrg}} <authOrganizationId>
|
|
32359
32380
|
\`\`\`
|
|
32360
32381
|
|
|
32361
32382
|
The command prints one JSON line; act on it:
|
|
32362
|
-
- \`{"event":"switched","status":"switched"|"already-aligned","
|
|
32363
|
-
- \`{"event":"not-member","
|
|
32383
|
+
- \`{"event":"switched","status":"switched"|"already-aligned","authOrganizationId":"...","organizationName":"...","apiKey":"..."}\`: success. The plugin now reads and writes that org and its API key has been replaced locally. Tell the user in one line: the plugin is now connected to **<organizationName>**. Then tell them to select **<organizationName>** with the in-app org switcher to align their browser with the plugin. Opening a plugin page link does not change the browser's active organization. Hold on to the \`apiKey\` value from this JSON; the next step uses it to sync the app's local key, and you must never echo that value to the user.
|
|
32384
|
+
- \`{"event":"not-member","authOrganizationId":"..."}\`: the user isn't a member of that org. Report it; do not retry.
|
|
32364
32385
|
- \`{"event":"error","reason":"..."}\`: report the reason.
|
|
32365
32386
|
|
|
32366
32387
|
Do not print or ask for the API key, and do not surface the \`apiKey\` value to the user; the command replaces the plugin's copy for you and hands you that value solely for the next step.
|
package/package.json
CHANGED