@multiplayer-app/sandbox 0.0.16 → 0.0.17

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 (76) hide show
  1. package/dist/agents/notebook.agent.d.ts +4 -0
  2. package/dist/agents/notebook.agent.d.ts.map +1 -0
  3. package/dist/agents/notebook.agent.js +48 -0
  4. package/dist/agents/notebook.agent.js.map +1 -0
  5. package/dist/agents/shared/content-generator-system-prompt.d.ts +1 -1
  6. package/dist/agents/shared/content-generator-system-prompt.d.ts.map +1 -1
  7. package/dist/agents/shared/content-generator-system-prompt.js +3 -3
  8. package/dist/agents/shared/notebook-agent-system-prompt.d.ts +2 -0
  9. package/dist/agents/shared/notebook-agent-system-prompt.d.ts.map +1 -0
  10. package/dist/agents/shared/notebook-agent-system-prompt.js +64 -0
  11. package/dist/agents/shared/notebook-agent-system-prompt.js.map +1 -0
  12. package/dist/agents/shared/notebook-tools.d.ts +24 -0
  13. package/dist/agents/shared/notebook-tools.d.ts.map +1 -0
  14. package/dist/agents/shared/notebook-tools.js +383 -0
  15. package/dist/agents/shared/notebook-tools.js.map +1 -0
  16. package/dist/agents/shared/publish-session-artifacts.tool.d.ts +2 -0
  17. package/dist/agents/shared/publish-session-artifacts.tool.d.ts.map +1 -1
  18. package/dist/agents/shared/publish-session-artifacts.tool.js +41 -26
  19. package/dist/agents/shared/publish-session-artifacts.tool.js.map +1 -1
  20. package/dist/agents/shared/update-session-artifacts.tool.d.ts.map +1 -1
  21. package/dist/agents/shared/update-session-artifacts.tool.js +37 -20
  22. package/dist/agents/shared/update-session-artifacts.tool.js.map +1 -1
  23. package/dist/agents.d.ts.map +1 -1
  24. package/dist/agents.js +2 -0
  25. package/dist/agents.js.map +1 -1
  26. package/dist/context.d.ts +2 -1
  27. package/dist/context.d.ts.map +1 -1
  28. package/dist/context.js.map +1 -1
  29. package/dist/create-builder-api.d.ts +3 -1
  30. package/dist/create-builder-api.d.ts.map +1 -1
  31. package/dist/create-builder-api.js +1 -0
  32. package/dist/create-builder-api.js.map +1 -1
  33. package/dist/index.d.ts +1 -0
  34. package/dist/index.d.ts.map +1 -1
  35. package/dist/index.js +3 -1
  36. package/dist/index.js.map +1 -1
  37. package/dist/lib/notebooks/notebook-assistant.d.ts +2 -0
  38. package/dist/lib/notebooks/notebook-assistant.d.ts.map +1 -1
  39. package/dist/lib/notebooks/notebook-assistant.js +1 -0
  40. package/dist/lib/notebooks/notebook-assistant.js.map +1 -1
  41. package/dist/lib/notebooks/notebook-yjs-blocks.d.ts +46 -0
  42. package/dist/lib/notebooks/notebook-yjs-blocks.d.ts.map +1 -0
  43. package/dist/lib/notebooks/notebook-yjs-blocks.js +223 -0
  44. package/dist/lib/notebooks/notebook-yjs-blocks.js.map +1 -0
  45. package/dist/lib/session-artifacts/hashline-tags.d.ts +17 -0
  46. package/dist/lib/session-artifacts/hashline-tags.d.ts.map +1 -0
  47. package/dist/lib/session-artifacts/hashline-tags.js +69 -0
  48. package/dist/lib/session-artifacts/hashline-tags.js.map +1 -0
  49. package/dist/lib/session-artifacts/parse-hashline-diff.d.ts +1 -0
  50. package/dist/lib/session-artifacts/parse-hashline-diff.d.ts.map +1 -1
  51. package/dist/lib/session-artifacts/parse-hashline-diff.js +30 -9
  52. package/dist/lib/session-artifacts/parse-hashline-diff.js.map +1 -1
  53. package/dist/lib/session-pages/html-artifact-template.d.ts +12 -0
  54. package/dist/lib/session-pages/html-artifact-template.d.ts.map +1 -0
  55. package/dist/lib/session-pages/html-artifact-template.js +46 -0
  56. package/dist/lib/session-pages/html-artifact-template.js.map +1 -0
  57. package/dist/lib/session-pages/write-session-artifacts.d.ts +4 -0
  58. package/dist/lib/session-pages/write-session-artifacts.d.ts.map +1 -1
  59. package/dist/lib/session-pages/write-session-artifacts.js +8 -1
  60. package/dist/lib/session-pages/write-session-artifacts.js.map +1 -1
  61. package/dist/lib/socket/artifact-events.d.ts.map +1 -1
  62. package/dist/lib/socket/artifact-events.js +8 -1
  63. package/dist/lib/socket/artifact-events.js.map +1 -1
  64. package/dist/lib/sql-schema.d.ts +1 -0
  65. package/dist/lib/sql-schema.d.ts.map +1 -1
  66. package/dist/realtime/session-artifact-yjs-store.d.ts +7 -0
  67. package/dist/realtime/session-artifact-yjs-store.d.ts.map +1 -1
  68. package/dist/realtime/session-artifact-yjs-store.js +29 -0
  69. package/dist/realtime/session-artifact-yjs-store.js.map +1 -1
  70. package/dist/routes/chats/multiUserMessages.d.ts.map +1 -1
  71. package/dist/routes/chats/multiUserMessages.js +2 -0
  72. package/dist/routes/chats/multiUserMessages.js.map +1 -1
  73. package/dist/routes/chats/stream.d.ts.map +1 -1
  74. package/dist/routes/chats/stream.js +2 -0
  75. package/dist/routes/chats/stream.js.map +1 -1
  76. package/package.json +1 -1
@@ -0,0 +1,4 @@
1
+ import type { AgentConfig } from '@multiplayer-app/ai-agent-types';
2
+ import type { BuilderApiAgentDeps } from '../builder-api-config';
3
+ export declare function createNotebookAgent(deps: BuilderApiAgentDeps): AgentConfig;
4
+ //# sourceMappingURL=notebook.agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebook.agent.d.ts","sourceRoot":"","sources":["../../src/agents/notebook.agent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAA;AAElE,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAA;AAOhE,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,mBAAmB,GAAG,WAAW,CA2C1E"}
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createNotebookAgent = createNotebookAgent;
4
+ const ai_agent_types_1 = require("@multiplayer-app/ai-agent-types");
5
+ const logger_1 = require("../logger");
6
+ const notebook_yjs_blocks_1 = require("../lib/notebooks/notebook-yjs-blocks");
7
+ const session_artifact_yjs_store_1 = require("../realtime/session-artifact-yjs-store");
8
+ const notebook_agent_system_prompt_1 = require("./shared/notebook-agent-system-prompt");
9
+ const notebook_tools_1 = require("./shared/notebook-tools");
10
+ function createNotebookAgent(deps) {
11
+ return {
12
+ name: 'notebook-assistant',
13
+ description: 'Reads, searches, and edits the collaborative notebook the user has open, including runnable SQL, code, and chart blocks',
14
+ defaultModel: deps.defaultModel,
15
+ systemPrompt: notebook_agent_system_prompt_1.NOTEBOOK_AGENT_SYSTEM_PROMPT,
16
+ stopWhen: () => false,
17
+ prepareStep: async (options, context) => {
18
+ if (options.stepCount > 0) {
19
+ return undefined;
20
+ }
21
+ try {
22
+ const target = await (0, notebook_tools_1.resolveNotebookTarget)(context);
23
+ const fragment = await (0, session_artifact_yjs_store_1.getSessionArtifactYjsStore)().getNotebookFragment(target.accountId, target.notebookId);
24
+ const outline = (0, notebook_yjs_blocks_1.buildOutline)((0, notebook_yjs_blocks_1.readFragmentBlocks)(fragment));
25
+ return {
26
+ messages: [
27
+ ...options.messages,
28
+ {
29
+ role: 'system',
30
+ content: `Current notebook outline (index: type — preview):\n${outline.length > 0
31
+ ? outline.map((entry) => `${entry.index}: ${entry.type} — ${entry.preview}`).join('\n')
32
+ : '(empty notebook)'}`,
33
+ },
34
+ ],
35
+ };
36
+ }
37
+ catch (err) {
38
+ (0, logger_1.getBuilderApiLogger)().warn({ err }, 'Notebook agent: failed to inject outline');
39
+ return undefined;
40
+ }
41
+ },
42
+ tools: [
43
+ { type: ai_agent_types_1.AgentToolType.REQUEST_CLARIFICATION, userConfigurable: true },
44
+ ...notebook_tools_1.notebookTools,
45
+ ],
46
+ };
47
+ }
48
+ //# sourceMappingURL=notebook.agent.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebook.agent.js","sourceRoot":"","sources":["../../src/agents/notebook.agent.ts"],"names":[],"mappings":";;AASA,kDA2CC;AAnDD,oEAA+D;AAE/D,sCAA+C;AAC/C,8EAAuF;AACvF,uFAAmF;AACnF,wFAAoF;AACpF,4DAA8E;AAE9E,SAAgB,mBAAmB,CAAC,IAAyB;IAC3D,OAAO;QACL,IAAI,EAAE,oBAAoB;QAC1B,WAAW,EACT,yHAAyH;QAC3H,YAAY,EAAE,IAAI,CAAC,YAAY;QAC/B,YAAY,EAAE,2DAA4B;QAC1C,QAAQ,EAAE,GAAG,EAAE,CAAC,KAAK;QACrB,WAAW,EAAE,KAAK,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE;YACtC,IAAI,OAAO,CAAC,SAAS,GAAG,CAAC,EAAE,CAAC;gBAC1B,OAAO,SAAS,CAAA;YAClB,CAAC;YAED,IAAI,CAAC;gBACH,MAAM,MAAM,GAAG,MAAM,IAAA,sCAAqB,EAAC,OAAO,CAAC,CAAA;gBACnD,MAAM,QAAQ,GAAG,MAAM,IAAA,uDAA0B,GAAE,CAAC,mBAAmB,CACrE,MAAM,CAAC,SAAS,EAChB,MAAM,CAAC,UAAU,CAClB,CAAA;gBACD,MAAM,OAAO,GAAG,IAAA,kCAAY,EAAC,IAAA,wCAAkB,EAAC,QAAQ,CAAC,CAAC,CAAA;gBAC1D,OAAO;oBACL,QAAQ,EAAE;wBACR,GAAG,OAAO,CAAC,QAAQ;wBACnB;4BACE,IAAI,EAAE,QAAiB;4BACvB,OAAO,EAAE,sDACP,OAAO,CAAC,MAAM,GAAG,CAAC;gCAChB,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,GAAG,KAAK,CAAC,KAAK,KAAK,KAAK,CAAC,IAAI,MAAM,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;gCACvF,CAAC,CAAC,kBACN,EAAE;yBACH;qBACF;iBACF,CAAA;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,IAAA,4BAAmB,GAAE,CAAC,IAAI,CAAC,EAAE,GAAG,EAAE,EAAE,0CAA0C,CAAC,CAAA;gBAC/E,OAAO,SAAS,CAAA;YAClB,CAAC;QACH,CAAC;QACD,KAAK,EAAE;YACL,EAAE,IAAI,EAAE,8BAAa,CAAC,qBAAqB,EAAE,gBAAgB,EAAE,IAAI,EAAE;YACrE,GAAG,8BAAa;SACjB;KACF,CAAA;AACH,CAAC"}
@@ -1,3 +1,3 @@
1
1
  /** Shared system prompt for content-generator / html-generator agents. */
2
- export declare const CONTENT_GENERATOR_SYSTEM_PROMPT = "You generate and update session artifacts for both UI and docs. Use publishSessionArtifacts for NEW files and updateSessionArtifact for EXISTING files.\n\nWorkflow:\n1. Decide output mode:\n - UI/HTML (default): each .html page is self-contained \u2014 page logic in <script> and only small overrides in <style> (same file, e.g. index.html). For multiple pages, publish one .html per page (index.html, about.html, \u2026), each self-contained.\n - Split assets (only when the user explicitly asks): separate styles.css, script.js, and/or extra .css/.js, linked from HTML via relative URLs (./styles.css, ./script.js).\n - Docs: .md files such as README.md, docs/architecture.md\n - Optional data: JSON under data/ (e.g. data/metrics.json), loaded from inline <script> when needed.\n2. Keep paths relative (no leading slash). Do not add styles.css or script.js unless the user requested split files or you are extending an existing split layout.\n3. Existing session artifacts are listed in a system message.\n4. New paths: publishSessionArtifacts with task, artifacts[], and parentContext. parentContext MUST include: (a) outputs from any knowledge tools you called this session (e.g. getWeather), (b) relevant prior conversation excerpts, (c) concrete data values the subagent cannot fetch itself. The subagent has NO access to your chat history or tool results \u2014 if data is not in parentContext, it will be missing from the page.\n5. Existing paths: updateSessionArtifact with parentContext and task (include the path). One path per call. Same parentContext rules as step 4.\n6. Mixed create + update: publish new paths only, then update each existing path separately.\n7. previewPath: primary .md for doc-only publishes; main entry .html (usually index.html) for UI.\n8. After publish, give previewUrl; after edit, the updated path; after read/Q&A, relay excerpts/summary only.\n\nHTML / UI (Pico CSS):\n- Use Pico-friendly HTML5: <!DOCTYPE html>, <html lang=\"...\">, charset + viewport in <head>, <body> with <main class=\"container\"> (or class=\"container-fluid\") wrapping content.\n- Prefer semantic Pico elements: header, nav, main, section, article, aside, footer, table, figure, button, input, select, textarea, details, dialog. Use Pico patterns for grids/cards (e.g. class=\"grid\") instead of large custom layout CSS.\n- Keep custom <style> minimal (only what Pico cannot express). \n- Put behavior in <script>.\n\nRules:\n- Prefer concise, production-grade output.\n- Do not overwrite existing paths via publishSessionArtifacts.\n- You do not have validateHtml or validateMarkdown; delegated subagents run validation.\n- When editing, keep the same layout model as the session (inline vs split files).";
2
+ export declare const CONTENT_GENERATOR_SYSTEM_PROMPT = "You generate and update session artifacts for both UI and docs. Use publishSessionArtifacts for NEW files and updateSessionArtifact for EXISTING files.\n\nWorkflow:\n1. Decide output mode:\n - UI/HTML (default): publish body/main fragments per .html page (page logic in <script>, small overrides in <style>). The server wraps fragments in a Pico CSS template \u2014 do not generate <!DOCTYPE>/<html>/<head> boilerplate unless the user explicitly wants a full custom document.\n - Split assets (only when the user explicitly asks): separate styles.css, script.js, and/or extra .css/.js, linked from HTML via relative URLs (./styles.css, ./script.js).\n - Docs: .md files such as README.md, docs/architecture.md\n - Optional data: JSON under data/ (e.g. data/metrics.json), loaded from inline <script> when needed.\n2. Keep paths relative (no leading slash). Do not add styles.css or script.js unless the user requested split files or you are extending an existing split layout.\n3. Existing session artifacts are listed in a system message.\n4. New paths: publishSessionArtifacts with task, artifacts[], and parentContext. parentContext MUST include: (a) outputs from any knowledge tools you called this session (e.g. getWeather), (b) relevant prior conversation excerpts, (c) concrete data values the subagent cannot fetch itself. The subagent has NO access to your chat history or tool results \u2014 if data is not in parentContext, it will be missing from the page.\n5. Existing paths: updateSessionArtifact with parentContext and task (include the path). One path per call. Same parentContext rules as step 4.\n6. Mixed create + update: publish new paths only, then update each existing path separately.\n7. previewPath: primary .md for doc-only publishes; main entry .html (usually index.html) for UI.\n8. After publish, give previewUrl; after edit, the updated path; after read/Q&A, relay excerpts/summary only.\n\nHTML / UI (Pico CSS):\n- New .html files: send fragments only (semantic body content); server adds Pico template shell.\n- Prefer semantic Pico elements: header, nav, section, article, aside, footer, table, figure, button, input, select, textarea, details, dialog. Use Pico patterns for grids/cards (e.g. class=\"grid\") instead of large custom layout CSS.\n- Keep custom <style> minimal (only what Pico cannot express). \n- Put behavior in <script>.\n\nRules:\n- Prefer concise, production-grade output.\n- Do not overwrite existing paths via publishSessionArtifacts.\n- You do not have validateHtml or validateMarkdown; delegated subagents run validation.\n- When editing, keep the same layout model as the session (inline vs split files).";
3
3
  //# sourceMappingURL=content-generator-system-prompt.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"content-generator-system-prompt.d.ts","sourceRoot":"","sources":["../../../src/agents/shared/content-generator-system-prompt.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,eAAO,MAAM,+BAA+B,+qFA0BuC,CAAA"}
1
+ {"version":3,"file":"content-generator-system-prompt.d.ts","sourceRoot":"","sources":["../../../src/agents/shared/content-generator-system-prompt.ts"],"names":[],"mappings":"AAAA,0EAA0E;AAC1E,eAAO,MAAM,+BAA+B,mnFA0BuC,CAAA"}
@@ -6,7 +6,7 @@ exports.CONTENT_GENERATOR_SYSTEM_PROMPT = `You generate and update session artif
6
6
 
7
7
  Workflow:
8
8
  1. Decide output mode:
9
- - UI/HTML (default): each .html page is self-contained — page logic in <script> and only small overrides in <style> (same file, e.g. index.html). For multiple pages, publish one .html per page (index.html, about.html, …), each self-contained.
9
+ - UI/HTML (default): publish body/main fragments per .html page (page logic in <script>, small overrides in <style>). The server wraps fragments in a Pico CSS template do not generate <!DOCTYPE>/<html>/<head> boilerplate unless the user explicitly wants a full custom document.
10
10
  - Split assets (only when the user explicitly asks): separate styles.css, script.js, and/or extra .css/.js, linked from HTML via relative URLs (./styles.css, ./script.js).
11
11
  - Docs: .md files such as README.md, docs/architecture.md
12
12
  - Optional data: JSON under data/ (e.g. data/metrics.json), loaded from inline <script> when needed.
@@ -19,8 +19,8 @@ Workflow:
19
19
  8. After publish, give previewUrl; after edit, the updated path; after read/Q&A, relay excerpts/summary only.
20
20
 
21
21
  HTML / UI (Pico CSS):
22
- - Use Pico-friendly HTML5: <!DOCTYPE html>, <html lang="...">, charset + viewport in <head>, <body> with <main class="container"> (or class="container-fluid") wrapping content.
23
- - Prefer semantic Pico elements: header, nav, main, section, article, aside, footer, table, figure, button, input, select, textarea, details, dialog. Use Pico patterns for grids/cards (e.g. class="grid") instead of large custom layout CSS.
22
+ - New .html files: send fragments only (semantic body content); server adds Pico template shell.
23
+ - Prefer semantic Pico elements: header, nav, section, article, aside, footer, table, figure, button, input, select, textarea, details, dialog. Use Pico patterns for grids/cards (e.g. class="grid") instead of large custom layout CSS.
24
24
  - Keep custom <style> minimal (only what Pico cannot express).
25
25
  - Put behavior in <script>.
26
26
 
@@ -0,0 +1,2 @@
1
+ export declare const NOTEBOOK_AGENT_SYSTEM_PROMPT = "You are a collaborative notebook copilot. You work on the notebook the user currently has open; your edits appear live in their editor (and for every other connected collaborator) the moment a tool call succeeds. There is no separate apply step \u2014 never paste notebook content into chat when the user asks you to add or change it; use the tools.\n\n## Workflow\n\n1. ALWAYS call getNotebookOutline first to see the current blocks and their indexes.\n2. Read before you change: use readNotebookBlocks on the relevant range before updateNotebookBlock, and pass expectedType so concurrent human edits are caught.\n3. Prefer targeted edits (insertNotebookBlocks, updateNotebookBlock, deleteNotebookBlocks) over replaceNotebookContent, which wipes the whole document.\n4. Block indexes shift after every write and other people may be editing at the same time \u2014 re-check the outline (every write tool returns a fresh one) before further edits.\n5. Before writing sqlBlock queries or answering data questions, call getSqlSchema; use runSqlQuery to inspect real data.\n6. Use searchNotebook to locate content in long notebooks instead of reading everything.\n\n## Document format\n\nBlocks are TipTap (ProseMirror) JSON nodes. Rich text lives in \"content\" arrays of {\"type\":\"text\",\"text\":\"...\",\"marks\":[...]} nodes; marks are {\"type\":\"bold\"|\"italic\"|\"strike\"|\"code\"|\"underline\"|\"highlight\"|\"link\",...} (link marks take \"attrs\":{\"href\":\"...\"}).\n\nStandard blocks:\n- {\"type\":\"paragraph\",\"content\":[textNodes]}\n- {\"type\":\"heading\",\"attrs\":{\"level\":1..6},\"content\":[textNodes]}\n- {\"type\":\"bulletList\"|\"orderedList\",\"content\":[{\"type\":\"listItem\",\"content\":[paragraphs]}]}\n- {\"type\":\"taskList\",\"content\":[{\"type\":\"taskItem\",\"attrs\":{\"checked\":false},\"content\":[paragraphs]}]}\n- {\"type\":\"codeBlock\",\"attrs\":{\"language\":\"javascript\"},\"content\":[{\"type\":\"text\",\"text\":\"...\"}]} \u2014 display-only code, never executed\n- {\"type\":\"blockquote\",\"content\":[paragraphs]}\n- {\"type\":\"horizontalRule\"}\n- {\"type\":\"table\",\"content\":[{\"type\":\"tableRow\",\"content\":[{\"type\":\"tableHeader\"|\"tableCell\",\"content\":[paragraphs]}]}]}\n\n## Runnable blocks\n\nRunnable blocks are atoms: all data lives in attrs, there is no \"content\" array. Each needs a unique \"_globalName\" \u2014 a short camelCase JavaScript identifier. When a block runs, its result is stored under that name and every OTHER runnable block can read it as a global variable with exactly that name. A block that has not been run yet is undefined \u2014 code must handle that. \"_id\" is generated automatically if omitted.\n\n### sqlBlock\n{\"type\":\"sqlBlock\",\"attrs\":{\"_globalName\":\"usersByRole\",\"databaseName\":\"<name from getSqlSchema>\",\"query\":\"SELECT ...\"}}\n- Exactly one PostgreSQL SELECT statement. The connection is READ ONLY \u2014 INSERT/UPDATE/DELETE/DDL or multiple statements fail.\n- Its global value after running: {columns: string[], rows: Array<Record<string, value>>, rowCount: number, durationMs: number}. Other blocks read <name>.rows / <name>.columns.\n\n### runnableCodeBlock\n{\"type\":\"runnableCodeBlock\",\"attrs\":{\"_globalName\":\"topProducts\",\"content\":\"<JavaScript source>\",\"language\":\"javascript\"}}\nExecutes in a QuickJS sandbox VM \u2014 NOT a browser:\n- No DOM, no window, no document, no fetch, no timers. console.log/warn/error work (they log to the browser devtools console, not into the notebook).\n- Other runnable blocks' results are plain globals by their _globalName (e.g. usersByRole.rows).\n- The block's VALUE is its last evaluated expression \u2014 end the code with the expression you want to expose to other blocks (no return statement at top level). Example: \"const totals = usersByRole.rows.map(r => r.amount); totals\" exposes the array.\n- npm libraries: ESM imports are fetched from esm.sh \u2014 \"import _ from 'lodash'\" works; CommonJS/AMD via \"await require('name')\". Prefer plain JavaScript; imports cost time against the limit.\n- Hard limits: ~1 second CPU time, 640 KB memory. Keep computations small; do heavy filtering/aggregation in sqlBlock queries instead.\n\n### chartBlock\n{\"type\":\"chartBlock\",\"attrs\":{\"_globalName\":\"salesChart\",\"title\":\"...\",\"html\":\"...\",\"css\":\"...\",\"javascript\":\"...\",\"language\":\"javascript\"}}\nRenders in a sandboxed iframe assembled as: your \"css\" in a <style> tag, your \"html\" inside a container div in the body, your \"javascript\" as a <script type=\"module\"> that runs after the html is parsed.\n- The iframe has NO libraries preloaded. Every library must be loaded via a <script> tag inside the \"html\" attr, or the code fails (e.g. \"Chart is not defined\"). Use Chart.js by default: the \"html\" attr MUST start with <script src=\"https://cdn.jsdelivr.net/npm/chart.js\"></script> followed by a <canvas> element, and \"javascript\" creates the Chart instance on that canvas.\n- Other runnable blocks' results are injected as read-only const globals by _globalName (sqlBlock: read <name>.rows / <name>.columns). Handle the not-yet-run undefined case.\n- \"javascript\" is an ES module: top-level await and URL imports are allowed.\n- Network: use proxyFetch(url, options) for HTTP requests (routed through the app). Direct fetch/XHR is rate-limited to 5 requests per domain per 10s; WebSocket, sendBeacon, and clipboard are blocked. Prefer chart data from block globals, not network calls.\n- The iframe auto-resizes to its content and has a transparent background; the text color follows the app theme (light or dark), so avoid hard-coding backgrounds or text colors in \"css\".\n- Runtime errors are shown on the block in the editor, so a broken chartBlock is visible to the user.\n\nOnly use the block types listed above \u2014 unknown types (including restApiBlock, which is disabled in this notebook) are dropped by the editor.\n\n## Style\n\n- Keep chat replies short: say what you changed and where, not the full content you wrote.\n- When asked questions about the notebook, answer from the actual blocks (read them first).\n- If a request is ambiguous about where or what to change, ask before writing.";
2
+ //# sourceMappingURL=notebook-agent-system-prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebook-agent-system-prompt.d.ts","sourceRoot":"","sources":["../../../src/agents/shared/notebook-agent-system-prompt.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,4BAA4B,unMA2DsC,CAAA"}
@@ -0,0 +1,64 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.NOTEBOOK_AGENT_SYSTEM_PROMPT = void 0;
4
+ exports.NOTEBOOK_AGENT_SYSTEM_PROMPT = `You are a collaborative notebook copilot. You work on the notebook the user currently has open; your edits appear live in their editor (and for every other connected collaborator) the moment a tool call succeeds. There is no separate apply step — never paste notebook content into chat when the user asks you to add or change it; use the tools.
5
+
6
+ ## Workflow
7
+
8
+ 1. ALWAYS call getNotebookOutline first to see the current blocks and their indexes.
9
+ 2. Read before you change: use readNotebookBlocks on the relevant range before updateNotebookBlock, and pass expectedType so concurrent human edits are caught.
10
+ 3. Prefer targeted edits (insertNotebookBlocks, updateNotebookBlock, deleteNotebookBlocks) over replaceNotebookContent, which wipes the whole document.
11
+ 4. Block indexes shift after every write and other people may be editing at the same time — re-check the outline (every write tool returns a fresh one) before further edits.
12
+ 5. Before writing sqlBlock queries or answering data questions, call getSqlSchema; use runSqlQuery to inspect real data.
13
+ 6. Use searchNotebook to locate content in long notebooks instead of reading everything.
14
+
15
+ ## Document format
16
+
17
+ Blocks are TipTap (ProseMirror) JSON nodes. Rich text lives in "content" arrays of {"type":"text","text":"...","marks":[...]} nodes; marks are {"type":"bold"|"italic"|"strike"|"code"|"underline"|"highlight"|"link",...} (link marks take "attrs":{"href":"..."}).
18
+
19
+ Standard blocks:
20
+ - {"type":"paragraph","content":[textNodes]}
21
+ - {"type":"heading","attrs":{"level":1..6},"content":[textNodes]}
22
+ - {"type":"bulletList"|"orderedList","content":[{"type":"listItem","content":[paragraphs]}]}
23
+ - {"type":"taskList","content":[{"type":"taskItem","attrs":{"checked":false},"content":[paragraphs]}]}
24
+ - {"type":"codeBlock","attrs":{"language":"javascript"},"content":[{"type":"text","text":"..."}]} — display-only code, never executed
25
+ - {"type":"blockquote","content":[paragraphs]}
26
+ - {"type":"horizontalRule"}
27
+ - {"type":"table","content":[{"type":"tableRow","content":[{"type":"tableHeader"|"tableCell","content":[paragraphs]}]}]}
28
+
29
+ ## Runnable blocks
30
+
31
+ Runnable blocks are atoms: all data lives in attrs, there is no "content" array. Each needs a unique "_globalName" — a short camelCase JavaScript identifier. When a block runs, its result is stored under that name and every OTHER runnable block can read it as a global variable with exactly that name. A block that has not been run yet is undefined — code must handle that. "_id" is generated automatically if omitted.
32
+
33
+ ### sqlBlock
34
+ {"type":"sqlBlock","attrs":{"_globalName":"usersByRole","databaseName":"<name from getSqlSchema>","query":"SELECT ..."}}
35
+ - Exactly one PostgreSQL SELECT statement. The connection is READ ONLY — INSERT/UPDATE/DELETE/DDL or multiple statements fail.
36
+ - Its global value after running: {columns: string[], rows: Array<Record<string, value>>, rowCount: number, durationMs: number}. Other blocks read <name>.rows / <name>.columns.
37
+
38
+ ### runnableCodeBlock
39
+ {"type":"runnableCodeBlock","attrs":{"_globalName":"topProducts","content":"<JavaScript source>","language":"javascript"}}
40
+ Executes in a QuickJS sandbox VM — NOT a browser:
41
+ - No DOM, no window, no document, no fetch, no timers. console.log/warn/error work (they log to the browser devtools console, not into the notebook).
42
+ - Other runnable blocks' results are plain globals by their _globalName (e.g. usersByRole.rows).
43
+ - The block's VALUE is its last evaluated expression — end the code with the expression you want to expose to other blocks (no return statement at top level). Example: "const totals = usersByRole.rows.map(r => r.amount); totals" exposes the array.
44
+ - npm libraries: ESM imports are fetched from esm.sh — "import _ from 'lodash'" works; CommonJS/AMD via "await require('name')". Prefer plain JavaScript; imports cost time against the limit.
45
+ - Hard limits: ~1 second CPU time, 640 KB memory. Keep computations small; do heavy filtering/aggregation in sqlBlock queries instead.
46
+
47
+ ### chartBlock
48
+ {"type":"chartBlock","attrs":{"_globalName":"salesChart","title":"...","html":"...","css":"...","javascript":"...","language":"javascript"}}
49
+ Renders in a sandboxed iframe assembled as: your "css" in a <style> tag, your "html" inside a container div in the body, your "javascript" as a <script type="module"> that runs after the html is parsed.
50
+ - The iframe has NO libraries preloaded. Every library must be loaded via a <script> tag inside the "html" attr, or the code fails (e.g. "Chart is not defined"). Use Chart.js by default: the "html" attr MUST start with <script src="https://cdn.jsdelivr.net/npm/chart.js"></script> followed by a <canvas> element, and "javascript" creates the Chart instance on that canvas.
51
+ - Other runnable blocks' results are injected as read-only const globals by _globalName (sqlBlock: read <name>.rows / <name>.columns). Handle the not-yet-run undefined case.
52
+ - "javascript" is an ES module: top-level await and URL imports are allowed.
53
+ - Network: use proxyFetch(url, options) for HTTP requests (routed through the app). Direct fetch/XHR is rate-limited to 5 requests per domain per 10s; WebSocket, sendBeacon, and clipboard are blocked. Prefer chart data from block globals, not network calls.
54
+ - The iframe auto-resizes to its content and has a transparent background; the text color follows the app theme (light or dark), so avoid hard-coding backgrounds or text colors in "css".
55
+ - Runtime errors are shown on the block in the editor, so a broken chartBlock is visible to the user.
56
+
57
+ Only use the block types listed above — unknown types (including restApiBlock, which is disabled in this notebook) are dropped by the editor.
58
+
59
+ ## Style
60
+
61
+ - Keep chat replies short: say what you changed and where, not the full content you wrote.
62
+ - When asked questions about the notebook, answer from the actual blocks (read them first).
63
+ - If a request is ambiguous about where or what to change, ask before writing.`;
64
+ //# sourceMappingURL=notebook-agent-system-prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebook-agent-system-prompt.js","sourceRoot":"","sources":["../../../src/agents/shared/notebook-agent-system-prompt.ts"],"names":[],"mappings":";;;AAAa,QAAA,4BAA4B,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;+EA2DmC,CAAA"}
@@ -0,0 +1,24 @@
1
+ import type { AdditionalContext, AgentTool } from '@multiplayer-app/ai-agent-types';
2
+ interface NotebookTarget {
3
+ accountId: string;
4
+ notebookId: string;
5
+ }
6
+ /**
7
+ * The notebook id rides on chat message metadata (attached client-side by the
8
+ * NotebookChatPanel via useChatMetadata) and is forwarded into `context.data.metadata`
9
+ * by the chat stream routes. Approval-resume payloads may drop it, so fall back to
10
+ * the metadata persisted on the chat record.
11
+ */
12
+ declare function resolveNotebookTarget(context?: AdditionalContext): Promise<NotebookTarget>;
13
+ export declare const getNotebookOutlineTool: AgentTool;
14
+ export declare const readNotebookBlocksTool: AgentTool;
15
+ export declare const searchNotebookTool: AgentTool;
16
+ export declare const insertNotebookBlocksTool: AgentTool;
17
+ export declare const updateNotebookBlockTool: AgentTool;
18
+ export declare const deleteNotebookBlocksTool: AgentTool;
19
+ export declare const replaceNotebookContentTool: AgentTool;
20
+ export declare const getSqlSchemaTool: AgentTool;
21
+ export declare const runSqlQueryTool: AgentTool;
22
+ export declare const notebookTools: AgentTool[];
23
+ export { resolveNotebookTarget };
24
+ //# sourceMappingURL=notebook-tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"notebook-tools.d.ts","sourceRoot":"","sources":["../../../src/agents/shared/notebook-tools.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,SAAS,EAAE,MAAM,iCAAiC,CAAA;AAoBnF,UAAU,cAAc;IACtB,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;;;;GAKG;AACH,iBAAe,qBAAqB,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,OAAO,CAAC,cAAc,CAAC,CAsBzF;AA6BD,eAAO,MAAM,sBAAsB,EAAE,SA4BpC,CAAA;AAOD,eAAO,MAAM,sBAAsB,EAAE,SAwCpC,CAAA;AAMD,eAAO,MAAM,kBAAkB,EAAE,SAmChC,CAAA;AAOD,eAAO,MAAM,wBAAwB,EAAE,SAmCtC,CAAA;AAWD,eAAO,MAAM,uBAAuB,EAAE,SAiDrC,CAAA;AAOD,eAAO,MAAM,wBAAwB,EAAE,SA8CtC,CAAA;AAMD,eAAO,MAAM,0BAA0B,EAAE,SAoCxC,CAAA;AAED,eAAO,MAAM,gBAAgB,EAAE,SA0B9B,CAAA;AAOD,eAAO,MAAM,eAAe,EAAE,SA6B7B,CAAA;AAED,eAAO,MAAM,aAAa,EAAE,SAAS,EAUpC,CAAA;AAED,OAAO,EAAE,qBAAqB,EAAE,CAAA"}
@@ -0,0 +1,383 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.notebookTools = exports.runSqlQueryTool = exports.getSqlSchemaTool = exports.replaceNotebookContentTool = exports.deleteNotebookBlocksTool = exports.updateNotebookBlockTool = exports.insertNotebookBlocksTool = exports.searchNotebookTool = exports.readNotebookBlocksTool = exports.getNotebookOutlineTool = void 0;
4
+ exports.resolveNotebookTarget = resolveNotebookTarget;
5
+ const ai_agent_types_1 = require("@multiplayer-app/ai-agent-types");
6
+ const zod_1 = require("zod");
7
+ const context_1 = require("../../context");
8
+ const notebook_assistant_1 = require("../../lib/notebooks/notebook-assistant");
9
+ const notebook_yjs_blocks_1 = require("../../lib/notebooks/notebook-yjs-blocks");
10
+ const session_artifact_yjs_store_1 = require("../../realtime/session-artifact-yjs-store");
11
+ const READ_BLOCKS_CHAR_LIMIT = 60000;
12
+ const SQL_RESULT_ROW_LIMIT = 50;
13
+ /**
14
+ * The notebook id rides on chat message metadata (attached client-side by the
15
+ * NotebookChatPanel via useChatMetadata) and is forwarded into `context.data.metadata`
16
+ * by the chat stream routes. Approval-resume payloads may drop it, so fall back to
17
+ * the metadata persisted on the chat record.
18
+ */
19
+ async function resolveNotebookTarget(context) {
20
+ var _a, _b, _c;
21
+ const accountId = (_a = context === null || context === void 0 ? void 0 : context.data) === null || _a === void 0 ? void 0 : _a.accountId;
22
+ if (!accountId) {
23
+ throw new Error('Account ID is required');
24
+ }
25
+ const metadata = (_b = context === null || context === void 0 ? void 0 : context.data) === null || _b === void 0 ? void 0 : _b.metadata;
26
+ let notebookId = typeof (metadata === null || metadata === void 0 ? void 0 : metadata.notebookId) === 'string' ? metadata.notebookId : undefined;
27
+ if (!notebookId) {
28
+ const chatId = (_c = context === null || context === void 0 ? void 0 : context.data) === null || _c === void 0 ? void 0 : _c.chatId;
29
+ if (chatId) {
30
+ const chat = await (0, context_1.getAgentService)().getChatProcessor().getChat(chatId);
31
+ const chatMetadata = chat === null || chat === void 0 ? void 0 : chat.metadata;
32
+ notebookId = typeof (chatMetadata === null || chatMetadata === void 0 ? void 0 : chatMetadata.notebookId) === 'string' ? chatMetadata.notebookId : undefined;
33
+ }
34
+ }
35
+ if (!notebookId) {
36
+ throw new Error('Notebook ID is missing from chat metadata');
37
+ }
38
+ return { accountId, notebookId };
39
+ }
40
+ function getNotebookRepository() {
41
+ const repository = (0, context_1.getBuilderApiContext)().notebookRepository;
42
+ if (!repository) {
43
+ throw new Error('Notebook repository is not configured');
44
+ }
45
+ return repository;
46
+ }
47
+ async function readNotebookBlocksFor(target) {
48
+ const fragment = await (0, session_artifact_yjs_store_1.getSessionArtifactYjsStore)().getNotebookFragment(target.accountId, target.notebookId);
49
+ return (0, notebook_yjs_blocks_1.readFragmentBlocks)(fragment);
50
+ }
51
+ const outlineEntrySchema = zod_1.z.object({
52
+ index: zod_1.z.number(),
53
+ type: zod_1.z.string(),
54
+ preview: zod_1.z.string(),
55
+ attrs: zod_1.z.record(zod_1.z.string(), zod_1.z.unknown()).optional(),
56
+ });
57
+ async function currentOutline(target) {
58
+ return (0, notebook_yjs_blocks_1.buildOutline)(await readNotebookBlocksFor(target));
59
+ }
60
+ exports.getNotebookOutlineTool = {
61
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
62
+ userConfigurable: true,
63
+ data: {
64
+ needsApproval: false,
65
+ title: 'getNotebookOutline',
66
+ description: 'List the notebook title and a numbered outline of its top-level blocks (index, type, text preview). Always call this before reading or editing blocks.',
67
+ inputSchema: zod_1.z.object({}),
68
+ outputSchema: zod_1.z.object({
69
+ title: zod_1.z.string(),
70
+ blockCount: zod_1.z.number(),
71
+ blocks: zod_1.z.array(outlineEntrySchema),
72
+ }),
73
+ execute: async (_input, context) => {
74
+ const target = await resolveNotebookTarget(context);
75
+ const notebook = await getNotebookRepository().getById(target.accountId, target.notebookId);
76
+ if (!notebook) {
77
+ throw new Error('Notebook not found');
78
+ }
79
+ const blocks = await readNotebookBlocksFor(target);
80
+ return {
81
+ title: notebook.title,
82
+ blockCount: blocks.length,
83
+ blocks: (0, notebook_yjs_blocks_1.buildOutline)(blocks),
84
+ };
85
+ },
86
+ },
87
+ };
88
+ const readNotebookBlocksInputSchema = zod_1.z.object({
89
+ from: zod_1.z.number().int().min(0).optional().describe('First top-level block index (inclusive, default 0)'),
90
+ to: zod_1.z.number().int().min(0).optional().describe('Last top-level block index (inclusive, default last block)'),
91
+ });
92
+ exports.readNotebookBlocksTool = {
93
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
94
+ userConfigurable: true,
95
+ data: {
96
+ needsApproval: false,
97
+ title: 'readNotebookBlocks',
98
+ description: 'Read the full TipTap JSON of top-level notebook blocks in an index range. Use getNotebookOutline first to pick the range; prefer narrow ranges for large notebooks.',
99
+ inputSchema: readNotebookBlocksInputSchema,
100
+ outputSchema: zod_1.z.object({
101
+ blocks: zod_1.z.array(zod_1.z.object({ index: zod_1.z.number(), block: notebook_yjs_blocks_1.tipTapNodeSchema })),
102
+ truncated: zod_1.z.boolean(),
103
+ }),
104
+ execute: async (input, context) => {
105
+ var _a, _b;
106
+ const target = await resolveNotebookTarget(context);
107
+ const allBlocks = await readNotebookBlocksFor(target);
108
+ const from = (_a = input.from) !== null && _a !== void 0 ? _a : 0;
109
+ const to = Math.min((_b = input.to) !== null && _b !== void 0 ? _b : allBlocks.length - 1, allBlocks.length - 1);
110
+ const blocks = [];
111
+ let charCount = 0;
112
+ let truncated = false;
113
+ for (let index = from; index <= to; index += 1) {
114
+ const block = allBlocks[index];
115
+ if (!block) {
116
+ continue;
117
+ }
118
+ charCount += JSON.stringify(block).length;
119
+ if (charCount > READ_BLOCKS_CHAR_LIMIT && blocks.length > 0) {
120
+ truncated = true;
121
+ break;
122
+ }
123
+ blocks.push({ index, block });
124
+ }
125
+ return { blocks, truncated };
126
+ },
127
+ },
128
+ };
129
+ const searchNotebookInputSchema = zod_1.z.object({
130
+ query: zod_1.z.string().min(1).describe('Case-insensitive text to find in block text, code, or SQL queries'),
131
+ });
132
+ exports.searchNotebookTool = {
133
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
134
+ userConfigurable: true,
135
+ data: {
136
+ needsApproval: false,
137
+ title: 'searchNotebook',
138
+ description: 'Find top-level blocks whose text, code, or SQL query contains the given text.',
139
+ inputSchema: searchNotebookInputSchema,
140
+ outputSchema: zod_1.z.object({
141
+ matches: zod_1.z.array(zod_1.z.object({ index: zod_1.z.number(), type: zod_1.z.string(), snippet: zod_1.z.string() })),
142
+ }),
143
+ execute: async (input, context) => {
144
+ const target = await resolveNotebookTarget(context);
145
+ const blocks = await readNotebookBlocksFor(target);
146
+ const needle = input.query.toLowerCase();
147
+ const matches = blocks.flatMap((block, index) => {
148
+ const text = (0, notebook_yjs_blocks_1.blockPlainText)(block);
149
+ const at = text.toLowerCase().indexOf(needle);
150
+ if (at < 0) {
151
+ return [];
152
+ }
153
+ const start = Math.max(0, at - 60);
154
+ return [{
155
+ index,
156
+ type: block.type,
157
+ snippet: text.slice(start, at + needle.length + 60),
158
+ }];
159
+ });
160
+ return { matches };
161
+ },
162
+ },
163
+ };
164
+ const insertNotebookBlocksInputSchema = zod_1.z.object({
165
+ at: zod_1.z.number().int().min(0).describe('Top-level insert position; 0 = start, blockCount = end'),
166
+ blocks: zod_1.z.array(notebook_yjs_blocks_1.tipTapNodeSchema).min(1).max(50).describe('TipTap block nodes to insert'),
167
+ });
168
+ exports.insertNotebookBlocksTool = {
169
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
170
+ userConfigurable: true,
171
+ data: {
172
+ needsApproval: false,
173
+ title: 'insertNotebookBlocks',
174
+ description: 'Insert TipTap blocks at a top-level position. Changes appear live in every open editor. Use getNotebookOutline first to pick the position.',
175
+ inputSchema: insertNotebookBlocksInputSchema,
176
+ outputSchema: zod_1.z.object({
177
+ insertedAt: zod_1.z.number(),
178
+ insertedCount: zod_1.z.number(),
179
+ outline: zod_1.z.array(outlineEntrySchema),
180
+ }),
181
+ execute: async (input, context) => {
182
+ const target = await resolveNotebookTarget(context);
183
+ let insertedAt = 0;
184
+ await (0, session_artifact_yjs_store_1.getSessionArtifactYjsStore)().mutateNotebook(target.accountId, target.notebookId, (fragment) => {
185
+ insertedAt = Math.min(input.at, fragment.length);
186
+ fragment.insert(insertedAt, input.blocks.map((block) => (0, notebook_yjs_blocks_1.tipTapNodeToYXml)((0, notebook_yjs_blocks_1.ensureRunnableBlockAttrs)(block))));
187
+ });
188
+ return {
189
+ insertedAt,
190
+ insertedCount: input.blocks.length,
191
+ outline: await currentOutline(target),
192
+ };
193
+ },
194
+ },
195
+ };
196
+ const updateNotebookBlockInputSchema = zod_1.z.object({
197
+ index: zod_1.z.number().int().min(0).describe('Top-level index of the block to replace'),
198
+ expectedType: zod_1.z
199
+ .string()
200
+ .optional()
201
+ .describe('Expected type of the current block at that index; the update fails if it differs'),
202
+ block: notebook_yjs_blocks_1.tipTapNodeSchema.describe('Replacement TipTap block node'),
203
+ });
204
+ exports.updateNotebookBlockTool = {
205
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
206
+ userConfigurable: true,
207
+ data: {
208
+ needsApproval: false,
209
+ title: 'updateNotebookBlock',
210
+ description: 'Replace one top-level block. Read the block first (readNotebookBlocks) and pass expectedType to guard against concurrent edits.',
211
+ inputSchema: updateNotebookBlockInputSchema,
212
+ outputSchema: zod_1.z.object({
213
+ index: zod_1.z.number(),
214
+ outline: zod_1.z.array(outlineEntrySchema),
215
+ }),
216
+ execute: async (input, context) => {
217
+ const target = await resolveNotebookTarget(context);
218
+ await (0, session_artifact_yjs_store_1.getSessionArtifactYjsStore)().mutateNotebook(target.accountId, target.notebookId, (fragment) => {
219
+ if (input.index >= fragment.length) {
220
+ throw new Error(`Block index ${input.index} is out of range (notebook has ${fragment.length} blocks); call getNotebookOutline again`);
221
+ }
222
+ if (input.expectedType) {
223
+ const existing = fragment.get(input.index);
224
+ const existingType = existing instanceof Object && 'nodeName' in existing
225
+ ? existing.nodeName
226
+ : 'text';
227
+ if (existingType !== input.expectedType) {
228
+ throw new Error(`Block at index ${input.index} is "${existingType}", expected "${input.expectedType}"; the notebook changed — call getNotebookOutline again`);
229
+ }
230
+ }
231
+ fragment.delete(input.index, 1);
232
+ fragment.insert(input.index, [(0, notebook_yjs_blocks_1.tipTapNodeToYXml)((0, notebook_yjs_blocks_1.ensureRunnableBlockAttrs)(input.block))]);
233
+ });
234
+ return {
235
+ index: input.index,
236
+ outline: await currentOutline(target),
237
+ };
238
+ },
239
+ },
240
+ };
241
+ const deleteNotebookBlocksInputSchema = zod_1.z.object({
242
+ from: zod_1.z.number().int().min(0).describe('First top-level block index to delete (inclusive)'),
243
+ to: zod_1.z.number().int().min(0).describe('Last top-level block index to delete (inclusive)'),
244
+ });
245
+ exports.deleteNotebookBlocksTool = {
246
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
247
+ userConfigurable: true,
248
+ data: {
249
+ needsApproval: false,
250
+ title: 'deleteNotebookBlocks',
251
+ description: 'Delete a range of top-level blocks. Verify indexes with getNotebookOutline first.',
252
+ inputSchema: deleteNotebookBlocksInputSchema,
253
+ outputSchema: zod_1.z.object({
254
+ deletedCount: zod_1.z.number(),
255
+ deleted: zod_1.z.array(outlineEntrySchema),
256
+ outline: zod_1.z.array(outlineEntrySchema),
257
+ }),
258
+ execute: async (input, context) => {
259
+ if (input.to < input.from) {
260
+ throw new Error('"to" must be greater than or equal to "from"');
261
+ }
262
+ const target = await resolveNotebookTarget(context);
263
+ let deletedCount = 0;
264
+ let deleted = [];
265
+ await (0, session_artifact_yjs_store_1.getSessionArtifactYjsStore)().mutateNotebook(target.accountId, target.notebookId, (fragment) => {
266
+ if (input.from >= fragment.length) {
267
+ throw new Error(`Block index ${input.from} is out of range (notebook has ${fragment.length} blocks)`);
268
+ }
269
+ deletedCount = Math.min(input.to, fragment.length - 1) - input.from + 1;
270
+ deleted = (0, notebook_yjs_blocks_1.buildOutline)((0, notebook_yjs_blocks_1.readFragmentBlocks)(fragment).slice(input.from, input.from + deletedCount));
271
+ fragment.delete(input.from, deletedCount);
272
+ });
273
+ return {
274
+ deletedCount,
275
+ deleted,
276
+ outline: await currentOutline(target),
277
+ };
278
+ },
279
+ },
280
+ };
281
+ const replaceNotebookContentInputSchema = zod_1.z.object({
282
+ blocks: zod_1.z.array(notebook_yjs_blocks_1.tipTapNodeSchema).max(200).describe('New TipTap blocks for the whole notebook'),
283
+ });
284
+ exports.replaceNotebookContentTool = {
285
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
286
+ userConfigurable: true,
287
+ data: {
288
+ needsApproval: false,
289
+ title: 'replaceNotebookContent',
290
+ description: 'Replace the ENTIRE notebook content. Destructive — prefer insertNotebookBlocks/updateNotebookBlock for targeted changes.',
291
+ inputSchema: replaceNotebookContentInputSchema,
292
+ outputSchema: zod_1.z.object({
293
+ blockCount: zod_1.z.number(),
294
+ outline: zod_1.z.array(outlineEntrySchema),
295
+ }),
296
+ execute: async (input, context) => {
297
+ const target = await resolveNotebookTarget(context);
298
+ await (0, session_artifact_yjs_store_1.getSessionArtifactYjsStore)().mutateNotebook(target.accountId, target.notebookId, (fragment) => {
299
+ if (fragment.length > 0) {
300
+ fragment.delete(0, fragment.length);
301
+ }
302
+ if (input.blocks.length > 0) {
303
+ fragment.insert(0, input.blocks.map((block) => (0, notebook_yjs_blocks_1.tipTapNodeToYXml)((0, notebook_yjs_blocks_1.ensureRunnableBlockAttrs)(block))));
304
+ }
305
+ });
306
+ return {
307
+ blockCount: input.blocks.length,
308
+ outline: await currentOutline(target),
309
+ };
310
+ },
311
+ },
312
+ };
313
+ exports.getSqlSchemaTool = {
314
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
315
+ userConfigurable: true,
316
+ data: {
317
+ needsApproval: false,
318
+ title: 'getSqlSchema',
319
+ description: 'List available SQL databases with their tables and columns. Call this before writing sqlBlock queries or running SQL.',
320
+ inputSchema: zod_1.z.object({}),
321
+ outputSchema: zod_1.z.object({
322
+ databases: zod_1.z.array(zod_1.z.object({ name: zod_1.z.string(), schema: zod_1.z.string() })),
323
+ }),
324
+ execute: async () => {
325
+ const provider = (0, context_1.getBuilderApiContext)().sqlSchemaProvider;
326
+ if (!provider) {
327
+ throw new Error('SQL schema provider is not configured');
328
+ }
329
+ const databases = await provider.listDatabases();
330
+ return {
331
+ databases: databases.map((database) => ({
332
+ name: database.name,
333
+ schema: (0, notebook_assistant_1.formatSqlDatabaseForPrompt)(database),
334
+ })),
335
+ };
336
+ },
337
+ },
338
+ };
339
+ const runSqlQueryInputSchema = zod_1.z.object({
340
+ query: zod_1.z.string().min(1).describe('A single PostgreSQL SELECT statement'),
341
+ databaseName: zod_1.z.string().min(1).describe('Database name from getSqlSchema'),
342
+ });
343
+ exports.runSqlQueryTool = {
344
+ type: ai_agent_types_1.AgentToolType.LOCAL_FUNCTION,
345
+ userConfigurable: true,
346
+ data: {
347
+ needsApproval: false,
348
+ title: 'runSqlQuery',
349
+ description: `Run a read-only SQL SELECT query and return up to ${SQL_RESULT_ROW_LIMIT} rows. Use it to inspect data before writing notebook content or sqlBlock queries.`,
350
+ inputSchema: runSqlQueryInputSchema,
351
+ outputSchema: zod_1.z.object({
352
+ columns: zod_1.z.array(zod_1.z.string()),
353
+ rows: zod_1.z.array(zod_1.z.record(zod_1.z.string(), zod_1.z.unknown())),
354
+ rowCount: zod_1.z.number(),
355
+ truncated: zod_1.z.boolean(),
356
+ }),
357
+ execute: async (input) => {
358
+ const executor = (0, context_1.getBuilderApiContext)().sqlExecutor;
359
+ if (!executor) {
360
+ throw new Error('SQL executor is not configured');
361
+ }
362
+ const result = await executor(input.query, input.databaseName);
363
+ return {
364
+ columns: result.columns,
365
+ rows: result.rows.slice(0, SQL_RESULT_ROW_LIMIT),
366
+ rowCount: result.rowCount,
367
+ truncated: result.rows.length > SQL_RESULT_ROW_LIMIT,
368
+ };
369
+ },
370
+ },
371
+ };
372
+ exports.notebookTools = [
373
+ exports.getNotebookOutlineTool,
374
+ exports.readNotebookBlocksTool,
375
+ exports.searchNotebookTool,
376
+ exports.insertNotebookBlocksTool,
377
+ exports.updateNotebookBlockTool,
378
+ exports.deleteNotebookBlocksTool,
379
+ exports.replaceNotebookContentTool,
380
+ exports.getSqlSchemaTool,
381
+ exports.runSqlQueryTool,
382
+ ];
383
+ //# sourceMappingURL=notebook-tools.js.map