@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.
Files changed (55) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/bundled-resources/runtimes/hf-transformers-openai-server.py +427 -0
  3. package/dist/bundled-resources/skills/tool-call-repair/SKILL.md +13 -11
  4. package/dist/bundled-resources/skills/tool-call-repair/references/failure-grammar.md +16 -10
  5. package/dist/bundled-resources/skills/tool-call-repair/references/text-protocol-grammar.md +14 -7
  6. package/dist/core/agent-session.d.ts +11 -3
  7. package/dist/core/agent-session.d.ts.map +1 -1
  8. package/dist/core/agent-session.js +132 -23
  9. package/dist/core/agent-session.js.map +1 -1
  10. package/dist/core/local-runtime-controller.d.ts +17 -9
  11. package/dist/core/local-runtime-controller.d.ts.map +1 -1
  12. package/dist/core/local-runtime-controller.js +124 -20
  13. package/dist/core/local-runtime-controller.js.map +1 -1
  14. package/dist/core/models/adaptation-store.d.ts +2 -0
  15. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  16. package/dist/core/models/adaptation-store.js +4 -0
  17. package/dist/core/models/adaptation-store.js.map +1 -1
  18. package/dist/core/models/default-model-suggestions.d.ts +4 -4
  19. package/dist/core/models/default-model-suggestions.d.ts.map +1 -1
  20. package/dist/core/models/default-model-suggestions.js +9 -0
  21. package/dist/core/models/default-model-suggestions.js.map +1 -1
  22. package/dist/core/models/local-registration.d.ts +12 -0
  23. package/dist/core/models/local-registration.d.ts.map +1 -1
  24. package/dist/core/models/local-registration.js +68 -0
  25. package/dist/core/models/local-registration.js.map +1 -1
  26. package/dist/core/models/local-runtime.d.ts +77 -1
  27. package/dist/core/models/local-runtime.d.ts.map +1 -1
  28. package/dist/core/models/local-runtime.js +295 -4
  29. package/dist/core/models/local-runtime.js.map +1 -1
  30. package/dist/core/models/model-ref.d.ts +4 -0
  31. package/dist/core/models/model-ref.d.ts.map +1 -1
  32. package/dist/core/models/model-ref.js +12 -3
  33. package/dist/core/models/model-ref.js.map +1 -1
  34. package/dist/core/tool-repair-health.d.ts.map +1 -1
  35. package/dist/core/tool-repair-health.js +2 -1
  36. package/dist/core/tool-repair-health.js.map +1 -1
  37. package/dist/modes/interactive/interactive-mode.d.ts +1 -0
  38. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  39. package/dist/modes/interactive/interactive-mode.js +4 -0
  40. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  41. package/dist/modes/interactive/local-model-commands.d.ts +3 -1
  42. package/dist/modes/interactive/local-model-commands.d.ts.map +1 -1
  43. package/dist/modes/interactive/local-model-commands.js +133 -19
  44. package/dist/modes/interactive/local-model-commands.js.map +1 -1
  45. package/docs/models.md +19 -1
  46. package/docs/tool-repair.md +2 -0
  47. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  48. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  49. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  50. package/examples/extensions/sandbox/package-lock.json +2 -2
  51. package/examples/extensions/sandbox/package.json +1 -1
  52. package/examples/extensions/with-deps/package-lock.json +2 -2
  53. package/examples/extensions/with-deps/package.json +1 -1
  54. package/npm-shrinkwrap.json +12 -12
  55. 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 = ["tool-tag", "tool-call", "fenced-json"];
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
- _messageHasEchoProbe(message, token) {
844
- return message.content.some((block) => block.type === "toolCall" && block.name === "echo" && block.arguments.data === token);
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 _runNativeToolProbeTrial(model, token) {
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._messageHasEchoProbe(await stream.result(), token);
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 = ["Tool probe results:", "Model | Verdict | Variant | Diagnostic", "--- | --- | --- | ---"];
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
- if (await this._runNativeToolProbeTrial(model, "pi-native-probe")) {
955
- this._storeToolProbe(modelKey, { version: TEXT_TOOL_PROTOCOL_VERSION, status: "native", probedAt });
956
- return { model: modelKey, verdict: "native" };
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 ??= `Text protocol variants failed: ${calibrated.variantsTried.join(", ")}`;
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, { version: TEXT_TOOL_PROTOCOL_VERSION, status: "none", probedAt, diagnostic });
979
- return { model: modelKey, verdict: "none", diagnostic };
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.