@mcoda/mswarm 0.1.110 → 0.1.112

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 (36) hide show
  1. package/dist/vendor/codali/cli/AskCommand.d.ts.map +1 -1
  2. package/dist/vendor/codali/cli/AskCommand.js +20 -1
  3. package/dist/vendor/codali/docdex/DocdexClient.d.ts +6 -0
  4. package/dist/vendor/codali/docdex/DocdexClient.d.ts.map +1 -1
  5. package/dist/vendor/codali/docdex/DocdexClient.js +2 -0
  6. package/dist/vendor/codali/gateway/CodaliGateway.d.ts +2 -1
  7. package/dist/vendor/codali/gateway/CodaliGateway.d.ts.map +1 -1
  8. package/dist/vendor/codali/gateway/CodaliGateway.js +104 -37
  9. package/dist/vendor/codali/gateway/CodaliGatewayTypes.d.ts +10 -0
  10. package/dist/vendor/codali/gateway/CodaliGatewayTypes.d.ts.map +1 -1
  11. package/dist/vendor/codali/gateway/EvidenceNormalizer.d.ts.map +1 -1
  12. package/dist/vendor/codali/gateway/EvidenceNormalizer.js +3 -0
  13. package/dist/vendor/codali/gateway/GatewayPlanner.d.ts.map +1 -1
  14. package/dist/vendor/codali/gateway/GatewayPlanner.js +37 -1
  15. package/dist/vendor/codali/gateway/GroundingMode.d.ts +35 -0
  16. package/dist/vendor/codali/gateway/GroundingMode.d.ts.map +1 -0
  17. package/dist/vendor/codali/gateway/GroundingMode.js +69 -0
  18. package/dist/vendor/codali/gateway/LocalGatewayProvider.d.ts +16 -0
  19. package/dist/vendor/codali/gateway/LocalGatewayProvider.d.ts.map +1 -1
  20. package/dist/vendor/codali/gateway/LocalGatewayProvider.js +24 -1
  21. package/dist/vendor/codali/gateway/LocalGatewayTaskRunner.d.ts.map +1 -1
  22. package/dist/vendor/codali/gateway/LocalGatewayTaskRunner.js +10 -1
  23. package/dist/vendor/codali/gateway/RelevanceJudge.d.ts.map +1 -1
  24. package/dist/vendor/codali/gateway/RelevanceJudge.js +25 -8
  25. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts +1 -0
  26. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
  27. package/dist/vendor/codali/providers/OpenAiCompatibleProvider.js +55 -3
  28. package/dist/vendor/codali/providers/ProviderTypes.d.ts +2 -0
  29. package/dist/vendor/codali/providers/ProviderTypes.d.ts.map +1 -1
  30. package/dist/vendor/codali/tools/ToolRegistry.d.ts +5 -1
  31. package/dist/vendor/codali/tools/ToolRegistry.d.ts.map +1 -1
  32. package/dist/vendor/codali/tools/ToolRegistry.js +79 -2
  33. package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts +13 -0
  34. package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts.map +1 -1
  35. package/dist/vendor/codali/tools/docdex/DocdexTools.js +167 -12
  36. package/package.json +3 -3
@@ -32,6 +32,22 @@ export declare const CODALI_MSWARM_PRIORITY = -10;
32
32
  export declare const providerNameForAdapter: (adapter: string | undefined) => string;
33
33
  export declare const createProviderForName: (name: string, config: ProviderConfig) => Provider;
34
34
  export declare const resolveMswarmApiKey: () => string | undefined;
35
+ /**
36
+ * The key for a self-hosted agent that is not behind the mswarm relay.
37
+ *
38
+ * mcoda stores agent secrets encrypted (`agent_auth.encrypted_secret`) and
39
+ * `agent list --json` reports only whether one is configured, so an agent
40
+ * registered with `authMode: bearer` and a direct base URL arrives here with no
41
+ * key at all. The provider then threw before making any request, which surfaced
42
+ * as a worker failing in 0ms on every call while the run still reported
43
+ * success — the finalizer answered without evidence rather than the run
44
+ * stopping on a configuration error.
45
+ *
46
+ * Codali therefore takes the key from the operator's own environment, matching
47
+ * how the mswarm key is read from local trusted config. The per-agent form wins
48
+ * so several self-hosted models can be used at once.
49
+ */
50
+ export declare const localAgentApiKeyEnvVar: (slug: string) => string;
35
51
  /**
36
52
  * Creates a provider for an assigned agent. The raw inventory entry carries the
37
53
  * transport details (base URL, runner kind, auth mode) that the tier resolver
@@ -1 +1 @@
1
- {"version":3,"file":"LocalGatewayProvider.d.ts","sourceRoot":"","sources":["../../src/gateway/LocalGatewayProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAE3E;;;;;;GAMG;AAEH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0CD;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAwB1C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,GAAG,SAAS,KAAG,MAapE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,QAAQ,cAAc,KACrB,QAWF,CAAC;AAYF,eAAO,MAAM,mBAAmB,QAAO,MAAM,GAAG,SA4B/C,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,YAAY,4BAA4B,EACxC,UAAS,oBAAyB,KACjC,QAkCF,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAIhD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAL9B,QAAQ,CAAC,IAAI,wBAAwB;gBAGlB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,QAAQ,EAAE,QAAQ,EAClB,WAAW,GAAE,MAAM,MAAM,GAAG,SAA2B;IAG1E,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ;IAK7C,QAAQ,CACZ,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAC3C,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;CAGpC"}
1
+ {"version":3,"file":"LocalGatewayProvider.d.ts","sourceRoot":"","sources":["../../src/gateway/LocalGatewayProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,QAAQ,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAC9E,OAAO,KAAK,EAAE,4BAA4B,EAAE,MAAM,wBAAwB,CAAC;AAE3E;;;;;;GAMG;AAEH,MAAM,WAAW,oBAAoB;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AA0CD;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,MAAM,CAAC;AAwB1C;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,GAAI,SAAS,MAAM,GAAG,SAAS,KAAG,MAapE,CAAC;AAEF,eAAO,MAAM,qBAAqB,GAChC,MAAM,MAAM,EACZ,QAAQ,cAAc,KACrB,QAWF,CAAC;AAYF,eAAO,MAAM,mBAAmB,QAAO,MAAM,GAAG,SA4B/C,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,sBAAsB,GAAI,MAAM,MAAM,KAAG,MACoB,CAAC;AAU3E;;;;GAIG;AACH,eAAO,MAAM,2BAA2B,GACtC,YAAY,4BAA4B,EACxC,UAAS,oBAAyB,KACjC,QAqCF,CAAC;AAEF;;;;;;;;GAQG;AACH,qBAAa,mBAAoB,YAAW,QAAQ;IAIhD,OAAO,CAAC,QAAQ,CAAC,SAAS;IAC1B,OAAO,CAAC,QAAQ,CAAC,QAAQ;IACzB,OAAO,CAAC,QAAQ,CAAC,WAAW;IAL9B,QAAQ,CAAC,IAAI,wBAAwB;gBAGlB,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,EACnC,QAAQ,EAAE,QAAQ,EAClB,WAAW,GAAE,MAAM,MAAM,GAAG,SAA2B;IAG1E,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,QAAQ;IAK7C,QAAQ,CACZ,OAAO,EAAE,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC,GAC3C,UAAU,CAAC,QAAQ,CAAC,UAAU,CAAC,CAAC;CAGpC"}
@@ -135,6 +135,26 @@ export const resolveMswarmApiKey = () => {
135
135
  cachedMswarmKey = null;
136
136
  return undefined;
137
137
  };
138
+ /**
139
+ * The key for a self-hosted agent that is not behind the mswarm relay.
140
+ *
141
+ * mcoda stores agent secrets encrypted (`agent_auth.encrypted_secret`) and
142
+ * `agent list --json` reports only whether one is configured, so an agent
143
+ * registered with `authMode: bearer` and a direct base URL arrives here with no
144
+ * key at all. The provider then threw before making any request, which surfaced
145
+ * as a worker failing in 0ms on every call while the run still reported
146
+ * success — the finalizer answered without evidence rather than the run
147
+ * stopping on a configuration error.
148
+ *
149
+ * Codali therefore takes the key from the operator's own environment, matching
150
+ * how the mswarm key is read from local trusted config. The per-agent form wins
151
+ * so several self-hosted models can be used at once.
152
+ */
153
+ export const localAgentApiKeyEnvVar = (slug) => `CODALI_AGENT_API_KEY_${slug.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}`;
154
+ const resolveLocalAgentApiKey = (slug) => {
155
+ const perAgent = slug ? process.env[localAgentApiKeyEnvVar(slug)]?.trim() : undefined;
156
+ return perAgent || process.env.CODALI_API_KEY?.trim() || undefined;
157
+ };
138
158
  const isMswarmEndpoint = (baseUrl) => Boolean(baseUrl && /(^|\/\/)([^/]*\.)?mswarm\.org/i.test(baseUrl));
139
159
  /**
140
160
  * Creates a provider for an assigned agent. The raw inventory entry carries the
@@ -153,9 +173,12 @@ export const createProviderForAssignment = (assignment, options = {}) => {
153
173
  const apiKey = options.apiKey ??
154
174
  readString(nested, ["apiKey", "api_key"]) ??
155
175
  readString(raw, ["apiKey", "api_key"]) ??
156
- (isMswarmEndpoint(baseUrl) ? resolveMswarmApiKey() : undefined);
176
+ (isMswarmEndpoint(baseUrl)
177
+ ? resolveMswarmApiKey()
178
+ : resolveLocalAgentApiKey(assignment.candidate.slug));
157
179
  const config = {
158
180
  model: assignment.candidate.model ?? readString(raw, ["defaultModel", "model"]) ?? "",
181
+ agentSlug: assignment.candidate.slug,
159
182
  baseUrl,
160
183
  apiKey,
161
184
  timeoutMs: options.timeoutMs ?? LOCAL_MODEL_TIMEOUT_MS,
@@ -1 +1 @@
1
- {"version":3,"file":"LocalGatewayTaskRunner.d.ts","sourceRoot":"","sources":["../../src/gateway/LocalGatewayTaskRunner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAEV,+BAA+B,EAC/B,gCAAgC,EAChC,6BAA6B,EAE9B,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,2EAA2E;AAC3E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAe1C,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,MAAM,2BAA2B,GACnC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAClF;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAClE;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AA6DN,qBAAa,sBAAuB,YAAW,6BAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,6BAA6B;IAE7D,GAAG,CACP,KAAK,EAAE,+BAA+B,GACrC,OAAO,CAAC,gCAAgC,CAAC;CAqT7C;AAED,eAAO,MAAM,4BAA4B,GACvC,SAAS,6BAA6B,KACrC,sBAA6D,CAAC;AAEjE,eAAO,MAAM,aAAa,UA3XD,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CA2X7B,CAAC"}
1
+ {"version":3,"file":"LocalGatewayTaskRunner.d.ts","sourceRoot":"","sources":["../../src/gateway/LocalGatewayTaskRunner.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,QAAQ,EAGT,MAAM,+BAA+B,CAAC;AACvC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAC7D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AAGzD,OAAO,KAAK,EAEV,+BAA+B,EAC/B,gCAAgC,EAChC,6BAA6B,EAE9B,MAAM,0BAA0B,CAAC;AAElC;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AAEH,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,IAAI,CAAC;AAEzC,2EAA2E;AAC3E,eAAO,MAAM,wBAAwB,IAAI,CAAC;AAe1C,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,QAAQ,CAAC;IACnB,QAAQ,EAAE,YAAY,CAAC;IACvB,WAAW,EAAE,WAAW,CAAC;IACzB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,2BAA2B,KAAK,IAAI,CAAC;CACxD;AAED,MAAM,MAAM,2BAA2B,GACnC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,EAAE,CAAA;CAAE,GAClF;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,OAAO,CAAA;CAAE,GAClE;IACE,IAAI,EAAE,aAAa,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,OAAO,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,GACD;IACE,IAAI,EAAE,UAAU,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,GAAG,QAAQ,CAAC;IAC/B,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACpB,CAAC;AAsEN,qBAAa,sBAAuB,YAAW,6BAA6B;IAC9D,OAAO,CAAC,QAAQ,CAAC,OAAO;gBAAP,OAAO,EAAE,6BAA6B;IAE7D,GAAG,CACP,KAAK,EAAE,+BAA+B,GACrC,OAAO,CAAC,gCAAgC,CAAC;CAqT7C;AAED,eAAO,MAAM,4BAA4B,GACvC,SAAS,6BAA6B,KACrC,sBAA6D,CAAC;AAEjE,eAAO,MAAM,aAAa,UApYD,OAAO,KAAG,KAAK,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,CAoY7B,CAAC"}
@@ -70,7 +70,16 @@ const buildTaskMessages = (input, hasTools) => {
70
70
  "You are a Codali gateway worker.",
71
71
  "Gather evidence for one bounded sub-task. Do not answer the user's overall question.",
72
72
  hasTools
73
- ? "Call the tools you need in a single batch. You get exactly one opportunity to call tools, so request everything you need at once."
73
+ ? [
74
+ "Call the tools you need in a single batch. You get exactly one opportunity to call tools, so request everything you need at once.",
75
+ // Told only that it had one chance, the worker reliably issued a
76
+ // single search and stopped. A search ranks whole files; it does not
77
+ // return the value of a constant or the contents of a directory, so
78
+ // questions of that shape came back unanswered with the budget for
79
+ // seven more calls unspent.
80
+ "One search is rarely enough. In the same batch, add the tools that cover what a search cannot: listing a directory's files, reading a named file, or looking up a symbol's definition.",
81
+ "Prefer several complementary calls over one broad one — unused calls cost nothing, a missing one costs the answer.",
82
+ ].join("\n")
74
83
  : "No tools are available. Answer from the task description alone or state what is missing.",
75
84
  "Report only what the tool results actually support. Never invent file paths, identifiers, figures, or quotations.",
76
85
  "If the results are insufficient, say so plainly instead of guessing; another round may be scheduled.",
@@ -1 +1 @@
1
- {"version":3,"file":"RelevanceJudge.d.ts","sourceRoot":"","sources":["../../src/gateway/RelevanceJudge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAyBrE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,OAAO,KAAG,MAAM,EAqB9D,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAeD;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,QAAQ,SAAS,MAAM,EAAE,KACxB,OAWF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,qBAAqB,KAC7B,cAyCF,CAAC"}
1
+ {"version":3,"file":"RelevanceJudge.d.ts","sourceRoot":"","sources":["../../src/gateway/RelevanceJudge.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAyBrE;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,GAAI,SAAS,OAAO,KAAG,MAAM,EAqB9D,CAAC;AAEF,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,QAAQ,CAAC;IACnB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAoCD;;;;;;;;;GASG;AACH,eAAO,MAAM,yBAAyB,GACpC,OAAO,MAAM,EACb,QAAQ,SAAS,MAAM,EAAE,KACxB,OAWF,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAC/B,SAAS,qBAAqB,KAC7B,cAyCF,CAAC"}
@@ -58,6 +58,25 @@ const STOPWORDS = new Set([
58
58
  "class", "file", "code", "show", "list", "find", "tell", "give", "about",
59
59
  "purpose", "exists", "existence", "summary", "summarize", "explain",
60
60
  ]);
61
+ /**
62
+ * Splits text into comparable words, breaking CamelCase as well as punctuation.
63
+ *
64
+ * A symbol name is one word to a human and several to a path. Asked "which file
65
+ * defines CodaliGatewayPlannerError", the question yields the single term
66
+ * `codaligatewayplannererror`, while `gateway/GatewayPlanner.ts` flattens to
67
+ * `gateway gatewayplanner ts` — no overlap, so the correct file was discarded.
68
+ * Splitting both sides on case boundaries puts `gateway` and `planner` on each
69
+ * side, and the match succeeds.
70
+ */
71
+ const wordsIn = (value) => value
72
+ // Insert a break between a lowercase/digit and a following uppercase, so
73
+ // `GatewayPlanner` becomes `Gateway Planner` before the lowercase pass.
74
+ .replace(/([a-z0-9])([A-Z])/g, "$1 $2")
75
+ // And between an acronym and a following word: `HTTPClient` -> `HTTP Client`.
76
+ .replace(/([A-Z]+)([A-Z][a-z])/g, "$1 $2")
77
+ .toLowerCase()
78
+ .split(/[^a-z0-9]+/)
79
+ .filter(Boolean);
61
80
  /**
62
81
  * Whether any result title shares a distinctive word with the question.
63
82
  *
@@ -69,16 +88,14 @@ const STOPWORDS = new Set([
69
88
  * results — which is where it earns its keep.
70
89
  */
71
90
  export const titlesShareTermsWithQuery = (query, titles) => {
72
- const terms = query
73
- .toLowerCase()
74
- .split(/[^a-z0-9]+/)
75
- .filter((word) => word.length > 3 && !STOPWORDS.has(word));
91
+ const terms = wordsIn(query).filter((word) => word.length > 3 && !STOPWORDS.has(word));
76
92
  if (terms.length === 0)
77
93
  return false;
78
- // Split titles the same way so `LocalGatewayTaskRunner.ts` matches
79
- // `localgatewaytaskrunner` from the question.
80
- const haystack = titles.join(" ").toLowerCase().replace(/[^a-z0-9]+/g, " ");
81
- return terms.some((term) => haystack.includes(term));
94
+ // Whole words only. Splitting both sides the same way already lets a symbol
95
+ // in the question meet the same symbol in a path, so a substring pass would
96
+ // add nothing but false matches ("string" hitting `StringUtils.ts`).
97
+ const haystack = ` ${wordsIn(titles.join(" ")).join(" ")} `;
98
+ return terms.some((term) => haystack.includes(` ${term} `));
82
99
  };
83
100
  export const createRelevanceJudge = (options) => async ({ query, results }) => {
84
101
  const titles = summarizeResultTitles(results);
@@ -1,4 +1,5 @@
1
1
  import type { Provider, ProviderConfig, ProviderRequest, ProviderResponse } from "./ProviderTypes.js";
2
+ export declare const fetchWithTransientRetry: (url: string, init: RequestInit, controller?: AbortController) => Promise<Response>;
2
3
  export declare class OpenAiCompatibleProvider implements Provider {
3
4
  private config;
4
5
  /** OpenAI-style function calling is supported and parsed from `tool_calls`. */
@@ -1 +1 @@
1
- {"version":3,"file":"OpenAiCompatibleProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OpenAiCompatibleProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EAEd,eAAe,EACf,gBAAgB,EAGjB,MAAM,oBAAoB,CAAC;AAsH5B,qBAAa,wBAAyB,YAAW,QAAQ;IAS3C,OAAO,CAAC,MAAM;IAR1B,+EAA+E;IAC/E,QAAQ,CAAC,iBAAiB,QAAQ;IAElC,IAAI,SAAuB;IAC3B,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,sBAAsB,CAAoC;gBAE9C,MAAM,EAAE,cAAc;IAWpC,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAsMnE,OAAO,CAAC,WAAW;CAepB"}
1
+ {"version":3,"file":"OpenAiCompatibleProvider.d.ts","sourceRoot":"","sources":["../../src/providers/OpenAiCompatibleProvider.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EACV,QAAQ,EACR,cAAc,EAEd,eAAe,EACf,gBAAgB,EAGjB,MAAM,oBAAoB,CAAC;AAgJ5B,eAAO,MAAM,uBAAuB,GAClC,KAAK,MAAM,EACX,MAAM,WAAW,EACjB,aAAa,eAAe,KAC3B,OAAO,CAAC,QAAQ,CAclB,CAAC;AAEF,qBAAa,wBAAyB,YAAW,QAAQ;IAS3C,OAAO,CAAC,MAAM;IAR1B,+EAA+E;IAC/E,QAAQ,CAAC,iBAAiB,QAAQ;IAElC,IAAI,SAAuB;IAC3B,OAAO,CAAC,WAAW,CAAoC;IACvD,OAAO,CAAC,QAAQ,CAAsB;IACtC,OAAO,CAAC,sBAAsB,CAAoC;gBAE9C,MAAM,EAAE,cAAc;IAWpC,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IA0MnE,OAAO,CAAC,WAAW;CA0BpB"}
@@ -80,6 +80,49 @@ const buildPromptOnlyFormatInstruction = (format) => {
80
80
  }
81
81
  return undefined;
82
82
  };
83
+ /**
84
+ * A single dropped connection must not fail a whole run.
85
+ *
86
+ * Self-hosted llama.cpp behind a relay closes sockets under load, surfacing as
87
+ * a bare `TypeError: fetch failed` with no status. Measured over fifty live
88
+ * questions this took out four runs outright — the caller saw an empty result,
89
+ * not a slow one. Retried, each of them succeeded.
90
+ *
91
+ * Deliberately narrow: only connection-level errors are retried. An HTTP error
92
+ * status is the server's considered answer and repeating it just wastes a
93
+ * minute, and an abort is our own timeout firing, where retrying would double
94
+ * the wait the caller already declined.
95
+ */
96
+ const TRANSIENT_RETRIES = 2;
97
+ const TRANSIENT_RETRY_DELAY_MS = 750;
98
+ const isTransientNetworkError = (error) => {
99
+ if (error instanceof Error && error.name === "AbortError")
100
+ return false;
101
+ const cause = error?.cause;
102
+ const code = cause?.code ?? error?.code;
103
+ if (typeof code === "string") {
104
+ return ["ECONNRESET", "ECONNREFUSED", "EPIPE", "ETIMEDOUT", "UND_ERR_SOCKET"].includes(code);
105
+ }
106
+ return error instanceof TypeError && /fetch failed|network|socket/i.test(error.message);
107
+ };
108
+ export const fetchWithTransientRetry = async (url, init, controller) => {
109
+ let lastError;
110
+ for (let attempt = 0; attempt <= TRANSIENT_RETRIES; attempt += 1) {
111
+ try {
112
+ return await fetch(url, init);
113
+ }
114
+ catch (error) {
115
+ lastError = error;
116
+ // Our own timeout already fired; there is no time left to spend.
117
+ if (controller?.signal.aborted || !isTransientNetworkError(error))
118
+ throw error;
119
+ if (attempt === TRANSIENT_RETRIES)
120
+ break;
121
+ await new Promise((resolve) => setTimeout(resolve, TRANSIENT_RETRY_DELAY_MS * (attempt + 1)));
122
+ }
123
+ }
124
+ throw lastError;
125
+ };
83
126
  export class OpenAiCompatibleProvider {
84
127
  constructor(config) {
85
128
  this.config = config;
@@ -156,12 +199,12 @@ export class OpenAiCompatibleProvider {
156
199
  const timeoutMs = this.config.timeoutMs ?? 60000;
157
200
  const timeout = setTimeout(() => controller.abort(), timeoutMs);
158
201
  try {
159
- const response = await fetch(url, {
202
+ const response = await fetchWithTransientRetry(url, {
160
203
  method: "POST",
161
204
  headers,
162
205
  body: JSON.stringify(body),
163
206
  signal: controller.signal,
164
- });
207
+ }, controller);
165
208
  if (!response.ok) {
166
209
  const errorBody = await response.text();
167
210
  throw new Error(`OpenAI-compatible error ${response.status}: ${errorBody}`);
@@ -284,7 +327,16 @@ export class OpenAiCompatibleProvider {
284
327
  };
285
328
  }
286
329
  if (!this.config.apiKey) {
287
- throw new Error("AUTH_REQUIRED: OpenAI-compatible provider API key missing; set CODALI_API_KEY.");
330
+ // Name the agent and the variable that fixes it. The old message named a
331
+ // single global key, which is wrong once more than one self-hosted model
332
+ // is registered, and gave no clue which agent had failed.
333
+ const slug = this.config.agentSlug;
334
+ const perAgent = slug
335
+ ? ` Set ${`CODALI_AGENT_API_KEY_${slug.toUpperCase().replace(/[^A-Z0-9]+/g, "_")}`}, or`
336
+ : "";
337
+ throw new Error(`AUTH_REQUIRED: no API key for ${slug ?? "this OpenAI-compatible agent"} ` +
338
+ `(auth mode "bearer", base URL ${this.config.baseUrl ?? "unset"}).` +
339
+ `${perAgent} set CODALI_API_KEY, or register the agent with auth mode "none".`);
288
340
  }
289
341
  return { mode: "bearer", authorization: `Bearer ${this.config.apiKey}` };
290
342
  }
@@ -71,6 +71,8 @@ export interface ProviderResponse {
71
71
  }
72
72
  export interface ProviderConfig {
73
73
  model: string;
74
+ /** Agent this provider serves, so failures can name it. */
75
+ agentSlug?: string;
74
76
  apiKey?: string;
75
77
  baseUrl?: string;
76
78
  timeoutMs?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"ProviderTypes.d.ts","sourceRoot":"","sources":["../../src/providers/ProviderTypes.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"ProviderTypes.d.ts","sourceRoot":"","sources":["../../src/providers/ProviderTypes.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,13 @@
1
- import { type ToolCapability, type ToolContext, type ToolDefinition, type ToolDescriptor, type ToolExecutionResult } from "./ToolTypes.js";
1
+ import { type ToolCapability, type ToolContext, type ToolDefinition, type ToolDescriptor, type ToolExecutionResult, type ToolSchemaDefinition } from "./ToolTypes.js";
2
2
  /**
3
3
  * Projects a registered tool into its model-facing descriptor. Kept as a free
4
4
  * function so connector adapters can reuse the same defaulting rules.
5
5
  */
6
6
  export declare const toolDescriptorFor: (tool: ToolDefinition) => ToolDescriptor;
7
+ export declare const sanitizeToolArguments: (value: unknown, schema: ToolSchemaDefinition | undefined) => {
8
+ value: unknown;
9
+ dropped: string[];
10
+ };
7
11
  export declare class ToolRegistry {
8
12
  private tools;
9
13
  register(tool: ToolDefinition): void;
@@ -1 +1 @@
1
- {"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/tools/ToolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EAGnB,KAAK,mBAAmB,EAGzB,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,cAAc,KAAG,cAOvD,CAAC;AA4QH,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAElD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOpC,IAAI,IAAI,cAAc,EAAE;IAIxB,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAQ/E;;;;OAIG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,EAAE;IAOpD,2EAA2E;IAC3E,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAaxE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAkC/F"}
1
+ {"version":3,"file":"ToolRegistry.d.ts","sourceRoot":"","sources":["../../src/tools/ToolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,cAAc,EACnB,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,cAAc,EAGnB,KAAK,mBAAmB,EACxB,KAAK,oBAAoB,EAE1B,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,GAAI,MAAM,cAAc,KAAG,cAOvD,CAAC;AA4HH,eAAO,MAAM,qBAAqB,GAChC,OAAO,OAAO,EACd,QAAQ,oBAAoB,GAAG,SAAS,KACvC;IAAE,KAAK,EAAE,OAAO,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAwBrC,CAAC;AAyLF,qBAAa,YAAY;IACvB,OAAO,CAAC,KAAK,CAAqC;IAElD,QAAQ,CAAC,IAAI,EAAE,cAAc,GAAG,IAAI;IAOpC,IAAI,IAAI,cAAc,EAAE;IAIxB,QAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,cAAc,EAAE,MAAM,GAAG,aAAa,GAAG,aAAa,CAAC,CAAC;IAQ/E;;;;OAIG;IACH,OAAO,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,cAAc,EAAE;IAOpD,2EAA2E;IAC3E,YAAY,CAAC,KAAK,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,GAAG,CAAC,cAAc,EAAE,cAAc,EAAE,CAAC;IAaxE,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,mBAAmB,CAAC;CAwC/F"}
@@ -79,6 +79,78 @@ const validateSchema = (schema, path = "$") => {
79
79
  }
80
80
  return undefined;
81
81
  };
82
+ /**
83
+ * Repairs arguments that are nearly right before validating them.
84
+ *
85
+ * A worker gets one batch of tool calls, so a rejected call is not retried — it
86
+ * takes the whole sub-task down. Measured against the live suite, small models
87
+ * lost calls to two trivial mistakes: naming a field `depth` when the schema
88
+ * says `maxDepth`, and sending `"2"` where a number was wanted. Both were
89
+ * reported as `tool_invalid_args` and the question came back unanswered.
90
+ *
91
+ * Two repairs, both safe:
92
+ *
93
+ * - **Unknown properties are dropped.** The handler would ignore them anyway;
94
+ * failing instead only converts a usable call into no call at all. The tool
95
+ * still runs with its documented defaults, which beats returning nothing.
96
+ * - **Scalar strings are coerced** to the declared type when they parse
97
+ * exactly. `"2"` becomes `2`; `"two"` stays a string and is still rejected.
98
+ *
99
+ * Nothing here weakens validation: a missing required argument, or a value that
100
+ * cannot be coerced, fails exactly as before.
101
+ */
102
+ const coerceScalar = (value, schema) => {
103
+ if (typeof value !== "string")
104
+ return value;
105
+ const types = readSchemaTypes(schema);
106
+ if (!types || types.some((type) => type === "string"))
107
+ return value;
108
+ const trimmed = value.trim();
109
+ if (types.includes("number") || types.includes("integer")) {
110
+ const parsed = Number(trimmed);
111
+ if (trimmed !== "" && Number.isFinite(parsed)) {
112
+ if (types.includes("integer") && !Number.isInteger(parsed))
113
+ return value;
114
+ return parsed;
115
+ }
116
+ }
117
+ if (types.includes("boolean")) {
118
+ if (trimmed.toLowerCase() === "true")
119
+ return true;
120
+ if (trimmed.toLowerCase() === "false")
121
+ return false;
122
+ }
123
+ return value;
124
+ };
125
+ export const sanitizeToolArguments = (value, schema) => {
126
+ const dropped = [];
127
+ const walk = (input, node, path) => {
128
+ if (!node)
129
+ return input;
130
+ if (Array.isArray(input)) {
131
+ return node.items ? input.map((entry, index) => walk(entry, node.items, `${path}[${index}]`)) : input;
132
+ }
133
+ if (!isObject(input))
134
+ return coerceScalar(input, node);
135
+ const properties = node.properties;
136
+ if (!properties)
137
+ return input;
138
+ const output = {};
139
+ for (const [key, entry] of Object.entries(input)) {
140
+ const propertySchema = properties[key];
141
+ if (!propertySchema) {
142
+ if (node.additionalProperties === true)
143
+ output[key] = entry;
144
+ else
145
+ dropped.push(path ? `${path}.${key}` : key);
146
+ continue;
147
+ }
148
+ output[key] = walk(entry, propertySchema, path ? `${path}.${key}` : key);
149
+ }
150
+ return output;
151
+ };
152
+ return { value: walk(value, schema, ""), dropped };
153
+ };
82
154
  const runtimeTypeOf = (value) => {
83
155
  if (value === null)
84
156
  return "null";
@@ -315,12 +387,17 @@ export class ToolRegistry {
315
387
  if (schemaError) {
316
388
  return { ok: false, output: "", error: schemaError };
317
389
  }
318
- const validationError = tool.inputSchema ? validateValue(args, tool.inputSchema) : undefined;
390
+ const sanitized = tool.inputSchema
391
+ ? sanitizeToolArguments(args, tool.inputSchema)
392
+ : { value: args, dropped: [] };
393
+ const validationError = tool.inputSchema
394
+ ? validateValue(sanitized.value, tool.inputSchema)
395
+ : undefined;
319
396
  if (validationError) {
320
397
  return { ok: false, output: "", error: validationError };
321
398
  }
322
399
  try {
323
- const result = await tool.handler(args, context);
400
+ const result = await tool.handler(sanitized.value, context);
324
401
  return { ok: true, output: result.output, data: result.data };
325
402
  }
326
403
  catch (error) {
@@ -1,5 +1,18 @@
1
1
  import type { ToolDefinition } from "../ToolTypes.js";
2
2
  import type { DocdexClient } from "../../docdex/DocdexClient.js";
3
+ /**
4
+ * Rewrites a path into the repo-relative form docdex accepts.
5
+ *
6
+ * Docdex answers `invalid path` for a leading slash, a `./` prefix, or an
7
+ * absolute path, and a model asked to list a repository reaches for exactly
8
+ * those. That took out every "which files are in X" question: the tool was
9
+ * chosen correctly and then rejected on a formatting detail. Normalising here
10
+ * is the adapter's job — the caller meant the same directory either way.
11
+ *
12
+ * Returns undefined for "the whole repository", which is what docdex wants when
13
+ * no path is given.
14
+ */
15
+ export declare const toRepoRelativePath: (value: string | undefined, workspaceRoot?: string) => string | undefined;
3
16
  /**
4
17
  * Judges whether search results actually answer the question.
5
18
  *
@@ -1 +1 @@
1
- {"version":3,"file":"DocdexTools.d.ts","sourceRoot":"","sources":["../../../src/tools/docdex/DocdexTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAsFjE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvB,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,YAAY,EACpB,UAAS,iBAAsB,KAC9B,cAAc,EAAgE,CAAC"}
1
+ {"version":3,"file":"DocdexTools.d.ts","sourceRoot":"","sources":["../../../src/tools/docdex/DocdexTools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AACtD,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,8BAA8B,CAAC;AAuFjE;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,kBAAkB,GAC7B,OAAO,MAAM,GAAG,SAAS,EACzB,gBAAgB,MAAM,KACrB,MAAM,GAAG,SAWX,CAAC;AAoHF;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;CAClB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;AAEvB,MAAM,WAAW,iBAAiB;IAChC,cAAc,CAAC,EAAE,cAAc,CAAC;CACjC;AAED,eAAO,MAAM,iBAAiB,GAC5B,QAAQ,YAAY,EACpB,UAAS,iBAAsB,KAC9B,cAAc,EAAgE,CAAC"}