@mcoda/codali 0.1.108 → 0.1.110
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/dist/agents/AgentInventory.d.ts +56 -0
- package/dist/agents/AgentInventory.d.ts.map +1 -0
- package/dist/agents/AgentInventory.js +131 -0
- package/dist/agents/RoleResolution.d.ts +49 -0
- package/dist/agents/RoleResolution.d.ts.map +1 -0
- package/dist/agents/RoleResolution.js +166 -0
- package/dist/api/ChatCompletionsAdapter.d.ts +76 -0
- package/dist/api/ChatCompletionsAdapter.d.ts.map +1 -0
- package/dist/api/ChatCompletionsAdapter.js +54 -0
- package/dist/api/CodaliApi.d.ts +78 -0
- package/dist/api/CodaliApi.d.ts.map +1 -0
- package/dist/api/CodaliApi.js +273 -0
- package/dist/api/CodaliServer.d.ts +42 -0
- package/dist/api/CodaliServer.d.ts.map +1 -0
- package/dist/api/CodaliServer.js +118 -0
- package/dist/cli/AskCommand.d.ts +66 -0
- package/dist/cli/AskCommand.d.ts.map +1 -0
- package/dist/cli/AskCommand.js +536 -0
- package/dist/cli/AuthCommand.d.ts +19 -0
- package/dist/cli/AuthCommand.d.ts.map +1 -0
- package/dist/cli/AuthCommand.js +161 -0
- package/dist/cli/ServeCommand.d.ts +5 -0
- package/dist/cli/ServeCommand.d.ts.map +1 -0
- package/dist/cli/ServeCommand.js +87 -0
- package/dist/cli/ToolsCommand.d.ts +22 -0
- package/dist/cli/ToolsCommand.d.ts.map +1 -0
- package/dist/cli/ToolsCommand.js +208 -0
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +29 -1
- package/dist/connectors/http/HttpToolDefinition.d.ts +74 -0
- package/dist/connectors/http/HttpToolDefinition.d.ts.map +1 -0
- package/dist/connectors/http/HttpToolDefinition.js +190 -0
- package/dist/connectors/http/HttpToolSource.d.ts +18 -0
- package/dist/connectors/http/HttpToolSource.d.ts.map +1 -0
- package/dist/connectors/http/HttpToolSource.js +29 -0
- package/dist/connectors/mcp/McpClient.d.ts +132 -0
- package/dist/connectors/mcp/McpClient.d.ts.map +1 -0
- package/dist/connectors/mcp/McpClient.js +215 -0
- package/dist/connectors/mcp/McpServerRegistry.d.ts +75 -0
- package/dist/connectors/mcp/McpServerRegistry.d.ts.map +1 -0
- package/dist/connectors/mcp/McpServerRegistry.js +180 -0
- package/dist/connectors/mcp/McpToolAdapter.d.ts +48 -0
- package/dist/connectors/mcp/McpToolAdapter.d.ts.map +1 -0
- package/dist/connectors/mcp/McpToolAdapter.js +101 -0
- package/dist/connectors/mcp/McpToolSource.d.ts +27 -0
- package/dist/connectors/mcp/McpToolSource.d.ts.map +1 -0
- package/dist/connectors/mcp/McpToolSource.js +33 -0
- package/dist/connectors/media/ImageGenerationTool.d.ts +43 -0
- package/dist/connectors/media/ImageGenerationTool.d.ts.map +1 -0
- package/dist/connectors/media/ImageGenerationTool.js +122 -0
- package/dist/connectors/oauth/DeviceCodeAuth.d.ts +74 -0
- package/dist/connectors/oauth/DeviceCodeAuth.d.ts.map +1 -0
- package/dist/connectors/oauth/DeviceCodeAuth.js +153 -0
- package/dist/docdex/DocdexClient.d.ts +2 -0
- package/dist/docdex/DocdexClient.d.ts.map +1 -1
- package/dist/docdex/DocdexClient.js +4 -0
- package/dist/gateway/CodaliGateway.d.ts +51 -3
- package/dist/gateway/CodaliGateway.d.ts.map +1 -1
- package/dist/gateway/CodaliGateway.js +241 -3
- package/dist/gateway/CodaliGatewayTypes.d.ts +34 -0
- package/dist/gateway/CodaliGatewayTypes.d.ts.map +1 -1
- package/dist/gateway/EvidenceNormalizer.d.ts.map +1 -1
- package/dist/gateway/EvidenceNormalizer.js +98 -1
- package/dist/gateway/Finalizer.d.ts +50 -0
- package/dist/gateway/Finalizer.d.ts.map +1 -0
- package/dist/gateway/Finalizer.js +79 -0
- package/dist/gateway/GatewayPlanner.d.ts +13 -0
- package/dist/gateway/GatewayPlanner.d.ts.map +1 -1
- package/dist/gateway/GatewayPlanner.js +81 -16
- package/dist/gateway/GatewayStateMachine.d.ts.map +1 -1
- package/dist/gateway/GatewayStateMachine.js +6 -0
- package/dist/gateway/GatewayTracer.d.ts +93 -0
- package/dist/gateway/GatewayTracer.d.ts.map +1 -0
- package/dist/gateway/GatewayTracer.js +214 -0
- package/dist/gateway/LocalGatewayProvider.d.ts +59 -0
- package/dist/gateway/LocalGatewayProvider.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayProvider.js +195 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts +79 -0
- package/dist/gateway/LocalGatewayTaskRunner.d.ts.map +1 -0
- package/dist/gateway/LocalGatewayTaskRunner.js +361 -0
- package/dist/gateway/RelevanceJudge.d.ts +25 -0
- package/dist/gateway/RelevanceJudge.d.ts.map +1 -0
- package/dist/gateway/RelevanceJudge.js +124 -0
- package/dist/gateway/ResponseSchema.d.ts +32 -0
- package/dist/gateway/ResponseSchema.d.ts.map +1 -0
- package/dist/gateway/ResponseSchema.js +120 -0
- package/dist/gateway/TemporalContext.d.ts +36 -0
- package/dist/gateway/TemporalContext.d.ts.map +1 -0
- package/dist/gateway/TemporalContext.js +115 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts +5 -0
- package/dist/gateway/ToolCapabilityCompiler.d.ts.map +1 -1
- package/dist/gateway/ToolCapabilityCompiler.js +27 -2
- package/dist/gateway/ToolDescriptorSource.d.ts +6 -0
- package/dist/gateway/ToolDescriptorSource.d.ts.map +1 -0
- package/dist/gateway/ToolDescriptorSource.js +30 -0
- package/dist/gateway/ToolExposure.d.ts +36 -0
- package/dist/gateway/ToolExposure.d.ts.map +1 -0
- package/dist/gateway/ToolExposure.js +154 -0
- package/dist/index.d.ts +57 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +45 -0
- package/dist/providers/ClaudeCliProvider.d.ts +2 -0
- package/dist/providers/ClaudeCliProvider.d.ts.map +1 -1
- package/dist/providers/ClaudeCliProvider.js +2 -0
- package/dist/providers/CodexCliProvider.d.ts +2 -0
- package/dist/providers/CodexCliProvider.d.ts.map +1 -1
- package/dist/providers/CodexCliProvider.js +2 -0
- package/dist/providers/MswarmWorkerProvider.d.ts +2 -0
- package/dist/providers/MswarmWorkerProvider.d.ts.map +1 -1
- package/dist/providers/MswarmWorkerProvider.js +2 -0
- package/dist/providers/OllamaRemoteProvider.d.ts +2 -0
- package/dist/providers/OllamaRemoteProvider.d.ts.map +1 -1
- package/dist/providers/OllamaRemoteProvider.js +2 -0
- package/dist/providers/OpenAiCompatibleProvider.d.ts +2 -0
- package/dist/providers/OpenAiCompatibleProvider.d.ts.map +1 -1
- package/dist/providers/OpenAiCompatibleProvider.js +2 -0
- package/dist/providers/ProviderTypes.d.ts +13 -0
- package/dist/providers/ProviderTypes.d.ts.map +1 -1
- package/dist/providers/ProviderTypes.js +1 -1
- package/dist/runcontext/CredentialFile.d.ts +12 -0
- package/dist/runcontext/CredentialFile.d.ts.map +1 -0
- package/dist/runcontext/CredentialFile.js +81 -0
- package/dist/runcontext/RunContextResolver.d.ts +126 -0
- package/dist/runcontext/RunContextResolver.d.ts.map +1 -0
- package/dist/runcontext/RunContextResolver.js +389 -0
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts +1 -1
- package/dist/storage/CodaliDatasetPrivacyEngine.d.ts.map +1 -1
- package/dist/storage/CodaliDatasetPrivacyEngine.js +12 -0
- package/dist/tools/ToolRegistry.d.ts +14 -1
- package/dist/tools/ToolRegistry.d.ts.map +1 -1
- package/dist/tools/ToolRegistry.js +38 -1
- package/dist/tools/ToolTypes.d.ts +35 -0
- package/dist/tools/ToolTypes.d.ts.map +1 -1
- package/dist/tools/ToolTypes.js +21 -0
- package/dist/tools/TruncateResult.d.ts +29 -0
- package/dist/tools/TruncateResult.d.ts.map +1 -0
- package/dist/tools/TruncateResult.js +91 -0
- package/dist/tools/diff/DiffTool.d.ts.map +1 -1
- package/dist/tools/diff/DiffTool.js +2 -0
- package/dist/tools/docdex/DocdexTools.d.ts +21 -1
- package/dist/tools/docdex/DocdexTools.d.ts.map +1 -1
- package/dist/tools/docdex/DocdexTools.js +151 -17
- package/dist/tools/filesystem/FileTools.d.ts.map +1 -1
- package/dist/tools/filesystem/FileTools.js +8 -0
- package/dist/tools/search/SearchTool.d.ts.map +1 -1
- package/dist/tools/search/SearchTool.js +3 -1
- package/dist/tools/shell/ShellTool.d.ts.map +1 -1
- package/dist/tools/shell/ShellTool.js +2 -0
- package/package.json +4 -3
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fitting a tool result into a budget without destroying it.
|
|
3
|
+
*
|
|
4
|
+
* Cutting a serialized payload at a character count leaves the model invalid
|
|
5
|
+
* JSON ending mid-token. Observed with `list_commits`: 12,063 characters cut at
|
|
6
|
+
* 12,000, so the model received a broken document and reported "I can only see
|
|
7
|
+
* one commit" — accurate about what survived, useless as an answer.
|
|
8
|
+
*
|
|
9
|
+
* Most oversized results are a list of similar things. Keeping whole items and
|
|
10
|
+
* saying how many were dropped preserves both validity and the fact that more
|
|
11
|
+
* exists, which is what the model needs to be honest about coverage.
|
|
12
|
+
*/
|
|
13
|
+
const NOTICE = (detail) => `\n\n[TRUNCATED: ${detail}. This result is INCOMPLETE — say so explicitly and do not present it as the full set.]`;
|
|
14
|
+
/**
|
|
15
|
+
* Finds the largest array in a payload — the part worth trimming. A connector
|
|
16
|
+
* usually wraps its list in an envelope (`{ value: [...] }`, `{ issues: [...] }`),
|
|
17
|
+
* so the array is rarely at the root.
|
|
18
|
+
*/
|
|
19
|
+
const findLargestArray = (value, depth = 0) => {
|
|
20
|
+
if (depth > 4)
|
|
21
|
+
return undefined;
|
|
22
|
+
if (Array.isArray(value))
|
|
23
|
+
return { parent: undefined, items: value };
|
|
24
|
+
if (!value || typeof value !== "object")
|
|
25
|
+
return undefined;
|
|
26
|
+
let best;
|
|
27
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
28
|
+
if (Array.isArray(entry)) {
|
|
29
|
+
if (!best || entry.length > best.items.length) {
|
|
30
|
+
best = { parent: value, key, items: entry };
|
|
31
|
+
}
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
const nested = findLargestArray(entry, depth + 1);
|
|
35
|
+
if (nested?.parent && (!best || nested.items.length > best.items.length)) {
|
|
36
|
+
best = { parent: nested.parent, key: nested.key, items: nested.items };
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
return best;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Trims a tool result to `limit` characters.
|
|
43
|
+
*
|
|
44
|
+
* When the payload holds a list, drops whole items from the end until it fits,
|
|
45
|
+
* so the result stays parseable. Otherwise falls back to a character cut, which
|
|
46
|
+
* is still better than silence for prose.
|
|
47
|
+
*/
|
|
48
|
+
export const truncateToolResult = (raw, serialized, limit) => {
|
|
49
|
+
if (serialized.length <= limit) {
|
|
50
|
+
return { text: serialized, truncated: false };
|
|
51
|
+
}
|
|
52
|
+
const found = findLargestArray(raw);
|
|
53
|
+
if (found && found.items.length > 1) {
|
|
54
|
+
const total = found.items.length;
|
|
55
|
+
// Binary search the largest prefix that fits, rather than dropping one at a
|
|
56
|
+
// time — a 500-item result would otherwise re-serialize 500 times.
|
|
57
|
+
let low = 1;
|
|
58
|
+
let high = total;
|
|
59
|
+
let bestFit = 1;
|
|
60
|
+
let bestText = "";
|
|
61
|
+
while (low <= high) {
|
|
62
|
+
const mid = Math.floor((low + high) / 2);
|
|
63
|
+
const kept = found.items.slice(0, mid);
|
|
64
|
+
const candidate = found.parent
|
|
65
|
+
? { ...found.parent, [found.key]: kept }
|
|
66
|
+
: kept;
|
|
67
|
+
const text = JSON.stringify(candidate, null, 2);
|
|
68
|
+
if (text.length <= limit) {
|
|
69
|
+
bestFit = mid;
|
|
70
|
+
bestText = text;
|
|
71
|
+
low = mid + 1;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
high = mid - 1;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (bestText) {
|
|
78
|
+
const dropped = total - bestFit;
|
|
79
|
+
return {
|
|
80
|
+
text: `${bestText}${NOTICE(`showing ${bestFit} of ${total} items; ${dropped} omitted`)}`,
|
|
81
|
+
truncated: true,
|
|
82
|
+
keptItems: bestFit,
|
|
83
|
+
droppedItems: dropped,
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
text: `${serialized.slice(0, limit)}${NOTICE(`${serialized.length - limit} more characters were cut`)}`,
|
|
89
|
+
truncated: true,
|
|
90
|
+
};
|
|
91
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"DiffTool.d.ts","sourceRoot":"","sources":["../../../src/tools/diff/DiffTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAanE,eAAO,MAAM,cAAc,QAAO,
|
|
1
|
+
{"version":3,"file":"DiffTool.d.ts","sourceRoot":"","sources":["../../../src/tools/diff/DiffTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAanE,eAAO,MAAM,cAAc,QAAO,cAwBhC,CAAC"}
|
|
@@ -12,6 +12,8 @@ const runGitStatus = (cwd) => {
|
|
|
12
12
|
export const createDiffTool = () => ({
|
|
13
13
|
name: "diff_summary",
|
|
14
14
|
description: "Show a git status summary of workspace changes.",
|
|
15
|
+
readOnly: true,
|
|
16
|
+
capability: "workspace",
|
|
15
17
|
inputSchema: {
|
|
16
18
|
type: "object",
|
|
17
19
|
properties: {
|
|
@@ -1,4 +1,24 @@
|
|
|
1
1
|
import type { ToolDefinition } from "../ToolTypes.js";
|
|
2
2
|
import type { DocdexClient } from "../../docdex/DocdexClient.js";
|
|
3
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Judges whether search results actually answer the question.
|
|
5
|
+
*
|
|
6
|
+
* Needed because presence is not relevance. The local index returns *something*
|
|
7
|
+
* for almost any query — "GDP of France 2025" scores 29.07 against this
|
|
8
|
+
* repository, higher than "gateway planner class" at 14.35, because a test
|
|
9
|
+
* fixture happens to contain the phrase. A score threshold would therefore be
|
|
10
|
+
* both arbitrary and wrong, and keyword rules ("if the query mentions GDP, go
|
|
11
|
+
* to the web") are exactly the hardcoding this project rules out.
|
|
12
|
+
*
|
|
13
|
+
* So the judgement is delegated to a model: cheap, generic, and it degrades to
|
|
14
|
+
* the old presence-based behaviour when no judge is supplied.
|
|
15
|
+
*/
|
|
16
|
+
export type RelevanceJudge = (input: {
|
|
17
|
+
query: string;
|
|
18
|
+
results: unknown;
|
|
19
|
+
}) => Promise<boolean>;
|
|
20
|
+
export interface DocdexToolOptions {
|
|
21
|
+
judgeRelevance?: RelevanceJudge;
|
|
22
|
+
}
|
|
23
|
+
export declare const createDocdexTools: (client: DocdexClient, options?: DocdexToolOptions) => ToolDefinition[];
|
|
4
24
|
//# sourceMappingURL=DocdexTools.d.ts.map
|
|
@@ -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;
|
|
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"}
|
|
@@ -2,7 +2,85 @@ const toOutput = (payload) => ({
|
|
|
2
2
|
output: typeof payload === "string" ? payload : JSON.stringify(payload, null, 2),
|
|
3
3
|
data: payload,
|
|
4
4
|
});
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
* Docdex tools that mutate state (index, memory, profile, repo binding). Every
|
|
7
|
+
* other docdex tool is read-only. Listed as the exception set so a newly added
|
|
8
|
+
* read tool is safe by default and a newly added write tool must be declared.
|
|
9
|
+
*/
|
|
10
|
+
const DOCDEX_WRITE_TOOLS = new Set([
|
|
11
|
+
"docdex_initialize",
|
|
12
|
+
"docdex_index_rebuild",
|
|
13
|
+
"docdex_index_ingest",
|
|
14
|
+
"docdex_memory_save",
|
|
15
|
+
"docdex_save_preference",
|
|
16
|
+
"docdex_delegate",
|
|
17
|
+
]);
|
|
18
|
+
/**
|
|
19
|
+
* Docdex is one capability from the orchestrator's point of view, except web
|
|
20
|
+
* research, which is a distinct capability ("current external information")
|
|
21
|
+
* even though docdex happens to serve it.
|
|
22
|
+
*/
|
|
23
|
+
const docdexCapabilityFor = (name) => name === "docdex_web_research" ? "web" : "docdex";
|
|
24
|
+
const isRecord = (value) => Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
25
|
+
/**
|
|
26
|
+
* Whether a docdex search payload actually returned anything usable. Docdex
|
|
27
|
+
* answers with `hits: []` rather than an error when the index has no match, so
|
|
28
|
+
* an empty result is a normal outcome that the waterfall must recognize.
|
|
29
|
+
*/
|
|
30
|
+
const hasSearchHits = (payload) => {
|
|
31
|
+
if (!isRecord(payload))
|
|
32
|
+
return false;
|
|
33
|
+
for (const key of ["hits", "results", "matches"]) {
|
|
34
|
+
const value = payload[key];
|
|
35
|
+
if (Array.isArray(value) && value.length > 0)
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
return false;
|
|
39
|
+
};
|
|
40
|
+
/**
|
|
41
|
+
* Whether a forced-web search actually discovered anything.
|
|
42
|
+
*
|
|
43
|
+
* Docdex reports web findings under `webDiscovery.discovery.results` and leaves
|
|
44
|
+
* `hits` empty until the fetched pages are indexed, so judging a web result by
|
|
45
|
+
* `hits` alone throws away everything it just found.
|
|
46
|
+
*/
|
|
47
|
+
const hasWebFindings = (payload) => {
|
|
48
|
+
if (hasSearchHits(payload))
|
|
49
|
+
return true;
|
|
50
|
+
if (!isRecord(payload))
|
|
51
|
+
return false;
|
|
52
|
+
const discovery = isRecord(payload.webDiscovery) ? payload.webDiscovery : undefined;
|
|
53
|
+
if (!discovery)
|
|
54
|
+
return false;
|
|
55
|
+
const inner = isRecord(discovery.discovery) ? discovery.discovery : undefined;
|
|
56
|
+
const results = inner?.results ?? discovery.results;
|
|
57
|
+
if (Array.isArray(results) && results.length > 0)
|
|
58
|
+
return true;
|
|
59
|
+
const fetches = discovery.fetches;
|
|
60
|
+
return Array.isArray(fetches) && fetches.length > 0;
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Whether a web-research payload carries anything quotable. Docdex answers a
|
|
64
|
+
* cache hit with discovery metadata only, which reads as success but gives a
|
|
65
|
+
* model nothing to cite.
|
|
66
|
+
*/
|
|
67
|
+
const hasWebContent = (payload) => {
|
|
68
|
+
if (!isRecord(payload))
|
|
69
|
+
return false;
|
|
70
|
+
for (const key of ["web_context", "webContext", "hits", "results"]) {
|
|
71
|
+
const value = payload[key];
|
|
72
|
+
if (Array.isArray(value) && value.length > 0)
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
};
|
|
77
|
+
const withDocdexMetadata = (tools) => tools.map((tool) => ({
|
|
78
|
+
...tool,
|
|
79
|
+
readOnly: tool.readOnly ?? !DOCDEX_WRITE_TOOLS.has(tool.name),
|
|
80
|
+
capability: tool.capability ?? docdexCapabilityFor(tool.name),
|
|
81
|
+
}));
|
|
82
|
+
export const createDocdexTools = (client, options = {}) => withDocdexMetadata(docdexToolDefinitions(client, options));
|
|
83
|
+
const docdexToolDefinitions = (client, options) => [
|
|
6
84
|
{
|
|
7
85
|
name: "docdex_health",
|
|
8
86
|
description: "Check docdex healthz endpoint.",
|
|
@@ -30,7 +108,12 @@ export const createDocdexTools = (client) => [
|
|
|
30
108
|
},
|
|
31
109
|
{
|
|
32
110
|
name: "docdex_search",
|
|
33
|
-
description: "Search
|
|
111
|
+
description: "Search the indexed repository and organizational memory for code, docs, and prior decisions. " +
|
|
112
|
+
"Searches locally first and falls back to the web when the local index has nothing relevant, " +
|
|
113
|
+
"so this is the default tool for both repo questions and general external questions. " +
|
|
114
|
+
"Returns file paths, doc ids, and a snippet from the START of each file — usually imports, " +
|
|
115
|
+
"not the part that answers the question. To explain what something does, follow up with " +
|
|
116
|
+
"docdex_symbols for its signature or docdex_open for the relevant lines.",
|
|
34
117
|
inputSchema: {
|
|
35
118
|
type: "object",
|
|
36
119
|
required: ["query"],
|
|
@@ -41,13 +124,42 @@ export const createDocdexTools = (client) => [
|
|
|
41
124
|
},
|
|
42
125
|
handler: async (args) => {
|
|
43
126
|
const { query, limit } = args;
|
|
44
|
-
const
|
|
45
|
-
|
|
127
|
+
const local = await client.search(query, { limit });
|
|
128
|
+
// The local-then-web waterfall lives here, inside the search tool, rather
|
|
129
|
+
// than in the orchestrator. The orchestrator should only have to know
|
|
130
|
+
// "search"; whether an answer comes from the repository index or the
|
|
131
|
+
// public web is an implementation detail of searching. Putting this
|
|
132
|
+
// decision in the router would make it special-case logic that every new
|
|
133
|
+
// question type has to be taught.
|
|
134
|
+
let localAnswers = hasSearchHits(local);
|
|
135
|
+
// Hits alone do not mean the question was answered. Ask a model whether
|
|
136
|
+
// they are actually relevant before settling for them.
|
|
137
|
+
if (localAnswers && options.judgeRelevance) {
|
|
138
|
+
try {
|
|
139
|
+
localAnswers = await options.judgeRelevance({ query, results: local });
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
// A judge that fails must not block a search that already succeeded.
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
if (!localAnswers) {
|
|
146
|
+
try {
|
|
147
|
+
const web = await client.search(query, { limit, forceWeb: true });
|
|
148
|
+
if (hasWebFindings(web)) {
|
|
149
|
+
return toOutput(web);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
catch {
|
|
153
|
+
// Web discovery being unavailable must not fail a local search that
|
|
154
|
+
// simply found nothing. Return the local (empty) result instead.
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return toOutput(local);
|
|
46
158
|
},
|
|
47
159
|
},
|
|
48
160
|
{
|
|
49
161
|
name: "docdex_open",
|
|
50
|
-
description: "
|
|
162
|
+
description: "Read an exact slice of a file, either by repo-relative path or by a doc id returned from a search. Use after a search has identified a target rather than guessing paths.",
|
|
51
163
|
inputSchema: {
|
|
52
164
|
type: "object",
|
|
53
165
|
properties: {
|
|
@@ -76,7 +188,9 @@ export const createDocdexTools = (client) => [
|
|
|
76
188
|
},
|
|
77
189
|
{
|
|
78
190
|
name: "docdex_symbols",
|
|
79
|
-
description: "
|
|
191
|
+
description: "List the definitions in a file with their exact signatures and line numbers — functions, " +
|
|
192
|
+
"classes, methods, exported constants. Use after docdex_search to find out what a file " +
|
|
193
|
+
"actually contains, since search snippets only show the file's opening lines.",
|
|
80
194
|
inputSchema: {
|
|
81
195
|
type: "object",
|
|
82
196
|
required: ["path"],
|
|
@@ -92,7 +206,7 @@ export const createDocdexTools = (client) => [
|
|
|
92
206
|
},
|
|
93
207
|
{
|
|
94
208
|
name: "docdex_ast",
|
|
95
|
-
description: "
|
|
209
|
+
description: "Query a file's syntax tree for precise structure: class and function definitions, call sites, imports. More exact than text search when the question is structural.",
|
|
96
210
|
inputSchema: {
|
|
97
211
|
type: "object",
|
|
98
212
|
required: ["path"],
|
|
@@ -109,7 +223,7 @@ export const createDocdexTools = (client) => [
|
|
|
109
223
|
},
|
|
110
224
|
{
|
|
111
225
|
name: "docdex_impact_graph",
|
|
112
|
-
description: "
|
|
226
|
+
description: "Show what depends on a file and what it depends on. Answers \"what breaks if this changes\" and identifies the blast radius of an edit.",
|
|
113
227
|
inputSchema: {
|
|
114
228
|
type: "object",
|
|
115
229
|
required: ["file"],
|
|
@@ -128,7 +242,7 @@ export const createDocdexTools = (client) => [
|
|
|
128
242
|
},
|
|
129
243
|
{
|
|
130
244
|
name: "docdex_impact_diagnostics",
|
|
131
|
-
description: "
|
|
245
|
+
description: "List unresolved or dynamic imports that the dependency graph could not follow, so gaps in impact analysis are visible rather than silent.",
|
|
132
246
|
inputSchema: {
|
|
133
247
|
type: "object",
|
|
134
248
|
properties: {
|
|
@@ -163,7 +277,7 @@ export const createDocdexTools = (client) => [
|
|
|
163
277
|
},
|
|
164
278
|
{
|
|
165
279
|
name: "docdex_tree",
|
|
166
|
-
description: "Render
|
|
280
|
+
description: "Render the repository folder tree with build output and vendor directories excluded. Use to orient in an unfamiliar repo instead of listing directories manually.",
|
|
167
281
|
inputSchema: {
|
|
168
282
|
type: "object",
|
|
169
283
|
properties: {
|
|
@@ -218,7 +332,7 @@ export const createDocdexTools = (client) => [
|
|
|
218
332
|
},
|
|
219
333
|
{
|
|
220
334
|
name: "docdex_get_profile",
|
|
221
|
-
description: "
|
|
335
|
+
description: "Read stored global preferences and constraints that should shape the answer, such as style rules or disallowed libraries.",
|
|
222
336
|
inputSchema: {
|
|
223
337
|
type: "object",
|
|
224
338
|
properties: {
|
|
@@ -251,7 +365,7 @@ export const createDocdexTools = (client) => [
|
|
|
251
365
|
},
|
|
252
366
|
{
|
|
253
367
|
name: "docdex_memory_recall",
|
|
254
|
-
description: "Recall
|
|
368
|
+
description: "Recall durable facts previously recorded about this repository - architectural decisions, gotchas, where things live.",
|
|
255
369
|
inputSchema: {
|
|
256
370
|
type: "object",
|
|
257
371
|
required: ["query"],
|
|
@@ -268,7 +382,7 @@ export const createDocdexTools = (client) => [
|
|
|
268
382
|
},
|
|
269
383
|
{
|
|
270
384
|
name: "docdex_web_research",
|
|
271
|
-
description: "
|
|
385
|
+
description: "Search the public web for current external information: facts, news, third-party documentation, anything not in this repository. Returns sourced results with URLs.",
|
|
272
386
|
inputSchema: {
|
|
273
387
|
type: "object",
|
|
274
388
|
required: ["query"],
|
|
@@ -282,7 +396,27 @@ export const createDocdexTools = (client) => [
|
|
|
282
396
|
},
|
|
283
397
|
handler: async (args) => {
|
|
284
398
|
const { query, forceWeb, skipLocalSearch, webLimit, noCache } = args;
|
|
285
|
-
|
|
399
|
+
let result = await client.webResearch(query, { forceWeb, skipLocalSearch, webLimit, noCache });
|
|
400
|
+
// A cache hit returns discovery metadata with no page content at all —
|
|
401
|
+
// no web_context, no hits — so the run sees that a search happened and
|
|
402
|
+
// nothing it can quote. Retrying uncached fetches the pages the cache
|
|
403
|
+
// was standing in for.
|
|
404
|
+
if (!noCache && !hasWebContent(result)) {
|
|
405
|
+
try {
|
|
406
|
+
const fresh = await client.webResearch(query, {
|
|
407
|
+
forceWeb,
|
|
408
|
+
skipLocalSearch,
|
|
409
|
+
webLimit,
|
|
410
|
+
noCache: true,
|
|
411
|
+
});
|
|
412
|
+
if (hasWebContent(fresh)) {
|
|
413
|
+
result = fresh;
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
catch {
|
|
417
|
+
// Keep the cached response rather than failing a search that worked.
|
|
418
|
+
}
|
|
419
|
+
}
|
|
286
420
|
return toOutput(result);
|
|
287
421
|
},
|
|
288
422
|
},
|
|
@@ -343,7 +477,7 @@ export const createDocdexTools = (client) => [
|
|
|
343
477
|
},
|
|
344
478
|
{
|
|
345
479
|
name: "docdex_batch_search",
|
|
346
|
-
description: "Run
|
|
480
|
+
description: "Run several related search queries in one call. Use when a question decomposes into multiple independent lookups, to save round trips.",
|
|
347
481
|
inputSchema: {
|
|
348
482
|
type: "object",
|
|
349
483
|
required: ["queries"],
|
|
@@ -376,7 +510,7 @@ export const createDocdexTools = (client) => [
|
|
|
376
510
|
},
|
|
377
511
|
{
|
|
378
512
|
name: "docdex_stats",
|
|
379
|
-
description: "
|
|
513
|
+
description: "Report index size and when it was last updated. Use to detect a stale index before trusting a negative search result.",
|
|
380
514
|
inputSchema: { type: "object", properties: {} },
|
|
381
515
|
handler: async () => {
|
|
382
516
|
const result = await client.stats();
|
|
@@ -385,7 +519,7 @@ export const createDocdexTools = (client) => [
|
|
|
385
519
|
},
|
|
386
520
|
{
|
|
387
521
|
name: "docdex_files",
|
|
388
|
-
description: "List
|
|
522
|
+
description: "List the files currently present in the index, to confirm coverage before concluding that something does not exist.",
|
|
389
523
|
inputSchema: {
|
|
390
524
|
type: "object",
|
|
391
525
|
properties: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileTools.d.ts","sourceRoot":"","sources":["../../../src/tools/filesystem/FileTools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAgEnE,eAAO,MAAM,eAAe,QAAO,cAAc,
|
|
1
|
+
{"version":3,"file":"FileTools.d.ts","sourceRoot":"","sources":["../../../src/tools/filesystem/FileTools.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAgEnE,eAAO,MAAM,eAAe,QAAO,cAAc,EAgGhD,CAAC"}
|
|
@@ -55,6 +55,8 @@ export const createFileTools = () => {
|
|
|
55
55
|
{
|
|
56
56
|
name: "read_file",
|
|
57
57
|
description: "Read a text file from the workspace.",
|
|
58
|
+
readOnly: true,
|
|
59
|
+
capability: "workspace",
|
|
58
60
|
inputSchema: {
|
|
59
61
|
type: "object",
|
|
60
62
|
required: ["path"],
|
|
@@ -73,6 +75,8 @@ export const createFileTools = () => {
|
|
|
73
75
|
{
|
|
74
76
|
name: "write_file",
|
|
75
77
|
description: "Write content to a file inside the workspace.",
|
|
78
|
+
readOnly: false,
|
|
79
|
+
capability: "workspace",
|
|
76
80
|
inputSchema: {
|
|
77
81
|
type: "object",
|
|
78
82
|
required: ["path", "content"],
|
|
@@ -96,6 +100,8 @@ export const createFileTools = () => {
|
|
|
96
100
|
{
|
|
97
101
|
name: "list_files",
|
|
98
102
|
description: "List files under a directory within the workspace.",
|
|
103
|
+
readOnly: true,
|
|
104
|
+
capability: "workspace",
|
|
99
105
|
inputSchema: {
|
|
100
106
|
type: "object",
|
|
101
107
|
properties: {
|
|
@@ -115,6 +121,8 @@ export const createFileTools = () => {
|
|
|
115
121
|
{
|
|
116
122
|
name: "stat_path",
|
|
117
123
|
description: "Get stat info for a file or directory.",
|
|
124
|
+
readOnly: true,
|
|
125
|
+
capability: "workspace",
|
|
118
126
|
inputSchema: {
|
|
119
127
|
type: "object",
|
|
120
128
|
required: ["path"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchTool.d.ts","sourceRoot":"","sources":["../../../src/tools/search/SearchTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA0BnE,eAAO,MAAM,gBAAgB,QAAO,
|
|
1
|
+
{"version":3,"file":"SearchTool.d.ts","sourceRoot":"","sources":["../../../src/tools/search/SearchTool.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAe,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA0BnE,eAAO,MAAM,gBAAgB,QAAO,cA0BlC,CAAC"}
|
|
@@ -22,7 +22,9 @@ const runGrepFallback = (query, cwd) => {
|
|
|
22
22
|
};
|
|
23
23
|
export const createSearchTool = () => ({
|
|
24
24
|
name: "search_repo",
|
|
25
|
-
description: "Search for text in the
|
|
25
|
+
description: "Search for literal text in the working tree. Use when an exact string is known; prefer docdex_search for conceptual questions.",
|
|
26
|
+
readOnly: true,
|
|
27
|
+
capability: "workspace",
|
|
26
28
|
inputSchema: {
|
|
27
29
|
type: "object",
|
|
28
30
|
required: ["query"],
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ShellTool.d.ts","sourceRoot":"","sources":["../../../src/tools/shell/ShellTool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA2C5F,eAAO,MAAM,eAAe,QAAO,
|
|
1
|
+
{"version":3,"file":"ShellTool.d.ts","sourceRoot":"","sources":["../../../src/tools/shell/ShellTool.ts"],"names":[],"mappings":"AAEA,OAAO,EAAwC,KAAK,cAAc,EAAE,MAAM,iBAAiB,CAAC;AA2C5F,eAAO,MAAM,eAAe,QAAO,cA2EjC,CAAC"}
|
|
@@ -41,6 +41,8 @@ const isDestructiveShellAction = (command, args) => {
|
|
|
41
41
|
export const createShellTool = () => ({
|
|
42
42
|
name: "run_shell",
|
|
43
43
|
description: "Run a shell command from the workspace root (allowlist only).",
|
|
44
|
+
readOnly: false,
|
|
45
|
+
capability: "shell",
|
|
44
46
|
inputSchema: {
|
|
45
47
|
type: "object",
|
|
46
48
|
required: ["command"],
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mcoda/codali",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.110",
|
|
4
4
|
"description": "Standalone tool-runner adapter for mcoda.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -34,8 +34,9 @@
|
|
|
34
34
|
"access": "public"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@
|
|
38
|
-
"@mcoda/
|
|
37
|
+
"@modelcontextprotocol/sdk": "1.30.0",
|
|
38
|
+
"@mcoda/db": "0.1.110",
|
|
39
|
+
"@mcoda/shared": "0.1.110"
|
|
39
40
|
},
|
|
40
41
|
"scripts": {
|
|
41
42
|
"build": "tsc -p tsconfig.json",
|