@marimo-team/islands 0.23.14-dev19 → 0.23.14-dev21
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/{chat-ui-9wA4feLE.js → chat-ui-CO8WuXGb.js} +347 -143
- package/dist/{code-visibility-CxDvzm2S.js → code-visibility-CPWEmIAX.js} +163 -171
- package/dist/{html-to-image-DBHfshED.js → html-to-image-DLSOS-bE.js} +2298 -2267
- package/dist/main.js +333 -333
- package/dist/{process-output-Dw6We6B6.js → process-output-B9ysqk1y.js} +1 -1
- package/dist/{reveal-component-tJhA77Am.js → reveal-component-BJwt0B2_.js} +2 -2
- package/package.json +2 -2
- package/src/components/editor/errors/__tests__/auto-fix.test.ts +11 -107
- package/src/components/editor/errors/auto-fix.tsx +11 -31
- package/src/components/editor/output/MarimoTracebackOutput.tsx +2 -2
- package/src/core/ai/context/__tests__/registry.test.ts +133 -3
- package/src/core/ai/context/providers/__tests__/datasource.test.ts +3 -1
- package/src/core/ai/context/providers/__tests__/error.test.ts +200 -15
- package/src/core/ai/context/providers/datasource.ts +27 -2
- package/src/core/ai/context/providers/error.ts +226 -36
- package/src/core/ai/context/registry.ts +77 -43
- package/src/core/codemirror/ai/resources.ts +15 -10
- package/src/core/errors/errors.ts +2 -1
- package/src/core/mime.ts +11 -4
- package/src/core/ai/context/providers/__tests__/__snapshots__/error.test.ts.snap +0 -3
|
@@ -9,11 +9,19 @@ import { MultiMap } from "@/utils/multi-map";
|
|
|
9
9
|
import type { TypedString } from "@/utils/typed";
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
|
-
* Unique identifier for a context item in the format "type
|
|
12
|
+
* Unique identifier for a context item in the format "type://id"
|
|
13
13
|
* e.g., "variable://my_var", "data://users", "file://config.py"
|
|
14
14
|
*/
|
|
15
15
|
export type ContextLocatorId = TypedString<"ContextLocatorId">;
|
|
16
16
|
|
|
17
|
+
function parseContextType(uri: ContextLocatorId): string | undefined {
|
|
18
|
+
const separator = uri.indexOf("://");
|
|
19
|
+
if (separator === -1) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return uri.slice(0, separator);
|
|
23
|
+
}
|
|
24
|
+
|
|
17
25
|
/**
|
|
18
26
|
* Base interface for context items that can be mentioned in AI prompts
|
|
19
27
|
*/
|
|
@@ -142,40 +150,80 @@ export class AIContextRegistry<T extends AIContextItem> {
|
|
|
142
150
|
);
|
|
143
151
|
}
|
|
144
152
|
|
|
153
|
+
private findProviderForUri(
|
|
154
|
+
uri: ContextLocatorId,
|
|
155
|
+
): AIContextProvider | undefined {
|
|
156
|
+
const type = parseContextType(uri);
|
|
157
|
+
if (!type) {
|
|
158
|
+
return undefined;
|
|
159
|
+
}
|
|
160
|
+
return [...this.providers].find(
|
|
161
|
+
(provider) =>
|
|
162
|
+
provider.contextType === type &&
|
|
163
|
+
provider.getItems().some((item) => item.uri === uri),
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
|
|
145
167
|
/**
|
|
146
|
-
*
|
|
168
|
+
* Resolve only the requested context items, querying each matching provider
|
|
147
169
|
*/
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
170
|
+
resolveItems(contextIds: ContextLocatorId[]): T[] {
|
|
171
|
+
if (contextIds.length === 0) {
|
|
172
|
+
return [];
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const idsByType = new MultiMap<string, ContextLocatorId>();
|
|
176
|
+
for (const contextId of contextIds) {
|
|
177
|
+
const type = parseContextType(contextId);
|
|
178
|
+
if (type) {
|
|
179
|
+
idsByType.add(type, contextId);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const itemsById = new Map<ContextLocatorId, T>();
|
|
184
|
+
for (const [type, ids] of idsByType.entries()) {
|
|
185
|
+
const providers = [...this.providers].filter(
|
|
186
|
+
(provider) => provider.contextType === type,
|
|
187
|
+
);
|
|
188
|
+
for (const provider of providers) {
|
|
189
|
+
const itemsByUri = new Map<ContextLocatorId, T>(
|
|
190
|
+
provider
|
|
191
|
+
.getItems()
|
|
192
|
+
.map((item) => [item.uri as ContextLocatorId, item as T]),
|
|
193
|
+
);
|
|
194
|
+
for (const id of ids) {
|
|
195
|
+
const item = itemsByUri.get(id);
|
|
196
|
+
if (item) {
|
|
197
|
+
itemsById.set(id, item);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
153
202
|
|
|
203
|
+
// Preserve the order in which the ids were requested, so formatted context
|
|
204
|
+
// matches the order the user mentioned them in the prompt.
|
|
205
|
+
const results: T[] = [];
|
|
154
206
|
for (const contextId of contextIds) {
|
|
155
|
-
const item =
|
|
207
|
+
const item = itemsById.get(contextId);
|
|
156
208
|
if (item) {
|
|
157
|
-
|
|
209
|
+
results.push(item);
|
|
158
210
|
}
|
|
159
211
|
}
|
|
212
|
+
return results;
|
|
213
|
+
}
|
|
160
214
|
|
|
161
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Get context information for mentioned items
|
|
217
|
+
*/
|
|
218
|
+
getContextInfo(contextIds: ContextLocatorId[]): T[] {
|
|
219
|
+
return this.resolveItems(contextIds);
|
|
162
220
|
}
|
|
163
221
|
|
|
164
222
|
/**
|
|
165
223
|
* Format context for AI prompt inclusion
|
|
166
224
|
*/
|
|
167
225
|
formatContextForAI(contextIds: ContextLocatorId[]): string {
|
|
168
|
-
const
|
|
169
|
-
this.getAllItems().map((item) => [item.uri as ContextLocatorId, item]),
|
|
170
|
-
);
|
|
171
|
-
|
|
172
|
-
const contextInfo: T[] = [];
|
|
173
|
-
for (const contextId of contextIds) {
|
|
174
|
-
const item = allItems.get(contextId);
|
|
175
|
-
if (item) {
|
|
176
|
-
contextInfo.push(item);
|
|
177
|
-
}
|
|
178
|
-
}
|
|
226
|
+
const contextInfo = this.resolveItems(contextIds);
|
|
179
227
|
|
|
180
228
|
if (contextInfo.length === 0) {
|
|
181
229
|
return "";
|
|
@@ -183,7 +231,7 @@ export class AIContextRegistry<T extends AIContextItem> {
|
|
|
183
231
|
|
|
184
232
|
return contextInfo
|
|
185
233
|
.map((item) => {
|
|
186
|
-
const provider = this.
|
|
234
|
+
const provider = this.findProviderForUri(item.uri as ContextLocatorId);
|
|
187
235
|
return provider?.formatContext(item) || "";
|
|
188
236
|
})
|
|
189
237
|
.join("\n\n");
|
|
@@ -195,36 +243,22 @@ export class AIContextRegistry<T extends AIContextItem> {
|
|
|
195
243
|
async getAttachmentsForContext(
|
|
196
244
|
contextIds: ContextLocatorId[],
|
|
197
245
|
): Promise<FileUIPart[]> {
|
|
198
|
-
const
|
|
199
|
-
this.getAllItems().map((item) => [item.uri as ContextLocatorId, item]),
|
|
200
|
-
);
|
|
201
|
-
|
|
202
|
-
const contextInfo: T[] = [];
|
|
203
|
-
for (const contextId of contextIds) {
|
|
204
|
-
const item = allItems.get(contextId);
|
|
205
|
-
if (item) {
|
|
206
|
-
contextInfo.push(item);
|
|
207
|
-
}
|
|
208
|
-
}
|
|
246
|
+
const contextInfo = this.resolveItems(contextIds);
|
|
209
247
|
|
|
210
248
|
if (contextInfo.length === 0) {
|
|
211
249
|
return [];
|
|
212
250
|
}
|
|
213
251
|
|
|
214
|
-
|
|
215
|
-
const itemsByProvider = new MultiMap<string, T>();
|
|
252
|
+
const itemsByProvider = new MultiMap<AIContextProvider, T>();
|
|
216
253
|
for (const item of contextInfo) {
|
|
217
|
-
const
|
|
218
|
-
|
|
254
|
+
const provider = this.findProviderForUri(item.uri as ContextLocatorId);
|
|
255
|
+
if (provider) {
|
|
256
|
+
itemsByProvider.add(provider, item);
|
|
257
|
+
}
|
|
219
258
|
}
|
|
220
259
|
|
|
221
|
-
// Collect attachments from all providers
|
|
222
260
|
const attachmentPromises = [...itemsByProvider.entries()].map(
|
|
223
|
-
async ([
|
|
224
|
-
const provider = this.getProvider(providerType);
|
|
225
|
-
if (!provider) {
|
|
226
|
-
return [];
|
|
227
|
-
}
|
|
261
|
+
async ([provider, items]) => {
|
|
228
262
|
try {
|
|
229
263
|
return await provider.getAttachments(items);
|
|
230
264
|
} catch (error) {
|
|
@@ -11,6 +11,7 @@ import {
|
|
|
11
11
|
resourceDecorations,
|
|
12
12
|
resourceInputFilter,
|
|
13
13
|
resourcesField,
|
|
14
|
+
resourceSync,
|
|
14
15
|
resourceTheme,
|
|
15
16
|
} from "@marimo-team/codemirror-mcp";
|
|
16
17
|
import {
|
|
@@ -38,25 +39,28 @@ const NONE_RESOURCE_FORMAT_COMPLETION = {
|
|
|
38
39
|
},
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
function getRegistryResources(store: JotaiStore): Resource[] {
|
|
43
|
+
const registry = getAIContextRegistry(store);
|
|
44
|
+
const resources = registry.getAllItems();
|
|
45
|
+
if (resources.length === 0) {
|
|
46
|
+
return NONE_RESOURCE;
|
|
47
|
+
}
|
|
48
|
+
return resources;
|
|
49
|
+
}
|
|
50
|
+
|
|
41
51
|
export function resourceExtension(opts: {
|
|
42
52
|
language: Language;
|
|
43
53
|
store: JotaiStore;
|
|
44
54
|
onAddFiles?: (files: File[]) => void;
|
|
45
55
|
}): Extension[] {
|
|
46
56
|
const { language, store, onAddFiles } = opts;
|
|
57
|
+
const getResources = () => getRegistryResources(store);
|
|
47
58
|
|
|
48
59
|
return [
|
|
49
60
|
language.data.of({
|
|
50
61
|
// Resource completion for static resources (variables, tables, etc.)
|
|
51
62
|
autocomplete: resourceCompletion(
|
|
52
|
-
async (): Promise<Resource[]> =>
|
|
53
|
-
const registry = getAIContextRegistry(store);
|
|
54
|
-
const resources = registry.getAllItems();
|
|
55
|
-
if (resources.length === 0) {
|
|
56
|
-
return NONE_RESOURCE;
|
|
57
|
-
}
|
|
58
|
-
return resources;
|
|
59
|
-
},
|
|
63
|
+
async (): Promise<Resource[]> => getResources(),
|
|
60
64
|
(resource) => {
|
|
61
65
|
if (resource.type === NONE_RESOURCE_TYPE) {
|
|
62
66
|
return NONE_RESOURCE_FORMAT_COMPLETION;
|
|
@@ -92,9 +96,10 @@ export function resourceExtension(opts: {
|
|
|
92
96
|
: []),
|
|
93
97
|
resourceDecorations,
|
|
94
98
|
resourceInputFilter,
|
|
99
|
+
// Resolve @-mention chips for programmatic prefills.
|
|
100
|
+
resourceSync(getResources, { logger: Logger }),
|
|
95
101
|
resourcesField.init(() => {
|
|
96
|
-
const
|
|
97
|
-
const resources = registry.getAllItems();
|
|
102
|
+
const resources = getRegistryResources(store);
|
|
98
103
|
return new Map(resources.map((resource) => [resource.uri, resource]));
|
|
99
104
|
}),
|
|
100
105
|
resourceTheme,
|
|
@@ -6,6 +6,7 @@ import type { AiCompletionCell } from "../ai/state";
|
|
|
6
6
|
import type { CellId } from "../cells/ids";
|
|
7
7
|
import type { MarimoError } from "../kernel/messages";
|
|
8
8
|
import { wrapInFunction } from "./utils";
|
|
9
|
+
import { store } from "../state/jotai";
|
|
9
10
|
|
|
10
11
|
interface AIFix {
|
|
11
12
|
setAiCompletionCell: (opts: AiCompletionCell) => void;
|
|
@@ -84,7 +85,7 @@ export function getAutoFixes(
|
|
|
84
85
|
description: "Fix the SQL statement",
|
|
85
86
|
fixType: "ai",
|
|
86
87
|
onFix: async (ctx) => {
|
|
87
|
-
const datasourceContext = getDatasourceContext(ctx.cellId);
|
|
88
|
+
const datasourceContext = getDatasourceContext(ctx.cellId, store);
|
|
88
89
|
let initialPrompt = `Fix the SQL statement: ${error.msg}.`;
|
|
89
90
|
if (datasourceContext) {
|
|
90
91
|
initialPrompt += `\nDatabase schema: ${datasourceContext}`;
|
package/src/core/mime.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/* Copyright 2026 Marimo. All rights reserved. */
|
|
2
2
|
import type { OutputMessage } from "./kernel/messages";
|
|
3
3
|
|
|
4
|
+
export function isMarimoErrorsMime(
|
|
5
|
+
mime: OutputMessage["mimetype"] | undefined,
|
|
6
|
+
) {
|
|
7
|
+
return mime === "application/vnd.marimo+error";
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export function isTracebackMime(mime: OutputMessage["mimetype"] | undefined) {
|
|
11
|
+
return mime === "application/vnd.marimo+traceback";
|
|
12
|
+
}
|
|
13
|
+
|
|
4
14
|
export function isErrorMime(mime: OutputMessage["mimetype"] | undefined) {
|
|
5
|
-
return (
|
|
6
|
-
mime === "application/vnd.marimo+error" ||
|
|
7
|
-
mime === "application/vnd.marimo+traceback"
|
|
8
|
-
);
|
|
15
|
+
return isMarimoErrorsMime(mime) || isTracebackMime(mime);
|
|
9
16
|
}
|