@components-kit/open-workbook-mcp-server 0.1.8 → 0.1.9
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/index.js +671 -38
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -14,6 +14,9 @@ const standalone = hasArg("--standalone") || process.env.OPEN_WORKBOOK_MCP_STAND
|
|
|
14
14
|
const catalogOptions = {
|
|
15
15
|
includePreview: process.env.OPEN_WORKBOOK_PREVIEW_TOOLS === "1"
|
|
16
16
|
};
|
|
17
|
+
const toolProfile = readArg("--tool-profile") ?? process.env.OPEN_WORKBOOK_TOOL_PROFILE ?? "full";
|
|
18
|
+
const explicitToolNames = parseToolNameList(readArg("--tools") ?? process.env.OPEN_WORKBOOK_TOOLS);
|
|
19
|
+
const disabledToolNames = parseToolNameList(readArg("--disable-tools") ?? process.env.OPEN_WORKBOOK_DISABLE_TOOLS);
|
|
17
20
|
const STYLE_DIMENSIONS = [
|
|
18
21
|
"columnWidths",
|
|
19
22
|
"rowHeights",
|
|
@@ -44,8 +47,99 @@ const STYLE_COPY_TOOL_DIMENSIONS = {
|
|
|
44
47
|
"excel.style.copy_page_layout": "pageLayout",
|
|
45
48
|
"excel.style.copy_hidden_rows_columns": "hiddenRowsColumns"
|
|
46
49
|
};
|
|
50
|
+
const COMPACT_PROFILE_TOOLS = new Set([
|
|
51
|
+
"excel.runtime.get_status",
|
|
52
|
+
"excel.runtime.get_capabilities",
|
|
53
|
+
"excel.runtime.get_active_context",
|
|
54
|
+
"excel.runtime.get_selection",
|
|
55
|
+
"excel.runtime.connect_addin",
|
|
56
|
+
"excel.runtime.ping_addin",
|
|
57
|
+
"excel.runtime.set_active_workbook",
|
|
58
|
+
"excel.runtime.set_active_sheet",
|
|
59
|
+
"excel.workbook.list_open_workbooks",
|
|
60
|
+
"excel.workbook.get_workbook_info",
|
|
61
|
+
"excel.workbook.get_workbook_map",
|
|
62
|
+
"excel.workbook.get_summary",
|
|
63
|
+
"excel.workbook.get_used_range_summary",
|
|
64
|
+
"excel.workbook.detect_external_changes",
|
|
65
|
+
"excel.workbook.calculate",
|
|
66
|
+
"excel.workbook.save",
|
|
67
|
+
"excel.sheet.list",
|
|
68
|
+
"excel.sheet.get_info",
|
|
69
|
+
"excel.sheet.get_summary",
|
|
70
|
+
"excel.sheet.get_used_range",
|
|
71
|
+
"excel.lookup.search_workbook",
|
|
72
|
+
"excel.lookup.find_headers",
|
|
73
|
+
"excel.lookup.find_tables_by_columns",
|
|
74
|
+
"excel.lookup.find_entity",
|
|
75
|
+
"excel.lookup.resolve_range",
|
|
76
|
+
"excel.lookup.inspect_match",
|
|
77
|
+
"excel.range.get_summary",
|
|
78
|
+
"excel.range.read_compact",
|
|
79
|
+
"excel.range.find_errors",
|
|
80
|
+
"excel.table.list",
|
|
81
|
+
"excel.table.get_info",
|
|
82
|
+
"excel.table.get_schema",
|
|
83
|
+
"excel.table.read_compact",
|
|
84
|
+
"excel.batch.validate",
|
|
85
|
+
"excel.batch.preflight",
|
|
86
|
+
"excel.batch.dry_run",
|
|
87
|
+
"excel.batch.apply",
|
|
88
|
+
"excel.batch.submit",
|
|
89
|
+
"excel.batch.submit_chunked",
|
|
90
|
+
"excel.job.list",
|
|
91
|
+
"excel.job.get",
|
|
92
|
+
"excel.job.wait",
|
|
93
|
+
"excel.workflow.prepare_session",
|
|
94
|
+
"excel.workflow.create_formula_sheet",
|
|
95
|
+
"excel.workflow.create_template_report",
|
|
96
|
+
"excel.workflow.create_pivot_chart_summary",
|
|
97
|
+
"excel.workflow.repair_formula_errors",
|
|
98
|
+
"excel.workflow.preview_risky_edit",
|
|
99
|
+
"excel.plan.create",
|
|
100
|
+
"excel.plan.preview",
|
|
101
|
+
"excel.plan.apply",
|
|
102
|
+
"excel.plan.rollback",
|
|
103
|
+
"excel.compact.get_resource",
|
|
104
|
+
"excel.compact.list_resources",
|
|
105
|
+
"excel.compact.clear_resources",
|
|
106
|
+
"excel.compact.get_cache_status",
|
|
107
|
+
"excel.compact.clear_cache",
|
|
108
|
+
"excel.snapshot.create",
|
|
109
|
+
"excel.snapshot.get_compact",
|
|
110
|
+
"excel.snapshot.compare_compact",
|
|
111
|
+
"excel.diff.summarize",
|
|
112
|
+
"excel.diff.get_compact",
|
|
113
|
+
"excel.validate.compact",
|
|
114
|
+
"excel.validate.no_formula_errors",
|
|
115
|
+
"excel.validate.no_broken_references",
|
|
116
|
+
"excel.validate.no_unintended_changes",
|
|
117
|
+
"excel.collab.get_status",
|
|
118
|
+
"excel.transaction.list",
|
|
119
|
+
"excel.transaction.get",
|
|
120
|
+
"excel.transaction.wait",
|
|
121
|
+
"excel.transaction.preview_rollback",
|
|
122
|
+
"excel.transaction.rollback"
|
|
123
|
+
]);
|
|
124
|
+
const READ_ONLY_PROFILE_TOOLS = new Set([...COMPACT_PROFILE_TOOLS].filter((name) => name.startsWith("excel.runtime.") ||
|
|
125
|
+
name.startsWith("excel.workbook.get_") ||
|
|
126
|
+
name === "excel.workbook.list_open_workbooks" ||
|
|
127
|
+
name.startsWith("excel.sheet.") ||
|
|
128
|
+
name.startsWith("excel.lookup.") ||
|
|
129
|
+
name.startsWith("excel.range.read_") ||
|
|
130
|
+
name === "excel.range.get_summary" ||
|
|
131
|
+
name === "excel.range.find_errors" ||
|
|
132
|
+
name.startsWith("excel.table.get_") ||
|
|
133
|
+
name === "excel.table.list" ||
|
|
134
|
+
name === "excel.table.read_compact" ||
|
|
135
|
+
name.startsWith("excel.compact.") ||
|
|
136
|
+
name.startsWith("excel.snapshot.get_") ||
|
|
137
|
+
name === "excel.snapshot.compare_compact" ||
|
|
138
|
+
name.startsWith("excel.diff.") ||
|
|
139
|
+
name.startsWith("excel.validate.") ||
|
|
140
|
+
name === "excel.collab.get_status"));
|
|
47
141
|
const runtime = await createRuntimeFacade();
|
|
48
|
-
const runtimeVersion = process.env.OPEN_WORKBOOK_VERSION ?? "0.1.
|
|
142
|
+
const runtimeVersion = process.env.OPEN_WORKBOOK_VERSION ?? "0.1.9";
|
|
49
143
|
const COMPACT_RESOURCE_LIMIT = 100;
|
|
50
144
|
const COMPACT_DEFAULT_RESOURCE_THRESHOLD_BYTES = 24_000;
|
|
51
145
|
const compactResources = new Map();
|
|
@@ -381,14 +475,15 @@ function registerRuntimeTools(mcp) {
|
|
|
381
475
|
title: "Get Open Workbook capabilities",
|
|
382
476
|
description: "Return complete tool/resource/prompt catalog status and runtime capability metadata.",
|
|
383
477
|
inputSchema: {
|
|
384
|
-
includePreview: z.boolean().optional()
|
|
478
|
+
includePreview: z.boolean().optional(),
|
|
479
|
+
includeFullCatalog: z.boolean().optional()
|
|
385
480
|
},
|
|
386
481
|
annotations: {
|
|
387
482
|
readOnlyHint: true,
|
|
388
483
|
destructiveHint: false,
|
|
389
484
|
openWorldHint: false
|
|
390
485
|
}
|
|
391
|
-
}, async ({ includePreview }) => jsonResult(
|
|
486
|
+
}, async ({ includePreview, includeFullCatalog }) => jsonResult(runtimeCapabilities(includePreview, includeFullCatalog)));
|
|
392
487
|
registerMcpTool(mcp, "excel.runtime.get_active_context", {
|
|
393
488
|
title: "Get active Excel context",
|
|
394
489
|
description: "Return active workbook context from the connected Excel add-in.",
|
|
@@ -434,6 +529,44 @@ function registerRuntimeTools(mcp) {
|
|
|
434
529
|
}
|
|
435
530
|
}, async ({ sheetName }) => jsonResult(await runtime.setActiveSheet(sheetName)));
|
|
436
531
|
}
|
|
532
|
+
function runtimeCapabilities(includePreview, includeFullCatalog) {
|
|
533
|
+
const capabilities = runtime.getCapabilities(includePreview === undefined ? {} : { includePreview });
|
|
534
|
+
if (toolProfile === "full" || includeFullCatalog === true) {
|
|
535
|
+
return capabilities;
|
|
536
|
+
}
|
|
537
|
+
const typed = capabilities;
|
|
538
|
+
const catalog = typed.catalog;
|
|
539
|
+
const exposedToolNames = exposedProfileToolNames();
|
|
540
|
+
return {
|
|
541
|
+
...typed,
|
|
542
|
+
catalog: catalog
|
|
543
|
+
? {
|
|
544
|
+
total: catalog.total,
|
|
545
|
+
stable: catalog.stable,
|
|
546
|
+
preview: catalog.preview,
|
|
547
|
+
planned: catalog.planned,
|
|
548
|
+
unsupported: catalog.unsupported,
|
|
549
|
+
profile: toolProfile,
|
|
550
|
+
exposed: exposedToolNames.length,
|
|
551
|
+
tools: exposedToolNames
|
|
552
|
+
}
|
|
553
|
+
: undefined,
|
|
554
|
+
resources: Array.isArray(typed.resources) ? { count: typed.resources.length } : typed.resources,
|
|
555
|
+
prompts: Array.isArray(typed.prompts) ? { count: typed.prompts.length } : typed.prompts
|
|
556
|
+
};
|
|
557
|
+
}
|
|
558
|
+
function exposedProfileToolNames() {
|
|
559
|
+
if (explicitToolNames !== undefined) {
|
|
560
|
+
return [...explicitToolNames].filter((name) => shouldExposeMcpTool(name)).sort();
|
|
561
|
+
}
|
|
562
|
+
if (toolProfile === "compact") {
|
|
563
|
+
return [...COMPACT_PROFILE_TOOLS].filter((name) => shouldExposeMcpTool(name)).sort();
|
|
564
|
+
}
|
|
565
|
+
if (toolProfile === "read-only" || toolProfile === "readonly") {
|
|
566
|
+
return [...READ_ONLY_PROFILE_TOOLS].filter((name) => shouldExposeMcpTool(name)).sort();
|
|
567
|
+
}
|
|
568
|
+
return [];
|
|
569
|
+
}
|
|
437
570
|
function registerWorkbookTools(mcp) {
|
|
438
571
|
registerMcpTool(mcp, "excel.workbook.list_open_workbooks", {
|
|
439
572
|
title: "List open Excel workbooks",
|
|
@@ -2090,7 +2223,7 @@ async function workflowPreflight(workbookId, includePreview = true) {
|
|
|
2090
2223
|
return {
|
|
2091
2224
|
status,
|
|
2092
2225
|
activeContext,
|
|
2093
|
-
capabilities:
|
|
2226
|
+
capabilities: runtimeCapabilities(includePreview),
|
|
2094
2227
|
workbookMap: await runtime.getWorkbookMap(),
|
|
2095
2228
|
collaboration: runtime.getCollaborationStatus(resolvedWorkbookId),
|
|
2096
2229
|
workbookId: resolvedWorkbookId
|
|
@@ -4098,13 +4231,13 @@ function registerSnapshotTools(mcp) {
|
|
|
4098
4231
|
if (!existing.ok || !("snapshot" in existing)) {
|
|
4099
4232
|
return jsonResult(existing);
|
|
4100
4233
|
}
|
|
4101
|
-
return jsonResult(await runtime.createWorkbookSnapshot({
|
|
4234
|
+
return jsonResult(compactSnapshotCreationResult(await runtime.createWorkbookSnapshot({
|
|
4102
4235
|
workbookId: existing.snapshot.workbookId,
|
|
4103
4236
|
reason: args.reason ?? `Refresh snapshot ${args.snapshotId}`,
|
|
4104
4237
|
ranges: existing.snapshot.affectedRanges
|
|
4105
|
-
}));
|
|
4238
|
+
})));
|
|
4106
4239
|
}
|
|
4107
|
-
return jsonResult(await runtime.createWorkbookSnapshot(snapshotRequest(args.workbookId, args.reason, args.ranges)));
|
|
4240
|
+
return jsonResult(compactSnapshotCreationResult(await runtime.createWorkbookSnapshot(snapshotRequest(args.workbookId, args.reason, args.ranges))));
|
|
4108
4241
|
});
|
|
4109
4242
|
}
|
|
4110
4243
|
registerMcpTool(mcp, "excel.snapshot.get", {
|
|
@@ -4233,10 +4366,19 @@ function registerEventTools(mcp) {
|
|
|
4233
4366
|
function registerCompactTools(mcp) {
|
|
4234
4367
|
registerMcpTool(mcp, "excel.compact.get_resource", {
|
|
4235
4368
|
title: "Get compact detail resource",
|
|
4236
|
-
description: "Fetch
|
|
4237
|
-
inputSchema: {
|
|
4369
|
+
description: "Fetch stored compact detail metadata by default. Set includePayload only when full detail is required.",
|
|
4370
|
+
inputSchema: {
|
|
4371
|
+
resourceId: z.string().optional(),
|
|
4372
|
+
resourceUri: z.string().optional(),
|
|
4373
|
+
mode: z.enum(["metadata", "preview", "page", "full"]).optional(),
|
|
4374
|
+
includePayload: z.boolean().optional(),
|
|
4375
|
+
maxPayloadBytes: z.number().int().min(0).optional(),
|
|
4376
|
+
maxEstimatedTokens: z.number().int().min(0).optional(),
|
|
4377
|
+
offset: z.number().int().min(0).optional(),
|
|
4378
|
+
limit: z.number().int().min(1).max(24000).optional()
|
|
4379
|
+
},
|
|
4238
4380
|
annotations: { readOnlyHint: true, destructiveHint: false, openWorldHint: false }
|
|
4239
|
-
}, ({ resourceId, resourceUri }) => jsonResult(getCompactResource(resourceId ?? compactResourceIdFromUri(resourceUri ?? ""))));
|
|
4381
|
+
}, ({ resourceId, resourceUri, mode, includePayload, maxPayloadBytes, maxEstimatedTokens, offset, limit }) => jsonResult(getCompactResource(resourceId ?? compactResourceIdFromUri(resourceUri ?? ""), compactResourceReadOptions({ mode, includePayload, maxPayloadBytes, maxEstimatedTokens, offset, limit }))));
|
|
4240
4382
|
registerMcpTool(mcp, "excel.compact.list_resources", {
|
|
4241
4383
|
title: "List compact detail resources",
|
|
4242
4384
|
description: "List stored compact detail resources without returning their payloads.",
|
|
@@ -4412,12 +4554,85 @@ function storeCompactResource(kind, payload, title) {
|
|
|
4412
4554
|
}
|
|
4413
4555
|
return resource;
|
|
4414
4556
|
}
|
|
4415
|
-
function getCompactResource(resourceId) {
|
|
4557
|
+
function getCompactResource(resourceId, options = {}) {
|
|
4416
4558
|
const resource = compactResources.get(compactResourceIdFromUri(resourceId));
|
|
4417
4559
|
if (!resource) {
|
|
4418
4560
|
return { ok: false, error: { code: "COMPACT_RESOURCE_NOT_FOUND", message: "Compact detail resource was not found or has expired." } };
|
|
4419
4561
|
}
|
|
4420
|
-
|
|
4562
|
+
const { payload, ...summary } = resource;
|
|
4563
|
+
const mode = options.mode ?? (options.includePayload === true ? "full" : "metadata");
|
|
4564
|
+
if (mode === "metadata") {
|
|
4565
|
+
return {
|
|
4566
|
+
ok: true,
|
|
4567
|
+
...summary,
|
|
4568
|
+
payloadAvailable: true,
|
|
4569
|
+
payloadIncluded: false,
|
|
4570
|
+
message: "Use mode=preview or mode=page for bounded inspection, or mode=full/includePayload=true for full detail."
|
|
4571
|
+
};
|
|
4572
|
+
}
|
|
4573
|
+
if (mode === "preview" || mode === "page") {
|
|
4574
|
+
const serialized = JSON.stringify(payload, null, 2);
|
|
4575
|
+
const defaultLimit = mode === "preview" ? 4000 : COMPACT_DEFAULT_RESOURCE_THRESHOLD_BYTES;
|
|
4576
|
+
const limit = Math.max(1, Math.min(options.limit ?? defaultLimit, COMPACT_DEFAULT_RESOURCE_THRESHOLD_BYTES));
|
|
4577
|
+
const offset = Math.max(0, Math.min(options.offset ?? 0, serialized.length));
|
|
4578
|
+
const text = serialized.slice(offset, offset + limit);
|
|
4579
|
+
const nextOffset = offset + text.length < serialized.length ? offset + text.length : undefined;
|
|
4580
|
+
return {
|
|
4581
|
+
ok: true,
|
|
4582
|
+
...summary,
|
|
4583
|
+
payloadAvailable: true,
|
|
4584
|
+
payloadIncluded: false,
|
|
4585
|
+
mode,
|
|
4586
|
+
format: "json-text",
|
|
4587
|
+
offset,
|
|
4588
|
+
limit,
|
|
4589
|
+
text,
|
|
4590
|
+
textBytes: Buffer.byteLength(text, "utf8"),
|
|
4591
|
+
totalCharacters: serialized.length,
|
|
4592
|
+
totalBytes: Buffer.byteLength(serialized, "utf8"),
|
|
4593
|
+
...(nextOffset !== undefined ? { nextOffset } : {})
|
|
4594
|
+
};
|
|
4595
|
+
}
|
|
4596
|
+
const overBudget = (options.maxPayloadBytes !== undefined && resource.payloadBytes > options.maxPayloadBytes) ||
|
|
4597
|
+
(options.maxEstimatedTokens !== undefined && resource.estimatedTokens > options.maxEstimatedTokens);
|
|
4598
|
+
if (overBudget) {
|
|
4599
|
+
return {
|
|
4600
|
+
ok: true,
|
|
4601
|
+
...summary,
|
|
4602
|
+
payloadAvailable: true,
|
|
4603
|
+
payloadIncluded: false,
|
|
4604
|
+
budgetExceeded: true,
|
|
4605
|
+
warnings: [
|
|
4606
|
+
{
|
|
4607
|
+
code: "COMPACT_RESOURCE_BUDGET_EXCEEDED",
|
|
4608
|
+
message: "Stored detail exceeded the requested response budget. Raise the budget or inspect a smaller resource."
|
|
4609
|
+
}
|
|
4610
|
+
]
|
|
4611
|
+
};
|
|
4612
|
+
}
|
|
4613
|
+
return { ok: true, ...summary, payloadAvailable: true, payloadIncluded: true, payload };
|
|
4614
|
+
}
|
|
4615
|
+
function compactResourceReadOptions(options) {
|
|
4616
|
+
const normalized = {};
|
|
4617
|
+
if (options.mode !== undefined) {
|
|
4618
|
+
normalized.mode = options.mode;
|
|
4619
|
+
}
|
|
4620
|
+
if (options.includePayload !== undefined) {
|
|
4621
|
+
normalized.includePayload = options.includePayload;
|
|
4622
|
+
}
|
|
4623
|
+
if (options.maxPayloadBytes !== undefined) {
|
|
4624
|
+
normalized.maxPayloadBytes = options.maxPayloadBytes;
|
|
4625
|
+
}
|
|
4626
|
+
if (options.maxEstimatedTokens !== undefined) {
|
|
4627
|
+
normalized.maxEstimatedTokens = options.maxEstimatedTokens;
|
|
4628
|
+
}
|
|
4629
|
+
if (options.offset !== undefined) {
|
|
4630
|
+
normalized.offset = options.offset;
|
|
4631
|
+
}
|
|
4632
|
+
if (options.limit !== undefined) {
|
|
4633
|
+
normalized.limit = options.limit;
|
|
4634
|
+
}
|
|
4635
|
+
return normalized;
|
|
4421
4636
|
}
|
|
4422
4637
|
function listCompactResources(kind, limit = COMPACT_RESOURCE_LIMIT) {
|
|
4423
4638
|
const resources = [...compactResources.values()]
|
|
@@ -4622,17 +4837,13 @@ async function compactRangeRead(args) {
|
|
|
4622
4837
|
const sampleAddress = compactWindowAddress(args.address, sample.rowOffset, columnOffset, sample.rowCount, columnLimit);
|
|
4623
4838
|
const sampleResult = await readRangeSnapshot(args.workbookId, args.sheetName, sampleAddress, facets);
|
|
4624
4839
|
const sampleSnapshot = (sampleResult.data ?? [])[0]?.snapshot;
|
|
4840
|
+
const compactSnapshot = compactRangeSnapshotPayload(sampleSnapshot, facets);
|
|
4625
4841
|
return {
|
|
4626
4842
|
label: sample.label,
|
|
4627
4843
|
rowOffset: sample.rowOffset,
|
|
4628
4844
|
rowCount: sample.rowCount,
|
|
4629
4845
|
address: sampleAddress,
|
|
4630
|
-
|
|
4631
|
-
values: sampleSnapshot?.values,
|
|
4632
|
-
formulas: sampleSnapshot?.formulas,
|
|
4633
|
-
text: sampleSnapshot?.text,
|
|
4634
|
-
numberFormat: sampleSnapshot?.numberFormat,
|
|
4635
|
-
style: sampleSnapshot?.style,
|
|
4846
|
+
...compactSnapshot,
|
|
4636
4847
|
ok: sampleResult.ok,
|
|
4637
4848
|
warnings: sampleResult.warnings ?? []
|
|
4638
4849
|
};
|
|
@@ -4652,15 +4863,11 @@ async function compactRangeRead(args) {
|
|
|
4652
4863
|
return withCompactTelemetry({ ok: false, ...summary, source: result }, { detailLevel: "compact", truncated, nextPage, maxPayloadBytes: args.maxPayloadBytes, maxEstimatedTokens: args.maxEstimatedTokens, resourceKind: "read", resourceTitle: "Compact range read error", budgetSummary: { ok: false, ...summary } });
|
|
4653
4864
|
}
|
|
4654
4865
|
const snapshot = (result.data ?? [])[0]?.snapshot;
|
|
4866
|
+
const compactSnapshot = compactRangeSnapshotPayload(snapshot, facets);
|
|
4655
4867
|
return withCompactTelemetry({
|
|
4656
4868
|
ok: true,
|
|
4657
4869
|
...summary,
|
|
4658
|
-
|
|
4659
|
-
values: snapshot?.values,
|
|
4660
|
-
formulas: snapshot?.formulas,
|
|
4661
|
-
text: snapshot?.text,
|
|
4662
|
-
numberFormat: snapshot?.numberFormat,
|
|
4663
|
-
style: snapshot?.style,
|
|
4870
|
+
...compactSnapshot,
|
|
4664
4871
|
warnings: result.warnings ?? [],
|
|
4665
4872
|
telemetry: result.telemetry
|
|
4666
4873
|
}, {
|
|
@@ -4687,6 +4894,132 @@ async function tableSchema(selector) {
|
|
|
4687
4894
|
}, { detailLevel: "summary" });
|
|
4688
4895
|
});
|
|
4689
4896
|
}
|
|
4897
|
+
function compactRangeSnapshotPayload(snapshot, facets) {
|
|
4898
|
+
if (!snapshot || typeof snapshot !== "object") {
|
|
4899
|
+
return {};
|
|
4900
|
+
}
|
|
4901
|
+
const matrixEntries = [
|
|
4902
|
+
["values", snapshot.values],
|
|
4903
|
+
["formulas", snapshot.formulas],
|
|
4904
|
+
["text", snapshot.text],
|
|
4905
|
+
["numberFormat", snapshot.numberFormat],
|
|
4906
|
+
["style", snapshot.style]
|
|
4907
|
+
];
|
|
4908
|
+
const requestedEntries = matrixEntries.filter(([name, value]) => compactFacetOutputRequested(name, facets) && Array.isArray(value));
|
|
4909
|
+
const bounds = compactMatrixBounds(requestedEntries.map(([, value]) => value));
|
|
4910
|
+
const output = {};
|
|
4911
|
+
if (snapshot.fingerprint !== undefined) {
|
|
4912
|
+
output.fingerprint = snapshot.fingerprint;
|
|
4913
|
+
}
|
|
4914
|
+
for (const [name, value] of requestedEntries) {
|
|
4915
|
+
output[name] = trimMatrixToBounds(value, bounds);
|
|
4916
|
+
}
|
|
4917
|
+
if (bounds.sourceRows > bounds.rows || bounds.sourceColumns > bounds.columns) {
|
|
4918
|
+
output.omittedEmpty = {
|
|
4919
|
+
trailingRows: Math.max(0, bounds.sourceRows - bounds.rows),
|
|
4920
|
+
trailingColumns: Math.max(0, bounds.sourceColumns - bounds.columns),
|
|
4921
|
+
sourceRows: bounds.sourceRows,
|
|
4922
|
+
sourceColumns: bounds.sourceColumns,
|
|
4923
|
+
returnedRows: bounds.rows,
|
|
4924
|
+
returnedColumns: bounds.columns
|
|
4925
|
+
};
|
|
4926
|
+
}
|
|
4927
|
+
return output;
|
|
4928
|
+
}
|
|
4929
|
+
function compactFacetOutputRequested(name, facets) {
|
|
4930
|
+
if (name === "numberFormat") {
|
|
4931
|
+
return facets.includes("numberFormat");
|
|
4932
|
+
}
|
|
4933
|
+
if (name === "style") {
|
|
4934
|
+
return facets.includes("style");
|
|
4935
|
+
}
|
|
4936
|
+
return facets.includes(name);
|
|
4937
|
+
}
|
|
4938
|
+
function compactMatrixBounds(matrices) {
|
|
4939
|
+
const sourceRows = matrices.reduce((max, matrix) => Math.max(max, matrix.length), 0);
|
|
4940
|
+
const sourceColumns = matrices.reduce((max, matrix) => Math.max(max, ...matrix.map((row) => Array.isArray(row) ? row.length : 0)), 0);
|
|
4941
|
+
let lastRow = -1;
|
|
4942
|
+
let lastColumn = -1;
|
|
4943
|
+
for (const matrix of matrices) {
|
|
4944
|
+
for (let rowIndex = 0; rowIndex < matrix.length; rowIndex += 1) {
|
|
4945
|
+
const row = matrix[rowIndex];
|
|
4946
|
+
if (!Array.isArray(row)) {
|
|
4947
|
+
continue;
|
|
4948
|
+
}
|
|
4949
|
+
for (let columnIndex = 0; columnIndex < row.length; columnIndex += 1) {
|
|
4950
|
+
if (!isCompactEmptyCell(row[columnIndex])) {
|
|
4951
|
+
lastRow = Math.max(lastRow, rowIndex);
|
|
4952
|
+
lastColumn = Math.max(lastColumn, columnIndex);
|
|
4953
|
+
}
|
|
4954
|
+
}
|
|
4955
|
+
}
|
|
4956
|
+
}
|
|
4957
|
+
return {
|
|
4958
|
+
sourceRows,
|
|
4959
|
+
sourceColumns,
|
|
4960
|
+
rows: lastRow + 1,
|
|
4961
|
+
columns: lastColumn + 1
|
|
4962
|
+
};
|
|
4963
|
+
}
|
|
4964
|
+
function trimMatrixToBounds(matrix, bounds) {
|
|
4965
|
+
if (bounds.rows === 0 || bounds.columns === 0) {
|
|
4966
|
+
return [];
|
|
4967
|
+
}
|
|
4968
|
+
return matrix.slice(0, bounds.rows).map((row) => Array.isArray(row) ? row.slice(0, bounds.columns) : []);
|
|
4969
|
+
}
|
|
4970
|
+
function isCompactEmptyCell(value) {
|
|
4971
|
+
if (value === undefined || value === null || value === "") {
|
|
4972
|
+
return true;
|
|
4973
|
+
}
|
|
4974
|
+
if (Array.isArray(value)) {
|
|
4975
|
+
return value.every(isCompactEmptyCell);
|
|
4976
|
+
}
|
|
4977
|
+
if (typeof value === "object") {
|
|
4978
|
+
return Object.keys(value).length === 0;
|
|
4979
|
+
}
|
|
4980
|
+
return false;
|
|
4981
|
+
}
|
|
4982
|
+
function compactTablePayload(table) {
|
|
4983
|
+
if (!table || typeof table !== "object") {
|
|
4984
|
+
return {};
|
|
4985
|
+
}
|
|
4986
|
+
const matrixEntries = [
|
|
4987
|
+
["values", table.values],
|
|
4988
|
+
["formulas", table.formulas],
|
|
4989
|
+
["text", table.text],
|
|
4990
|
+
["numberFormat", table.numberFormat]
|
|
4991
|
+
];
|
|
4992
|
+
const requestedEntries = matrixEntries.filter(([, value]) => Array.isArray(value));
|
|
4993
|
+
const rowBounds = compactTableRowBounds(requestedEntries.map(([, value]) => value));
|
|
4994
|
+
const output = {};
|
|
4995
|
+
if (table.headers !== undefined) {
|
|
4996
|
+
output.headers = table.headers;
|
|
4997
|
+
}
|
|
4998
|
+
for (const [name, value] of requestedEntries) {
|
|
4999
|
+
output[name] = value.slice(0, rowBounds.rows);
|
|
5000
|
+
}
|
|
5001
|
+
if (rowBounds.sourceRows > rowBounds.rows) {
|
|
5002
|
+
output.omittedEmpty = {
|
|
5003
|
+
trailingRows: rowBounds.sourceRows - rowBounds.rows,
|
|
5004
|
+
sourceRows: rowBounds.sourceRows,
|
|
5005
|
+
returnedRows: rowBounds.rows
|
|
5006
|
+
};
|
|
5007
|
+
}
|
|
5008
|
+
return output;
|
|
5009
|
+
}
|
|
5010
|
+
function compactTableRowBounds(matrices) {
|
|
5011
|
+
const sourceRows = matrices.reduce((max, matrix) => Math.max(max, matrix.length), 0);
|
|
5012
|
+
let lastRow = -1;
|
|
5013
|
+
for (const matrix of matrices) {
|
|
5014
|
+
for (let rowIndex = 0; rowIndex < matrix.length; rowIndex += 1) {
|
|
5015
|
+
const row = matrix[rowIndex];
|
|
5016
|
+
if (Array.isArray(row) && row.some((cell) => !isCompactEmptyCell(cell))) {
|
|
5017
|
+
lastRow = Math.max(lastRow, rowIndex);
|
|
5018
|
+
}
|
|
5019
|
+
}
|
|
5020
|
+
}
|
|
5021
|
+
return { sourceRows, rows: lastRow + 1 };
|
|
5022
|
+
}
|
|
4690
5023
|
async function compactTableRead(args) {
|
|
4691
5024
|
const mode = args.mode ?? "window";
|
|
4692
5025
|
const schemaResult = await runtime.getTableInfo(tableSelector(args));
|
|
@@ -4727,16 +5060,13 @@ async function compactTableRead(args) {
|
|
|
4727
5060
|
rowLimit: sample.rowCount
|
|
4728
5061
|
});
|
|
4729
5062
|
const sampleTable = sampleResult.table;
|
|
5063
|
+
const compactTable = compactTablePayload(sampleTable);
|
|
4730
5064
|
return {
|
|
4731
5065
|
label: sample.label,
|
|
4732
5066
|
rowOffset: sample.rowOffset,
|
|
4733
5067
|
rowCount: sample.rowCount,
|
|
4734
5068
|
ok: sampleResult.ok,
|
|
4735
|
-
|
|
4736
|
-
values: sampleTable?.values,
|
|
4737
|
-
formulas: sampleTable?.formulas,
|
|
4738
|
-
text: sampleTable?.text,
|
|
4739
|
-
numberFormat: sampleTable?.numberFormat
|
|
5069
|
+
...compactTable
|
|
4740
5070
|
};
|
|
4741
5071
|
}));
|
|
4742
5072
|
return withCompactTelemetry({ ok: true, ...summary, samples }, {
|
|
@@ -4760,14 +5090,11 @@ async function compactTableRead(args) {
|
|
|
4760
5090
|
rowLimit
|
|
4761
5091
|
});
|
|
4762
5092
|
const table = result.table;
|
|
5093
|
+
const compactTable = compactTablePayload(table);
|
|
4763
5094
|
return withCompactTelemetry({
|
|
4764
5095
|
ok: Boolean(result.ok),
|
|
4765
5096
|
...summary,
|
|
4766
|
-
|
|
4767
|
-
values: table?.values,
|
|
4768
|
-
formulas: table?.formulas,
|
|
4769
|
-
text: table?.text,
|
|
4770
|
-
numberFormat: table?.numberFormat,
|
|
5097
|
+
...compactTable,
|
|
4771
5098
|
source: result.ok ? undefined : result
|
|
4772
5099
|
}, {
|
|
4773
5100
|
detailLevel: "compact",
|
|
@@ -5149,6 +5476,37 @@ function compactSnapshot(snapshotId, maxPayloadBytes, maxEstimatedTokens) {
|
|
|
5149
5476
|
budgetSummary: summary
|
|
5150
5477
|
});
|
|
5151
5478
|
}
|
|
5479
|
+
function compactSnapshotCreationResult(result) {
|
|
5480
|
+
if (toolProfile === "full") {
|
|
5481
|
+
return result;
|
|
5482
|
+
}
|
|
5483
|
+
const snapshot = result?.snapshot;
|
|
5484
|
+
if (!snapshot) {
|
|
5485
|
+
return result;
|
|
5486
|
+
}
|
|
5487
|
+
const summary = snapshotSummary(snapshot);
|
|
5488
|
+
const stored = storeCompactResource("snapshot", result, `Snapshot detail: ${summary.snapshotId}`);
|
|
5489
|
+
return withCompactTelemetry({
|
|
5490
|
+
ok: result.ok,
|
|
5491
|
+
snapshot: summary
|
|
5492
|
+
}, {
|
|
5493
|
+
detailLevel: "summary",
|
|
5494
|
+
resourceUri: stored.uri,
|
|
5495
|
+
resourceKind: "snapshot",
|
|
5496
|
+
resourceTitle: `Snapshot detail: ${summary.snapshotId}`
|
|
5497
|
+
});
|
|
5498
|
+
}
|
|
5499
|
+
function snapshotSummary(snapshot) {
|
|
5500
|
+
return {
|
|
5501
|
+
snapshotId: snapshot.snapshotId,
|
|
5502
|
+
workbookId: snapshot.workbookId,
|
|
5503
|
+
createdAt: snapshot.createdAt,
|
|
5504
|
+
reason: snapshot.reason,
|
|
5505
|
+
affectedRangeCount: snapshot.affectedRanges?.length ?? 0,
|
|
5506
|
+
affectedRanges: snapshot.affectedRanges,
|
|
5507
|
+
payloadRangeCount: snapshot.payload?.rangeSnapshots?.length ?? snapshot.rangeSnapshots?.length ?? 0
|
|
5508
|
+
};
|
|
5509
|
+
}
|
|
5152
5510
|
function compactSnapshotDiff(leftSnapshotId, rightSnapshotId, maxPayloadBytes, maxEstimatedTokens) {
|
|
5153
5511
|
const result = runtime.compareSnapshots(leftSnapshotId, rightSnapshotId);
|
|
5154
5512
|
const diff = result.diff;
|
|
@@ -6241,7 +6599,7 @@ function escapeHtml(value) {
|
|
|
6241
6599
|
return value.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">");
|
|
6242
6600
|
}
|
|
6243
6601
|
function registerMcpTool(mcp, name, config, callback) {
|
|
6244
|
-
if (!
|
|
6602
|
+
if (!shouldExposeMcpTool(name)) {
|
|
6245
6603
|
return;
|
|
6246
6604
|
}
|
|
6247
6605
|
mcp.registerTool(name, config, async (args, extra) => {
|
|
@@ -6250,9 +6608,75 @@ function registerMcpTool(mcp, name, config, callback) {
|
|
|
6250
6608
|
if (isWorkbookMutatingMcpTool(name)) {
|
|
6251
6609
|
clearCompactCache(`mutation:${name}`);
|
|
6252
6610
|
}
|
|
6253
|
-
return decorated;
|
|
6611
|
+
return enforceCompactResultBudget(name, decorated);
|
|
6254
6612
|
});
|
|
6255
6613
|
}
|
|
6614
|
+
function enforceCompactResultBudget(toolName, result) {
|
|
6615
|
+
if (toolProfile === "full" || !isJsonTextResult(result)) {
|
|
6616
|
+
return result;
|
|
6617
|
+
}
|
|
6618
|
+
if (toolName === "excel.compact.get_resource") {
|
|
6619
|
+
return result;
|
|
6620
|
+
}
|
|
6621
|
+
const payloadBytes = Buffer.byteLength(result.content[0].text, "utf8");
|
|
6622
|
+
if (payloadBytes <= COMPACT_DEFAULT_RESOURCE_THRESHOLD_BYTES) {
|
|
6623
|
+
return result;
|
|
6624
|
+
}
|
|
6625
|
+
try {
|
|
6626
|
+
const payload = JSON.parse(result.content[0].text);
|
|
6627
|
+
if (payload.resourceUri !== undefined && payload.budgetExceeded === true) {
|
|
6628
|
+
return result;
|
|
6629
|
+
}
|
|
6630
|
+
const stored = storeCompactResource(compactResourceKindForTool(toolName), payload, `Full result: ${toolName}`);
|
|
6631
|
+
const summary = compactResultSummary(toolName, payload, payloadBytes, stored);
|
|
6632
|
+
return jsonResult(summary);
|
|
6633
|
+
}
|
|
6634
|
+
catch {
|
|
6635
|
+
const stored = storeCompactResource("generic", result.content[0].text, `Full text result: ${toolName}`);
|
|
6636
|
+
return jsonResult({
|
|
6637
|
+
ok: true,
|
|
6638
|
+
toolName,
|
|
6639
|
+
detailLevel: "summary",
|
|
6640
|
+
budgetExceeded: true,
|
|
6641
|
+
payloadBytes,
|
|
6642
|
+
estimatedTokens: Math.ceil(payloadBytes / 4),
|
|
6643
|
+
resourcePayloadBytes: stored.payloadBytes,
|
|
6644
|
+
resourceEstimatedTokens: stored.estimatedTokens,
|
|
6645
|
+
resourceUri: stored.uri,
|
|
6646
|
+
warnings: [
|
|
6647
|
+
{
|
|
6648
|
+
code: "COMPACT_RESULT_BUDGET_EXCEEDED",
|
|
6649
|
+
message: "Tool result exceeded compact response budget and was stored behind resourceUri."
|
|
6650
|
+
}
|
|
6651
|
+
]
|
|
6652
|
+
});
|
|
6653
|
+
}
|
|
6654
|
+
}
|
|
6655
|
+
function shouldExposeMcpTool(name) {
|
|
6656
|
+
if (!isToolExposed(name, catalogOptions)) {
|
|
6657
|
+
return false;
|
|
6658
|
+
}
|
|
6659
|
+
if (explicitToolNames !== undefined && !explicitToolNames.has(name)) {
|
|
6660
|
+
return false;
|
|
6661
|
+
}
|
|
6662
|
+
if (disabledToolNames?.has(name)) {
|
|
6663
|
+
return false;
|
|
6664
|
+
}
|
|
6665
|
+
if (explicitToolNames !== undefined) {
|
|
6666
|
+
return true;
|
|
6667
|
+
}
|
|
6668
|
+
if (toolProfile === "full") {
|
|
6669
|
+
return true;
|
|
6670
|
+
}
|
|
6671
|
+
if (toolProfile === "compact") {
|
|
6672
|
+
return COMPACT_PROFILE_TOOLS.has(name);
|
|
6673
|
+
}
|
|
6674
|
+
if (toolProfile === "read-only" || toolProfile === "readonly") {
|
|
6675
|
+
return READ_ONLY_PROFILE_TOOLS.has(name);
|
|
6676
|
+
}
|
|
6677
|
+
console.error(`Unknown OPEN_WORKBOOK_TOOL_PROFILE=${toolProfile}; falling back to full MCP tool surface.`);
|
|
6678
|
+
return true;
|
|
6679
|
+
}
|
|
6256
6680
|
function jsonResult(value) {
|
|
6257
6681
|
return {
|
|
6258
6682
|
content: [
|
|
@@ -6294,9 +6718,18 @@ function addCompactMutationProof(result) {
|
|
|
6294
6718
|
if (payload.compactProof !== undefined) {
|
|
6295
6719
|
return result;
|
|
6296
6720
|
}
|
|
6721
|
+
const compactProof = summarizeMutationProof(payload);
|
|
6722
|
+
if (toolProfile === "full") {
|
|
6723
|
+
return jsonResult({
|
|
6724
|
+
...payload,
|
|
6725
|
+
compactProof
|
|
6726
|
+
});
|
|
6727
|
+
}
|
|
6728
|
+
const stored = storeCompactResource("mutation", payload, "Full mutation result");
|
|
6297
6729
|
return jsonResult({
|
|
6298
|
-
...payload,
|
|
6299
|
-
compactProof
|
|
6730
|
+
...compactMutationPayload(payload),
|
|
6731
|
+
compactProof,
|
|
6732
|
+
resourceUri: stored.uri
|
|
6300
6733
|
});
|
|
6301
6734
|
}
|
|
6302
6735
|
catch {
|
|
@@ -6333,6 +6766,196 @@ function summarizeMutationProof(payload) {
|
|
|
6333
6766
|
estimatedTokens: Math.ceil(Buffer.byteLength(JSON.stringify(payload), "utf8") / 4)
|
|
6334
6767
|
};
|
|
6335
6768
|
}
|
|
6769
|
+
function compactMutationPayload(payload) {
|
|
6770
|
+
const output = {};
|
|
6771
|
+
for (const [key, value] of Object.entries(payload)) {
|
|
6772
|
+
if (key === "beforeSnapshot" || key === "afterSnapshot") {
|
|
6773
|
+
output[key] = value && typeof value === "object" ? snapshotSummary(value) : value;
|
|
6774
|
+
continue;
|
|
6775
|
+
}
|
|
6776
|
+
if (key === "backup") {
|
|
6777
|
+
output[key] = summarizeBackup(value);
|
|
6778
|
+
continue;
|
|
6779
|
+
}
|
|
6780
|
+
if (key === "diff") {
|
|
6781
|
+
output[key] = summarizeDiffResult(value);
|
|
6782
|
+
continue;
|
|
6783
|
+
}
|
|
6784
|
+
if (key === "planPreview") {
|
|
6785
|
+
output[key] = summarizePlanPreview(value);
|
|
6786
|
+
continue;
|
|
6787
|
+
}
|
|
6788
|
+
if (key === "applyResult") {
|
|
6789
|
+
output[key] = summarizeOperationResult(value);
|
|
6790
|
+
continue;
|
|
6791
|
+
}
|
|
6792
|
+
if (key === "beforeSnapshotResult") {
|
|
6793
|
+
output[key] = summarizeOperationResult(value);
|
|
6794
|
+
continue;
|
|
6795
|
+
}
|
|
6796
|
+
output[key] = value;
|
|
6797
|
+
}
|
|
6798
|
+
return output;
|
|
6799
|
+
}
|
|
6800
|
+
function summarizeBackup(value) {
|
|
6801
|
+
if (!value || typeof value !== "object") {
|
|
6802
|
+
return value;
|
|
6803
|
+
}
|
|
6804
|
+
const record = value;
|
|
6805
|
+
return {
|
|
6806
|
+
backupId: record.backupId,
|
|
6807
|
+
workbookId: record.workbookId,
|
|
6808
|
+
kind: record.kind,
|
|
6809
|
+
reason: record.reason,
|
|
6810
|
+
createdAt: record.createdAt,
|
|
6811
|
+
affectedRangeCount: record.affectedRanges?.length ?? 0,
|
|
6812
|
+
affectedRanges: record.affectedRanges,
|
|
6813
|
+
payloadRef: record.payloadRef
|
|
6814
|
+
};
|
|
6815
|
+
}
|
|
6816
|
+
function summarizeDiffResult(value) {
|
|
6817
|
+
if (!value || typeof value !== "object") {
|
|
6818
|
+
return value;
|
|
6819
|
+
}
|
|
6820
|
+
const record = value;
|
|
6821
|
+
const diff = record.diff ?? record;
|
|
6822
|
+
return {
|
|
6823
|
+
ok: record.ok,
|
|
6824
|
+
diffId: record.diffId,
|
|
6825
|
+
summary: diff.summary ?? {
|
|
6826
|
+
title: diff.title,
|
|
6827
|
+
changedRanges: Array.isArray(diff.changedRanges) ? diff.changedRanges.slice(0, 20) : undefined,
|
|
6828
|
+
changedRangesTruncated: Array.isArray(diff.changedRanges) && diff.changedRanges.length > 20,
|
|
6829
|
+
cellsChanged: diff.cellsChanged,
|
|
6830
|
+
formulasChanged: diff.formulasChanged,
|
|
6831
|
+
stylesChanged: diff.stylesChanged,
|
|
6832
|
+
tablesChanged: diff.tablesChanged,
|
|
6833
|
+
sheetsChanged: diff.sheetsChanged,
|
|
6834
|
+
destructiveLevel: diff.destructiveLevel
|
|
6835
|
+
}
|
|
6836
|
+
};
|
|
6837
|
+
}
|
|
6838
|
+
function summarizePlanPreview(value) {
|
|
6839
|
+
if (!value || typeof value !== "object") {
|
|
6840
|
+
return value;
|
|
6841
|
+
}
|
|
6842
|
+
const record = value;
|
|
6843
|
+
return {
|
|
6844
|
+
ok: record.ok,
|
|
6845
|
+
planId: record.planId,
|
|
6846
|
+
operationCount: record.operationCount ?? record.operations?.length,
|
|
6847
|
+
requiredBackupCount: record.requiredBackups?.length ?? 0,
|
|
6848
|
+
requiredBackups: record.requiredBackups,
|
|
6849
|
+
diffSummary: record.diffSummary ?? summarizeDiffResult(record.diff),
|
|
6850
|
+
confirmationRequired: record.confirmationRequired,
|
|
6851
|
+
confirmationToken: record.confirmationToken,
|
|
6852
|
+
warnings: Array.isArray(record.warnings) ? record.warnings.length : record.warnings
|
|
6853
|
+
};
|
|
6854
|
+
}
|
|
6855
|
+
function summarizeOperationResult(value) {
|
|
6856
|
+
if (!value || typeof value !== "object") {
|
|
6857
|
+
return value;
|
|
6858
|
+
}
|
|
6859
|
+
const record = value;
|
|
6860
|
+
return {
|
|
6861
|
+
ok: record.ok,
|
|
6862
|
+
transactionId: record.transactionId,
|
|
6863
|
+
transactionStatus: record.transactionStatus,
|
|
6864
|
+
rollbackAvailable: record.rollbackAvailable,
|
|
6865
|
+
backups: record.backups,
|
|
6866
|
+
backup: summarizeBackup(record.backup),
|
|
6867
|
+
warnings: Array.isArray(record.warnings) ? record.warnings.length : record.warnings,
|
|
6868
|
+
telemetry: record.telemetry,
|
|
6869
|
+
error: record.error
|
|
6870
|
+
};
|
|
6871
|
+
}
|
|
6872
|
+
function compactResourceKindForTool(toolName) {
|
|
6873
|
+
if (toolName.includes(".snapshot.")) {
|
|
6874
|
+
return "snapshot";
|
|
6875
|
+
}
|
|
6876
|
+
if (toolName.includes(".diff.")) {
|
|
6877
|
+
return "diff";
|
|
6878
|
+
}
|
|
6879
|
+
if (toolName.includes(".validate.")) {
|
|
6880
|
+
return "validation";
|
|
6881
|
+
}
|
|
6882
|
+
if (isWorkbookMutatingMcpTool(toolName)) {
|
|
6883
|
+
return "mutation";
|
|
6884
|
+
}
|
|
6885
|
+
if (toolName.includes(".read") || toolName.includes(".lookup.") || toolName.includes(".summary") || toolName.includes(".schema")) {
|
|
6886
|
+
return "read";
|
|
6887
|
+
}
|
|
6888
|
+
return "generic";
|
|
6889
|
+
}
|
|
6890
|
+
function compactResultSummary(toolName, payload, payloadBytes, stored) {
|
|
6891
|
+
return {
|
|
6892
|
+
ok: payload.ok ?? true,
|
|
6893
|
+
toolName,
|
|
6894
|
+
detailLevel: "summary",
|
|
6895
|
+
budgetExceeded: true,
|
|
6896
|
+
payloadBytes: Math.min(payloadBytes, COMPACT_DEFAULT_RESOURCE_THRESHOLD_BYTES),
|
|
6897
|
+
estimatedTokens: Math.ceil(Math.min(payloadBytes, COMPACT_DEFAULT_RESOURCE_THRESHOLD_BYTES) / 4),
|
|
6898
|
+
resourcePayloadBytes: stored.payloadBytes,
|
|
6899
|
+
resourceEstimatedTokens: stored.estimatedTokens,
|
|
6900
|
+
resourceUri: stored.uri,
|
|
6901
|
+
summary: summarizePayloadForBudget(payload),
|
|
6902
|
+
warnings: [
|
|
6903
|
+
...asWarningArray(payload.warnings),
|
|
6904
|
+
{
|
|
6905
|
+
code: "COMPACT_RESULT_BUDGET_EXCEEDED",
|
|
6906
|
+
message: "Tool result exceeded compact response budget and was stored behind resourceUri."
|
|
6907
|
+
}
|
|
6908
|
+
]
|
|
6909
|
+
};
|
|
6910
|
+
}
|
|
6911
|
+
function summarizePayloadForBudget(payload) {
|
|
6912
|
+
return {
|
|
6913
|
+
transactionId: payload.transactionId,
|
|
6914
|
+
transactionStatus: payload.transactionStatus,
|
|
6915
|
+
taskId: payload.taskId,
|
|
6916
|
+
rollbackAvailable: payload.rollbackAvailable,
|
|
6917
|
+
backups: payload.backups,
|
|
6918
|
+
backup: summarizeBackup(payload.backup),
|
|
6919
|
+
snapshot: payload.snapshot && typeof payload.snapshot === "object" ? snapshotSummary(payload.snapshot) : undefined,
|
|
6920
|
+
diffSummary: payload.diffSummary ?? summarizeDiffResult(payload.diff),
|
|
6921
|
+
compactProof: payload.compactProof,
|
|
6922
|
+
telemetry: payload.telemetry,
|
|
6923
|
+
validation: validationSummary(payload),
|
|
6924
|
+
table: summarizeTablePayload(payload.table),
|
|
6925
|
+
source: summarizeSourcePayload(payload)
|
|
6926
|
+
};
|
|
6927
|
+
}
|
|
6928
|
+
function summarizeTablePayload(value) {
|
|
6929
|
+
if (!value || typeof value !== "object") {
|
|
6930
|
+
return undefined;
|
|
6931
|
+
}
|
|
6932
|
+
const table = value;
|
|
6933
|
+
return {
|
|
6934
|
+
info: table.info
|
|
6935
|
+
? {
|
|
6936
|
+
workbookId: table.info.workbookId,
|
|
6937
|
+
tableName: table.info.tableName,
|
|
6938
|
+
rowCount: table.info.rowCount,
|
|
6939
|
+
columnCount: table.info.columnCount
|
|
6940
|
+
}
|
|
6941
|
+
: undefined,
|
|
6942
|
+
headerCount: Array.isArray(table.headers?.[0]) ? table.headers[0].length : undefined,
|
|
6943
|
+
rowCount: Array.isArray(table.values) ? table.values.length : undefined,
|
|
6944
|
+
hasValues: Array.isArray(table.values),
|
|
6945
|
+
hasFormulas: Array.isArray(table.formulas),
|
|
6946
|
+
hasText: Array.isArray(table.text),
|
|
6947
|
+
hasNumberFormat: Array.isArray(table.numberFormat)
|
|
6948
|
+
};
|
|
6949
|
+
}
|
|
6950
|
+
function summarizeSourcePayload(payload) {
|
|
6951
|
+
if (Array.isArray(payload.data)) {
|
|
6952
|
+
return {
|
|
6953
|
+
dataCount: payload.data.length,
|
|
6954
|
+
snapshotCount: payload.data.filter((item) => Boolean(item.snapshot)).length
|
|
6955
|
+
};
|
|
6956
|
+
}
|
|
6957
|
+
return undefined;
|
|
6958
|
+
}
|
|
6336
6959
|
function validationSummary(payload) {
|
|
6337
6960
|
const issueCount = typeof payload.issueCount === "number" ? payload.issueCount : undefined;
|
|
6338
6961
|
const issues = Array.isArray(payload.issues) ? payload.issues : undefined;
|
|
@@ -6382,6 +7005,16 @@ function readArg(name) {
|
|
|
6382
7005
|
}
|
|
6383
7006
|
return undefined;
|
|
6384
7007
|
}
|
|
7008
|
+
function parseToolNameList(value) {
|
|
7009
|
+
if (value === undefined || value.trim() === "") {
|
|
7010
|
+
return undefined;
|
|
7011
|
+
}
|
|
7012
|
+
const names = value
|
|
7013
|
+
.split(",")
|
|
7014
|
+
.map((item) => item.trim())
|
|
7015
|
+
.filter(Boolean);
|
|
7016
|
+
return names.length > 0 ? new Set(names) : undefined;
|
|
7017
|
+
}
|
|
6385
7018
|
function trimTrailingSlash(value) {
|
|
6386
7019
|
return value.endsWith("/") ? value.slice(0, -1) : value;
|
|
6387
7020
|
}
|