@cyanheads/nasa-power-mcp-server 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (83) hide show
  1. package/AGENTS.md +2 -2
  2. package/CLAUDE.md +2 -2
  3. package/README.md +9 -5
  4. package/changelog/0.4.x/0.4.1.md +20 -0
  5. package/changelog/0.4.x/0.4.2.md +16 -0
  6. package/dist/config/server-config.d.ts +29 -0
  7. package/dist/config/server-config.d.ts.map +1 -1
  8. package/dist/config/server-config.js +29 -0
  9. package/dist/config/server-config.js.map +1 -1
  10. package/dist/mcp-server/tools/definitions/comparison-contracts.d.ts.map +1 -1
  11. package/dist/mcp-server/tools/definitions/comparison-contracts.js +10 -4
  12. package/dist/mcp-server/tools/definitions/comparison-contracts.js.map +1 -1
  13. package/dist/mcp-server/tools/definitions/nasa-power-compare-locations.tool.d.ts +17 -3
  14. package/dist/mcp-server/tools/definitions/nasa-power-compare-locations.tool.d.ts.map +1 -1
  15. package/dist/mcp-server/tools/definitions/nasa-power-compare-locations.tool.js +19 -3
  16. package/dist/mcp-server/tools/definitions/nasa-power-compare-locations.tool.js.map +1 -1
  17. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-describe.tool.d.ts +3 -3
  18. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-describe.tool.d.ts.map +1 -1
  19. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-describe.tool.js +3 -3
  20. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-describe.tool.js.map +1 -1
  21. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-drop.tool.d.ts +3 -3
  22. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-drop.tool.d.ts.map +1 -1
  23. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-drop.tool.js +3 -3
  24. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-drop.tool.js.map +1 -1
  25. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-query.tool.d.ts +3 -3
  26. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-query.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-query.tool.js +3 -3
  28. package/dist/mcp-server/tools/definitions/nasa-power-dataframe-query.tool.js.map +1 -1
  29. package/dist/mcp-server/tools/definitions/nasa-power-get-climatology.tool.d.ts +37 -3
  30. package/dist/mcp-server/tools/definitions/nasa-power-get-climatology.tool.d.ts.map +1 -1
  31. package/dist/mcp-server/tools/definitions/nasa-power-get-climatology.tool.js +20 -4
  32. package/dist/mcp-server/tools/definitions/nasa-power-get-climatology.tool.js.map +1 -1
  33. package/dist/mcp-server/tools/definitions/nasa-power-get-region.tool.d.ts +17 -3
  34. package/dist/mcp-server/tools/definitions/nasa-power-get-region.tool.d.ts.map +1 -1
  35. package/dist/mcp-server/tools/definitions/nasa-power-get-region.tool.js +26 -6
  36. package/dist/mcp-server/tools/definitions/nasa-power-get-region.tool.js.map +1 -1
  37. package/dist/mcp-server/tools/definitions/nasa-power-get-timeseries.tool.d.ts +37 -3
  38. package/dist/mcp-server/tools/definitions/nasa-power-get-timeseries.tool.d.ts.map +1 -1
  39. package/dist/mcp-server/tools/definitions/nasa-power-get-timeseries.tool.js +20 -4
  40. package/dist/mcp-server/tools/definitions/nasa-power-get-timeseries.tool.js.map +1 -1
  41. package/dist/mcp-server/tools/definitions/nasa-power-list-reference.tool.js +3 -3
  42. package/dist/mcp-server/tools/definitions/nasa-power-list-reference.tool.js.map +1 -1
  43. package/dist/mcp-server/tools/definitions/nasa-power-search-parameters.tool.d.ts.map +1 -1
  44. package/dist/mcp-server/tools/definitions/nasa-power-search-parameters.tool.js +14 -5
  45. package/dist/mcp-server/tools/definitions/nasa-power-search-parameters.tool.js.map +1 -1
  46. package/dist/mcp-server/tools/definitions/point-contracts.d.ts +22 -2
  47. package/dist/mcp-server/tools/definitions/point-contracts.d.ts.map +1 -1
  48. package/dist/mcp-server/tools/definitions/point-contracts.js +16 -6
  49. package/dist/mcp-server/tools/definitions/point-contracts.js.map +1 -1
  50. package/dist/services/canvas/canvas-service.d.ts +59 -6
  51. package/dist/services/canvas/canvas-service.d.ts.map +1 -1
  52. package/dist/services/canvas/canvas-service.js +172 -42
  53. package/dist/services/canvas/canvas-service.js.map +1 -1
  54. package/dist/services/canvas/errors.d.ts +12 -3
  55. package/dist/services/canvas/errors.d.ts.map +1 -1
  56. package/dist/services/canvas/errors.js +25 -5
  57. package/dist/services/canvas/errors.js.map +1 -1
  58. package/dist/services/canvas/inline-split.d.ts +73 -0
  59. package/dist/services/canvas/inline-split.d.ts.map +1 -0
  60. package/dist/services/canvas/inline-split.js +358 -0
  61. package/dist/services/canvas/inline-split.js.map +1 -0
  62. package/dist/services/canvas/producer-estimate.d.ts +13 -0
  63. package/dist/services/canvas/producer-estimate.d.ts.map +1 -0
  64. package/dist/services/canvas/producer-estimate.js +82 -0
  65. package/dist/services/canvas/producer-estimate.js.map +1 -0
  66. package/dist/services/power/normalize.d.ts.map +1 -1
  67. package/dist/services/power/normalize.js +4 -10
  68. package/dist/services/power/normalize.js.map +1 -1
  69. package/dist/services/power/power-service.d.ts +18 -2
  70. package/dist/services/power/power-service.d.ts.map +1 -1
  71. package/dist/services/power/power-service.js +89 -52
  72. package/dist/services/power/power-service.js.map +1 -1
  73. package/dist/services/power/presets.d.ts +7 -2
  74. package/dist/services/power/presets.d.ts.map +1 -1
  75. package/dist/services/power/presets.js +27 -2
  76. package/dist/services/power/presets.js.map +1 -1
  77. package/dist/services/power/unserved-parameters.d.ts +11 -0
  78. package/dist/services/power/unserved-parameters.d.ts.map +1 -0
  79. package/dist/services/power/unserved-parameters.js +47 -0
  80. package/dist/services/power/unserved-parameters.js.map +1 -0
  81. package/package.json +1 -1
  82. package/server.json +3 -3
  83. package/skills/nasa-power-guide/SKILL.md +10 -10
@@ -1 +1 @@
1
- {"version":3,"file":"nasa-power-search-parameters.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/nasa-power-search-parameters.tool.ts"],"names":[],"mappings":"AAAA,6IAA6I;AAC7I,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AACjE,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC;AAC/D,OAAO,EACL,eAAe,EACf,qBAAqB,EACrB,eAAe,EACf,wBAAwB,EACxB,gBAAgB,GACjB,MAAM,2BAA2B,CAAC;AAEnC,MAAM,iBAAiB,GAAG,qBAAqB,CAAC,MAAM,CAAC;IACrD,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,6BAA6B,CAAC;CACzD,CAAC,CAAC;AAEH,iEAAiE;AACjE,MAAM,CAAC,MAAM,oBAAoB,GAAG,IAAI,CAAC,8BAA8B,EAAE;IACvE,KAAK,EAAE,8BAA8B;IACrC,WAAW,EACT,+SAA+S;IACjT,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAC9E,KAAK,EAAE,CAAC,CAAC,YAAY,CAAC;QACpB,SAAS,EAAE,eAAe,CAAC,OAAO,CAAC,IAAI,CAAC;QACxC,kBAAkB,EAAE,gBAAgB,CAAC,OAAO,CAAC,OAAO,CAAC;QACrD,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,GAAG,CAAC,GAAG,CAAC;aACR,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,0DAA0D,CAAC;QACvE,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,OAAO,CAAC,CAAC,CAAC;aACV,QAAQ,CAAC,+CAA+C,CAAC;QAC5D,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CAAC,4EAA4E,CAAC;KAC1F,CAAC;IACF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,SAAS,EAAE,eAAe;QAC1B,kBAAkB,EAAE,gBAAgB;QACpC,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8BAA8B,CAAC;QAC3D,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2BAA2B,CAAC;QACxD,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAC1E,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;QAC1E,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,uCAAuC,CAAC;QACtE,SAAS,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;QAClF,OAAO,EAAE,CAAC;aACP,KAAK,CAAC,iBAAiB,CAAC,QAAQ,CAAC,sCAAsC,CAAC,CAAC;aACzE,QAAQ,CAAC,kCAAkC,CAAC;KAChD,CAAC;IACF,UAAU,EAAE;QACV,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CAAC,0EAA0E,CAAC;KACxF;IACD,MAAM,EAAE;QACN;YACE,MAAM,EAAE,uBAAuB;YAC/B,IAAI,EAAE,gBAAgB,CAAC,WAAW;YAClC,IAAI,EAAE,uCAAuC;YAC7C,QAAQ,EACN,0GAA0G;YAC5G,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,SAAS;SACpB;QACD;YACE,MAAM,EAAE,oBAAoB;YAC5B,IAAI,EAAE,gBAAgB,CAAC,WAAW;YAClC,IAAI,EAAE,yCAAyC;YAC/C,QAAQ,EAAE,oEAAoE;YAC9E,SAAS,EAAE,IAAI;YACf,QAAQ,EAAE,SAAS;SACpB;QACD;YACE,MAAM,EAAE,eAAe;YACvB,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,2DAA2D;YACjE,QAAQ,EAAE,wBAAwB;YAClC,QAAQ,EAAE,SAAS;SACpB;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,eAAe;YACtC,IAAI,EAAE,mCAAmC;YACzC,QAAQ,EACN,8IAA8I;YAChJ,QAAQ,EAAE,SAAS;SACpB;KACF;IACD,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACzC,MAAM,UAAU,GAAG,MAAM,eAAe,EAAE,CAAC,UAAU,CACnD,KAAK,CAAC,SAAS,EACf,KAAK,CAAC,kBAAkB,EACxB,GAAG,CACJ,CAAC;QACF,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACvE,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC;aACvC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE;YACxB,MAAM,IAAI,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,EAAE,KAAK,CAAC,UAAU,CAAC;iBAC9C,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,KAAK,SAAS,CAAC;iBACtC,IAAI,CAAC,GAAG,CAAC;iBACT,WAAW,EAAE,CAAC;YACjB,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;QACvD,CAAC,CAAC;aACD,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,aAAa,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,GAAG,CAAC,MAAM,CAAC,cAAc,EAAE,CAAC;QAC5B,MAAM,OAAO,GAAa,EAAE,CAAC;QAC7B,IAAI,KAAK,CAAC,KAAK,GAAG,KAAK;YACrB,OAAO,CAAC,IAAI,CAAC,uEAAuE,CAAC,CAAC;QACxF,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YACtB,OAAO,CAAC,IAAI,CACV,sJAAsJ,CACvJ,CAAC;QACJ,IAAI,OAAO,CAAC,MAAM;YAAE,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACzD,OAAO;YACL,GAAG,KAAK;YACR,KAAK;YACL,KAAK,EAAE,OAAO,CAAC,MAAM;YACrB,OAAO,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM;YAC9C,SAAS,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,GAAG,OAAO,CAAC,MAAM;YAChD,OAAO,EAAE,OAAO;iBACb,KAAK,CAAC,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,MAAM,GAAG,KAAK,CAAC;iBACzC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,KAAK,CAAC,EAAE,GAAG,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;SACvE,CAAC;IACJ,CAAC;IACD,MAAM,EAAE,gBAAgB;CACzB,CAAC,CAAC"}
1
+ {"version":3,"file":"nasa-power-search-parameters.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/nasa-power-search-parameters.tool.ts"],"names":[],"mappings":"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"}
@@ -2,7 +2,7 @@
2
2
  import type { Context } from '@cyanheads/mcp-ts-core';
3
3
  import { z } from '@cyanheads/mcp-ts-core';
4
4
  import { type PowerRequest } from '../../../services/power/index.js';
5
- /** Full scientific envelope with exact row count and optional staged pointer. */
5
+ /** Full scientific envelope with exact row count and optional staged pointers. */
6
6
  export declare const PointOutputSchema: z.ZodObject<{
7
7
  request: z.ZodObject<{
8
8
  community: z.ZodDefault<z.ZodEnum<{
@@ -175,7 +175,27 @@ export declare const PointOutputSchema: z.ZodObject<{
175
175
  describeTool: z.ZodLiteral<"nasa_power_dataframe_describe">;
176
176
  queryTool: z.ZodLiteral<"nasa_power_dataframe_query">;
177
177
  }, z.core.$strip>>;
178
+ summaryCount: z.ZodOptional<z.ZodNumber>;
179
+ summaryDataset: z.ZodOptional<z.ZodObject<{
180
+ canvas_id: z.ZodString;
181
+ table: z.ZodString;
182
+ rowCount: z.ZodNumber;
183
+ expiresAt: z.ZodString;
184
+ columns: z.ZodArray<z.ZodObject<{
185
+ name: z.ZodString;
186
+ type: z.ZodString;
187
+ nullable: z.ZodBoolean;
188
+ units: z.ZodOptional<z.ZodString>;
189
+ valueKind: z.ZodOptional<z.ZodEnum<{
190
+ categorical: "categorical";
191
+ number: "number";
192
+ orientation: "orientation";
193
+ }>>;
194
+ }, z.core.$strip>>;
195
+ describeTool: z.ZodLiteral<"nasa_power_dataframe_describe">;
196
+ queryTool: z.ZodLiteral<"nasa_power_dataframe_query">;
197
+ }, z.core.$strip>>;
178
198
  }, z.core.$strip>;
179
- /** Source retrieval and presentation share one producer reservation and deadline signal. */
199
+ /** Source retrieval and presentation share one producer reservation and the deadline started at tool entry. */
180
200
  export declare function presentPoint(request: PowerRequest, canvasId: string | undefined, ctx: Context, sourceTool: string): Promise<import("../../../services/canvas/index.js").PresentedDataset<import("../../../services/power/index.js").PowerDataset>>;
181
201
  //# sourceMappingURL=point-contracts.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"point-contracts.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/point-contracts.ts"],"names":[],"mappings":"AAAA,sHAAsH;AACtH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAE3C,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAC;AAEnC,iFAAiF;AACjF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAK5B,CAAC;AAEH,4FAA4F;AAC5F,wBAAgB,YAAY,CAC1B,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,MAAM,oHASnB"}
1
+ {"version":3,"file":"point-contracts.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/point-contracts.ts"],"names":[],"mappings":"AAAA,sHAAsH;AACtH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C,OAAO,EAIL,KAAK,YAAY,EAClB,MAAM,2BAA2B,CAAC;AAEnC,kFAAkF;AAClF,eAAO,MAAM,iBAAiB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAa5B,CAAC;AAEH,+GAA+G;AAC/G,wBAAgB,YAAY,CAC1B,OAAO,EAAE,YAAY,EACrB,QAAQ,EAAE,MAAM,GAAG,SAAS,EAC5B,GAAG,EAAE,OAAO,EACZ,UAAU,EAAE,MAAM,oHAkBnB"}
@@ -1,19 +1,29 @@
1
1
  import { z } from '@cyanheads/mcp-ts-core';
2
2
  import { getCanvasService } from '../../../services/canvas/index.js';
3
+ import { estimatePointBytes } from '../../../services/canvas/producer-estimate.js';
3
4
  import { DatasetHandleSchema, getPowerService, PowerDatasetSchema, } from '../../../services/power/index.js';
4
- /** Full scientific envelope with exact row count and optional staged pointer. */
5
+ /** Full scientific envelope with exact row count and optional staged pointers. */
5
6
  export const PointOutputSchema = PowerDatasetSchema.extend({
6
7
  rowCount: z.number().int().describe('Exact full normalized observation count'),
7
8
  dataset: DatasetHandleSchema.nullable().describe('Full-table handle when observations exceed inline budget; null otherwise'),
9
+ summaryCount: z
10
+ .number()
11
+ .int()
12
+ .optional()
13
+ .describe('Exact complete summary count when summaries are staged; summaries then holds one'),
14
+ summaryDataset: DatasetHandleSchema.optional().describe('Complete summaries ordered by summaryIndex; SQL NULL units restore an omitted source unit'),
8
15
  });
9
- /** Source retrieval and presentation share one producer reservation and deadline signal. */
16
+ /** Source retrieval and presentation share one producer reservation and the deadline started at tool entry. */
10
17
  export function presentPoint(request, canvasId, ctx, sourceTool) {
11
- return getCanvasService().withProducer('single', ctx, async (producerCtx) => {
18
+ const canvas = getCanvasService();
19
+ return canvas.withProducer(estimatePointBytes(request), ctx, async (producerCtx, lease) => {
12
20
  const power = getPowerService();
13
- const budget = power.createCallBudget(producerCtx);
21
+ const budget = power.createCallBudget(producerCtx, false, {
22
+ deadlineMs: lease.remainingMs(),
23
+ onHeldBytes: lease.bodyBytes,
24
+ });
14
25
  const callCtx = { ...producerCtx, signal: budget.signal };
15
- const dataset = await power.point(request, callCtx, budget);
16
- return getCanvasService().present(dataset, canvasId, callCtx, sourceTool);
26
+ return canvas.presentPoint(await power.point(request, callCtx, budget), canvasId, callCtx, sourceTool, lease);
17
27
  });
18
28
  }
19
29
  //# sourceMappingURL=point-contracts.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"point-contracts.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/point-contracts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,kBAAkB,GAEnB,MAAM,2BAA2B,CAAC;AAEnC,iFAAiF;AACjF,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,MAAM,CAAC;IACzD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;IAC9E,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAC9C,0EAA0E,CAC3E;CACF,CAAC,CAAC;AAEH,4FAA4F;AAC5F,MAAM,UAAU,YAAY,CAC1B,OAAqB,EACrB,QAA4B,EAC5B,GAAY,EACZ,UAAkB;IAElB,OAAO,gBAAgB,EAAE,CAAC,YAAY,CAAC,QAAQ,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE;QAC1E,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;QACnD,MAAM,OAAO,GAAG,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1D,MAAM,OAAO,GAAG,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,CAAC;QAC5D,OAAO,gBAAgB,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAC5E,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"point-contracts.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/point-contracts.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,kBAAkB,EAAE,MAAM,wCAAwC,CAAC;AAC5E,OAAO,EACL,mBAAmB,EACnB,eAAe,EACf,kBAAkB,GAEnB,MAAM,2BAA2B,CAAC;AAEnC,kFAAkF;AAClF,MAAM,CAAC,MAAM,iBAAiB,GAAG,kBAAkB,CAAC,MAAM,CAAC;IACzD,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,EAAE,CAAC,QAAQ,CAAC,yCAAyC,CAAC;IAC9E,OAAO,EAAE,mBAAmB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAC9C,0EAA0E,CAC3E;IACD,YAAY,EAAE,CAAC;SACZ,MAAM,EAAE;SACR,GAAG,EAAE;SACL,QAAQ,EAAE;SACV,QAAQ,CAAC,kFAAkF,CAAC;IAC/F,cAAc,EAAE,mBAAmB,CAAC,QAAQ,EAAE,CAAC,QAAQ,CACrD,2FAA2F,CAC5F;CACF,CAAC,CAAC;AAEH,+GAA+G;AAC/G,MAAM,UAAU,YAAY,CAC1B,OAAqB,EACrB,QAA4B,EAC5B,GAAY,EACZ,UAAkB;IAElB,MAAM,MAAM,GAAG,gBAAgB,EAAE,CAAC;IAClC,OAAO,MAAM,CAAC,YAAY,CAAC,kBAAkB,CAAC,OAAO,CAAC,EAAE,GAAG,EAAE,KAAK,EAAE,WAAW,EAAE,KAAK,EAAE,EAAE;QACxF,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,KAAK,CAAC,gBAAgB,CAAC,WAAW,EAAE,KAAK,EAAE;YACxD,UAAU,EAAE,KAAK,CAAC,WAAW,EAAE;YAC/B,WAAW,EAAE,KAAK,CAAC,SAAS;SAC7B,CAAC,CAAC;QACH,MAAM,OAAO,GAAG,EAAE,GAAG,WAAW,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;QAC1D,OAAO,MAAM,CAAC,YAAY,CACxB,MAAM,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,EAC3C,QAAQ,EACR,OAAO,EACP,UAAU,EACV,KAAK,CACN,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
@@ -3,13 +3,36 @@ import type { DataCanvas } from '@cyanheads/mcp-ts-core/canvas';
3
3
  import type { AppConfig } from '@cyanheads/mcp-ts-core/config';
4
4
  import type { StorageService } from '@cyanheads/mcp-ts-core/storage';
5
5
  import { type ServerConfig } from '../../config/server-config.js';
6
+ import { type PowerDataset } from '../power/index.js';
7
+ import { type ComparisonShape, type RegionShape, type SplitPlanner } from './inline-split.js';
6
8
  import { type ComparisonDataset, type PresentableDataset, type PresentedDataset, type RegionalSummaryDataset, type ScientificColumn } from './types.js';
7
9
  type SummaryTable = {
8
- key: 'buckets' | 'locations' | 'regional';
10
+ /** `summaries` returns as `summaryDataset`; `buckets` and `locations` as `summaryDatasets`. */
11
+ key: 'buckets' | 'locations' | 'summaries';
9
12
  table: string;
10
13
  rows: Record<string, string | number | boolean | null | undefined>[];
11
14
  columns: ScientificColumn[];
12
15
  };
16
+ /**
17
+ * One admitted producing call. Its deadline started at tool entry, so admission wait, fetch,
18
+ * normalization and staging share it. The reservation starts at the caller's estimate and grows
19
+ * atomically when measured bytes exceed it; growth that would breach the tenant or process
20
+ * in-flight ceiling aborts the call with `producer_capacity_exhausted`.
21
+ */
22
+ export type ProducerLease = {
23
+ /** Milliseconds left of the call deadline. */
24
+ remainingMs(): number;
25
+ /** Record the decoded upstream body bytes this call holds now; a discarded attempt's body is not held. */
26
+ bodyBytes(total: number): void;
27
+ /** Record the normalized row bytes this call holds so far. */
28
+ rowBytes(total: number): void;
29
+ };
30
+ /** Presentation inputs beyond the dataset; producers pass their lease and split planner. */
31
+ export type PresentOptions = {
32
+ lease?: ProducerLease | undefined;
33
+ /** Sizes the `canvas_required` refusal's split; defaults to the inline row-prefix capacity alone. */
34
+ split?: SplitPlanner;
35
+ };
13
36
  /** Service dependencies; native lifecycle settings are supplied to the framework at startup. */
14
37
  export type CanvasServiceOptions = {
15
38
  canvas?: DataCanvas;
@@ -28,6 +51,7 @@ export declare class CanvasService {
28
51
  private readonly canvasLimits;
29
52
  private readonly records;
30
53
  private readonly producers;
54
+ private readonly waiters;
31
55
  private readonly operations;
32
56
  private readonly shutdownController;
33
57
  private queryCount;
@@ -37,15 +61,44 @@ export declare class CanvasService {
37
61
  constructor(options: CanvasServiceOptions);
38
62
  /** Availability is a configuration fact; native initialization can still fail. */
39
63
  get enabled(): boolean;
40
- /** Producer admission includes cache-hit copies and spans fetch through presentation. */
41
- withProducer<T>(kind: 'single' | 'comparison', ctx: Context, run: (ctx: Context) => Promise<T>): Promise<T>;
64
+ /**
65
+ * Run one producing call under an in-flight reservation of `estimateBytes`, an upper bound the
66
+ * caller computes from its request before fetching (see `producer-estimate.ts`). The call's
67
+ * deadline starts here, at tool entry. When the producer count or the tenant or process byte
68
+ * ceiling is exhausted, admission waits up to the queue wait inside that deadline, admitting
69
+ * waiters in arrival order as capacity frees. A call that fits may overtake a waiting one until
70
+ * the oldest waiter has waited the overtake window; after that, calls queue behind it, so it
71
+ * cannot be starved by smaller calls that keep its bytes in use. A call still waiting is refused with
72
+ * `producer_capacity_exhausted`. A waiting call aborted by its caller rejects with the caller's
73
+ * reason and holds no reservation; shutdown rejects every waiter.
74
+ */
75
+ withProducer<T>(estimateBytes: number, ctx: Context, run: (ctx: Context, lease: ProducerLease) => Promise<T>): Promise<T>;
76
+ /** Reserve atomically when both counts and byte ceilings allow it; otherwise nothing changes. */
77
+ private tryAdmit;
78
+ /** Admit at once, or queue until capacity frees, the caller aborts, the wait ends, or shutdown. */
79
+ private admit;
80
+ /** Whether a waiter has waited long enough that later calls may no longer overtake it. */
81
+ private overtakeClosed;
82
+ /**
83
+ * Release and waiter-exit path: admit each queued call, in arrival order, that now fits,
84
+ * stopping at a waiter that does not fit once later calls may no longer overtake it.
85
+ */
86
+ private admitWaiters;
42
87
  /** Stage comparison summaries with observations only when the scientific envelope overflows. */
43
- presentComparison<T extends ComparisonDataset>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string): Promise<PresentedDataset<T>>;
88
+ presentComparison<T extends ComparisonDataset & ComparisonShape>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string, lease?: ProducerLease): Promise<PresentedDataset<T>>;
44
89
  /** Stage complete cross-cell summaries when the no-observation regional envelope overflows. */
45
- presentRegion<T extends RegionalSummaryDataset>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string): Promise<PresentedDataset<T>>;
90
+ presentRegion<T extends RegionalSummaryDataset & RegionShape>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string, lease?: ProducerLease): Promise<PresentedDataset<T>>;
91
+ /** Stage complete per-column summaries when the no-observation point envelope overflows. */
92
+ presentPoint<T extends PowerDataset>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string, lease?: ProducerLease): Promise<PresentedDataset<T>>;
93
+ /**
94
+ * Present unchanged when the envelope without observations fits. Otherwise one summary stays
95
+ * inline beside the exact `summaryCount`, and the complete summaries stage as a related table
96
+ * ordered by `summaryIndex`. The split planner always sees the complete dataset.
97
+ */
98
+ private presentSummarized;
46
99
  private summaryTable;
47
100
  /** Preserve the scientific envelope with complete staging and bounded whole-row previews. */
48
- present<T extends PresentableDataset>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string, related?: SummaryTable[]): Promise<PresentedDataset<T>>;
101
+ present<T extends PresentableDataset>(dataset: T, canvasId: string | undefined, ctx: Context, sourceTool: string, options?: PresentOptions, related?: SummaryTable[]): Promise<PresentedDataset<T>>;
49
102
  /** Inspect only the supplied canvas, including original scientific provenance. */
50
103
  describe(canvasId: string, input: {
51
104
  table?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"canvas-service.d.ts","sourceRoot":"","sources":["../../../src/services/canvas/canvas-service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"canvas-service.d.ts","sourceRoot":"","sources":["../../../src/services/canvas/canvas-service.ts"],"names":[],"mappings":"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"}
@@ -5,6 +5,7 @@ import { POWER_LIMITS } from '../../config/server-config.js';
5
5
  import { powerError } from '../power/index.js';
6
6
  import { canvasError, safeCanvasError } from './errors.js';
7
7
  import { formatFaithfully } from './format.js';
8
+ import { comparisonSplit, pointSplit, prefixSplit, regionSplit, splitRecovery, } from './inline-split.js';
8
9
  import { ProvenanceSchema, QueryResultSchema, } from './types.js';
9
10
  /** Explicit token access, atomic admission, and native-lifecycle reconciliation. */
10
11
  export class CanvasService {
@@ -15,6 +16,7 @@ export class CanvasService {
15
16
  canvasLimits;
16
17
  records = new Map();
17
18
  producers = new Set();
19
+ waiters = [];
18
20
  operations = new Set();
19
21
  shutdownController = new AbortController();
20
22
  queryCount = 0;
@@ -41,48 +43,151 @@ export class CanvasService {
41
43
  get enabled() {
42
44
  return this.canvas !== undefined;
43
45
  }
44
- /** Producer admission includes cache-hit copies and spans fetch through presentation. */
45
- async withProducer(kind, ctx, run) {
46
+ /**
47
+ * Run one producing call under an in-flight reservation of `estimateBytes`, an upper bound the
48
+ * caller computes from its request before fetching (see `producer-estimate.ts`). The call's
49
+ * deadline starts here, at tool entry. When the producer count or the tenant or process byte
50
+ * ceiling is exhausted, admission waits up to the queue wait inside that deadline, admitting
51
+ * waiters in arrival order as capacity frees. A call that fits may overtake a waiting one until
52
+ * the oldest waiter has waited the overtake window; after that, calls queue behind it, so it
53
+ * cannot be starved by smaller calls that keep its bytes in use. A call still waiting is refused with
54
+ * `producer_capacity_exhausted`. A waiting call aborted by its caller rejects with the caller's
55
+ * reason and holds no reservation; shutdown rejects every waiter.
56
+ */
57
+ async withProducer(estimateBytes, ctx, run) {
46
58
  this.assertRunning();
47
59
  ctx.signal.throwIfAborted();
48
- const bytes = (kind === 'comparison' ? POWER_LIMITS.comparisonBodyBytes : POWER_LIMITS.bodyBytes) +
49
- POWER_LIMITS.rowBytes;
60
+ const tenant = this.tenant(ctx);
61
+ const entered = this.now();
62
+ const deadline = new AbortController();
63
+ const timer = setTimeout(() => deadline.abort(new DOMException('The operation timed out.', 'TimeoutError')), POWER_LIMITS.deadlineMs);
64
+ let producer;
65
+ try {
66
+ producer = await this.admit(tenant, estimateBytes, ctx.signal);
67
+ const admitted = producer;
68
+ const signal = AbortSignal.any([
69
+ ctx.signal,
70
+ admitted.controller.signal,
71
+ this.shutdownController.signal,
72
+ deadline.signal,
73
+ ]);
74
+ const measured = { body: 0, rows: 0 };
75
+ const grow = () => {
76
+ const total = measured.body + measured.rows;
77
+ if (total <= admitted.bytes)
78
+ return;
79
+ const others = [...this.producers].filter((item) => item !== admitted);
80
+ const sum = (items) => items.reduce((acc, item) => acc + item.bytes, 0);
81
+ if (sum(others) + total > POWER_LIMITS.processInflightBytes ||
82
+ sum(others.filter((item) => item.tenant === admitted.tenant)) + total >
83
+ POWER_LIMITS.tenantInflightBytes) {
84
+ const error = canvasError('producer_capacity_exhausted', 'This data call outgrew its in-flight reservation while other data calls hold the remaining capacity.');
85
+ admitted.controller.abort(error);
86
+ throw error;
87
+ }
88
+ admitted.bytes = total;
89
+ };
90
+ return await run({ ...ctx, signal }, {
91
+ remainingMs: () => Math.max(0, entered + POWER_LIMITS.deadlineMs - this.now()),
92
+ bodyBytes: (total) => {
93
+ measured.body = total;
94
+ grow();
95
+ },
96
+ rowBytes: (total) => {
97
+ measured.rows = total;
98
+ grow();
99
+ },
100
+ });
101
+ }
102
+ finally {
103
+ clearTimeout(timer);
104
+ if (producer) {
105
+ this.producers.delete(producer);
106
+ producer.finish();
107
+ this.admitWaiters();
108
+ }
109
+ }
110
+ }
111
+ /** Reserve atomically when both counts and byte ceilings allow it; otherwise nothing changes. */
112
+ tryAdmit(tenant, bytes) {
50
113
  const active = [...this.producers];
51
- const total = active.reduce((sum, p) => sum + p.bytes, 0);
52
- const tenant = active
53
- .filter((p) => p.tenant === ctx.tenantId)
54
- .reduce((sum, p) => sum + p.bytes, 0);
114
+ const total = active.reduce((sum, item) => sum + item.bytes, 0);
115
+ const owned = active
116
+ .filter((item) => item.tenant === tenant)
117
+ .reduce((sum, item) => sum + item.bytes, 0);
55
118
  if (active.length >= POWER_LIMITS.producers ||
56
119
  total + bytes > POWER_LIMITS.processInflightBytes ||
57
- tenant + bytes > POWER_LIMITS.tenantInflightBytes)
58
- throw canvasError('canvas_capacity_exhausted', 'Producer memory or concurrency capacity is exhausted.');
59
- const controller = new AbortController();
60
- const signal = AbortSignal.any([
61
- ctx.signal,
62
- controller.signal,
63
- this.shutdownController.signal,
64
- AbortSignal.timeout(POWER_LIMITS.deadlineMs),
65
- ]);
120
+ owned + bytes > POWER_LIMITS.tenantInflightBytes)
121
+ return undefined;
66
122
  const { promise: settled, resolve: finish } = Promise.withResolvers();
67
123
  const producer = {
68
- tenant: this.tenant(ctx),
124
+ tenant,
69
125
  bytes,
70
- controller,
126
+ controller: new AbortController(),
71
127
  settled,
128
+ finish,
72
129
  };
73
130
  this.producers.add(producer);
74
- try {
75
- return await run({ ...ctx, signal });
76
- }
77
- finally {
78
- this.producers.delete(producer);
79
- finish();
131
+ return producer;
132
+ }
133
+ /** Admit at once, or queue until capacity frees, the caller aborts, the wait ends, or shutdown. */
134
+ admit(tenant, bytes, signal) {
135
+ const head = this.waiters[0];
136
+ const immediate = !head || !this.overtakeClosed(head) ? this.tryAdmit(tenant, bytes) : undefined;
137
+ if (immediate)
138
+ return Promise.resolve(immediate);
139
+ return new Promise((resolve, reject) => {
140
+ const settle = () => {
141
+ clearTimeout(timer);
142
+ signal.removeEventListener('abort', onAbort);
143
+ this.waiters.splice(this.waiters.indexOf(waiter), 1);
144
+ };
145
+ const waiter = {
146
+ tenant,
147
+ bytes,
148
+ since: this.now(),
149
+ admit: (producer) => {
150
+ settle();
151
+ resolve(producer);
152
+ },
153
+ refuse: (error) => {
154
+ settle();
155
+ reject(error);
156
+ },
157
+ };
158
+ /** A waiter that leaves may have been the head holding later calls that already fit. */
159
+ const leave = (error) => {
160
+ waiter.refuse(error);
161
+ this.admitWaiters();
162
+ };
163
+ const onAbort = () => leave(signal.reason);
164
+ const timer = setTimeout(() => leave(canvasError('producer_capacity_exhausted', 'Other data calls held the producer capacity for the whole admission wait.')), POWER_LIMITS.queueWaitMs);
165
+ signal.addEventListener('abort', onAbort, { once: true });
166
+ this.waiters.push(waiter);
167
+ });
168
+ }
169
+ /** Whether a waiter has waited long enough that later calls may no longer overtake it. */
170
+ overtakeClosed(waiter) {
171
+ return this.now() - waiter.since >= POWER_LIMITS.queueOvertakeMs;
172
+ }
173
+ /**
174
+ * Release and waiter-exit path: admit each queued call, in arrival order, that now fits,
175
+ * stopping at a waiter that does not fit once later calls may no longer overtake it.
176
+ */
177
+ admitWaiters() {
178
+ for (const waiter of [...this.waiters]) {
179
+ const producer = this.tryAdmit(waiter.tenant, waiter.bytes);
180
+ if (producer)
181
+ waiter.admit(producer);
182
+ else if (this.overtakeClosed(waiter))
183
+ return;
80
184
  }
81
185
  }
82
186
  /** Stage comparison summaries with observations only when the scientific envelope overflows. */
83
- presentComparison(dataset, canvasId, ctx, sourceTool) {
187
+ presentComparison(dataset, canvasId, ctx, sourceTool, lease) {
188
+ const options = { lease, split: comparisonSplit(dataset) };
84
189
  if (this.fits({ ...dataset, rows: [], rowCount: dataset.rows.length, dataset: null }))
85
- return this.present(dataset, canvasId, ctx, sourceTool);
190
+ return this.present(dataset, canvasId, ctx, sourceTool, options);
86
191
  const summaryRows = {
87
192
  buckets: dataset.summaries.map((summary, summaryIndex) => ({ ...summary, summaryIndex })),
88
193
  locations: dataset.locations
@@ -99,18 +204,36 @@ export class CanvasService {
99
204
  summaryCount: location.summaries.length,
100
205
  })),
101
206
  };
102
- return this.present(compact, canvasId, ctx, sourceTool, tables);
207
+ return this.present(compact, canvasId, ctx, sourceTool, options, tables);
103
208
  }
104
209
  /** Stage complete cross-cell summaries when the no-observation regional envelope overflows. */
105
- presentRegion(dataset, canvasId, ctx, sourceTool) {
210
+ presentRegion(dataset, canvasId, ctx, sourceTool, lease) {
211
+ return this.presentSummarized(dataset, canvasId, ctx, sourceTool, {
212
+ lease,
213
+ split: regionSplit(dataset),
214
+ });
215
+ }
216
+ /** Stage complete per-column summaries when the no-observation point envelope overflows. */
217
+ presentPoint(dataset, canvasId, ctx, sourceTool, lease) {
218
+ return this.presentSummarized(dataset, canvasId, ctx, sourceTool, {
219
+ lease,
220
+ split: pointSplit(dataset),
221
+ });
222
+ }
223
+ /**
224
+ * Present unchanged when the envelope without observations fits. Otherwise one summary stays
225
+ * inline beside the exact `summaryCount`, and the complete summaries stage as a related table
226
+ * ordered by `summaryIndex`. The split planner always sees the complete dataset.
227
+ */
228
+ presentSummarized(dataset, canvasId, ctx, sourceTool, options) {
106
229
  if (this.fits({ ...dataset, rows: [], rowCount: dataset.rows.length, dataset: null }))
107
- return this.present(dataset, canvasId, ctx, sourceTool);
108
- const summaries = this.summaryTable('regional', dataset.summaries.map((summary, summaryIndex) => ({ ...summary, summaryIndex })));
230
+ return this.present(dataset, canvasId, ctx, sourceTool, options);
231
+ const summaries = this.summaryTable('summaries', dataset.summaries.map((summary, summaryIndex) => ({ ...summary, summaryIndex })));
109
232
  return this.present({
110
233
  ...dataset,
111
234
  summaries: dataset.summaries.slice(0, 1),
112
235
  summaryCount: dataset.summaries.length,
113
- }, canvasId, ctx, sourceTool, [summaries]);
236
+ }, canvasId, ctx, sourceTool, options, [summaries]);
114
237
  }
115
238
  summaryTable(key, rows) {
116
239
  const strings = new Set([
@@ -146,7 +269,7 @@ export class CanvasService {
146
269
  };
147
270
  }
148
271
  /** Preserve the scientific envelope with complete staging and bounded whole-row previews. */
149
- async present(dataset, canvasId, ctx, sourceTool, related = []) {
272
+ async present(dataset, canvasId, ctx, sourceTool, options = {}, related = []) {
150
273
  this.assertRunning();
151
274
  ctx.signal.throwIfAborted();
152
275
  const serialized = JSON.stringify(dataset.rows);
@@ -157,6 +280,7 @@ export class CanvasService {
157
280
  related.some((item) => item.rows.length > POWER_LIMITS.rows) ||
158
281
  dataset.parameters.length > POWER_LIMITS.columns)
159
282
  throw powerError('dataset_limit', 'Normalized dataset exceeds the analytical workload limit.');
283
+ options.lease?.rowBytes(bytes + relatedBytes);
160
284
  const inline = { ...dataset, rowCount: dataset.rows.length, dataset: null };
161
285
  if (!related.length && this.fits(inline))
162
286
  return inline;
@@ -174,10 +298,10 @@ export class CanvasService {
174
298
  queryTool: 'nasa_power_dataframe_query',
175
299
  });
176
300
  const relatedHandles = (id, expiresAt) => {
177
- const regional = related.find((item) => item.key === 'regional');
178
- if (regional)
301
+ const summaries = related.find((item) => item.key === 'summaries');
302
+ if (summaries)
179
303
  return {
180
- summaryDataset: handle(id, expiresAt, regional.table, regional.rows.length, regional.columns),
304
+ summaryDataset: handle(id, expiresAt, summaries.table, summaries.rows.length, summaries.columns),
181
305
  };
182
306
  const buckets = related.find((item) => item.key === 'buckets');
183
307
  const locations = related.find((item) => item.key === 'locations');
@@ -199,8 +323,11 @@ export class CanvasService {
199
323
  });
200
324
  const preview = this.preview(dataset.rows, (rows) => output('0000000000', new Date(this.now()).toISOString(), rows));
201
325
  const canvas = this.canvas;
202
- if (!canvas)
203
- throw canvasError('canvas_required', 'This complete dataset requires an analytical workspace.');
326
+ if (!canvas) {
327
+ const rowCount = dataset.rows.length;
328
+ const split = (options.split ?? prefixSplit(dataset))((output) => this.fits(output));
329
+ throw canvasError('canvas_required', 'This complete dataset requires an analytical workspace.', splitRecovery(rowCount, split), { rowCount, inlineRows: split.inlineRows, calls: split.calls });
330
+ }
204
331
  await this.reconcile();
205
332
  ctx.signal.throwIfAborted();
206
333
  const record = this.reserve(canvasId, ctx, table, bytes, columns, dataset, sourceTool, related);
@@ -293,7 +420,7 @@ export class CanvasService {
293
420
  ? 'The effective row limit is 1000; larger requested limits are capped.'
294
421
  : undefined;
295
422
  if (this.queryCount >= POWER_LIMITS.queries)
296
- throw canvasError('canvas_capacity_exhausted', 'Analytical query concurrency is exhausted.');
423
+ throw canvasError('canvas_busy', 'Analytical query concurrency is exhausted.');
297
424
  this.queryCount++;
298
425
  try {
299
426
  return await this.operate(canvasId, ctx, async (instance) => {
@@ -358,6 +485,8 @@ export class CanvasService {
358
485
  this.stopped = true;
359
486
  clearInterval(this.timer);
360
487
  this.shutdownController.abort();
488
+ for (const waiter of [...this.waiters])
489
+ waiter.refuse(new McpError(JsonRpcErrorCode.ServiceUnavailable, 'Analytical workspace is shutting down.'));
361
490
  for (const producer of this.producers)
362
491
  producer.controller.abort();
363
492
  await Promise.allSettled([...this.producers].map((producer) => producer.settled));
@@ -446,10 +575,11 @@ export class CanvasService {
446
575
  throw canvasError('canvas_capacity_exhausted', 'The process or tenant canvas-count limit is exhausted.', this.config.dataframeDropEnabled
447
576
  ? 'Reuse an explicit live canvas_id, drop all tables from a canvas, or wait for canvas expiry.'
448
577
  : 'Reuse an explicit live canvas_id, or wait for canvas expiry.');
578
+ if (record?.busy)
579
+ throw canvasError('canvas_busy', 'Another operation is active on this canvas.');
449
580
  if (retained(records) + bytes + relatedBytes > POWER_LIMITS.processRetainedBytes ||
450
581
  retained(tenantRecords) + bytes + relatedBytes > POWER_LIMITS.tenantRetainedBytes ||
451
- (record &&
452
- (record.busy || record.tables.size + 1 + related.length > POWER_LIMITS.tablesPerCanvas)))
582
+ (record && record.tables.size + 1 + related.length > POWER_LIMITS.tablesPerCanvas))
453
583
  throw canvasError('canvas_capacity_exhausted', 'Analytical workspace memory or table capacity is exhausted.');
454
584
  const { rows: _rows, ...envelope } = dataset;
455
585
  const provenance = ProvenanceSchema.parse({
@@ -582,7 +712,7 @@ export class CanvasService {
582
712
  if (!record || record.tenant !== ctx.tenantId || record.pending)
583
713
  throw canvasError('canvas_not_found', 'Canvas not found or expired.', drop ? 'The canvas has expired or is absent; there is nothing left to remove.' : undefined);
584
714
  if (record.busy)
585
- throw canvasError('canvas_capacity_exhausted', 'Another operation is active on this canvas.');
715
+ throw canvasError('canvas_busy', 'Another operation is active on this canvas.');
586
716
  record.busy = true;
587
717
  const operation = (async () => {
588
718
  try {