@caupulican/pi-adaptative 0.81.13 → 0.81.16
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 +19 -0
- package/dist/bundled-resources/runtimes/hf-transformers-openai-server.py +427 -0
- package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +13 -11
- package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +16 -10
- package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +14 -7
- package/dist/core/agent-session.d.ts +11 -3
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +132 -23
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/local-runtime-controller.d.ts +17 -9
- package/dist/core/local-runtime-controller.d.ts.map +1 -1
- package/dist/core/local-runtime-controller.js +124 -20
- package/dist/core/local-runtime-controller.js.map +1 -1
- package/dist/core/models/adaptation-store.d.ts +2 -0
- package/dist/core/models/adaptation-store.d.ts.map +1 -1
- package/dist/core/models/adaptation-store.js +4 -0
- package/dist/core/models/adaptation-store.js.map +1 -1
- package/dist/core/models/default-model-suggestions.d.ts +4 -4
- package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
- package/dist/core/models/default-model-suggestions.js +9 -0
- package/dist/core/models/default-model-suggestions.js.map +1 -1
- package/dist/core/models/local-registration.d.ts +12 -0
- package/dist/core/models/local-registration.d.ts.map +1 -1
- package/dist/core/models/local-registration.js +68 -0
- package/dist/core/models/local-registration.js.map +1 -1
- package/dist/core/models/local-runtime.d.ts +77 -1
- package/dist/core/models/local-runtime.d.ts.map +1 -1
- package/dist/core/models/local-runtime.js +295 -4
- package/dist/core/models/local-runtime.js.map +1 -1
- package/dist/core/models/model-ref.d.ts +4 -0
- package/dist/core/models/model-ref.d.ts.map +1 -1
- package/dist/core/models/model-ref.js +12 -3
- package/dist/core/models/model-ref.js.map +1 -1
- package/dist/core/tool-repair-health.d.ts.map +1 -1
- package/dist/core/tool-repair-health.js +2 -1
- package/dist/core/tool-repair-health.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +1 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +4 -0
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/interactive/local-model-commands.d.ts +3 -1
- package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
- package/dist/modes/interactive/local-model-commands.js +133 -19
- package/dist/modes/interactive/local-model-commands.js.map +1 -1
- package/docs/models.md +19 -1
- package/docs/tool-repair.md +2 -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
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
1
|
+
import { readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
2
3
|
import { basename, dirname, join } from "node:path";
|
|
3
4
|
import { classifyFailure, compactToolResultDetailsForRetention, computeRetryDelayMs, createCustomMessage, DEFAULT_RETRY_POLICY, RetryController, sleepAbortable, withStreamIdleWatchdog, } from "@caupulican/pi-agent-core";
|
|
4
5
|
import { calculateContextTokens, compact, createDeterministicCompaction, estimateContextTokens, getLatestCompactionEntry, prepareCompaction, runCompactionLoop, shouldCompact, } from "@caupulican/pi-agent-core/node";
|
|
@@ -60,12 +61,22 @@ const MODEL_ADAPTATION_REPAIR_THRESHOLD = 3;
|
|
|
60
61
|
const TEXT_TOOL_PROTOCOL_VERSION = 1;
|
|
61
62
|
const TEXT_TOOL_PROTOCOL_TRIALS_PER_VARIANT = 2;
|
|
62
63
|
const TEXT_TOOL_PROTOCOL_PARSE_FAILURE_THRESHOLD = 3;
|
|
63
|
-
const TEXT_TOOL_PROTOCOL_VARIANTS = [
|
|
64
|
+
const TEXT_TOOL_PROTOCOL_VARIANTS = [
|
|
65
|
+
"tool-tag",
|
|
66
|
+
"tool-call",
|
|
67
|
+
"fenced-json",
|
|
68
|
+
"function-xml",
|
|
69
|
+
];
|
|
64
70
|
const TEXT_TOOL_PROTOCOL_ECHO_TOOL = {
|
|
65
71
|
name: "echo",
|
|
66
72
|
description: "Echo calibration data",
|
|
67
73
|
parameters: Type.Object({ data: Type.String() }),
|
|
68
74
|
};
|
|
75
|
+
const NATIVE_TOOL_PROBE_READ_TOOL = {
|
|
76
|
+
name: "read",
|
|
77
|
+
description: "Read file contents",
|
|
78
|
+
parameters: Type.Object({ path: Type.String() }),
|
|
79
|
+
};
|
|
69
80
|
/** Test-only override of the stream-idle bounds. Read per-request by the wiring's resolver. */
|
|
70
81
|
let streamIdleOptionsOverride;
|
|
71
82
|
/**
|
|
@@ -151,6 +162,7 @@ export class AgentSession {
|
|
|
151
162
|
_repairModeSessionCounts = new Map();
|
|
152
163
|
_textProtocolParseFailures = new Map();
|
|
153
164
|
_textProtocolParseObservedThisTurn = false;
|
|
165
|
+
_textProtocolValidationOutcomeThisTurn;
|
|
154
166
|
/** Assembles the session's base system prompt from live session state (see
|
|
155
167
|
* system-prompt-builder.ts); owns the paired _baseSystemPromptOptions. */
|
|
156
168
|
_systemPromptBuilder;
|
|
@@ -507,6 +519,7 @@ export class AgentSession {
|
|
|
507
519
|
previousToolArgumentValidation?.(taggedEvent);
|
|
508
520
|
this._analytics.recordToolArgumentValidation(taggedEvent);
|
|
509
521
|
this._recordToolValidationBounce(taggedEvent);
|
|
522
|
+
this._handleTextToolProtocolValidationOutcome(taggedEvent);
|
|
510
523
|
this._handleModelAdaptationTelemetry(taggedEvent);
|
|
511
524
|
};
|
|
512
525
|
this._treeNavigator = new SessionTreeNavigator({
|
|
@@ -837,30 +850,67 @@ export class AgentSession {
|
|
|
837
850
|
return {
|
|
838
851
|
systemPrompt: `${primer}\n\n${instruction}`,
|
|
839
852
|
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
840
|
-
tools: [TEXT_TOOL_PROTOCOL_ECHO_TOOL],
|
|
841
853
|
};
|
|
842
854
|
}
|
|
843
|
-
|
|
844
|
-
return message.content.some((block) =>
|
|
855
|
+
_messageHasToolCallWithStringArgument(message, toolName, argName, argValue) {
|
|
856
|
+
return message.content.some((block) => {
|
|
857
|
+
if (block.type !== "toolCall" || block.name !== toolName)
|
|
858
|
+
return false;
|
|
859
|
+
const args = block.arguments;
|
|
860
|
+
return (typeof args === "object" &&
|
|
861
|
+
args !== null &&
|
|
862
|
+
!Array.isArray(args) &&
|
|
863
|
+
args[argName] === argValue);
|
|
864
|
+
});
|
|
865
|
+
}
|
|
866
|
+
_nativeToolProbeSystemPrompt(instruction) {
|
|
867
|
+
const base = (this.agent.state.systemPrompt ?? "").trim();
|
|
868
|
+
return base ? `${base}\n\n${instruction}` : instruction;
|
|
869
|
+
}
|
|
870
|
+
async _runNativeReadTaskProbeTrial(model, path) {
|
|
871
|
+
const instruction = `Native tool-call capability probe: task-scale read. Use provider-native tool calling, not prose. ` +
|
|
872
|
+
`Call read exactly once with path exactly "${path}".`;
|
|
873
|
+
const stream = await this._streamForToolProbe(model, {
|
|
874
|
+
systemPrompt: this._nativeToolProbeSystemPrompt(instruction),
|
|
875
|
+
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
876
|
+
tools: [NATIVE_TOOL_PROBE_READ_TOOL],
|
|
877
|
+
}, { textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 768 });
|
|
878
|
+
return this._messageHasToolCallWithStringArgument(await stream.result(), "read", "path", path);
|
|
845
879
|
}
|
|
846
|
-
async
|
|
847
|
-
const instruction = `Native tool-call capability probe. Use provider-native tool calling, not prose. ` +
|
|
880
|
+
async _runNativeEchoToolProbeTrial(model, token) {
|
|
881
|
+
const instruction = `Native tool-call capability probe: echo-only. Use provider-native tool calling, not prose. ` +
|
|
848
882
|
`Call echo with data exactly "${token}".`;
|
|
849
883
|
const stream = await this._streamForToolProbe(model, {
|
|
850
|
-
systemPrompt: instruction,
|
|
884
|
+
systemPrompt: this._nativeToolProbeSystemPrompt(instruction),
|
|
851
885
|
messages: [{ role: "user", content: [{ type: "text", text: instruction }], timestamp: Date.now() }],
|
|
852
886
|
tools: [TEXT_TOOL_PROTOCOL_ECHO_TOOL],
|
|
853
|
-
}, { textToolCallProtocol: false, maxRetries: 0 });
|
|
854
|
-
return this.
|
|
887
|
+
}, { textToolCallProtocol: false, maxRetries: 0, temperature: 0, maxTokens: 256 });
|
|
888
|
+
return this._messageHasToolCallWithStringArgument(await stream.result(), "echo", "data", token);
|
|
889
|
+
}
|
|
890
|
+
async _gradeNativeToolCallingForModel(model, token) {
|
|
891
|
+
const path = join(tmpdir(), `pi-native-probe-${process.pid}-${Date.now()}.txt`);
|
|
892
|
+
writeFileSync(path, token, "utf-8");
|
|
893
|
+
try {
|
|
894
|
+
const taskPassed = await this._runNativeReadTaskProbeTrial(model, path);
|
|
895
|
+
if (taskPassed)
|
|
896
|
+
return "task";
|
|
897
|
+
const echoPassed = await this._runNativeEchoToolProbeTrial(model, token);
|
|
898
|
+
if (echoPassed)
|
|
899
|
+
return "echo-only";
|
|
900
|
+
return "absent";
|
|
901
|
+
}
|
|
902
|
+
finally {
|
|
903
|
+
rmSync(path, { force: true });
|
|
904
|
+
}
|
|
855
905
|
}
|
|
856
906
|
async _runTextProtocolTrial(model, variant, token) {
|
|
857
907
|
const stream = await this._streamForToolProbe(model, this._textProtocolCalibrationContext(variant, token), {
|
|
858
908
|
textToolCallProtocol: false,
|
|
859
909
|
maxRetries: 0,
|
|
910
|
+
temperature: 0,
|
|
911
|
+
maxTokens: 256,
|
|
860
912
|
});
|
|
861
913
|
const message = await stream.result();
|
|
862
|
-
if (this._messageHasEchoProbe(message, token))
|
|
863
|
-
return true;
|
|
864
914
|
const text = message.content
|
|
865
915
|
.filter((block) => block.type === "text")
|
|
866
916
|
.map((block) => block.text)
|
|
@@ -932,12 +982,17 @@ export class AgentSession {
|
|
|
932
982
|
return `${model.provider}/${model.id}`;
|
|
933
983
|
}
|
|
934
984
|
_formatToolProbeReport(results) {
|
|
935
|
-
const lines = [
|
|
985
|
+
const lines = [
|
|
986
|
+
"Tool probe results:",
|
|
987
|
+
"Model | Verdict | Variant | Native grade | Diagnostic",
|
|
988
|
+
"--- | --- | --- | --- | ---",
|
|
989
|
+
];
|
|
936
990
|
for (const result of results) {
|
|
937
991
|
lines.push([
|
|
938
992
|
result.model,
|
|
939
993
|
result.verdict,
|
|
940
994
|
result.variant ?? "-",
|
|
995
|
+
result.nativeGrade ?? "-",
|
|
941
996
|
result.diagnostic ? result.diagnostic.replace(/\s+/g, " ").slice(0, 160) : "-",
|
|
942
997
|
].join(" | "));
|
|
943
998
|
}
|
|
@@ -949,12 +1004,23 @@ export class AgentSession {
|
|
|
949
1004
|
async _probeToolCallingForModel(model) {
|
|
950
1005
|
const modelKey = this._modelRef(model);
|
|
951
1006
|
const probedAt = new Date().toISOString();
|
|
1007
|
+
let nativeGrade = "absent";
|
|
952
1008
|
let diagnostic;
|
|
953
1009
|
try {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
1010
|
+
nativeGrade = await this._gradeNativeToolCallingForModel(model, "pi-native-probe");
|
|
1011
|
+
if (nativeGrade === "task") {
|
|
1012
|
+
this._storeToolProbe(modelKey, {
|
|
1013
|
+
version: TEXT_TOOL_PROTOCOL_VERSION,
|
|
1014
|
+
status: "native",
|
|
1015
|
+
probedAt,
|
|
1016
|
+
nativeGrade,
|
|
1017
|
+
});
|
|
1018
|
+
return { model: modelKey, verdict: "native", nativeGrade };
|
|
957
1019
|
}
|
|
1020
|
+
diagnostic =
|
|
1021
|
+
nativeGrade === "echo-only"
|
|
1022
|
+
? "Native echo probe passed but task-scale read probe failed."
|
|
1023
|
+
: "Native task-scale read and echo probes did not produce provider-native tool calls.";
|
|
958
1024
|
}
|
|
959
1025
|
catch (error) {
|
|
960
1026
|
diagnostic = error instanceof Error ? error.message : String(error);
|
|
@@ -967,16 +1033,24 @@ export class AgentSession {
|
|
|
967
1033
|
status: "text-protocol",
|
|
968
1034
|
probedAt: calibrated.calibratedAt,
|
|
969
1035
|
variant: calibrated.variant,
|
|
1036
|
+
nativeGrade,
|
|
1037
|
+
diagnostic,
|
|
970
1038
|
});
|
|
971
|
-
return { model: modelKey, verdict: "text-protocol", variant: calibrated.variant };
|
|
1039
|
+
return { model: modelKey, verdict: "text-protocol", variant: calibrated.variant, nativeGrade, diagnostic };
|
|
972
1040
|
}
|
|
973
|
-
diagnostic
|
|
1041
|
+
diagnostic = `${diagnostic ? `${diagnostic} ` : ""}Text protocol variants failed: ${calibrated.variantsTried.join(", ")}`;
|
|
974
1042
|
}
|
|
975
1043
|
catch (error) {
|
|
976
1044
|
diagnostic = error instanceof Error ? error.message : String(error);
|
|
977
1045
|
}
|
|
978
|
-
this._storeToolProbe(modelKey, {
|
|
979
|
-
|
|
1046
|
+
this._storeToolProbe(modelKey, {
|
|
1047
|
+
version: TEXT_TOOL_PROTOCOL_VERSION,
|
|
1048
|
+
status: "none",
|
|
1049
|
+
probedAt,
|
|
1050
|
+
nativeGrade,
|
|
1051
|
+
diagnostic,
|
|
1052
|
+
});
|
|
1053
|
+
return { model: modelKey, verdict: "none", nativeGrade, diagnostic };
|
|
980
1054
|
}
|
|
981
1055
|
async _resolveToolProbeModels(target) {
|
|
982
1056
|
const trimmed = target?.trim();
|
|
@@ -1007,10 +1081,8 @@ export class AgentSession {
|
|
|
1007
1081
|
_handleTextToolProtocolParse(event) {
|
|
1008
1082
|
this._textProtocolParseObservedThisTurn = true;
|
|
1009
1083
|
const modelKey = `${event.provider}/${event.model}`;
|
|
1010
|
-
if (event.status === "parsed")
|
|
1011
|
-
this._textProtocolParseFailures.delete(modelKey);
|
|
1084
|
+
if (event.status === "parsed")
|
|
1012
1085
|
return;
|
|
1013
|
-
}
|
|
1014
1086
|
const signature = `${event.variant}:${event.reason ?? "failed"}`;
|
|
1015
1087
|
const previous = this._textProtocolParseFailures.get(modelKey);
|
|
1016
1088
|
const repeats = previous?.signature === signature ? previous.repeats + 1 : 1;
|
|
@@ -1024,7 +1096,40 @@ export class AgentSession {
|
|
|
1024
1096
|
}
|
|
1025
1097
|
this._textProtocolParseFailures.delete(modelKey);
|
|
1026
1098
|
}
|
|
1099
|
+
_handleTextToolProtocolValidationOutcome(event) {
|
|
1100
|
+
if (event.source !== "text-protocol")
|
|
1101
|
+
return;
|
|
1102
|
+
const protocol = this.agent.textToolCallProtocol;
|
|
1103
|
+
const variant = protocol === true ? "tool-tag" : protocol ? protocol.variant : undefined;
|
|
1104
|
+
if (!variant)
|
|
1105
|
+
return;
|
|
1106
|
+
const status = event.outcome === "bounced" ? "failed" : "parsed";
|
|
1107
|
+
if (this._textProtocolValidationOutcomeThisTurn?.status === "parsed" && status === "failed")
|
|
1108
|
+
return;
|
|
1109
|
+
this._textProtocolValidationOutcomeThisTurn = {
|
|
1110
|
+
provider: event.provider ?? this.agent.state.model.provider,
|
|
1111
|
+
model: event.model ?? this.agent.state.model.id,
|
|
1112
|
+
variant,
|
|
1113
|
+
status,
|
|
1114
|
+
callCount: 1,
|
|
1115
|
+
textLength: 0,
|
|
1116
|
+
...(status === "failed" && {
|
|
1117
|
+
reason: event.errorKeywords?.includes("unknown_tool") ? "unknown-tool" : "validation-failed",
|
|
1118
|
+
}),
|
|
1119
|
+
};
|
|
1120
|
+
}
|
|
1027
1121
|
_recordTextToolProtocolParseOutcomeFromLastAssistant() {
|
|
1122
|
+
const validationOutcome = this._textProtocolValidationOutcomeThisTurn;
|
|
1123
|
+
this._textProtocolValidationOutcomeThisTurn = undefined;
|
|
1124
|
+
if (validationOutcome?.status === "parsed") {
|
|
1125
|
+
this._textProtocolParseObservedThisTurn = true;
|
|
1126
|
+
this._textProtocolParseFailures.delete(`${validationOutcome.provider}/${validationOutcome.model}`);
|
|
1127
|
+
return;
|
|
1128
|
+
}
|
|
1129
|
+
if (validationOutcome) {
|
|
1130
|
+
this._handleTextToolProtocolParse(validationOutcome);
|
|
1131
|
+
return;
|
|
1132
|
+
}
|
|
1028
1133
|
if (this._textProtocolParseObservedThisTurn)
|
|
1029
1134
|
return;
|
|
1030
1135
|
const protocol = this.agent.textToolCallProtocol;
|
|
@@ -1903,6 +2008,9 @@ export class AgentSession {
|
|
|
1903
2008
|
getLocalRuntime(baseUrl) {
|
|
1904
2009
|
return this._localRuntimeController.getLocalRuntime(baseUrl);
|
|
1905
2010
|
}
|
|
2011
|
+
getTransformersRuntime(modelId, baseUrl) {
|
|
2012
|
+
return this._localRuntimeController.getTransformersRuntime(modelId, baseUrl);
|
|
2013
|
+
}
|
|
1906
2014
|
/** models.json registers a local model's baseUrl as `<server>/v1` (OpenAI-compat); the runtime's
|
|
1907
2015
|
* own health/boot endpoints are on the Ollama-native server root. Delegates to
|
|
1908
2016
|
* {@link LocalRuntimeController}; kept here for `_warnIfManualModelChoiceIsRisky`'s own use. */
|
|
@@ -2181,6 +2289,7 @@ export class AgentSession {
|
|
|
2181
2289
|
}
|
|
2182
2290
|
preflightResult?.(true);
|
|
2183
2291
|
this._textProtocolParseObservedThisTurn = false;
|
|
2292
|
+
this._textProtocolValidationOutcomeThisTurn = undefined;
|
|
2184
2293
|
await this._modelRouter.runRoutedTurn(messages, routedTurnModel, routedTurnRouteDecision);
|
|
2185
2294
|
this._recordTextToolProtocolParseOutcomeFromLastAssistant();
|
|
2186
2295
|
// R4: score whether the agent actually used the recalled context, so the recall gate can adapt.
|