@kienmatu/inkos-studio 1.0.1 → 4.0.0
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/api/server.d.ts.map +1 -1
- package/dist/api/server.js +156 -23
- package/dist/api/server.js.map +1 -1
- package/dist/api/task-store.d.ts +1 -0
- package/dist/api/task-store.d.ts.map +1 -1
- package/dist/api/task-store.js +3 -0
- package/dist/api/task-store.js.map +1 -1
- package/dist/assets/{FilmWizard-CxoOJ7MQ.js → FilmWizard-BmrPbkFz.js} +1 -1
- package/dist/assets/{FlowView-Bt0EtmEr.js → FlowView-SbRviH5b.js} +1 -1
- package/dist/assets/{_baseUniq-ZL9pmMqM.js → _baseUniq-BkEZO23S.js} +1 -1
- package/dist/assets/{arc-B8qI0bEW.js → arc-DzsKsGBX.js} +1 -1
- package/dist/assets/{architectureDiagram-Q4EWVU46-BMqx63uW.js → architectureDiagram-Q4EWVU46-7-keOyLG.js} +1 -1
- package/dist/assets/{blockDiagram-DXYQGD6D-CpTeW9T5.js → blockDiagram-DXYQGD6D-CkWKO82x.js} +1 -1
- package/dist/assets/{c4Diagram-AHTNJAMY-DEMZhRny.js → c4Diagram-AHTNJAMY-D6DRnA_K.js} +1 -1
- package/dist/assets/channel-vMyuwkSI.js +1 -0
- package/dist/assets/{chunk-4BX2VUAB-CATTVIYo.js → chunk-4BX2VUAB-Cmg88BNH.js} +1 -1
- package/dist/assets/{chunk-4TB4RGXK-BVSOdPwi.js → chunk-4TB4RGXK-CMZP43JX.js} +1 -1
- package/dist/assets/{chunk-55IACEB6-roBKSgqh.js → chunk-55IACEB6-CDFZTSkf.js} +1 -1
- package/dist/assets/{chunk-EDXVE4YY-DcL-JJvQ.js → chunk-EDXVE4YY-f2fO2QMj.js} +1 -1
- package/dist/assets/{chunk-FMBD7UC4-CTt3nqty.js → chunk-FMBD7UC4-C8gUvwB8.js} +1 -1
- package/dist/assets/{chunk-OYMX7WX6-BKloZua_.js → chunk-OYMX7WX6-DaqAIa4a.js} +1 -1
- package/dist/assets/{chunk-QZHKN3VN-CksGJW6L.js → chunk-QZHKN3VN-BdHnVE44.js} +1 -1
- package/dist/assets/{chunk-YZCP3GAM-DFUs85Mo.js → chunk-YZCP3GAM-CTNEwMvq.js} +1 -1
- package/dist/assets/classDiagram-6PBFFD2Q-DlUnDT-R.js +1 -0
- package/dist/assets/classDiagram-v2-HSJHXN6E-DlUnDT-R.js +1 -0
- package/dist/assets/clone-CgzdGWcq.js +1 -0
- package/dist/assets/{cose-bilkent-S5V4N54A-BhjR9QKW.js → cose-bilkent-S5V4N54A-KpZHVU8t.js} +1 -1
- package/dist/assets/{dagre-KV5264BT-S0WgqeWF.js → dagre-KV5264BT-aiy2OT89.js} +1 -1
- package/dist/assets/{diagram-5BDNPKRD-iziIar_1.js → diagram-5BDNPKRD-pNT8yMDm.js} +1 -1
- package/dist/assets/{diagram-G4DWMVQ6-DGiQ4b3V.js → diagram-G4DWMVQ6-oxZhaIi5.js} +1 -1
- package/dist/assets/{diagram-MMDJMWI5-Ctfv9R4Z.js → diagram-MMDJMWI5-kwn_dxKS.js} +1 -1
- package/dist/assets/{diagram-TYMM5635-DpzPFDFI.js → diagram-TYMM5635-DXa2AxN_.js} +1 -1
- package/dist/assets/{erDiagram-SMLLAGMA-e51DloYW.js → erDiagram-SMLLAGMA-CAgK4N7D.js} +1 -1
- package/dist/assets/{flowDiagram-DWJPFMVM-TyuMrie7.js → flowDiagram-DWJPFMVM-BeYsHcsf.js} +1 -1
- package/dist/assets/{ganttDiagram-T4ZO3ILL-sewHvhyH.js → ganttDiagram-T4ZO3ILL-BU8wq8NL.js} +1 -1
- package/dist/assets/{gitGraphDiagram-UUTBAWPF-DI7YNaAi.js → gitGraphDiagram-UUTBAWPF-BgivHLNi.js} +1 -1
- package/dist/assets/{graph-iCANBjLp.js → graph-CSwQtVwF.js} +1 -1
- package/dist/assets/{highlighted-body-OFNGDK62-DTkXdU8M.js → highlighted-body-OFNGDK62-DqKI0DVm.js} +1 -1
- package/dist/assets/{index-3FC9cBAw.js → index-Bz4G_Cuu.js} +308 -308
- package/dist/assets/index-CTu6WYGu.css +1 -0
- package/dist/assets/{infoDiagram-42DDH7IO-KcOGgxDZ.js → infoDiagram-42DDH7IO-B4Aw1ReL.js} +1 -1
- package/dist/assets/{ishikawaDiagram-UXIWVN3A-DN46kos1.js → ishikawaDiagram-UXIWVN3A-ZVIYN2tB.js} +1 -1
- package/dist/assets/{journeyDiagram-VCZTEJTY-CSnW-uiU.js → journeyDiagram-VCZTEJTY-UaC8xj7j.js} +1 -1
- package/dist/assets/{kanban-definition-6JOO6SKY-DgeKhYzm.js → kanban-definition-6JOO6SKY-B4pC4qyO.js} +1 -1
- package/dist/assets/{layout-C3k8b-wj.js → layout-BYNOhtZE.js} +1 -1
- package/dist/assets/{linear-CSj-zsdP.js → linear-DcH0KvpB.js} +1 -1
- package/dist/assets/{min-BkU8UOgQ.js → min-B7b9i4d3.js} +1 -1
- package/dist/assets/{mindmap-definition-QFDTVHPH-jaWIxQM2.js → mindmap-definition-QFDTVHPH-LYMoC9qk.js} +1 -1
- package/dist/assets/{pieDiagram-DEJITSTG-DSCNVEy0.js → pieDiagram-DEJITSTG-CmdIR1nD.js} +1 -1
- package/dist/assets/{quadrantDiagram-34T5L4WZ-6Aki-Mea.js → quadrantDiagram-34T5L4WZ-Dy5E2ZXi.js} +1 -1
- package/dist/assets/{requirementDiagram-MS252O5E-CIA-stPo.js → requirementDiagram-MS252O5E-CvO01yCF.js} +1 -1
- package/dist/assets/{sankeyDiagram-XADWPNL6-Dm92baLv.js → sankeyDiagram-XADWPNL6-lV90jm6N.js} +1 -1
- package/dist/assets/{sequenceDiagram-FGHM5R23-CijKhpBV.js → sequenceDiagram-FGHM5R23-BXYteJo4.js} +1 -1
- package/dist/assets/{stateDiagram-FHFEXIEX-BoRVlJdY.js → stateDiagram-FHFEXIEX-DwuM_25x.js} +1 -1
- package/dist/assets/stateDiagram-v2-QKLJ7IA2-CVwGByU6.js +1 -0
- package/dist/assets/{timeline-definition-GMOUNBTQ-Dgq0GzH4.js → timeline-definition-GMOUNBTQ-D5FpweXf.js} +1 -1
- package/dist/assets/{value-BU9Hdjc2.js → value-DKBwu4y3.js} +1 -1
- package/dist/assets/{vennDiagram-DHZGUBPP-DrIu0Q4b.js → vennDiagram-DHZGUBPP-S83B5bJw.js} +1 -1
- package/dist/assets/{wardley-RL74JXVD-BumycEok.js → wardley-RL74JXVD-DiagH8qG.js} +1 -1
- package/dist/assets/{wardleyDiagram-NUSXRM2D-3fn4THet.js → wardleyDiagram-NUSXRM2D-C_njDDS0.js} +1 -1
- package/dist/assets/{xychartDiagram-5P7HB3ND-BMcrjrBB.js → xychartDiagram-5P7HB3ND-DDLHFTQ4.js} +1 -1
- package/dist/index.html +2 -2
- package/package.json +2 -2
- package/dist/assets/channel-DxRmlnS_.js +0 -1
- package/dist/assets/classDiagram-6PBFFD2Q-Bkac267_.js +0 -1
- package/dist/assets/classDiagram-v2-HSJHXN6E-Bkac267_.js +0 -1
- package/dist/assets/clone-CmiP6enp.js +0 -1
- package/dist/assets/index-8wiyHNEA.css +0 -1
- package/dist/assets/stateDiagram-v2-QKLJ7IA2-B2UHePPb.js +0 -1
package/dist/api/server.d.ts.map
CHANGED
|
@@ -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;AAM5B,OAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/api/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAC;AAM5B,OAAO,EAwHL,KAAK,aAAa,EAMlB,KAAK,aAAa,EAOnB,MAAM,sBAAsB,CAAC;AAkB9B,MAAM,MAAM,cAAc,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEhD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,OAAO,GAAG,cAAc,CAItE;AAGD,wBAAgB,IAAI,CAAC,IAAI,EAAE,cAAc,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAGtF;AA0jFD,wBAAgB,kBAAkB,CAAC,aAAa,EAAE,aAAa,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,GAAE;IAAE,QAAQ,CAAC,kBAAkB,CAAC,EAAE,aAAa,CAAA;CAAO,8EAsjI7I;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"}
|
package/dist/api/server.js
CHANGED
|
@@ -4,7 +4,7 @@ import { streamSSE } from "hono/streaming";
|
|
|
4
4
|
import { serve } from "@hono/node-server";
|
|
5
5
|
import { gzipSync } from "node:zlib";
|
|
6
6
|
import { randomUUID } from "node:crypto";
|
|
7
|
-
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, runWorkerAgent, buildExportArtifact, evaluateBookQuality, ConsolidatorAgent, DetectionConfigSchema, ResearchSearchConfigSchema, GLOBAL_ENV_PATH, COVER_PROVIDER_PRESETS, createPlayDB, PlayStore, buildPlayEntityImagePrompt, buildPlaySceneImagePrompt, generatePlayImage, readPlayImageManifest, readPlayImageSettings, writePlayImageSettings, Scheduler, coverSecretKey, normalizeCoverBaseUrl, resolveCoverProviderPreset, SessionKindSchema, normalizeActionSource as normalizeCoreActionSource, normalizeActionPayload as normalizeCoreActionPayload, normalizePlayMode as normalizeCorePlayMode, normalizeRequestedIntent as normalizeCoreRequestedIntent, normalizeSkillIdList as normalizeCoreSkillIdList, inferLanguage, toWritingLanguage, ingestMaterial, createSkillRegistry, loadAvailableAgentSkills, activatedSkillIds, mergeActivatedSkillGuidance, resolveProductionSkillActivations, parseAgentSkillDocument, getBuiltinPrompt, listBuiltinPromptPacks, listBuiltinPrompts, loadPromptPackPrompt, promptOverridePath, toPosixPath, createGenerateCoverTool, createInteractiveFilmCreationTool, createPlayStartTool, createScriptCreationTool, createShortFictionRunTool, createStoryboardCreationTool, createTranslationCreateTool, createFanficBookTool, createContinuationImportTool, createSpinoffBookTool, createImitationBookTool, createSubAgentTool, createDraftStructureTool, createConnectChoiceTool, createRemoveNodeTool, createLLMTranslationModel, deleteLatestChapter, executeEditTransaction, listChapterVersions, readChapterPlanDocument, readChapterUserBrief, readChapterVersion, saveChapterUserBrief, createTranslationProjectFromFile, loadTranslationChapter, loadTranslationManifest, runTranslationProject, writeTranslationExport, filmLLMDepsFromClient, applyGraphDelta, loadStoryGraph, reviewStoryGraph, exportInk, buildPlayableHtml, analyzeEmotionalArcs, analyzePathDistribution, generateNodeImage, defaultNodeImageDeps, } from "@kienmatu/inkos-core";
|
|
7
|
+
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, normalizeProbedModels, fetchWithProxy, chatCompletion, runWorkerAgent, buildExportArtifact, createProductionRunSnapshot, evaluateBookQuality, ConsolidatorAgent, DetectionConfigSchema, ResearchSearchConfigSchema, GLOBAL_ENV_PATH, COVER_PROVIDER_PRESETS, createPlayDB, PlayStore, buildPlayEntityImagePrompt, buildPlaySceneImagePrompt, generatePlayImage, readPlayImageManifest, readPlayImageSettings, writePlayImageSettings, Scheduler, coverSecretKey, normalizeCoverBaseUrl, resolveCoverProviderPreset, SessionKindSchema, normalizeActionSource as normalizeCoreActionSource, normalizeActionPayload as normalizeCoreActionPayload, normalizePlayMode as normalizeCorePlayMode, normalizeRequestedIntent as normalizeCoreRequestedIntent, normalizeSkillIdList as normalizeCoreSkillIdList, inferLanguage, toWritingLanguage, ingestMaterial, createSkillRegistry, loadAvailableAgentSkills, activatedSkillIds, mergeActivatedSkillGuidance, resolveProductionSkillActivations, parseAgentSkillDocument, getBuiltinPrompt, listBuiltinPromptPacks, listBuiltinPrompts, loadPromptPackPrompt, promptOverridePath, toPosixPath, createGenerateCoverTool, createInteractiveFilmCreationTool, createPlayStartTool, createScriptCreationTool, createShortFictionRunTool, createStoryboardCreationTool, createTranslationCreateTool, createFanficBookTool, createContinuationImportTool, createSpinoffBookTool, createImitationBookTool, createSubAgentTool, createDraftStructureTool, createConnectChoiceTool, createRemoveNodeTool, createLLMTranslationModel, deleteLatestChapter, executeEditTransaction, listChapterVersions, readChapterPlanDocument, readChapterUserBrief, readChapterVersion, saveChapterUserBrief, createTranslationProjectFromFile, loadTranslationChapter, loadTranslationManifest, runTranslationProject, writeTranslationExport, filmLLMDepsFromClient, applyGraphDelta, loadStoryGraph, reviewStoryGraph, exportInk, buildPlayableHtml, analyzeEmotionalArcs, analyzePathDistribution, generateNodeImage, defaultNodeImageDeps, writeProductionRunSnapshot, } from "@kienmatu/inkos-core";
|
|
8
8
|
import { isConfirmedProductionAction } from "../shared/confirmed-production.js";
|
|
9
9
|
import { summarizeToolResult } from "../shared/tool-result.js";
|
|
10
10
|
import { access, mkdir, readFile, readdir, rename, rm, stat, writeFile } from "node:fs/promises";
|
|
@@ -1267,18 +1267,79 @@ async function executeConfirmedProductionAction(args) {
|
|
|
1267
1267
|
throw new ConfirmedActionExecutionError(message, exec, error);
|
|
1268
1268
|
}
|
|
1269
1269
|
}
|
|
1270
|
-
function
|
|
1270
|
+
function parseProductionObservation(value) {
|
|
1271
1271
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1272
1272
|
return null;
|
|
1273
1273
|
const record = value;
|
|
1274
|
+
if (typeof record.metric !== "string"
|
|
1275
|
+
|| !["info", "warning", "blocking"].includes(String(record.severity))
|
|
1276
|
+
|| typeof record.repairable !== "boolean"
|
|
1277
|
+
|| (record.evidence !== undefined && typeof record.evidence !== "string")) {
|
|
1278
|
+
return null;
|
|
1279
|
+
}
|
|
1280
|
+
return {
|
|
1281
|
+
metric: record.metric,
|
|
1282
|
+
expected: record.expected,
|
|
1283
|
+
actual: record.actual,
|
|
1284
|
+
severity: record.severity,
|
|
1285
|
+
...(typeof record.evidence === "string" ? { evidence: record.evidence } : {}),
|
|
1286
|
+
repairable: record.repairable,
|
|
1287
|
+
};
|
|
1288
|
+
}
|
|
1289
|
+
function parseStudioShortRun(value, expectedStoryId) {
|
|
1290
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1291
|
+
return null;
|
|
1292
|
+
const record = value;
|
|
1293
|
+
const status = record.status;
|
|
1294
|
+
const artifacts = Array.isArray(record.artifacts) && record.artifacts.every((item) => typeof item === "string")
|
|
1295
|
+
? record.artifacts
|
|
1296
|
+
: null;
|
|
1297
|
+
const observations = Array.isArray(record.observations)
|
|
1298
|
+
? record.observations.map(parseProductionObservation)
|
|
1299
|
+
: null;
|
|
1300
|
+
if (record.version !== 1
|
|
1301
|
+
|| record.kind !== "short-fiction"
|
|
1302
|
+
|| record.id !== expectedStoryId
|
|
1303
|
+
|| (status !== "complete" && status !== "needs-review")
|
|
1304
|
+
|| typeof record.stage !== "string"
|
|
1305
|
+
|| !artifacts
|
|
1306
|
+
|| !observations
|
|
1307
|
+
|| observations.some((observation) => observation === null)
|
|
1308
|
+
|| typeof record.updatedAt !== "string"
|
|
1309
|
+
|| (record.model !== undefined && typeof record.model !== "string")
|
|
1310
|
+
|| (record.skillIds !== undefined && (!Array.isArray(record.skillIds) || !record.skillIds.every((item) => typeof item === "string")))
|
|
1311
|
+
|| (record.resumeCursor !== undefined && typeof record.resumeCursor !== "string")
|
|
1312
|
+
|| (record.error !== undefined && typeof record.error !== "string")) {
|
|
1313
|
+
return null;
|
|
1314
|
+
}
|
|
1315
|
+
return {
|
|
1316
|
+
version: 1,
|
|
1317
|
+
kind: "short-fiction",
|
|
1318
|
+
id: expectedStoryId,
|
|
1319
|
+
status,
|
|
1320
|
+
stage: record.stage,
|
|
1321
|
+
artifacts,
|
|
1322
|
+
observations: observations,
|
|
1323
|
+
...(typeof record.model === "string" ? { model: record.model } : {}),
|
|
1324
|
+
...(Array.isArray(record.skillIds) ? { skillIds: record.skillIds } : {}),
|
|
1325
|
+
...(typeof record.resumeCursor === "string" ? { resumeCursor: record.resumeCursor } : {}),
|
|
1326
|
+
...(typeof record.error === "string" ? { error: record.error } : {}),
|
|
1327
|
+
updatedAt: record.updatedAt,
|
|
1328
|
+
};
|
|
1329
|
+
}
|
|
1330
|
+
function parseVisibleShortRunIndex(value, expectedStoryId) {
|
|
1331
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1332
|
+
return null;
|
|
1333
|
+
const record = value;
|
|
1334
|
+
const status = record.status;
|
|
1274
1335
|
if (record.version !== 1
|
|
1275
1336
|
|| record.kind !== "short-fiction"
|
|
1276
1337
|
|| record.id !== expectedStoryId
|
|
1277
|
-
||
|
|
1338
|
+
|| (status !== "complete" && status !== "needs-review")
|
|
1278
1339
|
|| typeof record.updatedAt !== "string") {
|
|
1279
1340
|
return null;
|
|
1280
1341
|
}
|
|
1281
|
-
return { storyId: expectedStoryId, updatedAt: record.updatedAt };
|
|
1342
|
+
return { storyId: expectedStoryId, status, updatedAt: record.updatedAt };
|
|
1282
1343
|
}
|
|
1283
1344
|
function parseShortStoryTitle(value) {
|
|
1284
1345
|
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
@@ -1304,15 +1365,16 @@ async function loadStudioShortList(root) {
|
|
|
1304
1365
|
const shortDir = join(shortsDir, storyId);
|
|
1305
1366
|
try {
|
|
1306
1367
|
const status = JSON.parse(await readFile(join(shortDir, "status.json"), "utf-8"));
|
|
1307
|
-
const run =
|
|
1368
|
+
const run = parseVisibleShortRunIndex(status, storyId);
|
|
1308
1369
|
if (!run)
|
|
1309
1370
|
continue;
|
|
1310
1371
|
const story = JSON.parse(await readFile(join(shortDir, "final", "short-story.json"), "utf-8"));
|
|
1311
1372
|
const title = parseShortStoryTitle(story) ?? storyId;
|
|
1312
|
-
await
|
|
1373
|
+
await readFile(join(shortDir, "final", "full.md"), "utf-8");
|
|
1313
1374
|
shorts.push({
|
|
1314
1375
|
storyId,
|
|
1315
1376
|
title,
|
|
1377
|
+
status: run.status,
|
|
1316
1378
|
finalMarkdownPath: toPosixPath(join("shorts", storyId, "final", "full.md")),
|
|
1317
1379
|
updatedAt: run.updatedAt,
|
|
1318
1380
|
});
|
|
@@ -1325,7 +1387,6 @@ async function loadStudioShortList(root) {
|
|
|
1325
1387
|
}
|
|
1326
1388
|
const subscribers = new Set();
|
|
1327
1389
|
const bookCreateStatus = new Map();
|
|
1328
|
-
// 内存缓存:service -> 模型列表 + 更新时间戳;避免每次 sidebar 挂载时都打真实 LLM /models
|
|
1329
1390
|
const modelListCache = new Map();
|
|
1330
1391
|
function broadcast(event, data) {
|
|
1331
1392
|
for (const handler of subscribers) {
|
|
@@ -1407,16 +1468,50 @@ function normalizeServiceModelIds(value) {
|
|
|
1407
1468
|
}
|
|
1408
1469
|
return models;
|
|
1409
1470
|
}
|
|
1471
|
+
function normalizeServiceModelCapabilities(value, models) {
|
|
1472
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
1473
|
+
return {};
|
|
1474
|
+
const allowed = models ? new Set(models.map((model) => model.toLowerCase())) : undefined;
|
|
1475
|
+
const result = {};
|
|
1476
|
+
for (const [model, raw] of Object.entries(value)) {
|
|
1477
|
+
if (!model.trim() || (allowed && !allowed.has(model.toLowerCase())))
|
|
1478
|
+
continue;
|
|
1479
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw))
|
|
1480
|
+
continue;
|
|
1481
|
+
const record = raw;
|
|
1482
|
+
const contextWindow = positiveInteger(record.contextWindow);
|
|
1483
|
+
const candidateMax = positiveInteger(record.maxOutput);
|
|
1484
|
+
const maxOutput = candidateMax !== undefined
|
|
1485
|
+
&& (contextWindow === undefined || candidateMax <= contextWindow)
|
|
1486
|
+
? candidateMax
|
|
1487
|
+
: undefined;
|
|
1488
|
+
if (maxOutput === undefined && contextWindow === undefined)
|
|
1489
|
+
continue;
|
|
1490
|
+
result[model] = {
|
|
1491
|
+
...(maxOutput !== undefined ? { maxOutput } : {}),
|
|
1492
|
+
...(contextWindow !== undefined ? { contextWindow } : {}),
|
|
1493
|
+
};
|
|
1494
|
+
}
|
|
1495
|
+
return result;
|
|
1496
|
+
}
|
|
1497
|
+
function positiveInteger(value) {
|
|
1498
|
+
return typeof value === "number" && Number.isFinite(value) && Number.isInteger(value) && value > 0
|
|
1499
|
+
? value
|
|
1500
|
+
: undefined;
|
|
1501
|
+
}
|
|
1410
1502
|
function mergeServiceModelIds(...groups) {
|
|
1411
1503
|
return normalizeServiceModelIds(groups.flatMap((group) => group ?? []));
|
|
1412
1504
|
}
|
|
1413
1505
|
function normalizeServiceEntry(serviceId, value) {
|
|
1506
|
+
const models = Array.isArray(value.models) ? normalizeServiceModelIds(value.models) : undefined;
|
|
1507
|
+
const modelCapabilities = normalizeServiceModelCapabilities(value.modelCapabilities, models);
|
|
1414
1508
|
if (serviceId.startsWith("custom:")) {
|
|
1415
1509
|
return {
|
|
1416
1510
|
service: "custom",
|
|
1417
1511
|
name: decodeURIComponent(serviceId.slice("custom:".length)),
|
|
1418
1512
|
...(typeof value.baseUrl === "string" && value.baseUrl.length > 0 ? { baseUrl: value.baseUrl } : {}),
|
|
1419
|
-
...(
|
|
1513
|
+
...(models ? { models } : {}),
|
|
1514
|
+
...(Object.keys(modelCapabilities).length > 0 ? { modelCapabilities } : {}),
|
|
1420
1515
|
...(typeof value.temperature === "number" ? { temperature: value.temperature } : {}),
|
|
1421
1516
|
...(value.apiFormat === "chat" || value.apiFormat === "responses" ? { apiFormat: value.apiFormat } : {}),
|
|
1422
1517
|
...(typeof value.stream === "boolean" ? { stream: value.stream } : {}),
|
|
@@ -1427,7 +1522,8 @@ function normalizeServiceEntry(serviceId, value) {
|
|
|
1427
1522
|
service: "custom",
|
|
1428
1523
|
...(typeof value.name === "string" && value.name.length > 0 ? { name: value.name } : {}),
|
|
1429
1524
|
...(typeof value.baseUrl === "string" && value.baseUrl.length > 0 ? { baseUrl: value.baseUrl } : {}),
|
|
1430
|
-
...(
|
|
1525
|
+
...(models ? { models } : {}),
|
|
1526
|
+
...(Object.keys(modelCapabilities).length > 0 ? { modelCapabilities } : {}),
|
|
1431
1527
|
...(typeof value.temperature === "number" ? { temperature: value.temperature } : {}),
|
|
1432
1528
|
...(value.apiFormat === "chat" || value.apiFormat === "responses" ? { apiFormat: value.apiFormat } : {}),
|
|
1433
1529
|
...(typeof value.stream === "boolean" ? { stream: value.stream } : {}),
|
|
@@ -1435,7 +1531,8 @@ function normalizeServiceEntry(serviceId, value) {
|
|
|
1435
1531
|
}
|
|
1436
1532
|
return {
|
|
1437
1533
|
service: serviceId,
|
|
1438
|
-
...(
|
|
1534
|
+
...(models ? { models } : {}),
|
|
1535
|
+
...(Object.keys(modelCapabilities).length > 0 ? { modelCapabilities } : {}),
|
|
1439
1536
|
...(typeof value.temperature === "number" ? { temperature: value.temperature } : {}),
|
|
1440
1537
|
...(value.apiFormat === "chat" || value.apiFormat === "responses" ? { apiFormat: value.apiFormat } : {}),
|
|
1441
1538
|
...(typeof value.stream === "boolean" ? { stream: value.stream } : {}),
|
|
@@ -1448,15 +1545,7 @@ function normalizeServiceConfig(raw) {
|
|
|
1448
1545
|
if (Array.isArray(raw)) {
|
|
1449
1546
|
return raw
|
|
1450
1547
|
.filter((entry) => Boolean(entry) && typeof entry === "object")
|
|
1451
|
-
.map((entry) => (
|
|
1452
|
-
service: typeof entry.service === "string" && entry.service.length > 0 ? entry.service : "custom",
|
|
1453
|
-
...(typeof entry.name === "string" && entry.name.length > 0 ? { name: entry.name } : {}),
|
|
1454
|
-
...(typeof entry.baseUrl === "string" && entry.baseUrl.length > 0 ? { baseUrl: entry.baseUrl } : {}),
|
|
1455
|
-
...(Array.isArray(entry.models) ? { models: normalizeServiceModelIds(entry.models) } : {}),
|
|
1456
|
-
...(typeof entry.temperature === "number" ? { temperature: entry.temperature } : {}),
|
|
1457
|
-
...(entry.apiFormat === "chat" || entry.apiFormat === "responses" ? { apiFormat: entry.apiFormat } : {}),
|
|
1458
|
-
...(typeof entry.stream === "boolean" ? { stream: entry.stream } : {}),
|
|
1459
|
-
}));
|
|
1548
|
+
.map((entry) => normalizeServiceEntry(typeof entry.service === "string" && entry.service.length > 0 ? entry.service : "custom", entry));
|
|
1460
1549
|
}
|
|
1461
1550
|
if (raw && typeof raw === "object") {
|
|
1462
1551
|
return Object.entries(raw)
|
|
@@ -1474,6 +1563,9 @@ function mergeServiceConfig(existing, updates) {
|
|
|
1474
1563
|
...previous,
|
|
1475
1564
|
...update,
|
|
1476
1565
|
...(update.models === undefined && previous?.models ? { models: previous.models } : {}),
|
|
1566
|
+
...(update.modelCapabilities === undefined && previous?.modelCapabilities
|
|
1567
|
+
? { modelCapabilities: previous.modelCapabilities }
|
|
1568
|
+
: {}),
|
|
1477
1569
|
});
|
|
1478
1570
|
}
|
|
1479
1571
|
return [...merged.values()];
|
|
@@ -1518,6 +1610,12 @@ function syncTopLevelLlmMirror(llm) {
|
|
|
1518
1610
|
llm.apiFormat = selectedEntry.apiFormat;
|
|
1519
1611
|
if (selectedEntry.stream !== undefined)
|
|
1520
1612
|
llm.stream = selectedEntry.stream;
|
|
1613
|
+
if (selectedEntry.modelCapabilities && Object.keys(selectedEntry.modelCapabilities).length > 0) {
|
|
1614
|
+
llm.modelCapabilities = selectedEntry.modelCapabilities;
|
|
1615
|
+
}
|
|
1616
|
+
else {
|
|
1617
|
+
delete llm.modelCapabilities;
|
|
1618
|
+
}
|
|
1521
1619
|
}
|
|
1522
1620
|
async function loadRawConfig(root) {
|
|
1523
1621
|
const configPath = join(root, "inkos.json");
|
|
@@ -1893,10 +1991,7 @@ async function fetchModelsFromServiceBaseUrl(serviceId, baseUrl, apiKey, proxyUr
|
|
|
1893
1991
|
authFailed: res.status === 401 || res.status === 403,
|
|
1894
1992
|
};
|
|
1895
1993
|
}
|
|
1896
|
-
|
|
1897
|
-
return {
|
|
1898
|
-
models: (json.data ?? []).map((m) => ({ id: m.id, name: m.id })),
|
|
1899
|
-
};
|
|
1994
|
+
return { models: normalizeProbedModels(await res.json()) };
|
|
1900
1995
|
}
|
|
1901
1996
|
catch (error) {
|
|
1902
1997
|
return {
|
|
@@ -2067,6 +2162,7 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
|
|
|
2067
2162
|
const state = new StateManager(root);
|
|
2068
2163
|
let cachedConfig = initialConfig;
|
|
2069
2164
|
const activeConfirmedTasks = new Map();
|
|
2165
|
+
const confirmedTaskRevisions = new Map();
|
|
2070
2166
|
// 确认式生产任务的单任务名额(sessionId → taskId)。原来的检查是"await 读快照
|
|
2071
2167
|
// → 之后才 set controller"的 check-then-act:两个并发确认请求都能通过检查,
|
|
2072
2168
|
// 双任务同时启动、快照互相覆盖。这里在任何 await 之前同步占位,占位失败的
|
|
@@ -2090,8 +2186,11 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
|
|
|
2090
2186
|
const persistConfirmedTask = async (sessionId, requestedIntent, exec, sourceRequestId) => {
|
|
2091
2187
|
if (deletedSessionIds.has(sessionId))
|
|
2092
2188
|
return;
|
|
2189
|
+
const revision = (confirmedTaskRevisions.get(exec.id) ?? 0) + 1;
|
|
2190
|
+
confirmedTaskRevisions.set(exec.id, revision);
|
|
2093
2191
|
const snapshot = {
|
|
2094
2192
|
version: 1,
|
|
2193
|
+
revision,
|
|
2095
2194
|
sessionId,
|
|
2096
2195
|
...(sourceRequestId ? { sourceRequestId } : {}),
|
|
2097
2196
|
requestedIntent,
|
|
@@ -2102,7 +2201,10 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
|
|
|
2102
2201
|
...(exec.logs ? { logs: [...exec.logs] } : {}),
|
|
2103
2202
|
},
|
|
2104
2203
|
};
|
|
2204
|
+
// Publish the same durable snapshot that refresh recovery reads, so an
|
|
2205
|
+
// already-open task card sees milestone logs without requiring a reload.
|
|
2105
2206
|
await saveStudioTaskSnapshot(root, snapshot);
|
|
2207
|
+
broadcast("task:snapshot", snapshot);
|
|
2106
2208
|
};
|
|
2107
2209
|
const loadReconciledTaskSnapshot = async (sessionId) => {
|
|
2108
2210
|
const task = await loadStudioTaskSnapshot(root, sessionId);
|
|
@@ -4186,6 +4288,7 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
|
|
|
4186
4288
|
}
|
|
4187
4289
|
finally {
|
|
4188
4290
|
activeConfirmedTasks.delete(taskId);
|
|
4291
|
+
confirmedTaskRevisions.delete(taskId);
|
|
4189
4292
|
reservedProductionSessions.delete(reservedSessionId);
|
|
4190
4293
|
}
|
|
4191
4294
|
}
|
|
@@ -5395,6 +5498,36 @@ export function createStudioServer(initialConfig, root, overrides = {}) {
|
|
|
5395
5498
|
const shorts = await loadStudioShortList(root);
|
|
5396
5499
|
return c.json({ shorts });
|
|
5397
5500
|
});
|
|
5501
|
+
app.post("/api/v1/shorts/:id/complete", async (c) => {
|
|
5502
|
+
const storyId = c.req.param("id");
|
|
5503
|
+
if (!isSafeBookId(storyId)) {
|
|
5504
|
+
return c.json({ error: "Invalid short id" }, 400);
|
|
5505
|
+
}
|
|
5506
|
+
const runPath = join("shorts", storyId, "status.json");
|
|
5507
|
+
let raw;
|
|
5508
|
+
try {
|
|
5509
|
+
raw = JSON.parse(await readFile(join(root, runPath), "utf-8"));
|
|
5510
|
+
}
|
|
5511
|
+
catch {
|
|
5512
|
+
return c.json({ error: "Short not found" }, 404);
|
|
5513
|
+
}
|
|
5514
|
+
const run = parseStudioShortRun(raw, storyId);
|
|
5515
|
+
if (!run) {
|
|
5516
|
+
return c.json({ error: "Short status is invalid" }, 409);
|
|
5517
|
+
}
|
|
5518
|
+
if (run.status === "needs-review") {
|
|
5519
|
+
await writeProductionRunSnapshot({
|
|
5520
|
+
rootDir: root,
|
|
5521
|
+
runPath,
|
|
5522
|
+
run: createProductionRunSnapshot({
|
|
5523
|
+
...run,
|
|
5524
|
+
status: "complete",
|
|
5525
|
+
updatedAt: new Date().toISOString(),
|
|
5526
|
+
}),
|
|
5527
|
+
});
|
|
5528
|
+
}
|
|
5529
|
+
return c.json({ ok: true, storyId, status: "complete" });
|
|
5530
|
+
});
|
|
5398
5531
|
app.get("/api/v1/translations", async (c) => {
|
|
5399
5532
|
const translationsDir = join(root, "translations");
|
|
5400
5533
|
let entries = [];
|