@kienmatu/inkos-studio 3.3.0 → 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.
Files changed (63) hide show
  1. package/dist/api/server.d.ts.map +1 -1
  2. package/dist/api/server.js +51 -18
  3. package/dist/api/server.js.map +1 -1
  4. package/dist/assets/{FilmWizard-DsSZPo5A.js → FilmWizard-BmrPbkFz.js} +1 -1
  5. package/dist/assets/{FlowView-DtborsGc.js → FlowView-SbRviH5b.js} +1 -1
  6. package/dist/assets/{_baseUniq-BEIj9tcE.js → _baseUniq-BkEZO23S.js} +1 -1
  7. package/dist/assets/{arc-C7Rm_CAk.js → arc-DzsKsGBX.js} +1 -1
  8. package/dist/assets/{architectureDiagram-Q4EWVU46-DlmfKm7b.js → architectureDiagram-Q4EWVU46-7-keOyLG.js} +1 -1
  9. package/dist/assets/{blockDiagram-DXYQGD6D-DwWcyB5e.js → blockDiagram-DXYQGD6D-CkWKO82x.js} +1 -1
  10. package/dist/assets/{c4Diagram-AHTNJAMY-DJr7ig4J.js → c4Diagram-AHTNJAMY-D6DRnA_K.js} +1 -1
  11. package/dist/assets/channel-vMyuwkSI.js +1 -0
  12. package/dist/assets/{chunk-4BX2VUAB-BEbkhxPj.js → chunk-4BX2VUAB-Cmg88BNH.js} +1 -1
  13. package/dist/assets/{chunk-4TB4RGXK-CKlayWkT.js → chunk-4TB4RGXK-CMZP43JX.js} +1 -1
  14. package/dist/assets/{chunk-55IACEB6-Do_NAv20.js → chunk-55IACEB6-CDFZTSkf.js} +1 -1
  15. package/dist/assets/{chunk-EDXVE4YY-CIaC2_XQ.js → chunk-EDXVE4YY-f2fO2QMj.js} +1 -1
  16. package/dist/assets/{chunk-FMBD7UC4-DK2fFb-S.js → chunk-FMBD7UC4-C8gUvwB8.js} +1 -1
  17. package/dist/assets/{chunk-OYMX7WX6-DOk8ZO7Q.js → chunk-OYMX7WX6-DaqAIa4a.js} +1 -1
  18. package/dist/assets/{chunk-QZHKN3VN-CWQlxTIX.js → chunk-QZHKN3VN-BdHnVE44.js} +1 -1
  19. package/dist/assets/{chunk-YZCP3GAM-BKMKNDs_.js → chunk-YZCP3GAM-CTNEwMvq.js} +1 -1
  20. package/dist/assets/classDiagram-6PBFFD2Q-DlUnDT-R.js +1 -0
  21. package/dist/assets/classDiagram-v2-HSJHXN6E-DlUnDT-R.js +1 -0
  22. package/dist/assets/clone-CgzdGWcq.js +1 -0
  23. package/dist/assets/{cose-bilkent-S5V4N54A-CtsSt-S-.js → cose-bilkent-S5V4N54A-KpZHVU8t.js} +1 -1
  24. package/dist/assets/{dagre-KV5264BT-zROnUgJY.js → dagre-KV5264BT-aiy2OT89.js} +1 -1
  25. package/dist/assets/{diagram-5BDNPKRD-Ct6aFDWr.js → diagram-5BDNPKRD-pNT8yMDm.js} +1 -1
  26. package/dist/assets/{diagram-G4DWMVQ6-B2bwAps6.js → diagram-G4DWMVQ6-oxZhaIi5.js} +1 -1
  27. package/dist/assets/{diagram-MMDJMWI5-CbwZreHT.js → diagram-MMDJMWI5-kwn_dxKS.js} +1 -1
  28. package/dist/assets/{diagram-TYMM5635-gKzWLxCO.js → diagram-TYMM5635-DXa2AxN_.js} +1 -1
  29. package/dist/assets/{erDiagram-SMLLAGMA-DipB25lI.js → erDiagram-SMLLAGMA-CAgK4N7D.js} +1 -1
  30. package/dist/assets/{flowDiagram-DWJPFMVM-C9VuPnc4.js → flowDiagram-DWJPFMVM-BeYsHcsf.js} +1 -1
  31. package/dist/assets/{ganttDiagram-T4ZO3ILL-B2dTjD_8.js → ganttDiagram-T4ZO3ILL-BU8wq8NL.js} +1 -1
  32. package/dist/assets/{gitGraphDiagram-UUTBAWPF-BZXYA0Ec.js → gitGraphDiagram-UUTBAWPF-BgivHLNi.js} +1 -1
  33. package/dist/assets/{graph-iDCrfqrI.js → graph-CSwQtVwF.js} +1 -1
  34. package/dist/assets/{highlighted-body-OFNGDK62-CP2BM2l8.js → highlighted-body-OFNGDK62-DqKI0DVm.js} +1 -1
  35. package/dist/assets/{index-PEL5ijWf.js → index-Bz4G_Cuu.js} +286 -286
  36. package/dist/assets/{infoDiagram-42DDH7IO-Bd7gtY2E.js → infoDiagram-42DDH7IO-B4Aw1ReL.js} +1 -1
  37. package/dist/assets/{ishikawaDiagram-UXIWVN3A-HMp96hG2.js → ishikawaDiagram-UXIWVN3A-ZVIYN2tB.js} +1 -1
  38. package/dist/assets/{journeyDiagram-VCZTEJTY-D36jcF3p.js → journeyDiagram-VCZTEJTY-UaC8xj7j.js} +1 -1
  39. package/dist/assets/{kanban-definition-6JOO6SKY-C4wSbzoj.js → kanban-definition-6JOO6SKY-B4pC4qyO.js} +1 -1
  40. package/dist/assets/{layout-DqXRWJEx.js → layout-BYNOhtZE.js} +1 -1
  41. package/dist/assets/{linear-QlXzAe7A.js → linear-DcH0KvpB.js} +1 -1
  42. package/dist/assets/{min-iaA6vGbj.js → min-B7b9i4d3.js} +1 -1
  43. package/dist/assets/{mindmap-definition-QFDTVHPH-B-PCe4LP.js → mindmap-definition-QFDTVHPH-LYMoC9qk.js} +1 -1
  44. package/dist/assets/{pieDiagram-DEJITSTG-DRSPzSKd.js → pieDiagram-DEJITSTG-CmdIR1nD.js} +1 -1
  45. package/dist/assets/{quadrantDiagram-34T5L4WZ-D-c8JbLY.js → quadrantDiagram-34T5L4WZ-Dy5E2ZXi.js} +1 -1
  46. package/dist/assets/{requirementDiagram-MS252O5E-CdOoLbvR.js → requirementDiagram-MS252O5E-CvO01yCF.js} +1 -1
  47. package/dist/assets/{sankeyDiagram-XADWPNL6-CQDxnTGB.js → sankeyDiagram-XADWPNL6-lV90jm6N.js} +1 -1
  48. package/dist/assets/{sequenceDiagram-FGHM5R23-SZbPsgFb.js → sequenceDiagram-FGHM5R23-BXYteJo4.js} +1 -1
  49. package/dist/assets/{stateDiagram-FHFEXIEX-uFY2njzT.js → stateDiagram-FHFEXIEX-DwuM_25x.js} +1 -1
  50. package/dist/assets/stateDiagram-v2-QKLJ7IA2-CVwGByU6.js +1 -0
  51. package/dist/assets/{timeline-definition-GMOUNBTQ-n_oY30Kg.js → timeline-definition-GMOUNBTQ-D5FpweXf.js} +1 -1
  52. package/dist/assets/{value-hJ3k-Vla.js → value-DKBwu4y3.js} +1 -1
  53. package/dist/assets/{vennDiagram-DHZGUBPP-B9VAsWw3.js → vennDiagram-DHZGUBPP-S83B5bJw.js} +1 -1
  54. package/dist/assets/{wardley-RL74JXVD-DPynk1O-.js → wardley-RL74JXVD-DiagH8qG.js} +1 -1
  55. package/dist/assets/{wardleyDiagram-NUSXRM2D-BxHtrGEZ.js → wardleyDiagram-NUSXRM2D-C_njDDS0.js} +1 -1
  56. package/dist/assets/{xychartDiagram-5P7HB3ND-B3Hi8GO_.js → xychartDiagram-5P7HB3ND-DDLHFTQ4.js} +1 -1
  57. package/dist/index.html +1 -1
  58. package/package.json +2 -2
  59. package/dist/assets/channel-D3RJhFng.js +0 -1
  60. package/dist/assets/classDiagram-6PBFFD2Q-Ctnvqnpw.js +0 -1
  61. package/dist/assets/classDiagram-v2-HSJHXN6E-Ctnvqnpw.js +0 -1
  62. package/dist/assets/clone-BdOaHqQL.js +0 -1
  63. package/dist/assets/stateDiagram-v2-QKLJ7IA2-BJCQ3uMo.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;AAM5B,OAAO,EAuHL,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;AAwgFD,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"}
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"}
@@ -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, 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";
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";
@@ -1387,7 +1387,6 @@ async function loadStudioShortList(root) {
1387
1387
  }
1388
1388
  const subscribers = new Set();
1389
1389
  const bookCreateStatus = new Map();
1390
- // 内存缓存:service -> 模型列表 + 更新时间戳;避免每次 sidebar 挂载时都打真实 LLM /models
1391
1390
  const modelListCache = new Map();
1392
1391
  function broadcast(event, data) {
1393
1392
  for (const handler of subscribers) {
@@ -1469,16 +1468,50 @@ function normalizeServiceModelIds(value) {
1469
1468
  }
1470
1469
  return models;
1471
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
+ }
1472
1502
  function mergeServiceModelIds(...groups) {
1473
1503
  return normalizeServiceModelIds(groups.flatMap((group) => group ?? []));
1474
1504
  }
1475
1505
  function normalizeServiceEntry(serviceId, value) {
1506
+ const models = Array.isArray(value.models) ? normalizeServiceModelIds(value.models) : undefined;
1507
+ const modelCapabilities = normalizeServiceModelCapabilities(value.modelCapabilities, models);
1476
1508
  if (serviceId.startsWith("custom:")) {
1477
1509
  return {
1478
1510
  service: "custom",
1479
1511
  name: decodeURIComponent(serviceId.slice("custom:".length)),
1480
1512
  ...(typeof value.baseUrl === "string" && value.baseUrl.length > 0 ? { baseUrl: value.baseUrl } : {}),
1481
- ...(Array.isArray(value.models) ? { models: normalizeServiceModelIds(value.models) } : {}),
1513
+ ...(models ? { models } : {}),
1514
+ ...(Object.keys(modelCapabilities).length > 0 ? { modelCapabilities } : {}),
1482
1515
  ...(typeof value.temperature === "number" ? { temperature: value.temperature } : {}),
1483
1516
  ...(value.apiFormat === "chat" || value.apiFormat === "responses" ? { apiFormat: value.apiFormat } : {}),
1484
1517
  ...(typeof value.stream === "boolean" ? { stream: value.stream } : {}),
@@ -1489,7 +1522,8 @@ function normalizeServiceEntry(serviceId, value) {
1489
1522
  service: "custom",
1490
1523
  ...(typeof value.name === "string" && value.name.length > 0 ? { name: value.name } : {}),
1491
1524
  ...(typeof value.baseUrl === "string" && value.baseUrl.length > 0 ? { baseUrl: value.baseUrl } : {}),
1492
- ...(Array.isArray(value.models) ? { models: normalizeServiceModelIds(value.models) } : {}),
1525
+ ...(models ? { models } : {}),
1526
+ ...(Object.keys(modelCapabilities).length > 0 ? { modelCapabilities } : {}),
1493
1527
  ...(typeof value.temperature === "number" ? { temperature: value.temperature } : {}),
1494
1528
  ...(value.apiFormat === "chat" || value.apiFormat === "responses" ? { apiFormat: value.apiFormat } : {}),
1495
1529
  ...(typeof value.stream === "boolean" ? { stream: value.stream } : {}),
@@ -1497,7 +1531,8 @@ function normalizeServiceEntry(serviceId, value) {
1497
1531
  }
1498
1532
  return {
1499
1533
  service: serviceId,
1500
- ...(Array.isArray(value.models) ? { models: normalizeServiceModelIds(value.models) } : {}),
1534
+ ...(models ? { models } : {}),
1535
+ ...(Object.keys(modelCapabilities).length > 0 ? { modelCapabilities } : {}),
1501
1536
  ...(typeof value.temperature === "number" ? { temperature: value.temperature } : {}),
1502
1537
  ...(value.apiFormat === "chat" || value.apiFormat === "responses" ? { apiFormat: value.apiFormat } : {}),
1503
1538
  ...(typeof value.stream === "boolean" ? { stream: value.stream } : {}),
@@ -1510,15 +1545,7 @@ function normalizeServiceConfig(raw) {
1510
1545
  if (Array.isArray(raw)) {
1511
1546
  return raw
1512
1547
  .filter((entry) => Boolean(entry) && typeof entry === "object")
1513
- .map((entry) => ({
1514
- service: typeof entry.service === "string" && entry.service.length > 0 ? entry.service : "custom",
1515
- ...(typeof entry.name === "string" && entry.name.length > 0 ? { name: entry.name } : {}),
1516
- ...(typeof entry.baseUrl === "string" && entry.baseUrl.length > 0 ? { baseUrl: entry.baseUrl } : {}),
1517
- ...(Array.isArray(entry.models) ? { models: normalizeServiceModelIds(entry.models) } : {}),
1518
- ...(typeof entry.temperature === "number" ? { temperature: entry.temperature } : {}),
1519
- ...(entry.apiFormat === "chat" || entry.apiFormat === "responses" ? { apiFormat: entry.apiFormat } : {}),
1520
- ...(typeof entry.stream === "boolean" ? { stream: entry.stream } : {}),
1521
- }));
1548
+ .map((entry) => normalizeServiceEntry(typeof entry.service === "string" && entry.service.length > 0 ? entry.service : "custom", entry));
1522
1549
  }
1523
1550
  if (raw && typeof raw === "object") {
1524
1551
  return Object.entries(raw)
@@ -1536,6 +1563,9 @@ function mergeServiceConfig(existing, updates) {
1536
1563
  ...previous,
1537
1564
  ...update,
1538
1565
  ...(update.models === undefined && previous?.models ? { models: previous.models } : {}),
1566
+ ...(update.modelCapabilities === undefined && previous?.modelCapabilities
1567
+ ? { modelCapabilities: previous.modelCapabilities }
1568
+ : {}),
1539
1569
  });
1540
1570
  }
1541
1571
  return [...merged.values()];
@@ -1580,6 +1610,12 @@ function syncTopLevelLlmMirror(llm) {
1580
1610
  llm.apiFormat = selectedEntry.apiFormat;
1581
1611
  if (selectedEntry.stream !== undefined)
1582
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
+ }
1583
1619
  }
1584
1620
  async function loadRawConfig(root) {
1585
1621
  const configPath = join(root, "inkos.json");
@@ -1955,10 +1991,7 @@ async function fetchModelsFromServiceBaseUrl(serviceId, baseUrl, apiKey, proxyUr
1955
1991
  authFailed: res.status === 401 || res.status === 403,
1956
1992
  };
1957
1993
  }
1958
- const json = await res.json();
1959
- return {
1960
- models: (json.data ?? []).map((m) => ({ id: m.id, name: m.id })),
1961
- };
1994
+ return { models: normalizeProbedModels(await res.json()) };
1962
1995
  }
1963
1996
  catch (error) {
1964
1997
  return {