@kontextmind/kxm 0.7.60 → 0.7.63
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/.claude-plugin/marketplace.json +1 -1
- package/docs/contracts/lifecycles.md +1 -1
- package/package.json +1 -1
- package/plugins/kxm/.claude-plugin/plugin.json +1 -1
- package/plugins/kxm/dist/mcp-server.js +1 -1
- package/plugins/kxm/dist/runtime-supervisor.js +40 -7
- package/plugins/kxm/dist/runtime.js +46 -7
- package/plugins/kxm/package.json +1 -1
- package/plugins/kxm/src/engine.ts +61 -7
- package/plugins/kxm/src/mcp-server.ts +1 -1
- package/plugins/kxm/src/pi-producer.ts +10 -0
- package/schemas/run-event.schema.json +1 -0
|
@@ -100,7 +100,7 @@ created → accepted → dispatched → executing → result_recorded → termin
|
|
|
100
100
|
| `dispatched` | Attempt identity and dispatch intent persisted before process start |
|
|
101
101
|
| `executing` | Invocation admitted and the attempt capability is usable. This slice is in-process (no OS process identity yet); later recovery still requires exact process/session proof |
|
|
102
102
|
| `reattaching` | Runtime is verifying the same process/session and event cursor |
|
|
103
|
-
| `result_recorded` | Structured attempt result and referenced receipts are durably stored |
|
|
103
|
+
| `result_recorded` | Structured attempt result and referenced receipts are durably stored. When a producer **refused** (`resultClass: producer_rejected`), the payload may carry `producerError`: a **machine code only** (lowercase-underscore identifier, ≤64 chars, schema-enforced; capability material is redacted before extraction, and anything unclassifiable — including prose — records as `producer_error`). The routing record names the producer that actually ran: a live drive that fails authentication must never read in the log as a simulation |
|
|
104
104
|
| `retry_pending` | Policy permits another physical attempt after the prior attempt became terminal |
|
|
105
105
|
| `blocked_uncertain` | A dependent effect cannot be reconciled safely |
|
|
106
106
|
| `terminal` | The logical assignment outcome is final and immutable: passed, failed, or cancelled |
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"$schema": "https://json.schemastore.org/claude-code-plugin-manifest.json",
|
|
3
3
|
"name": "kxm",
|
|
4
4
|
"displayName": "KXM",
|
|
5
|
-
"version": "0.7.
|
|
5
|
+
"version": "0.7.63",
|
|
6
6
|
"description": "Headless multi-agent orchestration, durable workflows, and a live operator dashboard for Pi and Claude Code",
|
|
7
7
|
"author": {
|
|
8
8
|
"name": "KontextMind",
|
|
@@ -17121,7 +17121,7 @@ async function deliverInboxNotification(messageId, delivered, notify) {
|
|
|
17121
17121
|
}
|
|
17122
17122
|
|
|
17123
17123
|
// plugins/kxm/src/mcp-server.ts
|
|
17124
|
-
var VERSION = "0.7.
|
|
17124
|
+
var VERSION = "0.7.63";
|
|
17125
17125
|
var inbox = /* @__PURE__ */ new Map();
|
|
17126
17126
|
var notifiedInbox = /* @__PURE__ */ new Set();
|
|
17127
17127
|
var meshClient;
|
|
@@ -24601,15 +24601,29 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
24601
24601
|
}
|
|
24602
24602
|
};
|
|
24603
24603
|
function invokeProducer(producer, request) {
|
|
24604
|
+
const reason = (error) => {
|
|
24605
|
+
try {
|
|
24606
|
+
const raw = error instanceof Error ? error.message : error;
|
|
24607
|
+
const message = typeof raw === "string" ? raw : "";
|
|
24608
|
+
let text = message;
|
|
24609
|
+
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
24610
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
24611
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
24612
|
+
const code = match?.[0] ?? "";
|
|
24613
|
+
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
24614
|
+
} catch {
|
|
24615
|
+
return "producer_error";
|
|
24616
|
+
}
|
|
24617
|
+
};
|
|
24604
24618
|
let pending;
|
|
24605
24619
|
try {
|
|
24606
24620
|
pending = Promise.resolve(producer.produce(request));
|
|
24607
|
-
} catch {
|
|
24608
|
-
return Promise.resolve({ error: true });
|
|
24621
|
+
} catch (error) {
|
|
24622
|
+
return Promise.resolve({ error: true, errorCode: reason(error) });
|
|
24609
24623
|
}
|
|
24610
24624
|
return pending.then(
|
|
24611
24625
|
(result) => ({ result, error: false }),
|
|
24612
|
-
() => ({ error: true })
|
|
24626
|
+
(error) => ({ error: true, errorCode: reason(error) })
|
|
24613
24627
|
);
|
|
24614
24628
|
}
|
|
24615
24629
|
var kxmGateDispatchSeams = {};
|
|
@@ -24883,6 +24897,21 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
24883
24897
|
const parsed = (0, import_yaml5.parse)(readFileSync7(agentFile, "utf8"));
|
|
24884
24898
|
if (typeof parsed?.model === "string") {
|
|
24885
24899
|
agentModel = parsed.model;
|
|
24900
|
+
} else if (parsed?.model && typeof parsed.model === "object" && !Array.isArray(parsed.model)) {
|
|
24901
|
+
const declared = parsed.model;
|
|
24902
|
+
const providerOk = typeof declared.provider === "string" && declared.provider.length > 0 && !declared.provider.includes("/");
|
|
24903
|
+
const modelOk = typeof declared.model === "string" && declared.model.length > 0 && !declared.model.startsWith("/") && !declared.model.endsWith("/");
|
|
24904
|
+
if (providerOk && modelOk) {
|
|
24905
|
+
agentModel = `${declared.provider}/${declared.model}`;
|
|
24906
|
+
} else {
|
|
24907
|
+
return {
|
|
24908
|
+
error: {
|
|
24909
|
+
reason: "step_unsupported",
|
|
24910
|
+
field: "model",
|
|
24911
|
+
detail: "producer_route_unsupported: invalid model declaration"
|
|
24912
|
+
}
|
|
24913
|
+
};
|
|
24914
|
+
}
|
|
24886
24915
|
}
|
|
24887
24916
|
} catch {
|
|
24888
24917
|
}
|
|
@@ -25413,7 +25442,7 @@ async function drivePanel(context, panel, producer) {
|
|
|
25413
25442
|
if (kxmPanelDispatchSeams.failSettleMember?.(member)) {
|
|
25414
25443
|
throw runtimeError("run_events_illegal", runId, "member settlement write failed");
|
|
25415
25444
|
}
|
|
25416
|
-
settleMember(context, member, produced.result, produced.error);
|
|
25445
|
+
settleMember(context, member, produced.result, produced.error, produced.errorCode);
|
|
25417
25446
|
});
|
|
25418
25447
|
return true;
|
|
25419
25448
|
} catch (err) {
|
|
@@ -25568,7 +25597,7 @@ function producerRoutingRecord(context, dispatch, result, now) {
|
|
|
25568
25597
|
}
|
|
25569
25598
|
return parseRoutingRecordV2(record2);
|
|
25570
25599
|
}
|
|
25571
|
-
function settleMember(context, dispatch, result, produceError) {
|
|
25600
|
+
function settleMember(context, dispatch, result, produceError, produceErrorCode) {
|
|
25572
25601
|
const run = requireRun(context, dispatch.run.runId);
|
|
25573
25602
|
const state = foldStoredKxmRun(context, run);
|
|
25574
25603
|
const capability = context.eventStore.capabilityByAttempt(dispatch.attemptId);
|
|
@@ -25619,7 +25648,10 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
25619
25648
|
stepId: dispatch.stepId,
|
|
25620
25649
|
assignmentId: dispatch.assignmentId,
|
|
25621
25650
|
attemptId: dispatch.attemptId,
|
|
25622
|
-
|
|
25651
|
+
// Label the producer that actually ran: the old fallback printed "driver-simulated"
|
|
25652
|
+
// for every producer that was not literally "pi", so a live oneshot drive that
|
|
25653
|
+
// failed authentication read in the log as a simulation.
|
|
25654
|
+
harness: result?.harness ?? dispatch.producerId,
|
|
25623
25655
|
provider: result?.provider ?? "simulated",
|
|
25624
25656
|
requestedModel: result?.requestedModel ?? "simulated",
|
|
25625
25657
|
effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
|
|
@@ -25633,7 +25665,8 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
25633
25665
|
push("assignment.result_recorded", {
|
|
25634
25666
|
assignmentId: dispatch.assignmentId,
|
|
25635
25667
|
resultClass: "producer_rejected",
|
|
25636
|
-
status: "result_recorded"
|
|
25668
|
+
status: "result_recorded",
|
|
25669
|
+
...produceErrorCode !== void 0 ? { producerError: produceErrorCode } : {}
|
|
25637
25670
|
});
|
|
25638
25671
|
push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
|
|
25639
25672
|
push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "failed", status: "terminal" });
|
|
@@ -25113,15 +25113,29 @@ var KxmRunScheduler = class _KxmRunScheduler {
|
|
|
25113
25113
|
}
|
|
25114
25114
|
};
|
|
25115
25115
|
function invokeProducer(producer, request) {
|
|
25116
|
+
const reason = (error) => {
|
|
25117
|
+
try {
|
|
25118
|
+
const raw = error instanceof Error ? error.message : error;
|
|
25119
|
+
const message = typeof raw === "string" ? raw : "";
|
|
25120
|
+
let text = message;
|
|
25121
|
+
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
25122
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
25123
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
25124
|
+
const code = match?.[0] ?? "";
|
|
25125
|
+
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
25126
|
+
} catch {
|
|
25127
|
+
return "producer_error";
|
|
25128
|
+
}
|
|
25129
|
+
};
|
|
25116
25130
|
let pending;
|
|
25117
25131
|
try {
|
|
25118
25132
|
pending = Promise.resolve(producer.produce(request));
|
|
25119
|
-
} catch {
|
|
25120
|
-
return Promise.resolve({ error: true });
|
|
25133
|
+
} catch (error) {
|
|
25134
|
+
return Promise.resolve({ error: true, errorCode: reason(error) });
|
|
25121
25135
|
}
|
|
25122
25136
|
return pending.then(
|
|
25123
25137
|
(result) => ({ result, error: false }),
|
|
25124
|
-
() => ({ error: true })
|
|
25138
|
+
(error) => ({ error: true, errorCode: reason(error) })
|
|
25125
25139
|
);
|
|
25126
25140
|
}
|
|
25127
25141
|
var kxmGateDispatchSeams = {};
|
|
@@ -25395,6 +25409,21 @@ function resolveProducerRoute(projectRoot, step, agentId) {
|
|
|
25395
25409
|
const parsed = (0, import_yaml5.parse)(readFileSync7(agentFile, "utf8"));
|
|
25396
25410
|
if (typeof parsed?.model === "string") {
|
|
25397
25411
|
agentModel = parsed.model;
|
|
25412
|
+
} else if (parsed?.model && typeof parsed.model === "object" && !Array.isArray(parsed.model)) {
|
|
25413
|
+
const declared = parsed.model;
|
|
25414
|
+
const providerOk = typeof declared.provider === "string" && declared.provider.length > 0 && !declared.provider.includes("/");
|
|
25415
|
+
const modelOk = typeof declared.model === "string" && declared.model.length > 0 && !declared.model.startsWith("/") && !declared.model.endsWith("/");
|
|
25416
|
+
if (providerOk && modelOk) {
|
|
25417
|
+
agentModel = `${declared.provider}/${declared.model}`;
|
|
25418
|
+
} else {
|
|
25419
|
+
return {
|
|
25420
|
+
error: {
|
|
25421
|
+
reason: "step_unsupported",
|
|
25422
|
+
field: "model",
|
|
25423
|
+
detail: "producer_route_unsupported: invalid model declaration"
|
|
25424
|
+
}
|
|
25425
|
+
};
|
|
25426
|
+
}
|
|
25398
25427
|
}
|
|
25399
25428
|
} catch {
|
|
25400
25429
|
}
|
|
@@ -25925,7 +25954,7 @@ async function drivePanel(context, panel, producer) {
|
|
|
25925
25954
|
if (kxmPanelDispatchSeams.failSettleMember?.(member)) {
|
|
25926
25955
|
throw runtimeError("run_events_illegal", runId, "member settlement write failed");
|
|
25927
25956
|
}
|
|
25928
|
-
settleMember(context, member, produced.result, produced.error);
|
|
25957
|
+
settleMember(context, member, produced.result, produced.error, produced.errorCode);
|
|
25929
25958
|
});
|
|
25930
25959
|
return true;
|
|
25931
25960
|
} catch (err) {
|
|
@@ -26080,7 +26109,7 @@ function producerRoutingRecord(context, dispatch, result, now) {
|
|
|
26080
26109
|
}
|
|
26081
26110
|
return parseRoutingRecordV2(record2);
|
|
26082
26111
|
}
|
|
26083
|
-
function settleMember(context, dispatch, result, produceError) {
|
|
26112
|
+
function settleMember(context, dispatch, result, produceError, produceErrorCode) {
|
|
26084
26113
|
const run = requireRun(context, dispatch.run.runId);
|
|
26085
26114
|
const state = foldStoredKxmRun(context, run);
|
|
26086
26115
|
const capability = context.eventStore.capabilityByAttempt(dispatch.attemptId);
|
|
@@ -26131,7 +26160,10 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
26131
26160
|
stepId: dispatch.stepId,
|
|
26132
26161
|
assignmentId: dispatch.assignmentId,
|
|
26133
26162
|
attemptId: dispatch.attemptId,
|
|
26134
|
-
|
|
26163
|
+
// Label the producer that actually ran: the old fallback printed "driver-simulated"
|
|
26164
|
+
// for every producer that was not literally "pi", so a live oneshot drive that
|
|
26165
|
+
// failed authentication read in the log as a simulation.
|
|
26166
|
+
harness: result?.harness ?? dispatch.producerId,
|
|
26135
26167
|
provider: result?.provider ?? "simulated",
|
|
26136
26168
|
requestedModel: result?.requestedModel ?? "simulated",
|
|
26137
26169
|
effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
|
|
@@ -26145,7 +26177,8 @@ function settleMember(context, dispatch, result, produceError) {
|
|
|
26145
26177
|
push("assignment.result_recorded", {
|
|
26146
26178
|
assignmentId: dispatch.assignmentId,
|
|
26147
26179
|
resultClass: "producer_rejected",
|
|
26148
|
-
status: "result_recorded"
|
|
26180
|
+
status: "result_recorded",
|
|
26181
|
+
...produceErrorCode !== void 0 ? { producerError: produceErrorCode } : {}
|
|
26149
26182
|
});
|
|
26150
26183
|
push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
|
|
26151
26184
|
push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "failed", status: "terminal" });
|
|
@@ -28212,6 +28245,9 @@ function createKxmPiProducer(options = {}) {
|
|
|
28212
28245
|
}
|
|
28213
28246
|
function resolveModelForRequest(request) {
|
|
28214
28247
|
if (request.model) {
|
|
28248
|
+
if (request.provider) {
|
|
28249
|
+
return { provider: request.provider.toLowerCase(), model: request.model, thinking: request.thinking };
|
|
28250
|
+
}
|
|
28215
28251
|
const parsed2 = parseModelString(request.model);
|
|
28216
28252
|
return {
|
|
28217
28253
|
provider: request.provider?.toLowerCase() ?? parsed2.provider,
|
|
@@ -28222,6 +28258,9 @@ function createKxmPiProducer(options = {}) {
|
|
|
28222
28258
|
if (options.resolveModel) {
|
|
28223
28259
|
const resolved = options.resolveModel(request.agentId, request.runId);
|
|
28224
28260
|
if (resolved && resolved.model) {
|
|
28261
|
+
if (resolved.provider) {
|
|
28262
|
+
return { provider: resolved.provider.toLowerCase(), model: resolved.model, thinking: resolved.thinking };
|
|
28263
|
+
}
|
|
28225
28264
|
const parsed2 = parseModelString(resolved.model);
|
|
28226
28265
|
return {
|
|
28227
28266
|
provider: resolved.provider?.toLowerCase() ?? parsed2.provider,
|
package/plugins/kxm/package.json
CHANGED
|
@@ -854,15 +854,41 @@ function invokeProducer(
|
|
|
854
854
|
producer: KxmProducer,
|
|
855
855
|
request: KxmProducerRequest,
|
|
856
856
|
): Promise<{ result?: KxmProducerResult; error: boolean; errorCode?: string }> {
|
|
857
|
+
// The reason a producer refused is the single most useful fact about a failed attempt,
|
|
858
|
+
// and it used to be discarded here: a live drive that could not authenticate read in the
|
|
859
|
+
// event log exactly like a simulation that ran fine. But the message is producer-
|
|
860
|
+
// controlled text and must never reach durable records as-is — a producer that throws
|
|
861
|
+
// its capability (the hygiene contract tests exactly that) would persist the secret.
|
|
862
|
+
// So: redact the attempt capability and anything capability-shaped, then keep only a
|
|
863
|
+
// leading machine-code identifier (lowercase segments joined by underscores). Anything
|
|
864
|
+
// else — prose, free text, a redacted-to-empty message — records as producer_error.
|
|
865
|
+
const reason = (error: unknown): string => {
|
|
866
|
+
// Never throw while classifying a throw: a producer can reject with anything
|
|
867
|
+
// (Object.create(null) defeats String(), an Error whose message is not a string
|
|
868
|
+
// defeats split()), and a throwing classifier would reroute a producer_rejected
|
|
869
|
+
// settle into the execution-error path — the exact invisibility this exists to fix.
|
|
870
|
+
try {
|
|
871
|
+
const raw = error instanceof Error ? error.message : error;
|
|
872
|
+
const message = typeof raw === "string" ? raw : "";
|
|
873
|
+
let text = message;
|
|
874
|
+
if (request.capability) text = text.split(request.capability).join("[redacted]");
|
|
875
|
+
text = text.replace(/kxmcap_[A-Za-z0-9_-]+/g, "[redacted]");
|
|
876
|
+
const match = /^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}/.exec(text);
|
|
877
|
+
const code = match?.[0] ?? "";
|
|
878
|
+
return code.length > 0 && code.length <= 64 ? code : "producer_error";
|
|
879
|
+
} catch {
|
|
880
|
+
return "producer_error";
|
|
881
|
+
}
|
|
882
|
+
};
|
|
857
883
|
let pending: Promise<KxmProducerResult>;
|
|
858
884
|
try {
|
|
859
885
|
pending = Promise.resolve(producer.produce(request));
|
|
860
|
-
} catch {
|
|
861
|
-
return Promise.resolve({ error: true });
|
|
886
|
+
} catch (error) {
|
|
887
|
+
return Promise.resolve({ error: true, errorCode: reason(error) });
|
|
862
888
|
}
|
|
863
889
|
return pending.then(
|
|
864
890
|
(result) => ({ result, error: false }),
|
|
865
|
-
() => ({ error: true }),
|
|
891
|
+
(error) => ({ error: true, errorCode: reason(error) }),
|
|
866
892
|
);
|
|
867
893
|
}
|
|
868
894
|
|
|
@@ -1284,6 +1310,29 @@ function resolveProducerRoute(
|
|
|
1284
1310
|
const parsed = parse(readFileSync(agentFile, "utf8")) as Record<string, unknown>;
|
|
1285
1311
|
if (typeof parsed?.model === "string") {
|
|
1286
1312
|
agentModel = parsed.model;
|
|
1313
|
+
} else if (parsed?.model && typeof parsed.model === "object" && !Array.isArray(parsed.model)) {
|
|
1314
|
+
// The agent schema requires the object form (`{provider, model}`); reading only the
|
|
1315
|
+
// string form left every agent without a route unless it was literally named
|
|
1316
|
+
// `implementer`, which alone hit the hard-coded fallback below. A declared model
|
|
1317
|
+
// must actually drive the producer route. Model ids may themselves be namespaced
|
|
1318
|
+
// (`qwen/qwen3-coder-plus` under `openrouter`) — the provider is the only field
|
|
1319
|
+
// that may not contain the separator, because it is what the selector splits on.
|
|
1320
|
+
// A malformed declaration is an error, not an absence: falling through to the
|
|
1321
|
+
// fallback would silently route an agent that declared `openrouter` to Grok.
|
|
1322
|
+
const declared = parsed.model as { provider?: unknown; model?: unknown };
|
|
1323
|
+
const providerOk = typeof declared.provider === "string" && declared.provider.length > 0 && !declared.provider.includes("/");
|
|
1324
|
+
const modelOk = typeof declared.model === "string" && declared.model.length > 0 && !declared.model.startsWith("/") && !declared.model.endsWith("/");
|
|
1325
|
+
if (providerOk && modelOk) {
|
|
1326
|
+
agentModel = `${declared.provider}/${declared.model}`;
|
|
1327
|
+
} else {
|
|
1328
|
+
return {
|
|
1329
|
+
error: {
|
|
1330
|
+
reason: "step_unsupported",
|
|
1331
|
+
field: "model",
|
|
1332
|
+
detail: "producer_route_unsupported: invalid model declaration",
|
|
1333
|
+
},
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1287
1336
|
}
|
|
1288
1337
|
} catch {
|
|
1289
1338
|
// ignore
|
|
@@ -1755,7 +1804,7 @@ function appendExecuting(context: KxmRuntimeContext, dispatch: PreparedDispatch)
|
|
|
1755
1804
|
}
|
|
1756
1805
|
|
|
1757
1806
|
type MemberWork =
|
|
1758
|
-
| { attemptId: string; invoked: true; produced: { result?: KxmProducerResult; error: boolean } }
|
|
1807
|
+
| { attemptId: string; invoked: true; produced: { result?: KxmProducerResult; error: boolean; errorCode?: string } }
|
|
1759
1808
|
| { attemptId: string; invoked: false; skipped: true }
|
|
1760
1809
|
| { attemptId: string; invoked: false; appendFailed: true; error: unknown };
|
|
1761
1810
|
|
|
@@ -1896,7 +1945,7 @@ async function drivePanel(
|
|
|
1896
1945
|
});
|
|
1897
1946
|
};
|
|
1898
1947
|
|
|
1899
|
-
const settleInvoked = (member: PreparedDispatch, produced: { result?: KxmProducerResult; error: boolean }): boolean => {
|
|
1948
|
+
const settleInvoked = (member: PreparedDispatch, produced: { result?: KxmProducerResult; error: boolean; errorCode?: string }): boolean => {
|
|
1900
1949
|
if (produced.result?.effectUncertain) {
|
|
1901
1950
|
settlementFailed = true;
|
|
1902
1951
|
stopBirths = true;
|
|
@@ -1907,7 +1956,7 @@ async function drivePanel(
|
|
|
1907
1956
|
if (kxmPanelDispatchSeams.failSettleMember?.(member)) {
|
|
1908
1957
|
throw runtimeError("run_events_illegal", runId, "member settlement write failed");
|
|
1909
1958
|
}
|
|
1910
|
-
settleMember(context, member, produced.result, produced.error);
|
|
1959
|
+
settleMember(context, member, produced.result, produced.error, produced.errorCode);
|
|
1911
1960
|
});
|
|
1912
1961
|
return true;
|
|
1913
1962
|
} catch (err) {
|
|
@@ -2069,6 +2118,7 @@ function settleMember(
|
|
|
2069
2118
|
dispatch: PreparedDispatch,
|
|
2070
2119
|
result: KxmProducerResult | undefined,
|
|
2071
2120
|
produceError: boolean,
|
|
2121
|
+
produceErrorCode?: string,
|
|
2072
2122
|
): void {
|
|
2073
2123
|
const run = requireRun(context, dispatch.run.runId);
|
|
2074
2124
|
const state = foldStoredKxmRun(context, run);
|
|
@@ -2123,7 +2173,10 @@ function settleMember(
|
|
|
2123
2173
|
stepId: dispatch.stepId,
|
|
2124
2174
|
assignmentId: dispatch.assignmentId,
|
|
2125
2175
|
attemptId: dispatch.attemptId,
|
|
2126
|
-
|
|
2176
|
+
// Label the producer that actually ran: the old fallback printed "driver-simulated"
|
|
2177
|
+
// for every producer that was not literally "pi", so a live oneshot drive that
|
|
2178
|
+
// failed authentication read in the log as a simulation.
|
|
2179
|
+
harness: result?.harness ?? dispatch.producerId,
|
|
2127
2180
|
provider: result?.provider ?? "simulated",
|
|
2128
2181
|
requestedModel: result?.requestedModel ?? "simulated",
|
|
2129
2182
|
effectiveModel: result?.effectiveModel ?? result?.requestedModel ?? "simulated",
|
|
@@ -2139,6 +2192,7 @@ function settleMember(
|
|
|
2139
2192
|
assignmentId: dispatch.assignmentId,
|
|
2140
2193
|
resultClass: "producer_rejected",
|
|
2141
2194
|
status: "result_recorded",
|
|
2195
|
+
...(produceErrorCode !== undefined ? { producerError: produceErrorCode } : {}),
|
|
2142
2196
|
});
|
|
2143
2197
|
push("attempt.status_changed", { attemptId: dispatch.attemptId, status: "terminal" });
|
|
2144
2198
|
push("assignment.terminal", { assignmentId: dispatch.assignmentId, outcome: "failed", status: "terminal" });
|
|
@@ -8,7 +8,7 @@ import { AGENT_COMMANDS_MAP, enforceToolPolicy, getMcpTools, reconcileInbox } fr
|
|
|
8
8
|
import { deliverInboxNotification } from "./inbox.ts";
|
|
9
9
|
import type { HubEvent, MessageRecord } from "./protocol.ts";
|
|
10
10
|
|
|
11
|
-
const VERSION = "0.7.
|
|
11
|
+
const VERSION = "0.7.63";
|
|
12
12
|
const inbox = new Map<string, MessageRecord>();
|
|
13
13
|
const notifiedInbox = new Set<string>();
|
|
14
14
|
let meshClient: HubClient | undefined;
|
|
@@ -462,6 +462,13 @@ export function createKxmPiProducer(options: KxmPiProducerOptions = {}): KxmPiPr
|
|
|
462
462
|
|
|
463
463
|
function resolveModelForRequest(request: KxmProducerRequest): { provider: string; model: string; thinking?: string | undefined } {
|
|
464
464
|
if (request.model) {
|
|
465
|
+
// A separate provider field means the model id is bare and may itself be
|
|
466
|
+
// namespaced (`qwen/qwen3-coder-plus` under `openrouter`); reparsing it as a
|
|
467
|
+
// provider/model selector strips the namespace and sends the wrong model. Only
|
|
468
|
+
// parse when the provider must come from the string itself.
|
|
469
|
+
if (request.provider) {
|
|
470
|
+
return { provider: request.provider.toLowerCase(), model: request.model, thinking: request.thinking };
|
|
471
|
+
}
|
|
465
472
|
const parsed = parseModelString(request.model);
|
|
466
473
|
return {
|
|
467
474
|
provider: request.provider?.toLowerCase() ?? parsed.provider,
|
|
@@ -472,6 +479,9 @@ export function createKxmPiProducer(options: KxmPiProducerOptions = {}): KxmPiPr
|
|
|
472
479
|
if (options.resolveModel) {
|
|
473
480
|
const resolved = options.resolveModel(request.agentId, request.runId);
|
|
474
481
|
if (resolved && resolved.model) {
|
|
482
|
+
if (resolved.provider) {
|
|
483
|
+
return { provider: resolved.provider.toLowerCase(), model: resolved.model, thinking: resolved.thinking };
|
|
484
|
+
}
|
|
475
485
|
const parsed = parseModelString(resolved.model);
|
|
476
486
|
return {
|
|
477
487
|
provider: resolved.provider?.toLowerCase() ?? parsed.provider,
|
|
@@ -364,6 +364,7 @@
|
|
|
364
364
|
"runPlanHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
365
365
|
"capabilityHash": { "$ref": "common.schema.json#/$defs/sha256" },
|
|
366
366
|
"resultClass": { "enum": ["outcome", "outcome_unknown", "producer_rejected", "cancelled"] },
|
|
367
|
+
"producerError": { "type": "string", "pattern": "^[a-z][a-z0-9]*(?:_[a-z0-9]+){1,3}$", "maxLength": 64, "description": "Machine-code reason a producer refused (produce threw), present only for resultClass producer_rejected. Capability material is redacted before extraction; anything unclassifiable records as producer_error." },
|
|
367
368
|
"status": { "$ref": "common.schema.json#/$defs/lifecycleStatus" },
|
|
368
369
|
"previousStatus": { "$ref": "common.schema.json#/$defs/lifecycleStatus" },
|
|
369
370
|
"outcome": { "$ref": "common.schema.json#/$defs/identifier" },
|