@actalk/inkos-studio 1.6.1 → 1.6.3-canary.52.1

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 (65) hide show
  1. package/dist/api/server.d.ts.map +1 -1
  2. package/dist/api/server.js +163 -3
  3. package/dist/api/server.js.map +1 -1
  4. package/dist/assets/{FilmWizard-DEDrqO5H.js → FilmWizard-C_1W4acq.js} +1 -1
  5. package/dist/assets/{FlowView-DUBkKiff.js → FlowView-DvrwPvo2.js} +1 -1
  6. package/dist/assets/{_baseUniq-DYxaUtZI.js → _baseUniq-B-ZYRDWx.js} +1 -1
  7. package/dist/assets/{arc-CHuRYqSh.js → arc-Ciw3FGtr.js} +1 -1
  8. package/dist/assets/{architectureDiagram-Q4EWVU46-BRVULDTV.js → architectureDiagram-Q4EWVU46-mC_rz2X6.js} +1 -1
  9. package/dist/assets/{blockDiagram-DXYQGD6D-DKQr_EU5.js → blockDiagram-DXYQGD6D-D_GMBRzY.js} +1 -1
  10. package/dist/assets/{c4Diagram-AHTNJAMY-6OA3wnaj.js → c4Diagram-AHTNJAMY-CvmmAOg5.js} +1 -1
  11. package/dist/assets/channel-F10GB4f_.js +1 -0
  12. package/dist/assets/{chunk-4BX2VUAB-RPzgJJNb.js → chunk-4BX2VUAB-BPr0k8sP.js} +1 -1
  13. package/dist/assets/{chunk-4TB4RGXK-C4RNzHuu.js → chunk-4TB4RGXK-D-Y1Qj_T.js} +1 -1
  14. package/dist/assets/{chunk-55IACEB6-D7M7RO-J.js → chunk-55IACEB6-Bug_ufgD.js} +1 -1
  15. package/dist/assets/{chunk-EDXVE4YY-DZY9MFLO.js → chunk-EDXVE4YY-C7tD8L3k.js} +1 -1
  16. package/dist/assets/{chunk-FMBD7UC4-QMoMGo7W.js → chunk-FMBD7UC4-BU7HNA1K.js} +1 -1
  17. package/dist/assets/{chunk-OYMX7WX6-CQWjKnzn.js → chunk-OYMX7WX6-DQ_CIv08.js} +1 -1
  18. package/dist/assets/{chunk-QZHKN3VN-D16FUhg8.js → chunk-QZHKN3VN-HODyXosI.js} +1 -1
  19. package/dist/assets/{chunk-YZCP3GAM-CqRHihc7.js → chunk-YZCP3GAM-7Y8K_8MD.js} +1 -1
  20. package/dist/assets/classDiagram-6PBFFD2Q-BqBb7BDW.js +1 -0
  21. package/dist/assets/classDiagram-v2-HSJHXN6E-BqBb7BDW.js +1 -0
  22. package/dist/assets/clone-DOQmcAsj.js +1 -0
  23. package/dist/assets/{cose-bilkent-S5V4N54A-bfoOQLsv.js → cose-bilkent-S5V4N54A-D2kYbpZy.js} +1 -1
  24. package/dist/assets/{dagre-KV5264BT-BCyLituE.js → dagre-KV5264BT-BlyZQ0n0.js} +1 -1
  25. package/dist/assets/{diagram-5BDNPKRD-CPkN139r.js → diagram-5BDNPKRD-C3lJ6ObZ.js} +1 -1
  26. package/dist/assets/{diagram-G4DWMVQ6-DFLt39fl.js → diagram-G4DWMVQ6-hx-WGqJX.js} +1 -1
  27. package/dist/assets/{diagram-MMDJMWI5-DYYmrlVW.js → diagram-MMDJMWI5-CdI5Z_ZJ.js} +1 -1
  28. package/dist/assets/{diagram-TYMM5635-BZ3Pv-hE.js → diagram-TYMM5635-BmtYRsNe.js} +1 -1
  29. package/dist/assets/{erDiagram-SMLLAGMA-CAKauIJm.js → erDiagram-SMLLAGMA-DPokxoLy.js} +1 -1
  30. package/dist/assets/{flowDiagram-DWJPFMVM-KB2eEgGe.js → flowDiagram-DWJPFMVM-DFnf6GAZ.js} +1 -1
  31. package/dist/assets/{ganttDiagram-T4ZO3ILL-JMol99Z2.js → ganttDiagram-T4ZO3ILL-ymFoiBFD.js} +1 -1
  32. package/dist/assets/{gitGraphDiagram-UUTBAWPF-Bj2wACW5.js → gitGraphDiagram-UUTBAWPF-BOAZqylM.js} +1 -1
  33. package/dist/assets/{graph-mzOZJsmK.js → graph-BMumGBmN.js} +1 -1
  34. package/dist/assets/{highlighted-body-OFNGDK62-C5zsRw66.js → highlighted-body-OFNGDK62-DRX5PypI.js} +1 -1
  35. package/dist/assets/index-BZMnkfN7.css +1 -0
  36. package/dist/assets/{index-BXxzots5.js → index-MiIZL4f3.js} +291 -280
  37. package/dist/assets/{infoDiagram-42DDH7IO-DJiZjg4e.js → infoDiagram-42DDH7IO-D0iCgAlu.js} +1 -1
  38. package/dist/assets/{ishikawaDiagram-UXIWVN3A-D3C3S2GG.js → ishikawaDiagram-UXIWVN3A-WtqHTEzb.js} +1 -1
  39. package/dist/assets/{journeyDiagram-VCZTEJTY-oox1ioYZ.js → journeyDiagram-VCZTEJTY-DUlKzcQ-.js} +1 -1
  40. package/dist/assets/{kanban-definition-6JOO6SKY-DmK_6JO5.js → kanban-definition-6JOO6SKY-COYae0oO.js} +1 -1
  41. package/dist/assets/{layout-BU0zwXna.js → layout-Et_h2gsr.js} +1 -1
  42. package/dist/assets/{linear-BTTy9rEg.js → linear-DY_vot7D.js} +1 -1
  43. package/dist/assets/{min-CxsTU35L.js → min-CImNjYIc.js} +1 -1
  44. package/dist/assets/{mindmap-definition-QFDTVHPH-B9yvRvsY.js → mindmap-definition-QFDTVHPH-zOJ7uKnl.js} +1 -1
  45. package/dist/assets/{pieDiagram-DEJITSTG-BRDyhVEN.js → pieDiagram-DEJITSTG-BftexWKs.js} +1 -1
  46. package/dist/assets/{quadrantDiagram-34T5L4WZ-CHuq8duY.js → quadrantDiagram-34T5L4WZ-CHmM6MYD.js} +1 -1
  47. package/dist/assets/{requirementDiagram-MS252O5E-CPZMaTta.js → requirementDiagram-MS252O5E-eMzrziUe.js} +1 -1
  48. package/dist/assets/{sankeyDiagram-XADWPNL6-ukpqhioK.js → sankeyDiagram-XADWPNL6-B-Bgmxmu.js} +1 -1
  49. package/dist/assets/{sequenceDiagram-FGHM5R23-_HE4wLAQ.js → sequenceDiagram-FGHM5R23-cFT-__W_.js} +1 -1
  50. package/dist/assets/{stateDiagram-FHFEXIEX-CzvbU_vB.js → stateDiagram-FHFEXIEX-CVnHwqCo.js} +1 -1
  51. package/dist/assets/stateDiagram-v2-QKLJ7IA2-nhhJvKGq.js +1 -0
  52. package/dist/assets/{timeline-definition-GMOUNBTQ-CjOUyryC.js → timeline-definition-GMOUNBTQ-CKbNRuf9.js} +1 -1
  53. package/dist/assets/{value-BRre6T9m.js → value-IOfiG7E7.js} +1 -1
  54. package/dist/assets/{vennDiagram-DHZGUBPP-ByHmBMvF.js → vennDiagram-DHZGUBPP-BDoxftwQ.js} +1 -1
  55. package/dist/assets/{wardley-RL74JXVD-BJB7tkWD.js → wardley-RL74JXVD-5TXAieIJ.js} +1 -1
  56. package/dist/assets/{wardleyDiagram-NUSXRM2D-CPNSDUV6.js → wardleyDiagram-NUSXRM2D-CFpD2tIy.js} +1 -1
  57. package/dist/assets/{xychartDiagram-5P7HB3ND-BPC25pDH.js → xychartDiagram-5P7HB3ND-cP5C2vcw.js} +1 -1
  58. package/dist/index.html +2 -2
  59. package/package.json +2 -2
  60. package/dist/assets/channel-CbescFQS.js +0 -1
  61. package/dist/assets/classDiagram-6PBFFD2Q-BbJjgfyw.js +0 -1
  62. package/dist/assets/classDiagram-v2-HSJHXN6E-BbJjgfyw.js +0 -1
  63. package/dist/assets/clone-D07SvwIC.js +0 -1
  64. package/dist/assets/index-Pc31QmUJ.css +0 -1
  65. package/dist/assets/stateDiagram-v2-QKLJ7IA2-Zuwgf5Ss.js +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,OAAO,EAyFL,KAAK,aAAa,EAIlB,KAAK,aAAa,EAKnB,MAAM,oBAAoB,CAAC;AA+6D5B,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE;IAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,aAAa,CAAA;CAAO,8EAq4G7I;AAID,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,SAAO,EACX,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAK5B,OAAO,EAgGL,KAAK,aAAa,EAIlB,KAAK,aAAa,EAMnB,MAAM,oBAAoB,CAAC;AA8jE5B,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE;IAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,aAAa,CAAA;CAAO,8EAq7G7I;AAID,wBAAsB,iBAAiB,CACrC,IAAI,EAAE,MAAM,EACZ,IAAI,SAAO,EACX,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,GACxC,OAAO,CAAC,IAAI,CAAC,CA8Cf"}
@@ -3,7 +3,7 @@ import { cors } from "hono/cors";
3
3
  import { streamSSE } from "hono/streaming";
4
4
  import { serve } from "@hono/node-server";
5
5
  import { gzipSync } from "node:zlib";
6
- import { StateManager, PipelineRunner, createLLMClient, createLogger, createInteractionToolsFromDeps, computeAnalytics, loadProjectConfig, loadProjectSession, processProjectInteractionRequest, resolveSessionActiveBook, listBookSessions, loadBookSession, appendManualSessionMessages, createAndPersistBookSession, renameBookSession, deleteBookSession, migrateBookSession, SessionAlreadyMigratedError, runAgentSession, resolveServicePreset, resolveServiceProviderFamily, resolveServiceModelsBaseUrl, guessServiceFromBaseUrl, resolveServiceModel, loadSecrets, saveSecrets, listModelsForService, isApiKeyOptionalForEndpoint, getAllEndpoints, probeModelsFromUpstream, fetchWithProxy, chatCompletion, buildExportArtifact, evaluateBookQuality, ConsolidatorAgent, DetectionConfigSchema, ResearchSearchConfigSchema, InputGovernanceModeSchema, GLOBAL_ENV_PATH, COVER_PROVIDER_PRESETS, createPlayDB, PlayStore, buildPlayEntityImagePrompt, buildPlaySceneImagePrompt, generatePlayImage, readPlayImageManifest, readPlayImageSettings, writePlayImageSettings, Scheduler, coverSecretKey, resolveCoverProviderPreset, SessionKindSchema, isExplicitWriteChapterCommand, isUsablePlayInitialScene, isWriteNextInstruction, normalizeActionSource as normalizeCoreActionSource, normalizeActionPayload as normalizeCoreActionPayload, normalizePlayMode as normalizeCorePlayMode, normalizeRequestedIntent as normalizeCoreRequestedIntent, normalizeSkillIdList as normalizeCoreSkillIdList, inferLanguage, createSkillRegistry, loadConfiguredCapabilitySkills, CapabilitySkillManifestSchema, createGenerateCoverTool, createInteractiveFilmCreationTool, createPlayStartTool, createScriptCreationTool, createShortFictionRunTool, createStoryboardCreationTool, createSubAgentTool, createDraftStructureTool, createConnectChoiceTool, createRemoveNodeTool, filmLLMDepsFromClient, applyGraphDelta, loadStoryGraph, reviewStoryGraph, exportInk, buildPlayableHtml, analyzeEmotionalArcs, analyzePathDistribution, generateNodeImage, defaultNodeImageDeps, } from "@actalk/inkos-core";
6
+ import { StateManager, PipelineRunner, createLLMClient, createLogger, createInteractionToolsFromDeps, computeAnalytics, loadProjectConfig, loadProjectSession, processProjectInteractionRequest, resolveSessionActiveBook, listBookSessions, loadBookSession, appendManualSessionMessages, createAndPersistBookSession, renameBookSession, deleteBookSession, migrateBookSession, SessionAlreadyMigratedError, abortAgentSession, runAgentSession, resolveServicePreset, resolveServiceProviderFamily, resolveServiceModelsBaseUrl, guessServiceFromBaseUrl, resolveServiceModel, loadSecrets, saveSecrets, listModelsForService, isApiKeyOptionalForEndpoint, getAllEndpoints, probeModelsFromUpstream, fetchWithProxy, chatCompletion, buildExportArtifact, evaluateBookQuality, ConsolidatorAgent, DetectionConfigSchema, ResearchSearchConfigSchema, InputGovernanceModeSchema, GLOBAL_ENV_PATH, COVER_PROVIDER_PRESETS, createPlayDB, PlayStore, buildPlayEntityImagePrompt, buildPlaySceneImagePrompt, generatePlayImage, readPlayImageManifest, readPlayImageSettings, writePlayImageSettings, Scheduler, coverSecretKey, resolveCoverProviderPreset, SessionKindSchema, isExplicitWriteChapterCommand, isUsablePlayInitialScene, isWriteNextInstruction, normalizeActionSource as normalizeCoreActionSource, normalizeActionPayload as normalizeCoreActionPayload, normalizePlayMode as normalizeCorePlayMode, normalizeRequestedIntent as normalizeCoreRequestedIntent, normalizeSkillIdList as normalizeCoreSkillIdList, inferLanguage, createSkillRegistry, loadConfiguredCapabilitySkills, CapabilitySkillManifestSchema, getBuiltinPrompt, listBuiltinPromptPacks, listBuiltinPrompts, loadPromptPackPrompt, promptOverridePath, createGenerateCoverTool, createInteractiveFilmCreationTool, createPlayStartTool, createScriptCreationTool, createShortFictionRunTool, createStoryboardCreationTool, createSubAgentTool, createDraftStructureTool, createConnectChoiceTool, createRemoveNodeTool, filmLLMDepsFromClient, applyGraphDelta, loadStoryGraph, reviewStoryGraph, exportInk, buildPlayableHtml, analyzeEmotionalArcs, analyzePathDistribution, generateNodeImage, defaultNodeImageDeps, } from "@actalk/inkos-core";
7
7
  import { access, mkdir, readFile, readdir, rm, stat, writeFile } from "node:fs/promises";
8
8
  import { dirname, isAbsolute, join, relative, resolve } from "node:path";
9
9
  import { isSafeBookId } from "./safety.js";
@@ -351,6 +351,106 @@ function normalizeStudioSkillId(value, field = "skillId") {
351
351
  throw new ApiError(400, "INVALID_SKILL_ID", `Invalid ${field}: empty`);
352
352
  return id;
353
353
  }
354
+ const MAX_AGENT_ATTACHMENTS = 8;
355
+ const MAX_AGENT_ATTACHMENT_BYTES = 4 * 1024 * 1024;
356
+ const MAX_AGENT_ATTACHMENT_TEXT_CHARS = 120_000;
357
+ function safeUploadFileName(value) {
358
+ const trimmed = value.trim().replace(/[/\\\0]/g, "_").replace(/\s+/g, " ");
359
+ const safe = trimmed.replace(/[^\p{L}\p{N}._ -]+/gu, "_").slice(0, 120).trim();
360
+ return safe || "upload";
361
+ }
362
+ function isTextAttachment(filename, mimeType) {
363
+ const lower = filename.toLowerCase();
364
+ return mimeType.startsWith("text/")
365
+ || [
366
+ ".txt",
367
+ ".md",
368
+ ".markdown",
369
+ ".json",
370
+ ".csv",
371
+ ".tsv",
372
+ ".yaml",
373
+ ".yml",
374
+ ".log",
375
+ ].some((suffix) => lower.endsWith(suffix));
376
+ }
377
+ function parseDataUrl(dataUrl) {
378
+ const match = /^data:([^;,]+)?(?:;[^,]*)?;base64,(.*)$/s.exec(dataUrl);
379
+ if (!match) {
380
+ throw new ApiError(400, "INVALID_ATTACHMENT_DATA_URL", "Attachment must be a base64 data URL");
381
+ }
382
+ const mimeType = match[1]?.trim() || "application/octet-stream";
383
+ return { mimeType, buffer: Buffer.from(match[2] ?? "", "base64") };
384
+ }
385
+ async function normalizeAgentAttachments(root, sessionId, value) {
386
+ if (value === undefined || value === null)
387
+ return [];
388
+ if (!Array.isArray(value)) {
389
+ throw new ApiError(400, "INVALID_ATTACHMENTS", "attachments must be an array");
390
+ }
391
+ if (value.length > MAX_AGENT_ATTACHMENTS) {
392
+ throw new ApiError(413, "TOO_MANY_ATTACHMENTS", `At most ${MAX_AGENT_ATTACHMENTS} files can be attached to one message`);
393
+ }
394
+ const uploadDir = join(root, ".inkos", "uploads", safeUploadFileName(sessionId));
395
+ const out = [];
396
+ for (const [index, raw] of value.entries()) {
397
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
398
+ throw new ApiError(400, "INVALID_ATTACHMENT", "Each attachment must be an object");
399
+ }
400
+ const payload = raw;
401
+ const filename = safeUploadFileName(payload.filename || `upload-${index + 1}`);
402
+ if (!payload.dataUrl) {
403
+ throw new ApiError(400, "INVALID_ATTACHMENT", `Attachment ${filename} is missing dataUrl`);
404
+ }
405
+ const parsed = parseDataUrl(payload.dataUrl);
406
+ const mimeType = payload.mediaType?.trim() || parsed.mimeType;
407
+ if (parsed.buffer.byteLength > MAX_AGENT_ATTACHMENT_BYTES) {
408
+ throw new ApiError(413, "ATTACHMENT_TOO_LARGE", `${filename} exceeds ${MAX_AGENT_ATTACHMENT_BYTES} bytes`);
409
+ }
410
+ await mkdir(uploadDir, { recursive: true });
411
+ const storedName = `${Date.now()}-${index + 1}-${filename}`;
412
+ const storedPath = join(uploadDir, storedName);
413
+ await writeFile(storedPath, parsed.buffer);
414
+ const relPath = relative(root, storedPath);
415
+ if (mimeType.startsWith("image/")) {
416
+ out.push({
417
+ id: payload.id || `${Date.now()}-${index}`,
418
+ filename,
419
+ mimeType,
420
+ size: parsed.buffer.byteLength,
421
+ storedPath: relPath,
422
+ image: {
423
+ data: parsed.buffer.toString("base64"),
424
+ mimeType,
425
+ },
426
+ });
427
+ continue;
428
+ }
429
+ if (isTextAttachment(filename, mimeType)) {
430
+ const text = parsed.buffer.toString("utf-8");
431
+ if (text.length > MAX_AGENT_ATTACHMENT_TEXT_CHARS) {
432
+ throw new ApiError(413, "ATTACHMENT_TEXT_TOO_LARGE", `${filename} is too large to inject without semantic compaction`);
433
+ }
434
+ out.push({
435
+ id: payload.id || `${Date.now()}-${index}`,
436
+ filename,
437
+ mimeType,
438
+ size: parsed.buffer.byteLength,
439
+ storedPath: relPath,
440
+ text,
441
+ });
442
+ continue;
443
+ }
444
+ out.push({
445
+ id: payload.id || `${Date.now()}-${index}`,
446
+ filename,
447
+ mimeType,
448
+ size: parsed.buffer.byteLength,
449
+ storedPath: relPath,
450
+ });
451
+ }
452
+ return out;
453
+ }
354
454
  function projectSkillsDir(root) {
355
455
  return join(root, ".inkos", "skills");
356
456
  }
@@ -443,6 +543,27 @@ async function loadStudioSkills(root) {
443
543
  diagnostics: configured.diagnostics,
444
544
  };
445
545
  }
546
+ async function toStudioPromptPackPrompt(root, prompt) {
547
+ const loaded = await loadPromptPackPrompt({ promptId: prompt.id, projectRoot: root });
548
+ const overridePath = promptOverridePath(root, prompt.id);
549
+ return {
550
+ id: prompt.id,
551
+ packId: prompt.packId,
552
+ title: prompt.title,
553
+ defaultContent: prompt.content,
554
+ content: loaded.content,
555
+ source: loaded.source,
556
+ overridden: loaded.source === "project",
557
+ path: loaded.source === "project" ? relative(root, overridePath) : undefined,
558
+ };
559
+ }
560
+ function normalizeStudioPromptId(value) {
561
+ const promptId = typeof value === "string" ? value.trim().toLowerCase() : "";
562
+ if (!promptId || !getBuiltinPrompt(promptId)) {
563
+ throw new ApiError(404, "PROMPT_PACK_PROMPT_NOT_FOUND", `Prompt pack prompt not found: ${String(value)}`);
564
+ }
565
+ return promptId;
566
+ }
446
567
  async function listProjectSkillIds(root) {
447
568
  try {
448
569
  const entries = await readdir(projectSkillsDir(root), { withFileTypes: true });
@@ -2613,6 +2734,37 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
2613
2734
  const result = await loadStudioSkills(root);
2614
2735
  return c.json(result);
2615
2736
  });
2737
+ app.get("/api/v1/prompt-packs", async (c) => {
2738
+ const prompts = await Promise.all(listBuiltinPrompts().map((prompt) => toStudioPromptPackPrompt(root, prompt)));
2739
+ return c.json({
2740
+ packs: listBuiltinPromptPacks(),
2741
+ prompts,
2742
+ });
2743
+ });
2744
+ app.put("/api/v1/prompt-packs/:promptId", async (c) => {
2745
+ const promptId = normalizeStudioPromptId(c.req.param("promptId"));
2746
+ const payload = await c.req.json().catch(() => {
2747
+ throw new ApiError(400, "INVALID_PROMPT_PACK_PAYLOAD", "Prompt pack payload must be JSON");
2748
+ });
2749
+ const content = payload && typeof payload === "object" && "content" in payload
2750
+ ? payload.content
2751
+ : undefined;
2752
+ if (typeof content !== "string") {
2753
+ throw new ApiError(400, "INVALID_PROMPT_PACK_PAYLOAD", "content must be a string");
2754
+ }
2755
+ const file = promptOverridePath(root, promptId);
2756
+ await mkdir(dirname(file), { recursive: true });
2757
+ await writeFile(file, content, "utf-8");
2758
+ const prompt = listBuiltinPrompts().find((item) => item.id === promptId);
2759
+ return c.json({ prompt: await toStudioPromptPackPrompt(root, prompt) });
2760
+ });
2761
+ app.delete("/api/v1/prompt-packs/:promptId", async (c) => {
2762
+ const promptId = normalizeStudioPromptId(c.req.param("promptId"));
2763
+ const file = promptOverridePath(root, promptId);
2764
+ await rm(file, { force: true });
2765
+ const prompt = listBuiltinPrompts().find((item) => item.id === promptId);
2766
+ return c.json({ prompt: await toStudioPromptPackPrompt(root, prompt) });
2767
+ });
2616
2768
  app.post("/api/v1/skills", async (c) => {
2617
2769
  const payload = await c.req.json().catch(() => {
2618
2770
  throw new ApiError(400, "INVALID_SKILL_PAYLOAD", "Skill payload must be JSON");
@@ -3093,8 +3245,14 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
3093
3245
  await deleteBookSession(root, c.req.param("sessionId"));
3094
3246
  return c.json({ ok: true });
3095
3247
  });
3248
+ app.post("/api/v1/sessions/:sessionId/abort", async (c) => {
3249
+ const sessionId = c.req.param("sessionId");
3250
+ const aborted = abortAgentSession(root, sessionId);
3251
+ broadcast("agent:aborted", { sessionId, aborted });
3252
+ return c.json({ ok: true, aborted });
3253
+ });
3096
3254
  app.post("/api/v1/agent", async (c) => {
3097
- const { instruction, activeBookId, sessionId: reqSessionId, sessionKind: reqSessionKind, actionSource: reqActionSource, requestedIntent: reqRequestedIntent, actionPayload: reqActionPayload, requestedSkills: reqRequestedSkills, disabledSkills: reqDisabledSkills, playMode: reqPlayMode, model: reqModel, service: reqService, } = await c.req.json();
3255
+ const { instruction, activeBookId, sessionId: reqSessionId, sessionKind: reqSessionKind, actionSource: reqActionSource, requestedIntent: reqRequestedIntent, actionPayload: reqActionPayload, requestedSkills: reqRequestedSkills, disabledSkills: reqDisabledSkills, attachments: reqAttachments, playMode: reqPlayMode, model: reqModel, service: reqService, } = await c.req.json();
3098
3256
  const sessionId = reqSessionId;
3099
3257
  if (!instruction?.trim()) {
3100
3258
  return c.json({ error: "No instruction provided" }, 400);
@@ -3111,8 +3269,9 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
3111
3269
  const actionPayload = normalizeStudioActionPayload(reqActionPayload);
3112
3270
  const requestedSkills = normalizeStudioSkillIdList(reqRequestedSkills, "requestedSkills");
3113
3271
  const disabledSkills = normalizeStudioSkillIdList(reqDisabledSkills, "disabledSkills");
3272
+ const attachments = await normalizeAgentAttachments(root, sessionId, reqAttachments);
3114
3273
  const playMode = normalizeStudioPlayMode(reqPlayMode);
3115
- broadcast("agent:start", { instruction, activeBookId, sessionId, actionSource, requestedIntent, requestedSkills });
3274
+ broadcast("agent:start", { instruction, activeBookId, sessionId, actionSource, requestedIntent, requestedSkills, attachments: attachments.length });
3116
3275
  try {
3117
3276
  // Load config + create LLM client (pipeline created after model resolution)
3118
3277
  const config = await loadCurrentProjectConfig({ requireApiKey: false });
@@ -3494,6 +3653,7 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
3494
3653
  actionPayload,
3495
3654
  requestedSkills,
3496
3655
  disabledSkills,
3656
+ attachments,
3497
3657
  sessionId: bookSession.sessionId,
3498
3658
  language: surfaceLanguage,
3499
3659
  onContextCompression: (event) => {