sdl-mcp 0.11.13 → 0.12.0
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/README.md +1 -1
- package/config/sdlmcp.config.example.json +2 -2
- package/config/sdlmcp.config.schema.json +9 -5
- package/dist/.tsbuildinfo +1 -1
- package/dist/cli/commands/init.js +5 -5
- package/dist/cli/commands/tool-actions.d.ts.map +1 -1
- package/dist/cli/commands/tool-actions.js +28 -3
- package/dist/cli/commands/tool-actions.js.map +1 -1
- package/dist/code-mode/action-catalog.js +1 -1
- package/dist/code-mode/action-catalog.js.map +1 -1
- package/dist/code-mode/descriptions.d.ts.map +1 -1
- package/dist/code-mode/descriptions.js +1 -1
- package/dist/code-mode/descriptions.js.map +1 -1
- package/dist/code-mode/etag-cache.d.ts +9 -2
- package/dist/code-mode/etag-cache.d.ts.map +1 -1
- package/dist/code-mode/etag-cache.js +45 -2
- package/dist/code-mode/etag-cache.js.map +1 -1
- package/dist/code-mode/index.d.ts +8 -0
- package/dist/code-mode/index.d.ts.map +1 -1
- package/dist/code-mode/index.js +3 -1
- package/dist/code-mode/index.js.map +1 -1
- package/dist/code-mode/manual-generator.js +11 -11
- package/dist/code-mode/manual-generator.js.map +1 -1
- package/dist/code-mode/types.d.ts +6 -3
- package/dist/code-mode/types.d.ts.map +1 -1
- package/dist/code-mode/types.js +4 -2
- package/dist/code-mode/types.js.map +1 -1
- package/dist/code-mode/workflow-executor.d.ts.map +1 -1
- package/dist/code-mode/workflow-executor.js +33 -6
- package/dist/code-mode/workflow-executor.js.map +1 -1
- package/dist/code-mode/workflow-parser.d.ts +1 -1
- package/dist/code-mode/workflow-parser.d.ts.map +1 -1
- package/dist/code-mode/workflow-parser.js +13 -1
- package/dist/code-mode/workflow-parser.js.map +1 -1
- package/dist/config/types.d.ts +4 -4
- package/dist/config/types.d.ts.map +1 -1
- package/dist/config/types.js +5 -5
- package/dist/config/types.js.map +1 -1
- package/dist/indexer/summary-generator.d.ts +5 -0
- package/dist/indexer/summary-generator.d.ts.map +1 -1
- package/dist/indexer/summary-generator.js +240 -86
- package/dist/indexer/summary-generator.js.map +1 -1
- package/dist/indexer/symbol-embedding-text.d.ts +5 -10
- package/dist/indexer/symbol-embedding-text.d.ts.map +1 -1
- package/dist/indexer/symbol-embedding-text.js +200 -0
- package/dist/indexer/symbol-embedding-text.js.map +1 -1
- package/dist/mcp/context-response-projection.d.ts +0 -10
- package/dist/mcp/context-response-projection.d.ts.map +1 -1
- package/dist/mcp/context-response-projection.js +554 -35
- package/dist/mcp/context-response-projection.js.map +1 -1
- package/dist/mcp/response-compression.d.ts +3 -0
- package/dist/mcp/response-compression.d.ts.map +1 -1
- package/dist/mcp/response-compression.js +21 -14
- package/dist/mcp/response-compression.js.map +1 -1
- package/dist/mcp/server-instructions.js +7 -7
- package/dist/mcp/server-instructions.js.map +1 -1
- package/dist/mcp/token-usage.d.ts +5 -0
- package/dist/mcp/token-usage.d.ts.map +1 -1
- package/dist/mcp/token-usage.js +17 -0
- package/dist/mcp/token-usage.js.map +1 -1
- package/dist/mcp/tool-call-formatter.d.ts.map +1 -1
- package/dist/mcp/tool-call-formatter.js +4 -6
- package/dist/mcp/tool-call-formatter.js.map +1 -1
- package/dist/mcp/tools/repo.d.ts.map +1 -1
- package/dist/mcp/tools/repo.js +20 -19
- package/dist/mcp/tools/repo.js.map +1 -1
- package/dist/mcp/tools/response.d.ts.map +1 -1
- package/dist/mcp/tools/response.js +17 -2
- package/dist/mcp/tools/response.js.map +1 -1
- package/dist/mcp/tools/runtime.d.ts.map +1 -1
- package/dist/mcp/tools/runtime.js +7 -6
- package/dist/mcp/tools/runtime.js.map +1 -1
- package/dist/mcp/tools/usage.d.ts.map +1 -1
- package/dist/mcp/tools/usage.js +5 -0
- package/dist/mcp/tools/usage.js.map +1 -1
- package/dist/mcp/tools.d.ts +43 -61
- package/dist/mcp/tools.d.ts.map +1 -1
- package/dist/mcp/tools.js +50 -18
- package/dist/mcp/tools.js.map +1 -1
- package/dist/observability/aggregator.d.ts +3 -0
- package/dist/observability/aggregator.d.ts.map +1 -1
- package/dist/observability/aggregator.js +27 -0
- package/dist/observability/aggregator.js.map +1 -1
- package/dist/observability/event-tap.d.ts +6 -0
- package/dist/observability/event-tap.d.ts.map +1 -1
- package/dist/observability/event-tap.js.map +1 -1
- package/dist/observability/types.d.ts +9 -0
- package/dist/observability/types.d.ts.map +1 -1
- package/dist/observability/types.js.map +1 -1
- package/dist/runtime/response-artifacts.d.ts +14 -2
- package/dist/runtime/response-artifacts.d.ts.map +1 -1
- package/dist/runtime/response-artifacts.js +52 -17
- package/dist/runtime/response-artifacts.js.map +1 -1
- package/dist/server.d.ts +1 -1
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +118 -24
- package/dist/server.js.map +1 -1
- package/package.json +5 -5
- package/templates/SDL.md +6 -7
|
@@ -4,30 +4,32 @@
|
|
|
4
4
|
*/
|
|
5
5
|
/** Fields kept in the compact broad response before final model-content projection.
|
|
6
6
|
* Shared with context-engine.ts for pre-truncation compaction. */
|
|
7
|
-
|
|
8
|
-
"taskId",
|
|
7
|
+
const BROAD_MODEL_VISIBLE_FIELDS = new Set([
|
|
9
8
|
"taskType",
|
|
10
9
|
"success",
|
|
11
10
|
"summary",
|
|
12
11
|
"answer",
|
|
13
12
|
"finalEvidence",
|
|
14
13
|
"nextBestAction",
|
|
15
|
-
"retrievalEvidence",
|
|
16
|
-
"diagnostics",
|
|
17
14
|
"error",
|
|
18
15
|
"truncation",
|
|
16
|
+
]);
|
|
17
|
+
export const BROAD_VISIBLE_FIELDS = new Set([
|
|
18
|
+
...BROAD_MODEL_VISIBLE_FIELDS,
|
|
19
19
|
"etag",
|
|
20
|
-
"
|
|
20
|
+
"diagnostics",
|
|
21
|
+
"retrievalEvidence",
|
|
21
22
|
]);
|
|
22
23
|
/** Tool names eligible for context-specific compaction. */
|
|
23
24
|
const CONTEXT_TOOLS = new Set(["sdl.context"]);
|
|
25
|
+
const HIDDEN_ETAG_MODEL_FIELDS = new Set(["etag", "etagCache", "sliceEtag"]);
|
|
24
26
|
const ALWAYS_INTERNAL_MODEL_FIELDS = new Set([
|
|
25
27
|
"_displayFooter",
|
|
28
|
+
"_packedPayload",
|
|
26
29
|
"_packedStats",
|
|
27
30
|
"_rawContext",
|
|
28
31
|
"_tokenUsage",
|
|
29
32
|
"actionsTaken",
|
|
30
|
-
"backupPath",
|
|
31
33
|
"indexUpdate",
|
|
32
34
|
"metrics",
|
|
33
35
|
"packedStats",
|
|
@@ -36,12 +38,160 @@ const ALWAYS_INTERNAL_MODEL_FIELDS = new Set([
|
|
|
36
38
|
"serverDiagnostics",
|
|
37
39
|
"taskId",
|
|
38
40
|
"timings",
|
|
41
|
+
"tokenEstimate",
|
|
39
42
|
"totalTokens",
|
|
40
|
-
"
|
|
43
|
+
"etagCache",
|
|
44
|
+
"sliceEtag",
|
|
45
|
+
]);
|
|
46
|
+
const NO_OP_FALSE_FIELDS = new Set([
|
|
47
|
+
"truncated",
|
|
48
|
+
"truncation",
|
|
49
|
+
"blastRadiusTruncated",
|
|
50
|
+
]);
|
|
51
|
+
const NO_OP_NULL_FIELDS = new Set([
|
|
52
|
+
"signal",
|
|
41
53
|
]);
|
|
54
|
+
const NO_OP_EMPTY_ARRAY_FIELDS = new Set([
|
|
55
|
+
"warnings",
|
|
56
|
+
"quotingWarnings",
|
|
57
|
+
"serverDriftWarnings",
|
|
58
|
+
"filesSkipped",
|
|
59
|
+
"filesSkippedByReason",
|
|
60
|
+
"staleSymbols",
|
|
61
|
+
"missedIdentifiers",
|
|
62
|
+
]);
|
|
63
|
+
const COMPACT_FAILURE_TRACE_FIELDS = new Set([
|
|
64
|
+
"stepIndex",
|
|
65
|
+
"fn",
|
|
66
|
+
"action",
|
|
67
|
+
"kind",
|
|
68
|
+
"status",
|
|
69
|
+
"message",
|
|
70
|
+
"fallbackTools",
|
|
71
|
+
]);
|
|
72
|
+
const COMPACT_DEBUG_MODEL_FIELDS = new Set([
|
|
73
|
+
"aggregateStats",
|
|
74
|
+
"amplifiers",
|
|
75
|
+
"astFingerprint",
|
|
76
|
+
"bytes",
|
|
77
|
+
"bytesWritten",
|
|
78
|
+
"callResolution",
|
|
79
|
+
"clustersHint",
|
|
80
|
+
"confidenceDistribution",
|
|
81
|
+
"created",
|
|
82
|
+
"deduplicated",
|
|
83
|
+
"detailLevel",
|
|
84
|
+
"detailLevelMetadata",
|
|
85
|
+
"diagnostics",
|
|
86
|
+
"entryPoints",
|
|
87
|
+
"expiresAt",
|
|
88
|
+
"hotspots",
|
|
89
|
+
"lease",
|
|
90
|
+
"ledgerVersion",
|
|
91
|
+
"linesWritten",
|
|
92
|
+
"matchCount",
|
|
93
|
+
"matchedLineNumbers",
|
|
94
|
+
"mtimeMs",
|
|
95
|
+
"originalLines",
|
|
96
|
+
"pprBoosts",
|
|
97
|
+
"processes",
|
|
98
|
+
"relevance",
|
|
99
|
+
"returnedLines",
|
|
100
|
+
"searchedStreams",
|
|
101
|
+
"sessionDelta",
|
|
102
|
+
"sha256",
|
|
103
|
+
"shortId",
|
|
104
|
+
"sliceEtag",
|
|
105
|
+
"stderrPreview",
|
|
106
|
+
"stdinBytes",
|
|
107
|
+
"stdinSha256",
|
|
108
|
+
"stdoutPreview",
|
|
109
|
+
"symbolsRecorded",
|
|
110
|
+
"symbolIndex",
|
|
111
|
+
"symptomType",
|
|
112
|
+
"totalBytes",
|
|
113
|
+
"totalLines",
|
|
114
|
+
"truncationWarning",
|
|
115
|
+
"versionId",
|
|
116
|
+
"visibility",
|
|
117
|
+
"whyApproved",
|
|
118
|
+
]);
|
|
119
|
+
const REPO_ID_VISIBLE_TOOLS = new Set([
|
|
120
|
+
"repo.status",
|
|
121
|
+
"sdl.repo.status",
|
|
122
|
+
"repo.overview",
|
|
123
|
+
"sdl.repo.overview",
|
|
124
|
+
"delta.get",
|
|
125
|
+
"sdl.delta.get",
|
|
126
|
+
"sdl.workflow",
|
|
127
|
+
"workflow",
|
|
128
|
+
]);
|
|
129
|
+
const PRECONDITION_MODEL_FIELDS = new Set([
|
|
130
|
+
"astFingerprint",
|
|
131
|
+
"mtimeMs",
|
|
132
|
+
"preconditionSnapshot",
|
|
133
|
+
"sha256",
|
|
134
|
+
]);
|
|
135
|
+
const PRECONDITION_VISIBLE_TOOLS = new Set([
|
|
136
|
+
"search.edit",
|
|
137
|
+
"sdl.search.edit",
|
|
138
|
+
"symbol.edit",
|
|
139
|
+
"sdl.symbol.edit",
|
|
140
|
+
"symbol.getCard",
|
|
141
|
+
"sdl.symbol.getCard",
|
|
142
|
+
]);
|
|
143
|
+
const FILE_PRECONDITION_OPS = new Set([
|
|
144
|
+
"searchEditPreview",
|
|
145
|
+
"searchEditApply",
|
|
146
|
+
"symbolEditPreview",
|
|
147
|
+
"symbolEditApply",
|
|
148
|
+
"symbolEditApplyNow",
|
|
149
|
+
]);
|
|
150
|
+
const WORKFLOW_CHILD_TOOL_NAMES = {
|
|
151
|
+
actionSearch: "action.search",
|
|
152
|
+
codeHotPath: "code.getHotPath",
|
|
153
|
+
codeNeedWindow: "code.needWindow",
|
|
154
|
+
codeSkeleton: "code.getSkeleton",
|
|
155
|
+
deltaGet: "delta.get",
|
|
156
|
+
file: "sdl.file",
|
|
157
|
+
sdlFile: "sdl.file",
|
|
158
|
+
fileRead: "file.read",
|
|
159
|
+
fileWrite: "file.write",
|
|
160
|
+
indexRefresh: "index.refresh",
|
|
161
|
+
policyGet: "policy.get",
|
|
162
|
+
policySet: "policy.set",
|
|
163
|
+
prRiskAnalyze: "pr.risk.analyze",
|
|
164
|
+
repoOverview: "repo.overview",
|
|
165
|
+
repoStatus: "repo.status",
|
|
166
|
+
runtimeExecute: "runtime.execute",
|
|
167
|
+
runtimeQueryOutput: "runtime.queryOutput",
|
|
168
|
+
searchEdit: "search.edit",
|
|
169
|
+
sliceBuild: "slice.build",
|
|
170
|
+
sliceRefresh: "slice.refresh",
|
|
171
|
+
symbolEdit: "symbol.edit",
|
|
172
|
+
symbolGetCard: "symbol.getCard",
|
|
173
|
+
symbolGetCards: "symbol.getCards",
|
|
174
|
+
symbolSearch: "symbol.search",
|
|
175
|
+
usageStats: "usage.stats",
|
|
176
|
+
};
|
|
42
177
|
function isRecord(value) {
|
|
43
178
|
return Boolean(value && typeof value === "object" && !Array.isArray(value));
|
|
44
179
|
}
|
|
180
|
+
function stripEtagFieldsForModel(value) {
|
|
181
|
+
if (Array.isArray(value)) {
|
|
182
|
+
return value.map(stripEtagFieldsForModel);
|
|
183
|
+
}
|
|
184
|
+
if (!isRecord(value)) {
|
|
185
|
+
return value;
|
|
186
|
+
}
|
|
187
|
+
const projected = {};
|
|
188
|
+
for (const [key, itemValue] of Object.entries(value)) {
|
|
189
|
+
if (!HIDDEN_ETAG_MODEL_FIELDS.has(key)) {
|
|
190
|
+
projected[key] = stripEtagFieldsForModel(itemValue);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return projected;
|
|
194
|
+
}
|
|
45
195
|
function copyIfPresent(source, target, key) {
|
|
46
196
|
if (key in source) {
|
|
47
197
|
target[key] = source[key];
|
|
@@ -64,27 +214,121 @@ function projectEvidenceForModel(value) {
|
|
|
64
214
|
return projected;
|
|
65
215
|
});
|
|
66
216
|
}
|
|
217
|
+
function normalizedDetail(value) {
|
|
218
|
+
return value === "full" || value === "standard" ? value : "compact";
|
|
219
|
+
}
|
|
67
220
|
function modelOptionsFromArgs(args) {
|
|
68
221
|
const options = isRecord(args.options) ? args.options : {};
|
|
69
222
|
return {
|
|
70
|
-
|
|
223
|
+
detail: normalizedDetail(args.detail ?? options.detail),
|
|
224
|
+
includeDiagnostics: args.includeDiagnostics === true
|
|
225
|
+
|| options.includeDiagnostics === true,
|
|
71
226
|
includeRetrievalEvidence: args.includeRetrievalEvidence === true
|
|
72
227
|
|| options.includeRetrievalEvidence === true,
|
|
228
|
+
includeTelemetry: args.includeTelemetry === true
|
|
229
|
+
|| options.includeTelemetry === true,
|
|
230
|
+
includeTrace: args.trace !== undefined,
|
|
231
|
+
includeProcesses: args.includeProcesses === true,
|
|
232
|
+
includeResolutionMetadata: args.includeResolutionMetadata === true,
|
|
233
|
+
fileOp: typeof args.op === "string" ? args.op : undefined,
|
|
73
234
|
};
|
|
74
235
|
}
|
|
236
|
+
function isFullDetail(options) {
|
|
237
|
+
return options.detail === "full";
|
|
238
|
+
}
|
|
239
|
+
function isNoOpTruncationObject(value) {
|
|
240
|
+
if (!isRecord(value)) {
|
|
241
|
+
return false;
|
|
242
|
+
}
|
|
243
|
+
if (value.truncated === true
|
|
244
|
+
|| value.stdoutTruncated === true
|
|
245
|
+
|| value.stderrTruncated === true) {
|
|
246
|
+
return false;
|
|
247
|
+
}
|
|
248
|
+
return Object.keys(value).every((key) => key === "truncated"
|
|
249
|
+
|| key === "stdoutTruncated"
|
|
250
|
+
|| key === "stderrTruncated"
|
|
251
|
+
|| key === "totalStdoutBytes"
|
|
252
|
+
|| key === "totalStderrBytes");
|
|
253
|
+
}
|
|
254
|
+
function shouldDropNoOpField(key, value) {
|
|
255
|
+
if (value === false && NO_OP_FALSE_FIELDS.has(key)) {
|
|
256
|
+
return true;
|
|
257
|
+
}
|
|
258
|
+
if (key === "truncation" && isNoOpTruncationObject(value)) {
|
|
259
|
+
return true;
|
|
260
|
+
}
|
|
261
|
+
if (value === null && NO_OP_NULL_FIELDS.has(key)) {
|
|
262
|
+
return true;
|
|
263
|
+
}
|
|
264
|
+
if (Array.isArray(value)
|
|
265
|
+
&& value.length === 0
|
|
266
|
+
&& NO_OP_EMPTY_ARRAY_FIELDS.has(key)) {
|
|
267
|
+
return true;
|
|
268
|
+
}
|
|
269
|
+
if (key === "rollback" && isRecord(value)) {
|
|
270
|
+
return Object.keys(value).length === 0 || value.triggered === false;
|
|
271
|
+
}
|
|
272
|
+
return false;
|
|
273
|
+
}
|
|
274
|
+
function keepsPreconditionField(toolName, options) {
|
|
275
|
+
return PRECONDITION_VISIBLE_TOOLS.has(toolName)
|
|
276
|
+
|| ((toolName === "sdl.file" || toolName === "file")
|
|
277
|
+
&& typeof options.fileOp === "string"
|
|
278
|
+
&& FILE_PRECONDITION_OPS.has(options.fileOp));
|
|
279
|
+
}
|
|
75
280
|
function shouldKeepModelField(toolName, key, options) {
|
|
76
|
-
if (
|
|
281
|
+
if (isFullDetail(options)) {
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
284
|
+
if (key === "trace") {
|
|
285
|
+
return toolName === "sdl.workflow" && options.includeTrace;
|
|
286
|
+
}
|
|
287
|
+
if (PRECONDITION_MODEL_FIELDS.has(key) && keepsPreconditionField(toolName, options)) {
|
|
77
288
|
return true;
|
|
78
289
|
}
|
|
79
290
|
if (ALWAYS_INTERNAL_MODEL_FIELDS.has(key)) {
|
|
80
291
|
return false;
|
|
81
292
|
}
|
|
293
|
+
if (key === "repoId") {
|
|
294
|
+
return REPO_ID_VISIBLE_TOOLS.has(toolName);
|
|
295
|
+
}
|
|
296
|
+
if (key === "processes") {
|
|
297
|
+
return options.includeProcesses;
|
|
298
|
+
}
|
|
299
|
+
if (key === "callResolution") {
|
|
300
|
+
return options.includeResolutionMetadata;
|
|
301
|
+
}
|
|
302
|
+
if (COMPACT_DEBUG_MODEL_FIELDS.has(key)) {
|
|
303
|
+
return false;
|
|
304
|
+
}
|
|
305
|
+
if (toolName === "slice.build" && key === "budget") {
|
|
306
|
+
return false;
|
|
307
|
+
}
|
|
308
|
+
if ((toolName === "symbol.search" || toolName === "sdl.symbol.search") && key === "symbols") {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
82
311
|
if (key === "diagnostics") {
|
|
83
312
|
return options.includeDiagnostics;
|
|
84
313
|
}
|
|
85
314
|
if (key === "retrievalEvidence") {
|
|
86
315
|
return options.includeRetrievalEvidence;
|
|
87
316
|
}
|
|
317
|
+
if (key === "estimatedTokens"
|
|
318
|
+
|| key === "originalLines"
|
|
319
|
+
|| key === "matchedLineNumbers"
|
|
320
|
+
|| key === "generatedAt"
|
|
321
|
+
|| key === "tokenMetrics") {
|
|
322
|
+
return false;
|
|
323
|
+
}
|
|
324
|
+
if (options.detail === "compact"
|
|
325
|
+
&& !options.includeTelemetry
|
|
326
|
+
&& (key === "prefetchStats"
|
|
327
|
+
|| key === "strategyMetrics"
|
|
328
|
+
|| key === "topStrategies"
|
|
329
|
+
|| key === "healthComponents")) {
|
|
330
|
+
return false;
|
|
331
|
+
}
|
|
88
332
|
return true;
|
|
89
333
|
}
|
|
90
334
|
function projectGenericValueForModel(toolName, value, options) {
|
|
@@ -96,6 +340,12 @@ function projectGenericValueForModel(toolName, value, options) {
|
|
|
96
340
|
}
|
|
97
341
|
const projected = {};
|
|
98
342
|
for (const [key, itemValue] of Object.entries(value)) {
|
|
343
|
+
if (HIDDEN_ETAG_MODEL_FIELDS.has(key)) {
|
|
344
|
+
continue;
|
|
345
|
+
}
|
|
346
|
+
if (shouldDropNoOpField(key, itemValue)) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
99
349
|
if (key === "diagnostics" && options.includeDiagnostics) {
|
|
100
350
|
projected[key] = itemValue;
|
|
101
351
|
continue;
|
|
@@ -106,7 +356,7 @@ function projectGenericValueForModel(toolName, value, options) {
|
|
|
106
356
|
}
|
|
107
357
|
if (key === "policyDecision") {
|
|
108
358
|
const decision = isRecord(itemValue) ? itemValue : {};
|
|
109
|
-
if (Array.isArray(decision.deniedReasons)) {
|
|
359
|
+
if (Array.isArray(decision.deniedReasons) && decision.deniedReasons.length > 0) {
|
|
110
360
|
projected.policyDecision = { deniedReasons: decision.deniedReasons };
|
|
111
361
|
}
|
|
112
362
|
continue;
|
|
@@ -114,7 +364,11 @@ function projectGenericValueForModel(toolName, value, options) {
|
|
|
114
364
|
if (!shouldKeepModelField(toolName, key, options)) {
|
|
115
365
|
continue;
|
|
116
366
|
}
|
|
117
|
-
|
|
367
|
+
const projectedValue = projectGenericValueForModel(toolName, itemValue, options);
|
|
368
|
+
if (isRecord(projectedValue) && Object.keys(projectedValue).length === 0) {
|
|
369
|
+
continue;
|
|
370
|
+
}
|
|
371
|
+
projected[key] = projectedValue;
|
|
118
372
|
}
|
|
119
373
|
return projected;
|
|
120
374
|
}
|
|
@@ -131,8 +385,9 @@ function projectContextResultForModel(result, options) {
|
|
|
131
385
|
}
|
|
132
386
|
copyIfPresent(result, projected, "nextBestAction");
|
|
133
387
|
copyIfPresent(result, projected, "error");
|
|
134
|
-
|
|
135
|
-
|
|
388
|
+
if (result.truncation !== false) {
|
|
389
|
+
copyIfPresent(result, projected, "truncation");
|
|
390
|
+
}
|
|
136
391
|
if (options.includeRetrievalEvidence) {
|
|
137
392
|
copyIfPresent(result, projected, "retrievalEvidence");
|
|
138
393
|
}
|
|
@@ -141,57 +396,302 @@ function projectContextResultForModel(result, options) {
|
|
|
141
396
|
}
|
|
142
397
|
return projected;
|
|
143
398
|
}
|
|
399
|
+
function projectCompactFailureTrace(value) {
|
|
400
|
+
if (!isRecord(value)) {
|
|
401
|
+
return value;
|
|
402
|
+
}
|
|
403
|
+
const projected = {};
|
|
404
|
+
for (const [key, itemValue] of Object.entries(value)) {
|
|
405
|
+
if (COMPACT_FAILURE_TRACE_FIELDS.has(key)) {
|
|
406
|
+
projected[key] = itemValue;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
return projected;
|
|
410
|
+
}
|
|
411
|
+
function workflowStepArgsAt(workflowArgs, stepIndex) {
|
|
412
|
+
const steps = workflowArgs.steps;
|
|
413
|
+
if (!Array.isArray(steps)) {
|
|
414
|
+
return undefined;
|
|
415
|
+
}
|
|
416
|
+
const step = steps[stepIndex];
|
|
417
|
+
return isRecord(step) ? step.args : undefined;
|
|
418
|
+
}
|
|
419
|
+
function inferWorkflowFileOp(childToolName, result, args) {
|
|
420
|
+
if (isRecord(args) && typeof args.op === "string") {
|
|
421
|
+
return args.op;
|
|
422
|
+
}
|
|
423
|
+
if (childToolName === "sdl.file" && isRecord(result) && "preconditionSnapshot" in result) {
|
|
424
|
+
return "searchEditPreview";
|
|
425
|
+
}
|
|
426
|
+
return undefined;
|
|
427
|
+
}
|
|
428
|
+
function projectWorkflowStepResultForModel(fn, result, options, args) {
|
|
429
|
+
const childToolName = typeof fn === "string"
|
|
430
|
+
? WORKFLOW_CHILD_TOOL_NAMES[fn] ?? "sdl.workflow"
|
|
431
|
+
: "sdl.workflow";
|
|
432
|
+
const childArgOptions = isRecord(args) ? modelOptionsFromArgs(args) : undefined;
|
|
433
|
+
const fileOp = inferWorkflowFileOp(childToolName, result, args);
|
|
434
|
+
if (isFullDetail(options)) {
|
|
435
|
+
return stripEtagFieldsForModel(result);
|
|
436
|
+
}
|
|
437
|
+
const childOptions = {
|
|
438
|
+
...options,
|
|
439
|
+
detail: "compact",
|
|
440
|
+
includeDiagnostics: false,
|
|
441
|
+
includeRetrievalEvidence: false,
|
|
442
|
+
includeTelemetry: false,
|
|
443
|
+
includeTrace: false,
|
|
444
|
+
...(childArgOptions ?? {}),
|
|
445
|
+
fileOp: fileOp ?? childArgOptions?.fileOp ?? options.fileOp,
|
|
446
|
+
};
|
|
447
|
+
if (isFullDetail(childOptions)) {
|
|
448
|
+
return stripEtagFieldsForModel(result);
|
|
449
|
+
}
|
|
450
|
+
if (childToolName === "repo.status") {
|
|
451
|
+
if (childOptions.detail === "compact" && !childOptions.includeTelemetry) {
|
|
452
|
+
return isRecord(result) ? projectRepoStatusForModel(result, childOptions) : result;
|
|
453
|
+
}
|
|
454
|
+
return projectGenericValueForModel(childToolName, result, childOptions);
|
|
455
|
+
}
|
|
456
|
+
if (childToolName === "action.search" && childOptions.detail === "compact") {
|
|
457
|
+
return isRecord(result) ? projectActionSearchForModel(result) : result;
|
|
458
|
+
}
|
|
459
|
+
if (childToolName === "usage.stats") {
|
|
460
|
+
return isRecord(result) ? projectUsageStatsForModel(result) : result;
|
|
461
|
+
}
|
|
462
|
+
return projectGenericValueForModel(childToolName, result, childOptions);
|
|
463
|
+
}
|
|
464
|
+
function projectWorkflowResultForModel(result, options, workflowArgs = {}) {
|
|
465
|
+
const includeWorkflowTelemetry = options.includeTrace
|
|
466
|
+
|| options.includeDiagnostics
|
|
467
|
+
|| options.includeTelemetry
|
|
468
|
+
|| isFullDetail(options);
|
|
469
|
+
const projected = {};
|
|
470
|
+
const rawResults = Array.isArray(result.results) ? result.results : [];
|
|
471
|
+
projected.results = rawResults.map((item, index) => {
|
|
472
|
+
if (!isRecord(item)) {
|
|
473
|
+
return item;
|
|
474
|
+
}
|
|
475
|
+
const status = typeof item.status === "string" ? item.status : "ok";
|
|
476
|
+
const stepIndex = typeof item.stepIndex === "number" ? item.stepIndex : index;
|
|
477
|
+
const stepArgs = workflowStepArgsAt(workflowArgs, stepIndex) ?? item.args;
|
|
478
|
+
if (status === "ok") {
|
|
479
|
+
const successStep = { fn: item.fn };
|
|
480
|
+
if (includeWorkflowTelemetry) {
|
|
481
|
+
copyIfPresent(item, successStep, "stepIndex");
|
|
482
|
+
copyIfPresent(item, successStep, "tokens");
|
|
483
|
+
copyIfPresent(item, successStep, "durationMs");
|
|
484
|
+
copyIfPresent(item, successStep, "status");
|
|
485
|
+
}
|
|
486
|
+
if ("result" in item) {
|
|
487
|
+
successStep.result = projectWorkflowStepResultForModel(item.fn, item.result, options, stepArgs);
|
|
488
|
+
}
|
|
489
|
+
if (item.truncatedResponse) {
|
|
490
|
+
successStep.truncatedResponse = item.truncatedResponse;
|
|
491
|
+
}
|
|
492
|
+
return successStep;
|
|
493
|
+
}
|
|
494
|
+
const failureStep = { fn: item.fn, status };
|
|
495
|
+
copyIfPresent(item, failureStep, "error");
|
|
496
|
+
copyIfPresent(item, failureStep, "fallbackTools");
|
|
497
|
+
copyIfPresent(item, failureStep, "blockedByStep");
|
|
498
|
+
copyIfPresent(item, failureStep, "blockedByFn");
|
|
499
|
+
copyIfPresent(item, failureStep, "blockedByError");
|
|
500
|
+
if ("failureTrace" in item) {
|
|
501
|
+
failureStep.failureTrace = projectCompactFailureTrace(item.failureTrace);
|
|
502
|
+
}
|
|
503
|
+
if ("result" in item && item.result !== null && item.result !== undefined) {
|
|
504
|
+
failureStep.result = projectWorkflowStepResultForModel(item.fn, item.result, options, stepArgs);
|
|
505
|
+
}
|
|
506
|
+
return failureStep;
|
|
507
|
+
});
|
|
508
|
+
if (includeWorkflowTelemetry) {
|
|
509
|
+
copyIfPresent(result, projected, "durationMs");
|
|
510
|
+
copyIfPresent(result, projected, "totalTokens");
|
|
511
|
+
}
|
|
512
|
+
if (result.truncated === true) {
|
|
513
|
+
projected.truncated = true;
|
|
514
|
+
}
|
|
515
|
+
if (options.includeTrace) {
|
|
516
|
+
copyIfPresent(result, projected, "trace");
|
|
517
|
+
}
|
|
518
|
+
if (options.includeDiagnostics) {
|
|
519
|
+
copyIfPresent(result, projected, "diagnostics");
|
|
520
|
+
}
|
|
521
|
+
return projected;
|
|
522
|
+
}
|
|
523
|
+
function projectUsageStatsForModel(result) {
|
|
524
|
+
const projected = {};
|
|
525
|
+
copyIfPresent(result, projected, "formattedSummary");
|
|
526
|
+
return projected;
|
|
527
|
+
}
|
|
528
|
+
function projectDerivedStateForModel(value) {
|
|
529
|
+
if (!isRecord(value)) {
|
|
530
|
+
return value;
|
|
531
|
+
}
|
|
532
|
+
const projected = {};
|
|
533
|
+
copyIfPresent(value, projected, "stale");
|
|
534
|
+
for (const key of [
|
|
535
|
+
"clustersDirty",
|
|
536
|
+
"processesDirty",
|
|
537
|
+
"algorithmsDirty",
|
|
538
|
+
"summariesDirty",
|
|
539
|
+
"embeddingsDirty",
|
|
540
|
+
]) {
|
|
541
|
+
if (value[key] === true) {
|
|
542
|
+
projected[key] = true;
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
copyIfPresent(value, projected, "lastError");
|
|
546
|
+
copyIfPresent(value, projected, "nextBestAction");
|
|
547
|
+
return projected;
|
|
548
|
+
}
|
|
549
|
+
function watcherNeedsAttention(value) {
|
|
550
|
+
return value.running === false
|
|
551
|
+
|| value.stale === true
|
|
552
|
+
|| (typeof value.errors === "number" && value.errors > 0)
|
|
553
|
+
|| Boolean(value.fallbackReason);
|
|
554
|
+
}
|
|
555
|
+
function projectWatcherHealthForModel(value) {
|
|
556
|
+
if (!isRecord(value) || !watcherNeedsAttention(value)) {
|
|
557
|
+
return undefined;
|
|
558
|
+
}
|
|
559
|
+
const projected = {};
|
|
560
|
+
for (const key of [
|
|
561
|
+
"enabled",
|
|
562
|
+
"running",
|
|
563
|
+
"provider",
|
|
564
|
+
"fallbackReason",
|
|
565
|
+
"errors",
|
|
566
|
+
"queueDepth",
|
|
567
|
+
"stale",
|
|
568
|
+
]) {
|
|
569
|
+
copyIfPresent(value, projected, key);
|
|
570
|
+
}
|
|
571
|
+
return projected;
|
|
572
|
+
}
|
|
573
|
+
function projectRepoStatusForModel(result, options) {
|
|
574
|
+
const projected = {};
|
|
575
|
+
for (const key of [
|
|
576
|
+
"repoId",
|
|
577
|
+
"rootPath",
|
|
578
|
+
"latestVersionId",
|
|
579
|
+
"filesIndexed",
|
|
580
|
+
"symbolsIndexed",
|
|
581
|
+
"lastIndexedAt",
|
|
582
|
+
]) {
|
|
583
|
+
copyIfPresent(result, projected, key);
|
|
584
|
+
}
|
|
585
|
+
if (result.healthAvailable === true || result.healthScore !== undefined) {
|
|
586
|
+
copyIfPresent(result, projected, "healthAvailable");
|
|
587
|
+
copyIfPresent(result, projected, "healthScore");
|
|
588
|
+
}
|
|
589
|
+
if ("derivedState" in result) {
|
|
590
|
+
projected.derivedState = projectDerivedStateForModel(result.derivedState);
|
|
591
|
+
}
|
|
592
|
+
const compactWatcher = projectWatcherHealthForModel(result.watcherHealth);
|
|
593
|
+
if (compactWatcher !== undefined) {
|
|
594
|
+
projected.watcherHealth = compactWatcher;
|
|
595
|
+
}
|
|
596
|
+
copyIfPresent(result, projected, "nextBestAction");
|
|
597
|
+
if (options.includeDiagnostics) {
|
|
598
|
+
copyIfPresent(result, projected, "diagnostics");
|
|
599
|
+
}
|
|
600
|
+
if (options.includeRetrievalEvidence) {
|
|
601
|
+
copyIfPresent(result, projected, "retrievalEvidence");
|
|
602
|
+
}
|
|
603
|
+
return projected;
|
|
604
|
+
}
|
|
605
|
+
function compactSchemaSummary(value) {
|
|
606
|
+
if (!Array.isArray(value)) {
|
|
607
|
+
return value;
|
|
608
|
+
}
|
|
609
|
+
return value.map((field) => {
|
|
610
|
+
if (!isRecord(field)) {
|
|
611
|
+
return field;
|
|
612
|
+
}
|
|
613
|
+
const projected = {};
|
|
614
|
+
for (const key of ["name", "type", "required", "default", "enumValues", "subFields"]) {
|
|
615
|
+
if (key === "subFields") {
|
|
616
|
+
if ("subFields" in field) {
|
|
617
|
+
projected.subFields = compactSchemaSummary(field.subFields);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
else {
|
|
621
|
+
copyIfPresent(field, projected, key);
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
return projected;
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
function projectActionSearchForModel(result) {
|
|
628
|
+
const projected = {};
|
|
629
|
+
if (Array.isArray(result.actions)) {
|
|
630
|
+
projected.actions = result.actions.map((action) => {
|
|
631
|
+
if (!isRecord(action)) {
|
|
632
|
+
return action;
|
|
633
|
+
}
|
|
634
|
+
const compact = {};
|
|
635
|
+
copyIfPresent(action, compact, "action");
|
|
636
|
+
copyIfPresent(action, compact, "fn");
|
|
637
|
+
copyIfPresent(action, compact, "requiredParams");
|
|
638
|
+
copyIfPresent(action, compact, "disabled");
|
|
639
|
+
copyIfPresent(action, compact, "disabledReason");
|
|
640
|
+
if (isRecord(action.schemaSummary) && Array.isArray(action.schemaSummary.fields)) {
|
|
641
|
+
compact.schemaSummary = {
|
|
642
|
+
fields: compactSchemaSummary(action.schemaSummary.fields),
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
return compact;
|
|
646
|
+
});
|
|
647
|
+
}
|
|
648
|
+
copyIfPresent(result, projected, "summary");
|
|
649
|
+
copyIfPresent(result, projected, "total");
|
|
650
|
+
copyIfPresent(result, projected, "hasMore");
|
|
651
|
+
copyIfPresent(result, projected, "nextCursor");
|
|
652
|
+
copyIfPresent(result, projected, "disabledHint");
|
|
653
|
+
copyIfPresent(result, projected, "schemaHint");
|
|
654
|
+
return projected;
|
|
655
|
+
}
|
|
144
656
|
/**
|
|
145
657
|
* Returns true when the result looks like a broad context response that
|
|
146
658
|
* should be compacted.
|
|
147
659
|
*/
|
|
148
660
|
export function isBroadContextResult(toolName, result) {
|
|
149
|
-
if (!CONTEXT_TOOLS.has(toolName))
|
|
661
|
+
if (!CONTEXT_TOOLS.has(toolName)) {
|
|
150
662
|
return false;
|
|
151
|
-
|
|
663
|
+
}
|
|
664
|
+
if (!isRecord(result)) {
|
|
152
665
|
return false;
|
|
666
|
+
}
|
|
153
667
|
const r = result;
|
|
154
|
-
// Broad results have actionsTaken + path + metrics (precise mode strips some of these
|
|
155
|
-
// but still has actionsTaken). The key differentiator: broad mode has `answer` field.
|
|
156
|
-
// Also check it's not an error result (which should pass through unchanged).
|
|
157
668
|
return ("taskId" in r &&
|
|
158
669
|
"actionsTaken" in r &&
|
|
159
670
|
"answer" in r &&
|
|
160
671
|
r.success !== undefined);
|
|
161
672
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Project a broad context result to its compact internal response form.
|
|
164
|
-
* Returns the original result unchanged if it doesn't qualify.
|
|
165
|
-
*/
|
|
166
673
|
export function projectBroadContextResult(toolName, result) {
|
|
167
|
-
if (!isBroadContextResult(toolName, result))
|
|
674
|
+
if (!isBroadContextResult(toolName, result)) {
|
|
168
675
|
return result;
|
|
676
|
+
}
|
|
169
677
|
const r = result;
|
|
170
678
|
const projected = {};
|
|
171
679
|
for (const key of Object.keys(r)) {
|
|
172
|
-
if (
|
|
680
|
+
if (BROAD_MODEL_VISIBLE_FIELDS.has(key)) {
|
|
173
681
|
projected[key] = r[key];
|
|
174
682
|
}
|
|
175
683
|
}
|
|
176
684
|
return projected;
|
|
177
685
|
}
|
|
178
|
-
/**
|
|
179
|
-
* Project tool responses before token accounting while keeping the internal raw
|
|
180
|
-
* baseline hint that `computeTokenUsage()` needs.
|
|
181
|
-
*/
|
|
182
686
|
export function projectContextResultForUsageAccounting(toolName, result, args = {}) {
|
|
183
687
|
const projected = projectToolResultForModelContent(toolName, result, args);
|
|
184
|
-
if (!isRecord(projected)
|
|
688
|
+
if (!isRecord(projected)) {
|
|
185
689
|
return result;
|
|
186
690
|
}
|
|
187
|
-
const accountingResult = projected;
|
|
188
691
|
if ("_rawContext" in result) {
|
|
189
|
-
return {
|
|
190
|
-
...accountingResult,
|
|
191
|
-
_rawContext: result._rawContext,
|
|
192
|
-
};
|
|
692
|
+
return { ...projected, _rawContext: result._rawContext };
|
|
193
693
|
}
|
|
194
|
-
return
|
|
694
|
+
return projected;
|
|
195
695
|
}
|
|
196
696
|
/**
|
|
197
697
|
* Project the payload serialized into MCP text content for the model/user.
|
|
@@ -203,9 +703,28 @@ export function projectToolResultForModelContent(toolName, result, args = {}) {
|
|
|
203
703
|
return result;
|
|
204
704
|
}
|
|
205
705
|
const options = modelOptionsFromArgs(args);
|
|
706
|
+
if (toolName === "sdl.workflow" || toolName === "workflow") {
|
|
707
|
+
return projectWorkflowResultForModel(result, options, args);
|
|
708
|
+
}
|
|
709
|
+
if (isFullDetail(options)) {
|
|
710
|
+
return result;
|
|
711
|
+
}
|
|
206
712
|
if (CONTEXT_TOOLS.has(toolName) && ("answer" in result || "finalEvidence" in result)) {
|
|
207
713
|
return projectContextResultForModel(result, options);
|
|
208
714
|
}
|
|
715
|
+
if (toolName === "usage.stats" || toolName === "sdl.usage.stats") {
|
|
716
|
+
return projectUsageStatsForModel(result);
|
|
717
|
+
}
|
|
718
|
+
if (toolName === "repo.status" || toolName === "sdl.repo.status") {
|
|
719
|
+
if (options.detail === "compact" && !options.includeTelemetry) {
|
|
720
|
+
return projectRepoStatusForModel(result, options);
|
|
721
|
+
}
|
|
722
|
+
}
|
|
723
|
+
if (toolName === "action.search" || toolName === "sdl.action.search") {
|
|
724
|
+
if (options.detail === "compact") {
|
|
725
|
+
return projectActionSearchForModel(result);
|
|
726
|
+
}
|
|
727
|
+
}
|
|
209
728
|
return projectGenericValueForModel(toolName, result, options);
|
|
210
729
|
}
|
|
211
730
|
//# sourceMappingURL=context-response-projection.js.map
|