@marimo-team/islands 0.20.5-dev33 → 0.20.5-dev36
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/main.js
CHANGED
|
@@ -70710,7 +70710,7 @@ Image URL: ${r.imageUrl}`)), contextToXml({
|
|
|
70710
70710
|
return Logger.warn("Failed to get version from mount config"), null;
|
|
70711
70711
|
}
|
|
70712
70712
|
}
|
|
70713
|
-
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.20.5-
|
|
70713
|
+
const marimoVersionAtom = atom(getVersionFromMountConfig() || "0.20.5-dev36"), showCodeInRunModeAtom = atom(true);
|
|
70714
70714
|
atom(null);
|
|
70715
70715
|
var import_compiler_runtime$89 = require_compiler_runtime();
|
|
70716
70716
|
function useKeydownOnElement(e, r) {
|
|
@@ -92493,6 +92493,7 @@ ${c}
|
|
|
92493
92493
|
"lon",
|
|
92494
92494
|
"curveNumber",
|
|
92495
92495
|
"pointNumber",
|
|
92496
|
+
"pointNumbers",
|
|
92496
92497
|
"pointIndex"
|
|
92497
92498
|
];
|
|
92498
92499
|
function extractPoints(e) {
|
|
@@ -92500,8 +92501,11 @@ ${c}
|
|
|
92500
92501
|
let r;
|
|
92501
92502
|
return e.map((e2) => {
|
|
92502
92503
|
var _a3;
|
|
92503
|
-
let c = Array.isArray(e2.data.hovertemplate) ? e2.data.hovertemplate[0] : e2.data.hovertemplate;
|
|
92504
|
-
return !
|
|
92504
|
+
let c = pick_default(e2, STANDARD_POINT_KEYS), d = Array.isArray(e2.data.hovertemplate) ? e2.data.hovertemplate[0] : e2.data.hovertemplate;
|
|
92505
|
+
return !d || ((_a3 = e2.data) == null ? void 0 : _a3.type) === "heatmap" ? c : (r = r ? r.update(d) : createParser(d), {
|
|
92506
|
+
...c,
|
|
92507
|
+
...r.parse(e2)
|
|
92508
|
+
});
|
|
92505
92509
|
});
|
|
92506
92510
|
}
|
|
92507
92511
|
function _temp$7(e) {
|
package/package.json
CHANGED
|
@@ -488,6 +488,133 @@ describe("RunStaleCellsTool", () => {
|
|
|
488
488
|
// Output should be capped (2000 chars content + "Output:\n" prefix + truncation message)
|
|
489
489
|
expect(output.length).toBeLessThan(2200);
|
|
490
490
|
});
|
|
491
|
+
|
|
492
|
+
it("should omit output for cells that exceed total output budget", async () => {
|
|
493
|
+
const cellIds = Array.from(
|
|
494
|
+
{ length: 25 },
|
|
495
|
+
(_, i) => `budget-cell-${i}` as CellId,
|
|
496
|
+
);
|
|
497
|
+
const cellData: Record<string, { code: string; edited: boolean }> = {};
|
|
498
|
+
for (const id of cellIds) {
|
|
499
|
+
cellData[id] = { code: "x = 1", edited: true };
|
|
500
|
+
}
|
|
501
|
+
|
|
502
|
+
const notebook = MockNotebook.notebookState({ cellData });
|
|
503
|
+
store.set(notebookAtom, notebook);
|
|
504
|
+
|
|
505
|
+
vi.mocked(runCells).mockImplementation(async () => {
|
|
506
|
+
const updatedNotebook = store.get(notebookAtom);
|
|
507
|
+
for (const id of cellIds) {
|
|
508
|
+
updatedNotebook.cellRuntime[id] = {
|
|
509
|
+
...updatedNotebook.cellRuntime[id],
|
|
510
|
+
status: "idle",
|
|
511
|
+
};
|
|
512
|
+
}
|
|
513
|
+
store.set(notebookAtom, updatedNotebook);
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
// Each cell produces ~2008 chars of formatted output ("Output:\n" + 2000 chars).
|
|
517
|
+
// After 20 cells the running total exceeds MAX_TOOL_OUTPUT_CHARS (40,000).
|
|
518
|
+
const content = "a".repeat(2000);
|
|
519
|
+
vi.mocked(getCellContextData).mockReturnValue({
|
|
520
|
+
cellOutput: {
|
|
521
|
+
outputType: "text",
|
|
522
|
+
processedContent: content,
|
|
523
|
+
imageUrl: null,
|
|
524
|
+
output: { mimetype: "text/plain", data: content },
|
|
525
|
+
},
|
|
526
|
+
consoleOutputs: null,
|
|
527
|
+
cellName: "cell",
|
|
528
|
+
} as never);
|
|
529
|
+
|
|
530
|
+
const result = await tool.handler({}, toolContext as never);
|
|
531
|
+
|
|
532
|
+
expect(result.cellsToOutput?.[cellIds[0]]?.cellOutput).toContain(
|
|
533
|
+
"Output:",
|
|
534
|
+
);
|
|
535
|
+
expect(result.cellsToOutput?.[cellIds[24]]?.cellOutput).toBe(
|
|
536
|
+
"Cell executed (output omitted due to context limits).",
|
|
537
|
+
);
|
|
538
|
+
});
|
|
539
|
+
|
|
540
|
+
it("should use higher truncation limit for error outputs", async () => {
|
|
541
|
+
const notebook = MockNotebook.notebookState({
|
|
542
|
+
cellData: {
|
|
543
|
+
[cellId1]: { code: "raise Exception()", edited: true },
|
|
544
|
+
},
|
|
545
|
+
});
|
|
546
|
+
store.set(notebookAtom, notebook);
|
|
547
|
+
|
|
548
|
+
vi.mocked(runCells).mockImplementation(async () => {
|
|
549
|
+
const updatedNotebook = store.get(notebookAtom);
|
|
550
|
+
updatedNotebook.cellRuntime[cellId1] = {
|
|
551
|
+
...updatedNotebook.cellRuntime[cellId1],
|
|
552
|
+
status: "idle",
|
|
553
|
+
};
|
|
554
|
+
store.set(notebookAtom, updatedNotebook);
|
|
555
|
+
});
|
|
556
|
+
|
|
557
|
+
// 2500 chars sits between MAX_TEXT_OUTPUT_CHARS (2000) and MAX_ERROR_OUTPUT_CHARS (3000)
|
|
558
|
+
const errorContent = "E".repeat(2500);
|
|
559
|
+
vi.mocked(getCellContextData).mockReturnValue({
|
|
560
|
+
cellOutput: {
|
|
561
|
+
outputType: "text",
|
|
562
|
+
processedContent: errorContent,
|
|
563
|
+
imageUrl: null,
|
|
564
|
+
output: {
|
|
565
|
+
mimetype: "application/vnd.marimo+error",
|
|
566
|
+
data: errorContent,
|
|
567
|
+
},
|
|
568
|
+
},
|
|
569
|
+
consoleOutputs: null,
|
|
570
|
+
cellName: "cell1",
|
|
571
|
+
} as never);
|
|
572
|
+
|
|
573
|
+
const result = await tool.handler({}, toolContext as never);
|
|
574
|
+
|
|
575
|
+
const output = result.cellsToOutput?.[cellId1]?.cellOutput ?? "";
|
|
576
|
+
expect(output).not.toContain("[TRUNCATED:");
|
|
577
|
+
expect(output).toContain(errorContent);
|
|
578
|
+
});
|
|
579
|
+
|
|
580
|
+
it("should truncate large console output", async () => {
|
|
581
|
+
const notebook = MockNotebook.notebookState({
|
|
582
|
+
cellData: {
|
|
583
|
+
[cellId1]: { code: 'print("x" * 10000)', edited: true },
|
|
584
|
+
},
|
|
585
|
+
});
|
|
586
|
+
store.set(notebookAtom, notebook);
|
|
587
|
+
|
|
588
|
+
vi.mocked(runCells).mockImplementation(async () => {
|
|
589
|
+
const updatedNotebook = store.get(notebookAtom);
|
|
590
|
+
updatedNotebook.cellRuntime[cellId1] = {
|
|
591
|
+
...updatedNotebook.cellRuntime[cellId1],
|
|
592
|
+
status: "idle",
|
|
593
|
+
};
|
|
594
|
+
store.set(notebookAtom, updatedNotebook);
|
|
595
|
+
});
|
|
596
|
+
|
|
597
|
+
const largeConsoleText = "x".repeat(10_000);
|
|
598
|
+
vi.mocked(getCellContextData).mockReturnValue({
|
|
599
|
+
cellOutput: null,
|
|
600
|
+
consoleOutputs: [
|
|
601
|
+
{
|
|
602
|
+
outputType: "text",
|
|
603
|
+
processedContent: largeConsoleText,
|
|
604
|
+
imageUrl: null,
|
|
605
|
+
output: { mimetype: "text/plain", data: largeConsoleText },
|
|
606
|
+
},
|
|
607
|
+
],
|
|
608
|
+
cellName: "cell1",
|
|
609
|
+
} as never);
|
|
610
|
+
|
|
611
|
+
const result = await tool.handler({}, toolContext as never);
|
|
612
|
+
|
|
613
|
+
const consoleOutput =
|
|
614
|
+
result.cellsToOutput?.[cellId1]?.consoleOutput ?? "";
|
|
615
|
+
expect(consoleOutput).toContain("[TRUNCATED:");
|
|
616
|
+
expect(consoleOutput.length).toBeLessThan(2200);
|
|
617
|
+
});
|
|
491
618
|
});
|
|
492
619
|
|
|
493
620
|
describe("cell execution completion", () => {
|
|
@@ -97,7 +97,7 @@ export class RunStaleCellsTool
|
|
|
97
97
|
|
|
98
98
|
await runCells({
|
|
99
99
|
cellIds: staleCells,
|
|
100
|
-
sendRun
|
|
100
|
+
sendRun,
|
|
101
101
|
prepareForRun,
|
|
102
102
|
notebook,
|
|
103
103
|
});
|
|
@@ -121,8 +121,8 @@ export class RunStaleCellsTool
|
|
|
121
121
|
const updatedNotebook = store.get(notebookAtom);
|
|
122
122
|
|
|
123
123
|
const cellsToOutput = new Map<CellId, CellOutput | null>();
|
|
124
|
-
let resultMessage = "";
|
|
125
124
|
let outputHasErrors = false;
|
|
125
|
+
let hasAnyConsoleOutput = false;
|
|
126
126
|
let totalOutputChars = 0;
|
|
127
127
|
|
|
128
128
|
for (const cellId of staleCells) {
|
|
@@ -135,12 +135,10 @@ export class RunStaleCellsTool
|
|
|
135
135
|
const hasConsoleOutput = consoleOutputs && consoleOutputs.length > 0;
|
|
136
136
|
|
|
137
137
|
// Track errors regardless of budget
|
|
138
|
-
if (cellOutput && this.outputHasErrors(cellOutput)) {
|
|
139
|
-
outputHasErrors = true;
|
|
140
|
-
}
|
|
141
138
|
if (
|
|
142
|
-
|
|
143
|
-
|
|
139
|
+
(cellOutput && this.outputHasErrors(cellOutput)) ||
|
|
140
|
+
(hasConsoleOutput &&
|
|
141
|
+
consoleOutputs.some((output) => this.outputHasErrors(output)))
|
|
144
142
|
) {
|
|
145
143
|
outputHasErrors = true;
|
|
146
144
|
}
|
|
@@ -167,6 +165,7 @@ export class RunStaleCellsTool
|
|
|
167
165
|
}
|
|
168
166
|
|
|
169
167
|
if (hasConsoleOutput) {
|
|
168
|
+
hasAnyConsoleOutput = true;
|
|
170
169
|
consoleOutputString = consoleOutputs
|
|
171
170
|
.map((output) => this.formatOutputString(output))
|
|
172
171
|
.join("\n");
|
|
@@ -175,8 +174,6 @@ export class RunStaleCellsTool
|
|
|
175
174
|
MAX_TEXT_OUTPUT_CHARS,
|
|
176
175
|
);
|
|
177
176
|
totalOutputChars += consoleOutputString.length;
|
|
178
|
-
resultMessage +=
|
|
179
|
-
"Console output represents the stdout or stderr of the cell (eg. print statements).";
|
|
180
177
|
}
|
|
181
178
|
|
|
182
179
|
cellsToOutput.set(cellId, {
|
|
@@ -202,57 +199,50 @@ export class RunStaleCellsTool
|
|
|
202
199
|
return {
|
|
203
200
|
status: "success",
|
|
204
201
|
cellsToOutput: Object.fromEntries(cellsToOutput),
|
|
205
|
-
message:
|
|
202
|
+
message: hasAnyConsoleOutput
|
|
203
|
+
? "Console output represents the stdout or stderr of the cell (eg. print statements)."
|
|
204
|
+
: undefined,
|
|
206
205
|
next_steps: nextSteps,
|
|
207
206
|
};
|
|
208
207
|
};
|
|
209
208
|
|
|
210
209
|
private outputHasErrors(cellOutput: BaseOutput): boolean {
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
output.mimetype === "application/vnd.marimo+
|
|
214
|
-
|
|
215
|
-
) {
|
|
216
|
-
return true;
|
|
217
|
-
}
|
|
218
|
-
return false;
|
|
210
|
+
return (
|
|
211
|
+
cellOutput.output.mimetype === "application/vnd.marimo+error" ||
|
|
212
|
+
cellOutput.output.mimetype === "application/vnd.marimo+traceback"
|
|
213
|
+
);
|
|
219
214
|
}
|
|
220
215
|
|
|
221
216
|
private formatOutputString(cellOutput: BaseOutput): string {
|
|
222
|
-
let outputString = "";
|
|
223
217
|
const { outputType, processedContent, imageUrl, output } = cellOutput;
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
outputString += "Output:\n";
|
|
239
|
-
let content: string;
|
|
240
|
-
if (processedContent) {
|
|
241
|
-
content = processedContent;
|
|
242
|
-
} else if (typeof output.data === "string") {
|
|
243
|
-
content = output.data;
|
|
244
|
-
} else {
|
|
245
|
-
content = JSON.stringify(output.data);
|
|
246
|
-
}
|
|
247
|
-
outputString += this.truncateString(content, maxChars);
|
|
248
|
-
}
|
|
249
|
-
} else if (outputType === "media") {
|
|
250
|
-
outputString += `Media Output: Contains ${output.mimetype} content`;
|
|
251
|
-
if (imageUrl) {
|
|
252
|
-
outputString += `\nImage URL: ${imageUrl}`;
|
|
253
|
-
}
|
|
218
|
+
|
|
219
|
+
if (outputType === "media") {
|
|
220
|
+
const base = `Media Output: Contains ${output.mimetype} content`;
|
|
221
|
+
return imageUrl ? `${base}\nImage URL: ${imageUrl}` : base;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
if (output.mimetype === "text/html") {
|
|
225
|
+
// text/html (e.g. plotly figures, rich dataframes) can be millions of
|
|
226
|
+
// chars and is not interpretable by LLMs — summarize instead
|
|
227
|
+
const dataLength =
|
|
228
|
+
typeof output.data === "string"
|
|
229
|
+
? output.data.length
|
|
230
|
+
: JSON.stringify(output.data).length;
|
|
231
|
+
return `HTML Output: text/html content (${dataLength.toLocaleString()} chars). Full output visible in notebook UI.`;
|
|
254
232
|
}
|
|
255
|
-
|
|
233
|
+
|
|
234
|
+
const maxChars = this.outputHasErrors(cellOutput)
|
|
235
|
+
? MAX_ERROR_OUTPUT_CHARS
|
|
236
|
+
: MAX_TEXT_OUTPUT_CHARS;
|
|
237
|
+
|
|
238
|
+
let content = processedContent;
|
|
239
|
+
if (!content) {
|
|
240
|
+
content =
|
|
241
|
+
typeof output.data === "string"
|
|
242
|
+
? output.data
|
|
243
|
+
: JSON.stringify(output.data);
|
|
244
|
+
}
|
|
245
|
+
return `Output:\n${this.truncateString(content, maxChars)}`;
|
|
256
246
|
}
|
|
257
247
|
|
|
258
248
|
private truncateString(str: string, maxLength: number): string {
|
|
@@ -261,7 +251,6 @@ export class RunStaleCellsTool
|
|
|
261
251
|
}
|
|
262
252
|
return `${str.slice(0, maxLength)}\n\n[TRUNCATED: ${str.length.toLocaleString()} → ${maxLength.toLocaleString()} chars. Full output visible in the notebook UI.]`;
|
|
263
253
|
}
|
|
264
|
-
|
|
265
254
|
/**
|
|
266
255
|
* Wait for cells to finish executing (status becomes "idle")
|
|
267
256
|
* Returns true if all cells finished executing, false if the timeout was reached
|
|
@@ -250,6 +250,7 @@ const STANDARD_POINT_KEYS: string[] = [
|
|
|
250
250
|
"lon",
|
|
251
251
|
"curveNumber",
|
|
252
252
|
"pointNumber",
|
|
253
|
+
"pointNumbers",
|
|
253
254
|
"pointIndex",
|
|
254
255
|
];
|
|
255
256
|
|
|
@@ -263,6 +264,8 @@ function extractPoints(
|
|
|
263
264
|
let parser: PlotlyTemplateParser | undefined;
|
|
264
265
|
|
|
265
266
|
return points.map((point) => {
|
|
267
|
+
const standardPointFields = pick(point, STANDARD_POINT_KEYS);
|
|
268
|
+
|
|
266
269
|
// Get the first hovertemplate
|
|
267
270
|
const hovertemplate = Array.isArray(point.data.hovertemplate)
|
|
268
271
|
? point.data.hovertemplate[0]
|
|
@@ -271,13 +274,16 @@ function extractPoints(
|
|
|
271
274
|
// For chart types with standard point keys (e.g. heatmaps),
|
|
272
275
|
// or when there's no hovertemplate, pick keys directly from the point.
|
|
273
276
|
if (!hovertemplate || point.data?.type === "heatmap") {
|
|
274
|
-
return
|
|
277
|
+
return standardPointFields;
|
|
275
278
|
}
|
|
276
279
|
|
|
277
280
|
// Update or create a parser
|
|
278
281
|
parser = parser
|
|
279
282
|
? parser.update(hovertemplate)
|
|
280
283
|
: createParser(hovertemplate);
|
|
281
|
-
return
|
|
284
|
+
return {
|
|
285
|
+
...standardPointFields,
|
|
286
|
+
...parser.parse(point),
|
|
287
|
+
};
|
|
282
288
|
});
|
|
283
289
|
}
|