@caupulican/pi-adaptative 0.81.12 → 0.81.15
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 +14 -1
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +24 -18
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +16 -10
- package/dist/cli/list-models.d.ts.map +1 -1
- package/dist/cli/list-models.js +5 -0
- package/dist/cli/list-models.js.map +1 -1
- package/dist/core/agent-session.d.ts +30 -1
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +250 -21
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/model-registry.d.ts +1 -0
- package/dist/core/model-registry.d.ts.map +1 -1
- package/dist/core/model-registry.js +6 -0
- package/dist/core/model-registry.js.map +1 -1
- package/dist/core/models/adaptation-store.d.ts +18 -1
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +31 -3
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +5 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/core/tool-repair-health.d.ts.map +1 -1
- package/dist/core/tool-repair-health.js +21 -1
- package/dist/core/tool-repair-health.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +24 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +8 -0
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +23 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/docs/models.md +5 -1
- package/docs/rpc.md +39 -0
- package/docs/settings.md +4 -2
- package/docs/tool-repair.md +15 -5
- package/docs/usage.md +1 -0
- package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
- package/examples/extensions/custom-provider-anthropic/package.json +1 -1
- package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
- package/examples/extensions/sandbox/package-lock.json +2 -2
- package/examples/extensions/sandbox/package.json +1 -1
- package/examples/extensions/with-deps/package-lock.json +2 -2
- package/examples/extensions/with-deps/package.json +1 -1
- package/npm-shrinkwrap.json +12 -12
- package/package.json +4 -4
|
@@ -59,6 +59,7 @@ const RAW_STREAM_MARKER = Symbol.for("pi.rawStreamSimple");
|
|
|
59
59
|
const MODEL_ADAPTATION_REPAIR_THRESHOLD = 3;
|
|
60
60
|
const TEXT_TOOL_PROTOCOL_VERSION = 1;
|
|
61
61
|
const TEXT_TOOL_PROTOCOL_TRIALS_PER_VARIANT = 2;
|
|
62
|
+
const TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD = 3;
|
|
62
63
|
const TEXT_TOOL_PROTOCOL_VARIANTS = ["tool-tag", "tool-call", "fenced-json"];
|
|
63
64
|
const TEXT_TOOL_PROTOCOL_ECHO_TOOL = {
|
|
64
65
|
name: "echo",
|
|
@@ -148,6 +149,9 @@ export class AgentSession {
|
|
|
148
149
|
_localRuntimeController;
|
|
149
150
|
_modelAdaptationStore;
|
|
150
151
|
_repairModeSessionCounts = new Map();
|
|
152
|
+
_textProtocolParseFailures = new Map();
|
|
153
|
+
_textProtocolParseObservedThisTurn = false;
|
|
154
|
+
_textProtocolValidationOutcomeThisTurn;
|
|
151
155
|
/** Assembles the session's base system prompt from live session state (see
|
|
152
156
|
* system-prompt-builder.ts); owns the paired _baseSystemPromptOptions. */
|
|
153
157
|
_systemPromptBuilder;
|
|
@@ -258,6 +262,7 @@ export class AgentSession {
|
|
|
258
262
|
this._cwd = config.cwd;
|
|
259
263
|
this._agentDir = config.agentDir ?? getAgentDir();
|
|
260
264
|
this._modelAdaptationStore = ModelAdaptationStore.forAgentDir(this._agentDir);
|
|
265
|
+
this.agent.onTextToolProtocolParse = (event) => this._handleTextToolProtocolParse(event);
|
|
261
266
|
this._applyToolRepairLayerSettings();
|
|
262
267
|
this._collectWorkspaceSources = config.collectWorkspaceSources ?? collectWorkspaceSources;
|
|
263
268
|
this._localRuntimeController = new LocalRuntimeController({
|
|
@@ -503,6 +508,7 @@ export class AgentSession {
|
|
|
503
508
|
previousToolArgumentValidation?.(taggedEvent);
|
|
504
509
|
this._analytics.recordToolArgumentValidation(taggedEvent);
|
|
505
510
|
this._recordToolValidationBounce(taggedEvent);
|
|
511
|
+
this._handleTextToolProtocolValidationOutcome(taggedEvent);
|
|
506
512
|
this._handleModelAdaptationTelemetry(taggedEvent);
|
|
507
513
|
};
|
|
508
514
|
this._treeNavigator = new SessionTreeNavigator({
|
|
@@ -801,8 +807,31 @@ export class AgentSession {
|
|
|
801
807
|
return modelKey ? this._modelAdaptationStore.get(modelKey).rules : [];
|
|
802
808
|
}
|
|
803
809
|
_textProtocolFlag(model) {
|
|
810
|
+
// Phase 7 gating hierarchy: PI_TEXT_TOOL_CALL_PROTOCOL_DISABLED is resolved
|
|
811
|
+
// in _toolRepairSettings() as the env kill switch, then settings.toolRepair.textProtocol
|
|
812
|
+
// force-enables/disables globally, then Model.textToolCallProtocol opts in per model,
|
|
813
|
+
// then a persisted /toolprobe text-protocol verdict opts in that exact model. The
|
|
814
|
+
// calibration store is consulted after this flag; native provider tool calls still
|
|
815
|
+
// win when emitted, and this only enables the text-protocol fallback lane.
|
|
804
816
|
const override = this._toolRepairSettings().textProtocol;
|
|
805
|
-
|
|
817
|
+
if (override !== undefined)
|
|
818
|
+
return override;
|
|
819
|
+
if (model?.textToolCallProtocol === true)
|
|
820
|
+
return true;
|
|
821
|
+
const modelKey = this._modelAdaptationKeyFor(model);
|
|
822
|
+
return !!modelKey && this._modelAdaptationStore.get(modelKey).toolProbe?.status === "text-protocol";
|
|
823
|
+
}
|
|
824
|
+
async _streamForToolProbe(model, context, options) {
|
|
825
|
+
let requestOptions = options;
|
|
826
|
+
if (this._isRawStreamSimple(this.agent.streamFn)) {
|
|
827
|
+
const auth = await this._getRequiredRequestAuth(model);
|
|
828
|
+
requestOptions = {
|
|
829
|
+
...options,
|
|
830
|
+
apiKey: auth.apiKey,
|
|
831
|
+
headers: auth.headers || options.headers ? { ...auth.headers, ...options.headers } : undefined,
|
|
832
|
+
};
|
|
833
|
+
}
|
|
834
|
+
return this.agent.streamFn(model, context, requestOptions);
|
|
806
835
|
}
|
|
807
836
|
_textProtocolCalibrationContext(variant, token) {
|
|
808
837
|
const primer = generateTextToolProtocolPrimer([TEXT_TOOL_PROTOCOL_ECHO_TOOL], { variant });
|
|
@@ -810,18 +839,29 @@ export class AgentSession {
|
|
|
810
839
|
return {
|
|
811
840
|
systemPrompt: `${primer}\n\n${instruction}`,
|
|
812
841
|
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
813
|
-
tools: [TEXT_TOOL_PROTOCOL_ECHO_TOOL],
|
|
814
842
|
};
|
|
815
843
|
}
|
|
844
|
+
_messageHasEchoProbe(message, token) {
|
|
845
|
+
return message.content.some((block) => block.type === "toolCall" && block.name === "echo" && block.arguments.data === token);
|
|
846
|
+
}
|
|
847
|
+
async _runNativeToolProbeTrial(model, token) {
|
|
848
|
+
const instruction = `Native tool-call capability probe. Use provider-native tool calling, not prose. ` +
|
|
849
|
+
`Call echo with data exactly "${token}".`;
|
|
850
|
+
const stream = await this._streamForToolProbe(model, {
|
|
851
|
+
systemPrompt: instruction,
|
|
852
|
+
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
853
|
+
tools: [TEXT_TOOL_PROTOCOL_ECHO_TOOL],
|
|
854
|
+
}, { textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 256 });
|
|
855
|
+
return this._messageHasEchoProbe(await stream.result(), token);
|
|
856
|
+
}
|
|
816
857
|
async _runTextProtocolTrial(model, variant, token) {
|
|
817
|
-
const stream = await this.
|
|
858
|
+
const stream = await this._streamForToolProbe(model, this._textProtocolCalibrationContext(variant, token), {
|
|
818
859
|
textToolCallProtocol: false,
|
|
819
860
|
maxRetries: 0,
|
|
861
|
+
temperature: 0,
|
|
862
|
+
maxTokens: 256,
|
|
820
863
|
});
|
|
821
864
|
const message = await stream.result();
|
|
822
|
-
if (message.content.some((block) => block.type === "toolCall" && block.name === "echo" && block.arguments.data === token)) {
|
|
823
|
-
return true;
|
|
824
|
-
}
|
|
825
865
|
const text = message.content
|
|
826
866
|
.filter((block) => block.type === "text")
|
|
827
867
|
.map((block) => block.text)
|
|
@@ -832,6 +872,32 @@ export class AgentSession {
|
|
|
832
872
|
const parsed = parseTextToolCalls(text, [TEXT_TOOL_PROTOCOL_ECHO_TOOL]);
|
|
833
873
|
return parsed.calls.some((call) => call.name === "echo" && call.arguments.data === token);
|
|
834
874
|
}
|
|
875
|
+
async _calibrateTextToolProtocolForModel(model, modelKey, options) {
|
|
876
|
+
const variantsTried = [];
|
|
877
|
+
for (const variant of TEXT_TOOL_PROTOCOL_VARIANTS) {
|
|
878
|
+
variantsTried.push(variant);
|
|
879
|
+
let passed = true;
|
|
880
|
+
for (let trial = 0; trial < TEXT_TOOL_PROTOCOL_TRIALS_PER_VARIANT; trial++) {
|
|
881
|
+
const ok = await this._runTextProtocolTrial(model, variant, `pi-calibration-${trial + 1}`);
|
|
882
|
+
if (!ok) {
|
|
883
|
+
passed = false;
|
|
884
|
+
break;
|
|
885
|
+
}
|
|
886
|
+
}
|
|
887
|
+
if (passed) {
|
|
888
|
+
const calibratedAt = new Date().toISOString();
|
|
889
|
+
if (modelKey) {
|
|
890
|
+
this._modelAdaptationStore.setProtocol(modelKey, { version: TEXT_TOOL_PROTOCOL_VERSION, status: "calibrated", variant, calibratedAt }, calibratedAt);
|
|
891
|
+
}
|
|
892
|
+
return { status: "calibrated", variant, calibratedAt };
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
const attemptedAt = new Date().toISOString();
|
|
896
|
+
if (modelKey && options.persistFailure) {
|
|
897
|
+
this._modelAdaptationStore.setProtocol(modelKey, { version: TEXT_TOOL_PROTOCOL_VERSION, status: "failed", attemptedAt, variantsTried }, attemptedAt);
|
|
898
|
+
}
|
|
899
|
+
return { status: "failed", attemptedAt, variantsTried };
|
|
900
|
+
}
|
|
835
901
|
async _ensureTextToolProtocolForActiveModel() {
|
|
836
902
|
const model = this.agent.state.model;
|
|
837
903
|
if (!this._textProtocolFlag(model)) {
|
|
@@ -845,27 +911,182 @@ export class AgentSession {
|
|
|
845
911
|
}
|
|
846
912
|
const profile = this._modelAdaptationStore.get(modelKey);
|
|
847
913
|
if (profile.protocol?.version === TEXT_TOOL_PROTOCOL_VERSION) {
|
|
914
|
+
if (profile.protocol.status === "failed") {
|
|
915
|
+
this.agent.textToolCallProtocol = undefined;
|
|
916
|
+
throw new Error(`Previous text tool protocol calibration failed for ${modelKey} at ${profile.protocol.attemptedAt}. ` +
|
|
917
|
+
`Variants tried: ${profile.protocol.variantsTried.join(", ")}. ` +
|
|
918
|
+
`Run /toolhealth for details or /toolprotocol-reset ${modelKey} to retry calibration.`);
|
|
919
|
+
}
|
|
848
920
|
this.agent.textToolCallProtocol = { variant: profile.protocol.variant };
|
|
849
921
|
return;
|
|
850
922
|
}
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
923
|
+
const result = await this._calibrateTextToolProtocolForModel(model, modelKey, { persistFailure: true });
|
|
924
|
+
if (result.status === "calibrated") {
|
|
925
|
+
this.agent.textToolCallProtocol = { variant: result.variant };
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
this.agent.textToolCallProtocol = undefined;
|
|
929
|
+
throw new Error(`Model ${modelKey} cannot follow the text tool protocol after calibration. ` +
|
|
930
|
+
`Run /toolhealth for details or /toolprotocol-reset ${modelKey} to retry calibration.`);
|
|
931
|
+
}
|
|
932
|
+
_modelRef(model) {
|
|
933
|
+
return `${model.provider}/${model.id}`;
|
|
934
|
+
}
|
|
935
|
+
_formatToolProbeReport(results) {
|
|
936
|
+
const lines = ["Tool probe results:", "Model | Verdict | Variant | Diagnostic", "--- | --- | --- | ---"];
|
|
937
|
+
for (const result of results) {
|
|
938
|
+
lines.push([
|
|
939
|
+
result.model,
|
|
940
|
+
result.verdict,
|
|
941
|
+
result.variant ?? "-",
|
|
942
|
+
result.diagnostic ? result.diagnostic.replace(/\s+/g, " ").slice(0, 160) : "-",
|
|
943
|
+
].join(" | "));
|
|
944
|
+
}
|
|
945
|
+
return lines.join("\n");
|
|
946
|
+
}
|
|
947
|
+
_storeToolProbe(modelKey, probe) {
|
|
948
|
+
this._modelAdaptationStore.setToolProbe(modelKey, probe, probe.probedAt);
|
|
949
|
+
}
|
|
950
|
+
async _probeToolCallingForModel(model) {
|
|
951
|
+
const modelKey = this._modelRef(model);
|
|
952
|
+
const probedAt = new Date().toISOString();
|
|
953
|
+
let diagnostic;
|
|
954
|
+
try {
|
|
955
|
+
if (await this._runNativeToolProbeTrial(model, "pi-native-probe")) {
|
|
956
|
+
this._storeToolProbe(modelKey, { version: TEXT_TOOL_PROTOCOL_VERSION, status: "native", probedAt });
|
|
957
|
+
return { model: modelKey, verdict: "native" };
|
|
859
958
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
959
|
+
}
|
|
960
|
+
catch (error) {
|
|
961
|
+
diagnostic = error instanceof Error ? error.message : String(error);
|
|
962
|
+
}
|
|
963
|
+
try {
|
|
964
|
+
const calibrated = await this._calibrateTextToolProtocolForModel(model, modelKey, { persistFailure: false });
|
|
965
|
+
if (calibrated.status === "calibrated") {
|
|
966
|
+
this._storeToolProbe(modelKey, {
|
|
967
|
+
version: TEXT_TOOL_PROTOCOL_VERSION,
|
|
968
|
+
status: "text-protocol",
|
|
969
|
+
probedAt: calibrated.calibratedAt,
|
|
970
|
+
variant: calibrated.variant,
|
|
971
|
+
});
|
|
972
|
+
return { model: modelKey, verdict: "text-protocol", variant: calibrated.variant };
|
|
865
973
|
}
|
|
974
|
+
diagnostic ??= `Text protocol variants failed: ${calibrated.variantsTried.join(", ")}`;
|
|
866
975
|
}
|
|
867
|
-
|
|
868
|
-
|
|
976
|
+
catch (error) {
|
|
977
|
+
diagnostic = error instanceof Error ? error.message : String(error);
|
|
978
|
+
}
|
|
979
|
+
this._storeToolProbe(modelKey, { version: TEXT_TOOL_PROTOCOL_VERSION, status: "none", probedAt, diagnostic });
|
|
980
|
+
return { model: modelKey, verdict: "none", diagnostic };
|
|
981
|
+
}
|
|
982
|
+
async _resolveToolProbeModels(target) {
|
|
983
|
+
const trimmed = target?.trim();
|
|
984
|
+
if (!trimmed)
|
|
985
|
+
return this._modelRegistry.getAvailable();
|
|
986
|
+
const [provider, ...modelParts] = trimmed.split("/");
|
|
987
|
+
const modelId = modelParts.join("/");
|
|
988
|
+
if (!provider || !modelId)
|
|
989
|
+
throw new Error("Usage: /toolprobe [provider/model]");
|
|
990
|
+
const exact = this._modelRegistry.find(provider, modelId);
|
|
991
|
+
if (exact)
|
|
992
|
+
return [exact];
|
|
993
|
+
const current = this.agent.state.model;
|
|
994
|
+
if (current?.provider === provider && current.id === modelId)
|
|
995
|
+
return [current];
|
|
996
|
+
throw new Error(`Model not found: ${trimmed}`);
|
|
997
|
+
}
|
|
998
|
+
async probeToolCalling(target) {
|
|
999
|
+
const models = await this._resolveToolProbeModels(target);
|
|
1000
|
+
if (models.length === 0)
|
|
1001
|
+
throw new Error("No available models to probe.");
|
|
1002
|
+
const results = [];
|
|
1003
|
+
for (const model of models) {
|
|
1004
|
+
results.push(await this._probeToolCallingForModel(model));
|
|
1005
|
+
}
|
|
1006
|
+
return { results, table: this._formatToolProbeReport(results) };
|
|
1007
|
+
}
|
|
1008
|
+
_handleTextToolProtocolParse(event) {
|
|
1009
|
+
this._textProtocolParseObservedThisTurn = true;
|
|
1010
|
+
const modelKey = `${event.provider}/${event.model}`;
|
|
1011
|
+
if (event.status === "parsed")
|
|
1012
|
+
return;
|
|
1013
|
+
const signature = `${event.variant}:${event.reason ?? "failed"}`;
|
|
1014
|
+
const previous = this._textProtocolParseFailures.get(modelKey);
|
|
1015
|
+
const repeats = previous?.signature === signature ? previous.repeats + 1 : 1;
|
|
1016
|
+
this._textProtocolParseFailures.set(modelKey, { signature, repeats });
|
|
1017
|
+
if (repeats < TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD)
|
|
1018
|
+
return;
|
|
1019
|
+
const profile = this._modelAdaptationStore.get(modelKey);
|
|
1020
|
+
if (profile.protocol?.version === TEXT_TOOL_PROTOCOL_VERSION && profile.protocol.status !== "failed") {
|
|
1021
|
+
this._modelAdaptationStore.removeProtocol(modelKey);
|
|
1022
|
+
this.agent.textToolCallProtocol = undefined;
|
|
1023
|
+
}
|
|
1024
|
+
this._textProtocolParseFailures.delete(modelKey);
|
|
1025
|
+
}
|
|
1026
|
+
_handleTextToolProtocolValidationOutcome(event) {
|
|
1027
|
+
if (event.source !== "text-protocol")
|
|
1028
|
+
return;
|
|
1029
|
+
const protocol = this.agent.textToolCallProtocol;
|
|
1030
|
+
const variant = protocol === true ? "tool-tag" : protocol ? protocol.variant : undefined;
|
|
1031
|
+
if (!variant)
|
|
1032
|
+
return;
|
|
1033
|
+
const status = event.outcome === "bounced" ? "failed" : "parsed";
|
|
1034
|
+
if (this._textProtocolValidationOutcomeThisTurn?.status === "parsed" && status === "failed")
|
|
1035
|
+
return;
|
|
1036
|
+
this._textProtocolValidationOutcomeThisTurn = {
|
|
1037
|
+
provider: event.provider ?? this.agent.state.model.provider,
|
|
1038
|
+
model: event.model ?? this.agent.state.model.id,
|
|
1039
|
+
variant,
|
|
1040
|
+
status,
|
|
1041
|
+
callCount: 1,
|
|
1042
|
+
textLength: 0,
|
|
1043
|
+
...(status === "failed" && {
|
|
1044
|
+
reason: event.errorKeywords?.includes("unknown_tool") ? "unknown-tool" : "validation-failed",
|
|
1045
|
+
}),
|
|
1046
|
+
};
|
|
1047
|
+
}
|
|
1048
|
+
_recordTextToolProtocolParseOutcomeFromLastAssistant() {
|
|
1049
|
+
const validationOutcome = this._textProtocolValidationOutcomeThisTurn;
|
|
1050
|
+
this._textProtocolValidationOutcomeThisTurn = undefined;
|
|
1051
|
+
if (validationOutcome?.status === "parsed") {
|
|
1052
|
+
this._textProtocolParseObservedThisTurn = true;
|
|
1053
|
+
this._textProtocolParseFailures.delete(`${validationOutcome.provider}/${validationOutcome.model}`);
|
|
1054
|
+
return;
|
|
1055
|
+
}
|
|
1056
|
+
if (validationOutcome) {
|
|
1057
|
+
this._handleTextToolProtocolParse(validationOutcome);
|
|
1058
|
+
return;
|
|
1059
|
+
}
|
|
1060
|
+
if (this._textProtocolParseObservedThisTurn)
|
|
1061
|
+
return;
|
|
1062
|
+
const protocol = this.agent.textToolCallProtocol;
|
|
1063
|
+
if (protocol === false || protocol === true || !protocol?.variant)
|
|
1064
|
+
return;
|
|
1065
|
+
const response = this._findLastAssistantMessage();
|
|
1066
|
+
if (!response)
|
|
1067
|
+
return;
|
|
1068
|
+
const responseText = response.content
|
|
1069
|
+
.filter((content) => content.type === "text")
|
|
1070
|
+
.map((content) => content.text)
|
|
1071
|
+
.join("\n");
|
|
1072
|
+
if (!responseText)
|
|
1073
|
+
return;
|
|
1074
|
+
const parsed = parseTextToolCalls(responseText, this.agent.state.tools);
|
|
1075
|
+
const attempted = parsed.attempted || this._looksLikeTextToolProtocolAttempt(responseText);
|
|
1076
|
+
if (!attempted)
|
|
1077
|
+
return;
|
|
1078
|
+
this._handleTextToolProtocolParse({
|
|
1079
|
+
provider: this.agent.state.model.provider,
|
|
1080
|
+
model: this.agent.state.model.id,
|
|
1081
|
+
variant: protocol.variant,
|
|
1082
|
+
status: parsed.calls.length > 0 ? "parsed" : "failed",
|
|
1083
|
+
reason: parsed.failure,
|
|
1084
|
+
callCount: parsed.calls.length,
|
|
1085
|
+
textLength: responseText.length,
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
_looksLikeTextToolProtocolAttempt(text) {
|
|
1089
|
+
return /<pi:call\b|<tool_call\b|```(?:tool|tool_call)[\s\S]*"name"\s*:/i.test(text);
|
|
869
1090
|
}
|
|
870
1091
|
_recordToolValidationBounce(event) {
|
|
871
1092
|
if (event.outcome !== "bounced" || !event.failureShape || event.failureShape.length === 0)
|
|
@@ -1091,6 +1312,11 @@ export class AgentSession {
|
|
|
1091
1312
|
removeToolRepairRule(model, mode) {
|
|
1092
1313
|
return this._modelAdaptationStore.removeRule(model, mode);
|
|
1093
1314
|
}
|
|
1315
|
+
resetToolProtocolCalibration(model) {
|
|
1316
|
+
const removed = this._modelAdaptationStore.removeProtocol(model);
|
|
1317
|
+
this._textProtocolParseFailures.delete(model);
|
|
1318
|
+
return removed;
|
|
1319
|
+
}
|
|
1094
1320
|
/** Curation status for diagnostics/dashboard: settings, live telemetry, last refusal reason. */
|
|
1095
1321
|
/** Curation status for diagnostics/dashboard (delegates to {@link ContextPipeline.getContextCurationStatus}). */
|
|
1096
1322
|
getContextCurationStatus() {
|
|
@@ -1986,7 +2212,10 @@ export class AgentSession {
|
|
|
1986
2212
|
return;
|
|
1987
2213
|
}
|
|
1988
2214
|
preflightResult?.(true);
|
|
2215
|
+
this._textProtocolParseObservedThisTurn = false;
|
|
2216
|
+
this._textProtocolValidationOutcomeThisTurn = undefined;
|
|
1989
2217
|
await this._modelRouter.runRoutedTurn(messages, routedTurnModel, routedTurnRouteDecision);
|
|
2218
|
+
this._recordTextToolProtocolParseOutcomeFromLastAssistant();
|
|
1990
2219
|
// R4: score whether the agent actually used the recalled context, so the recall gate can adapt.
|
|
1991
2220
|
if (injectedRecall) {
|
|
1992
2221
|
const response = this._findLastAssistantMessage();
|