@mcoda/mswarm 0.1.60 → 0.1.61
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/codali-executor.d.ts +12 -0
- package/dist/codali-executor.d.ts.map +1 -1
- package/dist/codali-executor.js +18 -2
- package/dist/codali-executor.js.map +1 -1
- package/dist/runtime.d.ts +10 -0
- package/dist/runtime.d.ts.map +1 -1
- package/dist/runtime.js +87 -8
- package/dist/runtime.js.map +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +13 -2
- package/dist/server.js.map +1 -1
- package/dist/vendor/codali/docdex/DocdexClient.d.ts +45 -0
- package/dist/vendor/codali/docdex/DocdexClient.d.ts.map +1 -1
- package/dist/vendor/codali/docdex/DocdexClient.js +290 -29
- package/dist/vendor/codali/runtime/CodaliRuntime.d.ts +6 -0
- package/dist/vendor/codali/runtime/CodaliRuntime.d.ts.map +1 -1
- package/dist/vendor/codali/runtime/CodaliRuntime.js +73 -1
- package/dist/vendor/codali/tools/ToolRegistry.d.ts.map +1 -1
- package/dist/vendor/codali/tools/ToolRegistry.js +30 -0
- package/dist/vendor/codali/tools/ToolTypes.d.ts +1 -1
- package/dist/vendor/codali/tools/ToolTypes.d.ts.map +1 -1
- package/dist/vendor/codali/tools/ToolTypes.js +8 -0
- package/dist/vendor/codali/tools/docdex/DocdexTools.d.ts.map +1 -1
- package/dist/vendor/codali/tools/docdex/DocdexTools.js +37 -0
- package/package.json +3 -3
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { randomUUID } from "node:crypto";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
+
export class DocdexRuntimeError extends Error {
|
|
5
|
+
constructor(code, message, options = {}) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = code;
|
|
8
|
+
this.code = code;
|
|
9
|
+
this.status = options.status;
|
|
10
|
+
this.retryable = options.retryable ?? code === "docdex_unavailable";
|
|
11
|
+
this.details = options.details;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
const CAPABILITY_KEYS = [
|
|
5
15
|
"score_breakdown",
|
|
6
16
|
"rerank",
|
|
@@ -8,6 +18,93 @@ const CAPABILITY_KEYS = [
|
|
|
8
18
|
"retrieval_explanation",
|
|
9
19
|
"batch_search",
|
|
10
20
|
];
|
|
21
|
+
const DOCDEX_RUNTIME_ERROR_CODES = new Set([
|
|
22
|
+
"docdex_context_missing",
|
|
23
|
+
"docdex_api_key_missing",
|
|
24
|
+
"docdex_operation_not_allowed",
|
|
25
|
+
"docdex_auth_failed",
|
|
26
|
+
"docdex_repo_access_denied",
|
|
27
|
+
"docdex_unavailable",
|
|
28
|
+
]);
|
|
29
|
+
const DOCDEX_RUNTIME_OPERATIONS = new Set([
|
|
30
|
+
"health",
|
|
31
|
+
"initialize",
|
|
32
|
+
"search",
|
|
33
|
+
"snippet",
|
|
34
|
+
"open",
|
|
35
|
+
"symbols",
|
|
36
|
+
"ast",
|
|
37
|
+
"impact_graph",
|
|
38
|
+
"impact_diagnostics",
|
|
39
|
+
"dag_export",
|
|
40
|
+
"tree",
|
|
41
|
+
"memory_save",
|
|
42
|
+
"memory_recall",
|
|
43
|
+
"profile_read",
|
|
44
|
+
"profile_write",
|
|
45
|
+
"web_research",
|
|
46
|
+
"chat_context",
|
|
47
|
+
"rerank",
|
|
48
|
+
"batch_search",
|
|
49
|
+
"capabilities",
|
|
50
|
+
"stats",
|
|
51
|
+
"files",
|
|
52
|
+
"repo_inspect",
|
|
53
|
+
"index_rebuild",
|
|
54
|
+
"index_ingest",
|
|
55
|
+
"delegate",
|
|
56
|
+
"hooks_validate",
|
|
57
|
+
]);
|
|
58
|
+
const MCP_OPERATION_BY_METHOD = {
|
|
59
|
+
docdex_symbols: "symbols",
|
|
60
|
+
docdex_ast: "ast",
|
|
61
|
+
docdex_stats: "stats",
|
|
62
|
+
docdex_files: "files",
|
|
63
|
+
docdex_repo_inspect: "repo_inspect",
|
|
64
|
+
docdex_memory_save: "memory_save",
|
|
65
|
+
docdex_memory_recall: "memory_recall",
|
|
66
|
+
docdex_tree: "tree",
|
|
67
|
+
docdex_open: "open",
|
|
68
|
+
docdex_get_profile: "profile_read",
|
|
69
|
+
docdex_save_preference: "profile_write",
|
|
70
|
+
docdex_web_research: "web_research",
|
|
71
|
+
docdex_rerank: "rerank",
|
|
72
|
+
docdex_batch_search: "batch_search",
|
|
73
|
+
docdex_capabilities: "capabilities",
|
|
74
|
+
};
|
|
75
|
+
export const isDocdexRuntimeErrorCode = (value) => {
|
|
76
|
+
return typeof value === "string" && DOCDEX_RUNTIME_ERROR_CODES.has(value);
|
|
77
|
+
};
|
|
78
|
+
export const normalizeDocdexRuntimeOperation = (value) => {
|
|
79
|
+
const normalized = value.trim().replace(/[.-]/g, "_").toLowerCase();
|
|
80
|
+
const aliases = {
|
|
81
|
+
impact: "impact_graph",
|
|
82
|
+
diagnostics: "impact_diagnostics",
|
|
83
|
+
impact_diagnostics: "impact_diagnostics",
|
|
84
|
+
web: "web_research",
|
|
85
|
+
web_search: "web_research",
|
|
86
|
+
chat: "chat_context",
|
|
87
|
+
chat_completions: "chat_context",
|
|
88
|
+
context_chat: "chat_context",
|
|
89
|
+
open_file: "open",
|
|
90
|
+
snippet_fetch: "snippet",
|
|
91
|
+
profile: "profile_read",
|
|
92
|
+
get_profile: "profile_read",
|
|
93
|
+
save_preference: "profile_write",
|
|
94
|
+
memory: "memory_recall",
|
|
95
|
+
index: "index_rebuild",
|
|
96
|
+
hooks: "hooks_validate",
|
|
97
|
+
};
|
|
98
|
+
const aliased = aliases[normalized];
|
|
99
|
+
if (aliased)
|
|
100
|
+
return aliased;
|
|
101
|
+
return DOCDEX_RUNTIME_OPERATIONS.has(normalized)
|
|
102
|
+
? normalized
|
|
103
|
+
: undefined;
|
|
104
|
+
};
|
|
105
|
+
const escapeRegExp = (value) => {
|
|
106
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
107
|
+
};
|
|
11
108
|
export class DocdexClient {
|
|
12
109
|
constructor(options) {
|
|
13
110
|
this.options = options;
|
|
@@ -34,14 +131,80 @@ export class DocdexClient {
|
|
|
34
131
|
clearCapabilityCache() {
|
|
35
132
|
this.capabilitySnapshot = undefined;
|
|
36
133
|
}
|
|
134
|
+
runtimeAllowedOperations() {
|
|
135
|
+
if (!this.options.allowedOperations?.length)
|
|
136
|
+
return undefined;
|
|
137
|
+
const operations = this.options.allowedOperations
|
|
138
|
+
.map((entry) => normalizeDocdexRuntimeOperation(entry))
|
|
139
|
+
.filter((entry) => Boolean(entry));
|
|
140
|
+
return operations.length ? new Set(operations) : new Set();
|
|
141
|
+
}
|
|
142
|
+
runtimeCapability(operation) {
|
|
143
|
+
if (!this.options.capabilities)
|
|
144
|
+
return undefined;
|
|
145
|
+
for (const [key, value] of Object.entries(this.options.capabilities)) {
|
|
146
|
+
const normalized = normalizeDocdexRuntimeOperation(key);
|
|
147
|
+
if (normalized === operation && typeof value === "boolean") {
|
|
148
|
+
return value;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
return undefined;
|
|
152
|
+
}
|
|
153
|
+
redactSensitiveText(text) {
|
|
154
|
+
let output = text;
|
|
155
|
+
for (const secret of [this.options.apiKey, this.options.authToken]) {
|
|
156
|
+
if (typeof secret === "string" && secret.length >= 4) {
|
|
157
|
+
output = output.replace(new RegExp(escapeRegExp(secret), "g"), "[redacted]");
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
output = output.replace(/("(?:x-api-key|authorization|api[_-]?key|token|secret)"\s*:\s*")[^"]+(")/gi, "$1[redacted]$2");
|
|
161
|
+
output = output.replace(/((?:x-api-key|authorization|api[_-]?key|token|secret)\s*[:=]\s*)(?:Bearer\s+)?[^\s,;}]+/gi, "$1[redacted]");
|
|
162
|
+
return output;
|
|
163
|
+
}
|
|
164
|
+
runtimeError(code, message, options = {}) {
|
|
165
|
+
return new DocdexRuntimeError(code, this.redactSensitiveText(message), options);
|
|
166
|
+
}
|
|
167
|
+
assertRuntimeContext(operation) {
|
|
168
|
+
const credentialSource = this.options.credentialSource;
|
|
169
|
+
const requiresAttachedKey = credentialSource === "attached_mswarm_api_key";
|
|
170
|
+
if (requiresAttachedKey && (!this.options.apiKey || this.options.apiKey.trim().length === 0)) {
|
|
171
|
+
throw this.runtimeError("docdex_api_key_missing", "Docdex attached mswarm API key is required but was not provided.", { retryable: false, details: { operation, credential_source: credentialSource } });
|
|
172
|
+
}
|
|
173
|
+
if (this.options.required && this.resolveBaseUrl().length === 0) {
|
|
174
|
+
throw this.runtimeError("docdex_context_missing", "Docdex base_url is required for this job.", {
|
|
175
|
+
retryable: false,
|
|
176
|
+
details: { operation },
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
if (this.options.required && requiresAttachedKey && !this.repoId) {
|
|
180
|
+
throw this.runtimeError("docdex_context_missing", "Docdex repo_id is required for this job.", {
|
|
181
|
+
retryable: false,
|
|
182
|
+
details: { operation },
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
assertOperationAllowed(operation) {
|
|
187
|
+
this.assertRuntimeContext(operation);
|
|
188
|
+
const allowedOperations = this.runtimeAllowedOperations();
|
|
189
|
+
if (allowedOperations && !allowedOperations.has(operation)) {
|
|
190
|
+
throw this.runtimeError("docdex_operation_not_allowed", `Docdex operation is not allowed by this job: ${operation}`, { retryable: false, details: { operation } });
|
|
191
|
+
}
|
|
192
|
+
if (this.runtimeCapability(operation) === false) {
|
|
193
|
+
throw this.runtimeError("docdex_operation_not_allowed", `Docdex operation is disabled by this job capability map: ${operation}`, { retryable: false, details: { operation } });
|
|
194
|
+
}
|
|
195
|
+
}
|
|
37
196
|
resolveBaseUrl() {
|
|
38
197
|
const base = this.options.baseUrl.trim();
|
|
39
198
|
return base.endsWith("/") ? base.slice(0, -1) : base;
|
|
40
199
|
}
|
|
41
200
|
buildHeaders(dagSessionId) {
|
|
42
201
|
const headers = { "content-type": "application/json" };
|
|
43
|
-
if (this.options.
|
|
202
|
+
if (this.options.apiKey) {
|
|
203
|
+
headers["x-api-key"] = this.options.apiKey;
|
|
204
|
+
}
|
|
205
|
+
else if (this.options.authToken) {
|
|
44
206
|
headers.authorization = `Bearer ${this.options.authToken}`;
|
|
207
|
+
}
|
|
45
208
|
if (this.repoId)
|
|
46
209
|
headers["x-docdex-repo-id"] = this.repoId;
|
|
47
210
|
if (this.options.repoRoot)
|
|
@@ -54,17 +217,37 @@ export class DocdexClient {
|
|
|
54
217
|
async ensureHealth() {
|
|
55
218
|
if (this.healthChecked)
|
|
56
219
|
return;
|
|
57
|
-
|
|
220
|
+
let ok = false;
|
|
221
|
+
try {
|
|
222
|
+
ok = await this.healthCheck();
|
|
223
|
+
}
|
|
224
|
+
catch (error) {
|
|
225
|
+
if (error instanceof DocdexRuntimeError)
|
|
226
|
+
throw error;
|
|
227
|
+
throw this.runtimeError("docdex_unavailable", `Docdex health check failed: ${error instanceof Error ? error.message : String(error)}`, { retryable: true });
|
|
228
|
+
}
|
|
58
229
|
if (!ok) {
|
|
59
|
-
throw
|
|
230
|
+
throw this.runtimeError("docdex_unavailable", "Docdex health check failed", {
|
|
231
|
+
retryable: true,
|
|
232
|
+
});
|
|
60
233
|
}
|
|
61
234
|
}
|
|
62
235
|
async healthCheck() {
|
|
63
|
-
|
|
236
|
+
let response;
|
|
237
|
+
try {
|
|
238
|
+
response = await fetch(`${this.resolveBaseUrl()}/healthz`);
|
|
239
|
+
}
|
|
240
|
+
catch (error) {
|
|
241
|
+
throw this.runtimeError("docdex_unavailable", `Docdex health check failed: ${error instanceof Error ? error.message : String(error)}`, { retryable: true });
|
|
242
|
+
}
|
|
64
243
|
this.healthChecked = response.ok;
|
|
65
244
|
return response.ok;
|
|
66
245
|
}
|
|
67
246
|
async initialize(rootUri) {
|
|
247
|
+
this.assertOperationAllowed("initialize");
|
|
248
|
+
return this.initializeRepo(rootUri);
|
|
249
|
+
}
|
|
250
|
+
async initializeRepo(rootUri) {
|
|
68
251
|
await this.ensureHealth();
|
|
69
252
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/initialize`, {
|
|
70
253
|
method: "POST",
|
|
@@ -72,8 +255,7 @@ export class DocdexClient {
|
|
|
72
255
|
body: JSON.stringify({ rootUri }),
|
|
73
256
|
});
|
|
74
257
|
if (!response.ok) {
|
|
75
|
-
|
|
76
|
-
throw new Error(`Docdex initialize failed (${response.status}): ${body}`);
|
|
258
|
+
await this.throwResponseError(response, "initialize");
|
|
77
259
|
}
|
|
78
260
|
const payload = (await response.json());
|
|
79
261
|
const repoId = (payload.repo_id ?? payload.repoId ?? payload.repo);
|
|
@@ -87,7 +269,7 @@ export class DocdexClient {
|
|
|
87
269
|
return;
|
|
88
270
|
this.repoInitializeAttempted = true;
|
|
89
271
|
try {
|
|
90
|
-
await this.
|
|
272
|
+
await this.initializeRepo(pathToFileURL(path.resolve(this.options.repoRoot)).toString());
|
|
91
273
|
}
|
|
92
274
|
catch {
|
|
93
275
|
// Keep endpoint-specific calls responsible for reporting the final failure.
|
|
@@ -100,7 +282,47 @@ export class DocdexClient {
|
|
|
100
282
|
if (this.options.repoRoot)
|
|
101
283
|
params.set("repo_root", path.resolve(this.options.repoRoot));
|
|
102
284
|
}
|
|
285
|
+
extractErrorCode(body) {
|
|
286
|
+
const parsed = this.tryParseJson(body);
|
|
287
|
+
if (!parsed || typeof parsed !== "object")
|
|
288
|
+
return undefined;
|
|
289
|
+
const record = parsed;
|
|
290
|
+
const error = record.error && typeof record.error === "object"
|
|
291
|
+
? record.error
|
|
292
|
+
: undefined;
|
|
293
|
+
const code = error?.code ?? record.code;
|
|
294
|
+
return typeof code === "string" ? code : undefined;
|
|
295
|
+
}
|
|
296
|
+
mapResponseErrorCode(status, body) {
|
|
297
|
+
const extracted = this.extractErrorCode(body);
|
|
298
|
+
if (isDocdexRuntimeErrorCode(extracted))
|
|
299
|
+
return extracted;
|
|
300
|
+
const normalized = `${extracted ?? ""} ${body}`.toLowerCase();
|
|
301
|
+
if (/introspection_unavailable|unavailable|timeout|timed out|econnrefused|enotfound/.test(normalized)) {
|
|
302
|
+
return "docdex_unavailable";
|
|
303
|
+
}
|
|
304
|
+
if (/repo_access_denied|unknown_repo|repo.*denied|denied.*repo/.test(normalized)) {
|
|
305
|
+
return "docdex_repo_access_denied";
|
|
306
|
+
}
|
|
307
|
+
if (/scope_denied|operation_not_allowed|encrypted_operation_disabled|not allowed|forbidden_operation/.test(normalized)) {
|
|
308
|
+
return "docdex_operation_not_allowed";
|
|
309
|
+
}
|
|
310
|
+
if (status === 401 || status === 403 || /invalid_credentials|missing_credentials|ambiguous_credentials/.test(normalized)) {
|
|
311
|
+
return "docdex_auth_failed";
|
|
312
|
+
}
|
|
313
|
+
return "docdex_unavailable";
|
|
314
|
+
}
|
|
315
|
+
async throwResponseError(response, operation) {
|
|
316
|
+
const body = await response.text();
|
|
317
|
+
const code = this.mapResponseErrorCode(response.status, body);
|
|
318
|
+
throw this.runtimeError(code, `Docdex ${operation} failed (${response.status}): ${body}`, {
|
|
319
|
+
status: response.status,
|
|
320
|
+
retryable: code === "docdex_unavailable" && response.status >= 500,
|
|
321
|
+
details: { operation },
|
|
322
|
+
});
|
|
323
|
+
}
|
|
103
324
|
async search(query, options = {}) {
|
|
325
|
+
this.assertOperationAllowed("search");
|
|
104
326
|
await this.ensureHealth();
|
|
105
327
|
await this.ensureRepoInitialized();
|
|
106
328
|
const params = new URLSearchParams({ q: query });
|
|
@@ -114,12 +336,12 @@ export class DocdexClient {
|
|
|
114
336
|
headers: this.buildHeaders(dagSessionId),
|
|
115
337
|
});
|
|
116
338
|
if (!response.ok) {
|
|
117
|
-
|
|
118
|
-
throw new Error(`Docdex search failed (${response.status}): ${body}`);
|
|
339
|
+
await this.throwResponseError(response, "search");
|
|
119
340
|
}
|
|
120
341
|
return response.json();
|
|
121
342
|
}
|
|
122
343
|
async openSnippet(docId, options = {}) {
|
|
344
|
+
this.assertOperationAllowed("snippet");
|
|
123
345
|
await this.ensureHealth();
|
|
124
346
|
await this.ensureRepoInitialized();
|
|
125
347
|
const params = new URLSearchParams();
|
|
@@ -132,8 +354,7 @@ export class DocdexClient {
|
|
|
132
354
|
headers: this.buildHeaders(),
|
|
133
355
|
});
|
|
134
356
|
if (!response.ok) {
|
|
135
|
-
|
|
136
|
-
throw new Error(`Docdex snippet failed (${response.status}): ${body}`);
|
|
357
|
+
await this.throwResponseError(response, "snippet");
|
|
137
358
|
}
|
|
138
359
|
const contentType = response.headers.get("content-type") ?? "";
|
|
139
360
|
if (contentType.includes("application/json")) {
|
|
@@ -142,6 +363,7 @@ export class DocdexClient {
|
|
|
142
363
|
return response.text();
|
|
143
364
|
}
|
|
144
365
|
async impactGraph(file, options = {}) {
|
|
366
|
+
this.assertOperationAllowed("impact_graph");
|
|
145
367
|
await this.ensureHealth();
|
|
146
368
|
await this.ensureRepoInitialized();
|
|
147
369
|
const params = new URLSearchParams({ file });
|
|
@@ -156,12 +378,12 @@ export class DocdexClient {
|
|
|
156
378
|
headers: this.buildHeaders(),
|
|
157
379
|
});
|
|
158
380
|
if (!response.ok) {
|
|
159
|
-
|
|
160
|
-
throw new Error(`Docdex impact graph failed (${response.status}): ${body}`);
|
|
381
|
+
await this.throwResponseError(response, "impact graph");
|
|
161
382
|
}
|
|
162
383
|
return response.json();
|
|
163
384
|
}
|
|
164
385
|
async impactDiagnostics(options = {}) {
|
|
386
|
+
this.assertOperationAllowed("impact_diagnostics");
|
|
165
387
|
await this.ensureHealth();
|
|
166
388
|
await this.ensureRepoInitialized();
|
|
167
389
|
const params = new URLSearchParams();
|
|
@@ -176,12 +398,12 @@ export class DocdexClient {
|
|
|
176
398
|
headers: this.buildHeaders(),
|
|
177
399
|
});
|
|
178
400
|
if (!response.ok) {
|
|
179
|
-
|
|
180
|
-
throw new Error(`Docdex impact diagnostics failed (${response.status}): ${body}`);
|
|
401
|
+
await this.throwResponseError(response, "impact diagnostics");
|
|
181
402
|
}
|
|
182
403
|
return response.json();
|
|
183
404
|
}
|
|
184
405
|
async indexRebuild(libsSources) {
|
|
406
|
+
this.assertOperationAllowed("index_rebuild");
|
|
185
407
|
await this.ensureHealth();
|
|
186
408
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/index/rebuild`, {
|
|
187
409
|
method: "POST",
|
|
@@ -189,12 +411,12 @@ export class DocdexClient {
|
|
|
189
411
|
body: JSON.stringify(libsSources ? { libs_sources: libsSources } : {}),
|
|
190
412
|
});
|
|
191
413
|
if (!response.ok) {
|
|
192
|
-
|
|
193
|
-
throw new Error(`Docdex index rebuild failed (${response.status}): ${body}`);
|
|
414
|
+
await this.throwResponseError(response, "index rebuild");
|
|
194
415
|
}
|
|
195
416
|
return response.json();
|
|
196
417
|
}
|
|
197
418
|
async indexIngest(file) {
|
|
419
|
+
this.assertOperationAllowed("index_ingest");
|
|
198
420
|
await this.ensureHealth();
|
|
199
421
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/index/ingest`, {
|
|
200
422
|
method: "POST",
|
|
@@ -202,12 +424,12 @@ export class DocdexClient {
|
|
|
202
424
|
body: JSON.stringify({ file }),
|
|
203
425
|
});
|
|
204
426
|
if (!response.ok) {
|
|
205
|
-
|
|
206
|
-
throw new Error(`Docdex index ingest failed (${response.status}): ${body}`);
|
|
427
|
+
await this.throwResponseError(response, "index ingest");
|
|
207
428
|
}
|
|
208
429
|
return response.json();
|
|
209
430
|
}
|
|
210
431
|
async hooksValidate(files) {
|
|
432
|
+
this.assertOperationAllowed("hooks_validate");
|
|
211
433
|
await this.ensureHealth();
|
|
212
434
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/hooks/validate`, {
|
|
213
435
|
method: "POST",
|
|
@@ -215,12 +437,12 @@ export class DocdexClient {
|
|
|
215
437
|
body: JSON.stringify({ files }),
|
|
216
438
|
});
|
|
217
439
|
if (!response.ok) {
|
|
218
|
-
|
|
219
|
-
throw new Error(`Docdex hooks validate failed (${response.status}): ${body}`);
|
|
440
|
+
await this.throwResponseError(response, "hooks validate");
|
|
220
441
|
}
|
|
221
442
|
return response.json();
|
|
222
443
|
}
|
|
223
444
|
async delegate(payload) {
|
|
445
|
+
this.assertOperationAllowed("delegate");
|
|
224
446
|
await this.ensureHealth();
|
|
225
447
|
const response = await fetch(`${this.resolveBaseUrl()}/v1/delegate`, {
|
|
226
448
|
method: "POST",
|
|
@@ -228,12 +450,38 @@ export class DocdexClient {
|
|
|
228
450
|
body: JSON.stringify(payload),
|
|
229
451
|
});
|
|
230
452
|
if (!response.ok) {
|
|
231
|
-
|
|
232
|
-
|
|
453
|
+
await this.throwResponseError(response, "delegate");
|
|
454
|
+
}
|
|
455
|
+
return response.json();
|
|
456
|
+
}
|
|
457
|
+
async chatContext(messages, options = {}) {
|
|
458
|
+
this.assertOperationAllowed("chat_context");
|
|
459
|
+
await this.ensureHealth();
|
|
460
|
+
await this.ensureRepoInitialized();
|
|
461
|
+
const body = {
|
|
462
|
+
messages,
|
|
463
|
+
stream: false,
|
|
464
|
+
};
|
|
465
|
+
if (options.model)
|
|
466
|
+
body.model = options.model;
|
|
467
|
+
if (options.maxTokens !== undefined)
|
|
468
|
+
body.max_tokens = options.maxTokens;
|
|
469
|
+
if (options.temperature !== undefined)
|
|
470
|
+
body.temperature = options.temperature;
|
|
471
|
+
if (options.docdex)
|
|
472
|
+
body.docdex = options.docdex;
|
|
473
|
+
const response = await fetch(`${this.resolveBaseUrl()}/v1/chat/completions`, {
|
|
474
|
+
method: "POST",
|
|
475
|
+
headers: this.buildHeaders(this.dagSessionId),
|
|
476
|
+
body: JSON.stringify(body),
|
|
477
|
+
});
|
|
478
|
+
if (!response.ok) {
|
|
479
|
+
await this.throwResponseError(response, "chat context");
|
|
233
480
|
}
|
|
234
481
|
return response.json();
|
|
235
482
|
}
|
|
236
483
|
async dagExport(sessionId, options = {}) {
|
|
484
|
+
this.assertOperationAllowed("dag_export");
|
|
237
485
|
await this.ensureHealth();
|
|
238
486
|
await this.ensureRepoInitialized();
|
|
239
487
|
const params = new URLSearchParams({ session_id: sessionId });
|
|
@@ -247,7 +495,12 @@ export class DocdexClient {
|
|
|
247
495
|
});
|
|
248
496
|
const body = await response.text();
|
|
249
497
|
if (!response.ok) {
|
|
250
|
-
|
|
498
|
+
const code = this.mapResponseErrorCode(response.status, body);
|
|
499
|
+
throw this.runtimeError(code, `Docdex dag export failed (${response.status}): ${body}`, {
|
|
500
|
+
status: response.status,
|
|
501
|
+
retryable: code === "docdex_unavailable" && response.status >= 500,
|
|
502
|
+
details: { operation: "dag_export" },
|
|
503
|
+
});
|
|
251
504
|
}
|
|
252
505
|
const contentType = response.headers.get("content-type") ?? "";
|
|
253
506
|
if (contentType.includes("application/json")) {
|
|
@@ -261,6 +514,10 @@ export class DocdexClient {
|
|
|
261
514
|
return body;
|
|
262
515
|
}
|
|
263
516
|
async callMcp(method, params) {
|
|
517
|
+
const operation = MCP_OPERATION_BY_METHOD[method];
|
|
518
|
+
if (operation) {
|
|
519
|
+
this.assertOperationAllowed(operation);
|
|
520
|
+
}
|
|
264
521
|
await this.ensureHealth();
|
|
265
522
|
const payload = {
|
|
266
523
|
jsonrpc: "2.0",
|
|
@@ -274,12 +531,16 @@ export class DocdexClient {
|
|
|
274
531
|
body: JSON.stringify(payload),
|
|
275
532
|
});
|
|
276
533
|
if (!response.ok) {
|
|
277
|
-
|
|
278
|
-
throw new Error(`Docdex MCP failed (${response.status}): ${body}`);
|
|
534
|
+
await this.throwResponseError(response, "MCP");
|
|
279
535
|
}
|
|
280
536
|
const raw = (await response.json());
|
|
281
537
|
if (raw.error) {
|
|
282
|
-
|
|
538
|
+
const body = JSON.stringify(raw.error);
|
|
539
|
+
const code = this.mapResponseErrorCode(500, body);
|
|
540
|
+
throw this.runtimeError(code, raw.error.message ?? "Docdex MCP error", {
|
|
541
|
+
retryable: code === "docdex_unavailable",
|
|
542
|
+
details: { method },
|
|
543
|
+
});
|
|
283
544
|
}
|
|
284
545
|
return this.normalizeMcpResult(raw.result);
|
|
285
546
|
}
|
|
@@ -451,6 +712,7 @@ export class DocdexClient {
|
|
|
451
712
|
})).catch(() => this.webResearchHttp(query, options));
|
|
452
713
|
}
|
|
453
714
|
async webResearchHttp(query, options = {}) {
|
|
715
|
+
this.assertOperationAllowed("web_research");
|
|
454
716
|
await this.ensureHealth();
|
|
455
717
|
await this.ensureRepoInitialized();
|
|
456
718
|
const params = new URLSearchParams({ q: query });
|
|
@@ -469,8 +731,7 @@ export class DocdexClient {
|
|
|
469
731
|
headers: this.buildHeaders(this.dagSessionId),
|
|
470
732
|
});
|
|
471
733
|
if (!response.ok) {
|
|
472
|
-
|
|
473
|
-
throw new Error(`Docdex web research failed (${response.status}): ${body}`);
|
|
734
|
+
await this.throwResponseError(response, "web research");
|
|
474
735
|
}
|
|
475
736
|
return response.json();
|
|
476
737
|
}
|
|
@@ -14,10 +14,16 @@ export interface CodaliRuntimeProviderInput {
|
|
|
14
14
|
timeoutMs?: number;
|
|
15
15
|
}
|
|
16
16
|
export interface CodaliRuntimeDocdexInput {
|
|
17
|
+
enabled?: boolean;
|
|
17
18
|
baseUrl?: string;
|
|
18
19
|
repoRoot?: string;
|
|
19
20
|
repoId?: string;
|
|
20
21
|
dagSessionId?: string;
|
|
22
|
+
apiKey?: string;
|
|
23
|
+
credentialSource?: "attached_mswarm_api_key" | string;
|
|
24
|
+
required?: boolean;
|
|
25
|
+
allowedOperations?: string[];
|
|
26
|
+
capabilities?: Record<string, boolean | undefined>;
|
|
21
27
|
initialize?: boolean;
|
|
22
28
|
allowWeb?: boolean;
|
|
23
29
|
allowMemoryWrite?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CodaliRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/CodaliRuntime.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,gBAAgB,EAChB,QAAQ,EAER,eAAe,EAEf,aAAa,EACd,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"CodaliRuntime.d.ts","sourceRoot":"","sources":["../../src/runtime/CodaliRuntime.ts"],"names":[],"mappings":"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"}
|
|
@@ -4,7 +4,7 @@ import { createProvider } from "../providers/ProviderRegistry.js";
|
|
|
4
4
|
import { OpenAiCompatibleProvider } from "../providers/OpenAiCompatibleProvider.js";
|
|
5
5
|
import { OllamaRemoteProvider } from "../providers/OllamaRemoteProvider.js";
|
|
6
6
|
import { CodexCliProvider } from "../providers/CodexCliProvider.js";
|
|
7
|
-
import { DocdexClient } from "../docdex/DocdexClient.js";
|
|
7
|
+
import { DocdexClient, normalizeDocdexRuntimeOperation, } from "../docdex/DocdexClient.js";
|
|
8
8
|
import { createDiffTool } from "../tools/diff/DiffTool.js";
|
|
9
9
|
import { createDocdexTools } from "../tools/docdex/DocdexTools.js";
|
|
10
10
|
import { createFileTools } from "../tools/filesystem/FileTools.js";
|
|
@@ -29,6 +29,35 @@ const WEB_TOOL_NAMES = new Set(["docdex_web_research"]);
|
|
|
29
29
|
const MEMORY_WRITE_TOOL_NAMES = new Set(["docdex_memory_save"]);
|
|
30
30
|
const PROFILE_WRITE_TOOL_NAMES = new Set(["docdex_save_preference"]);
|
|
31
31
|
const INDEX_REBUILD_TOOL_NAMES = new Set(["docdex_index_rebuild", "docdex_index_ingest"]);
|
|
32
|
+
const DOCDEX_TOOL_OPERATIONS = new Map([
|
|
33
|
+
["docdex_health", ["health"]],
|
|
34
|
+
["docdex_initialize", ["initialize"]],
|
|
35
|
+
["docdex_search", ["search"]],
|
|
36
|
+
["docdex_open", ["open", "snippet"]],
|
|
37
|
+
["docdex_open_file", ["open"]],
|
|
38
|
+
["docdex_symbols", ["symbols"]],
|
|
39
|
+
["docdex_ast", ["ast"]],
|
|
40
|
+
["docdex_impact_graph", ["impact_graph"]],
|
|
41
|
+
["docdex_impact_diagnostics", ["impact_diagnostics"]],
|
|
42
|
+
["docdex_dag_export", ["dag_export"]],
|
|
43
|
+
["docdex_tree", ["tree"]],
|
|
44
|
+
["docdex_memory_save", ["memory_save"]],
|
|
45
|
+
["docdex_memory_recall", ["memory_recall"]],
|
|
46
|
+
["docdex_get_profile", ["profile_read"]],
|
|
47
|
+
["docdex_save_preference", ["profile_write"]],
|
|
48
|
+
["docdex_web_research", ["web_research"]],
|
|
49
|
+
["docdex_chat_context", ["chat_context"]],
|
|
50
|
+
["docdex_rerank", ["rerank"]],
|
|
51
|
+
["docdex_batch_search", ["batch_search"]],
|
|
52
|
+
["docdex_capabilities", ["capabilities"]],
|
|
53
|
+
["docdex_stats", ["stats"]],
|
|
54
|
+
["docdex_files", ["files"]],
|
|
55
|
+
["docdex_repo_inspect", ["repo_inspect"]],
|
|
56
|
+
["docdex_index_rebuild", ["index_rebuild"]],
|
|
57
|
+
["docdex_index_ingest", ["index_ingest"]],
|
|
58
|
+
["docdex_delegate", ["delegate"]],
|
|
59
|
+
["docdex_hooks_validate", ["hooks_validate"]],
|
|
60
|
+
]);
|
|
32
61
|
const RUNTIME_TO_PROTOCOL_NEEDS = new Map([
|
|
33
62
|
["docdex_search", ["docdex.search"]],
|
|
34
63
|
["docdex_open", ["docdex.open", "docdex.snippet"]],
|
|
@@ -36,6 +65,7 @@ const RUNTIME_TO_PROTOCOL_NEEDS = new Map([
|
|
|
36
65
|
["docdex_symbols", ["docdex.symbols"]],
|
|
37
66
|
["docdex_ast", ["docdex.ast"]],
|
|
38
67
|
["docdex_web_research", ["docdex.web"]],
|
|
68
|
+
["docdex_chat_context", ["docdex.chat_context"]],
|
|
39
69
|
["docdex_impact_graph", ["docdex.impact"]],
|
|
40
70
|
["docdex_impact_diagnostics", ["docdex.impact_diagnostics"]],
|
|
41
71
|
["docdex_tree", ["docdex.tree"]],
|
|
@@ -51,6 +81,7 @@ const PROTOCOL_TO_RUNTIME_TOOL_NAMES = new Map([
|
|
|
51
81
|
["docdex.symbols", ["docdex_symbols"]],
|
|
52
82
|
["docdex.ast", ["docdex_ast"]],
|
|
53
83
|
["docdex.web", ["docdex_web_research"]],
|
|
84
|
+
["docdex.chat_context", ["docdex_chat_context"]],
|
|
54
85
|
["docdex.impact", ["docdex_impact_graph"]],
|
|
55
86
|
["docdex.impact_diagnostics", ["docdex_impact_diagnostics"]],
|
|
56
87
|
["docdex.tree", ["docdex_tree"]],
|
|
@@ -516,10 +547,43 @@ const isRuntimeToolAllowed = (toolName, policy) => {
|
|
|
516
547
|
}
|
|
517
548
|
return true;
|
|
518
549
|
};
|
|
550
|
+
const allowedDocdexOperations = (docdex) => {
|
|
551
|
+
if (!docdex?.allowedOperations?.length)
|
|
552
|
+
return undefined;
|
|
553
|
+
const operations = docdex.allowedOperations
|
|
554
|
+
.map((entry) => normalizeDocdexRuntimeOperation(entry))
|
|
555
|
+
.filter((entry) => Boolean(entry));
|
|
556
|
+
return operations.length ? new Set(operations) : new Set();
|
|
557
|
+
};
|
|
558
|
+
const docdexCapabilityAllows = (docdex, operation) => {
|
|
559
|
+
if (!docdex?.capabilities)
|
|
560
|
+
return true;
|
|
561
|
+
for (const [key, value] of Object.entries(docdex.capabilities)) {
|
|
562
|
+
if (normalizeDocdexRuntimeOperation(key) === operation && value === false) {
|
|
563
|
+
return false;
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
return true;
|
|
567
|
+
};
|
|
568
|
+
const isDocdexRuntimeOperationAllowed = (toolName, docdex) => {
|
|
569
|
+
const operations = DOCDEX_TOOL_OPERATIONS.get(toolName);
|
|
570
|
+
if (!operations?.length)
|
|
571
|
+
return true;
|
|
572
|
+
const allowedOperations = allowedDocdexOperations(docdex);
|
|
573
|
+
return operations.some((operation) => {
|
|
574
|
+
if (allowedOperations && !allowedOperations.has(operation)) {
|
|
575
|
+
return false;
|
|
576
|
+
}
|
|
577
|
+
return docdexCapabilityAllows(docdex, operation);
|
|
578
|
+
});
|
|
579
|
+
};
|
|
519
580
|
const isDocdexToolAllowed = (toolName, docdex) => {
|
|
520
581
|
if (!toolName.startsWith("docdex_")) {
|
|
521
582
|
return true;
|
|
522
583
|
}
|
|
584
|
+
if (docdex?.enabled === false) {
|
|
585
|
+
return false;
|
|
586
|
+
}
|
|
523
587
|
if (docdex?.allowWeb === false && WEB_TOOL_NAMES.has(toolName)) {
|
|
524
588
|
return false;
|
|
525
589
|
}
|
|
@@ -532,6 +596,9 @@ const isDocdexToolAllowed = (toolName, docdex) => {
|
|
|
532
596
|
if (docdex?.allowIndexRebuild === false && INDEX_REBUILD_TOOL_NAMES.has(toolName)) {
|
|
533
597
|
return false;
|
|
534
598
|
}
|
|
599
|
+
if (!isDocdexRuntimeOperationAllowed(toolName, docdex)) {
|
|
600
|
+
return false;
|
|
601
|
+
}
|
|
535
602
|
return true;
|
|
536
603
|
};
|
|
537
604
|
const registerRuntimeTool = (registry, tool, policy, docdex) => {
|
|
@@ -563,6 +630,11 @@ const buildRuntimeToolRegistry = (input) => {
|
|
|
563
630
|
repoId: input.docdex?.repoId,
|
|
564
631
|
repoRoot: input.docdex?.repoRoot ?? input.workspace.root,
|
|
565
632
|
dagSessionId: input.docdex?.dagSessionId ?? input.metadata?.requestId,
|
|
633
|
+
apiKey: input.docdex?.apiKey,
|
|
634
|
+
credentialSource: input.docdex?.credentialSource,
|
|
635
|
+
required: input.docdex?.required,
|
|
636
|
+
allowedOperations: input.docdex?.allowedOperations,
|
|
637
|
+
capabilities: input.docdex?.capabilities,
|
|
566
638
|
});
|
|
567
639
|
for (const tool of createDocdexTools(docdexClient))
|
|
568
640
|
register(tool);
|