@shawnstack/quickforge 1.7.4 → 1.7.5
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/assets/AgentProfilesPage-XNjuqJs7.js +1 -0
- package/dist/assets/ChatPanelHost-CuF-PZpc.js +292 -0
- package/dist/assets/CloudAccountSettingsPage-GJSoi6sO.js +1 -0
- package/dist/assets/PluginsPage-BQgp0qN-.js +1 -0
- package/dist/assets/ScheduledTasksPage-DdekATzq.js +2 -0
- package/dist/assets/{SettingsWorkspacePage-B53_eDf2.js → SettingsWorkspacePage-Cb54Ic91.js} +389 -378
- package/dist/assets/ShareLinksSettingsPage-C75WJpaF.js +1 -0
- package/dist/assets/SharedConversationPage-CjMtSQTW.js +1 -0
- package/dist/assets/{TerminalDock-Dgg-_ZmU.js → TerminalDock-D4zJBJc4.js} +2 -2
- package/dist/assets/WorkspaceInspector-D9kdnLDd.js +36 -0
- package/dist/assets/{abnfDiagram-VRR7QNED-Dy7veffk.js → abnfDiagram-VRR7QNED-CMhVoYUh.js} +1 -1
- package/dist/assets/{arc-Bo3p2lGy.js → arc-w21O0TLn.js} +1 -1
- package/dist/assets/architecture-TIHT7OUA-DMwFMHxq.js +1 -0
- package/dist/assets/{architectureDiagram-ZJ3FMSHR-Cwx8qOvu.js → architectureDiagram-ZJ3FMSHR-C52qL6Hg.js} +1 -1
- package/dist/assets/{blockDiagram-677ZJIJ3-BiuaAOFa.js → blockDiagram-677ZJIJ3-CM3XbLol.js} +1 -1
- package/dist/assets/{c4Diagram-LMCZKHZV-BTcGfhK2.js → c4Diagram-LMCZKHZV-D7Bh1ui1.js} +1 -1
- package/dist/assets/channel-Duu1CuH9.js +1 -0
- package/dist/assets/chunk-2Q5K7J3B-B6rHWc4S.js +1 -0
- package/dist/assets/{chunk-32BRIVSS-B9PuF_RF.js → chunk-32BRIVSS-xgrtbT8e.js} +1 -1
- package/dist/assets/{chunk-52WLFC77-3zGItfIM.js → chunk-52WLFC77-CDbaHw80.js} +1 -1
- package/dist/assets/{chunk-5FCAYU7R-DQ66qlmt.js → chunk-5FCAYU7R-CcSvVbPc.js} +1 -1
- package/dist/assets/{chunk-5HE753X5-CLqTO-VF.js → chunk-5HE753X5-erFpzzgx.js} +1 -1
- package/dist/assets/{chunk-5JV3BV7I-Csxv1jr6.js → chunk-5JV3BV7I-rEhN9F6G.js} +1 -1
- package/dist/assets/{chunk-5TONJI2A-BCQttpBr.js → chunk-5TONJI2A-D8L-QTwD.js} +1 -1
- package/dist/assets/{chunk-5VM5RSS4-DEWJGSTb.js → chunk-5VM5RSS4-CjlfMBbM.js} +1 -1
- package/dist/assets/{chunk-7BUUIJ7U-DNorm9MM.js → chunk-7BUUIJ7U-CCcsI9XE.js} +1 -1
- package/dist/assets/{chunk-BIQX33UG-DgvY_BOT.js → chunk-BIQX33UG-FSqFbmb3.js} +1 -1
- package/dist/assets/{chunk-C7G6YPKG-DMvn9IPs.js → chunk-C7G6YPKG-ZMLUvfLy.js} +1 -1
- package/dist/assets/{chunk-CQNSW5MT-Dq2duUgr.js → chunk-CQNSW5MT-DZuBpk25.js} +1 -1
- package/dist/assets/{chunk-CYSBUYHQ-BovYyc4Y.js → chunk-CYSBUYHQ-CB26wsG0.js} +1 -1
- package/dist/assets/{chunk-EMLP6XTP-BMDOpuYN.js → chunk-EMLP6XTP-BbsM8oRw.js} +1 -1
- package/dist/assets/{chunk-EX3LRPZG-6eP2UPOf.js → chunk-EX3LRPZG-BcQhaqt7.js} +1 -1
- package/dist/assets/{chunk-FWX5IMBZ-D4q-wTSy.js → chunk-FWX5IMBZ-DrnrdrSu.js} +2 -2
- package/dist/assets/{chunk-HOUHSVGY-XjIcuzH7.js → chunk-HOUHSVGY-tdc-Z9eW.js} +1 -1
- package/dist/assets/{chunk-ICXQ74PX-YBXbanq9.js → chunk-ICXQ74PX-Cd7igVGt.js} +1 -1
- package/dist/assets/{chunk-JG7HCLWE-CcN3uNXF.js → chunk-JG7HCLWE-iXXGW8nf.js} +1 -1
- package/dist/assets/{chunk-JWPE2WC7-Cwg6AUAt.js → chunk-JWPE2WC7-BZ87mXEv.js} +1 -1
- package/dist/assets/{chunk-MOJQB5TN-NNspcGIU.js → chunk-MOJQB5TN-CLTjV5ov.js} +1 -1
- package/dist/assets/{chunk-MOZMSUNE-pMJ_jMos.js → chunk-MOZMSUNE-B3SCBrRH.js} +1 -1
- package/dist/assets/{chunk-OGEWGWER-CJy-3Ldv.js → chunk-OGEWGWER-TgvkXkFX.js} +1 -1
- package/dist/assets/{chunk-OSBZ3O6U-D7cLHHOA.js → chunk-OSBZ3O6U-B9E2E5v1.js} +1 -1
- package/dist/assets/{chunk-PUDLZKDR-D5YBi1Pi.js → chunk-PUDLZKDR-C5GMVYup.js} +1 -1
- package/dist/assets/{chunk-Q4XR5HBZ-DYmqQdIf.js → chunk-Q4XR5HBZ-fo5-HsqY.js} +1 -1
- package/dist/assets/{chunk-QBLGF6JB-Bfcx00X0.js → chunk-QBLGF6JB-Dwfg8sKc.js} +1 -1
- package/dist/assets/{chunk-R7FJI6CG-oXzadpZY.js → chunk-R7FJI6CG-DpBrv4ni.js} +1 -1
- package/dist/assets/{chunk-RYQCIY6F-Dt3-8yUh.js → chunk-RYQCIY6F-DzzmTl11.js} +1 -1
- package/dist/assets/{chunk-U6XO7XAA-B55eSvpx.js → chunk-U6XO7XAA-Dw6aviKa.js} +1 -1
- package/dist/assets/{chunk-V7JOEXUC-Btk4JwCt.js → chunk-V7JOEXUC-CEDazV6w.js} +1 -1
- package/dist/assets/chunk-VAUOI2AC-CWYjg8zE.js +1 -0
- package/dist/assets/{chunk-VR4S4FIN-DgaSiVOY.js → chunk-VR4S4FIN-C_-eEj-9.js} +1 -1
- package/dist/assets/{chunk-WYO6CB5R-rRDZ_Tta.js → chunk-WYO6CB5R-NF-MsJJR.js} +3 -3
- package/dist/assets/chunk-XXDRQBXY-DzTwx8ZH.js +1 -0
- package/dist/assets/{chunk-YOTPTUD7-BnFxj5o4.js → chunk-YOTPTUD7-DqzqtdII.js} +1 -1
- package/dist/assets/{chunk-ZGVPDNZ5-CrnlPlmJ.js → chunk-ZGVPDNZ5-CRrAYi4g.js} +1 -1
- package/dist/assets/{chunk-ZIRB5QZD-BYTiATIH.js → chunk-ZIRB5QZD-Dc1s5bLM.js} +1 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Cc63fLWP.js +1 -0
- package/dist/assets/classDiagram-v2-EOCWNBFH-CoXU0qT6.js +1 -0
- package/dist/assets/{cose-bilkent-JH36ORCC-BORKJRwF.js → cose-bilkent-JH36ORCC-cL247pHg.js} +1 -1
- package/dist/assets/cynefin-VYW2F7L2-C8yCvH_o.js +1 -0
- package/dist/assets/{cynefinDiagram-TSTJHNR4-BXKeaSl8.js → cynefinDiagram-TSTJHNR4-D4sZ7LYI.js} +1 -1
- package/dist/assets/{dagre-CrA0XVwJ.js → dagre-DmHb3Ctt.js} +1 -1
- package/dist/assets/{dagre-VKFMJZFB-ouq_lA1a.js → dagre-VKFMJZFB-BlsnSh-Q.js} +1 -1
- package/dist/assets/{diagram-FQU43EPY-BxR5kUiQ.js → diagram-FQU43EPY-DW1yQiRO.js} +1 -1
- package/dist/assets/{diagram-G47NLZAW-DWonk1sL.js → diagram-G47NLZAW-BTUAsFjb.js} +1 -1
- package/dist/assets/{diagram-NH7WQ7WH-fmV_wV5e.js → diagram-NH7WQ7WH-BcaomqSd.js} +1 -1
- package/dist/assets/{diagram-OA4YK3LP-DvOSRRiV.js → diagram-OA4YK3LP-DDLX7Xwr.js} +1 -1
- package/dist/assets/{diagram-WEI45ONY-Bp-xb3uS.js → diagram-WEI45ONY-CIave0An.js} +1 -1
- package/dist/assets/{ebnfDiagram-CCIWWBDH-BTlnwneA.js → ebnfDiagram-CCIWWBDH-Cr1Y6lPu.js} +1 -1
- package/dist/assets/{erDiagram-Q63AITRT-C3fFWGCm.js → erDiagram-Q63AITRT-D3EgiVVH.js} +1 -1
- package/dist/assets/{esm-oa69b5u4.js → esm-Df4edDpj.js} +2 -2
- package/dist/assets/eventmodeling-45OFAUF4-DO1vRTM0.js +1 -0
- package/dist/assets/flowDiagram-23GEKE2U-BS7KXcqn.js +1 -0
- package/dist/assets/{ganttDiagram-NO4QXBWP-DzAiojNi.js → ganttDiagram-NO4QXBWP-B0oyDIqK.js} +1 -1
- package/dist/assets/gitGraph-TEB2WS4Q-m5F5ef09.js +1 -0
- package/dist/assets/{gitGraphDiagram-IHSO6WYX-Cv57oNEA.js → gitGraphDiagram-IHSO6WYX-uQtr6IqK.js} +1 -1
- package/dist/assets/icons-CXPP1fFT.js +1 -0
- package/dist/assets/index-_ZhK6bvp.js +65 -0
- package/dist/assets/index-iVV2bP_f.css +3 -0
- package/dist/assets/info-DKCQHKI2-CZxPlQJ0.js +1 -0
- package/dist/assets/{infoDiagram-FWYZ7A6U-B5Z_O3Ro.js → infoDiagram-FWYZ7A6U-B_GzlLIM.js} +1 -1
- package/dist/assets/{ishikawaDiagram-FXEZZL3T-CKTK_TKV.js → ishikawaDiagram-FXEZZL3T-CKQIsSdU.js} +1 -1
- package/dist/assets/{journeyDiagram-5HDEW3XC-Cm9k4ywW.js → journeyDiagram-5HDEW3XC-DrrvzZL1.js} +1 -1
- package/dist/assets/{kanban-definition-HUTT4EX6-DzNteLwx.js → kanban-definition-HUTT4EX6-CJQRTdXz.js} +1 -1
- package/dist/assets/{line-BG78c_WJ.js → line-B4DxX7tC.js} +1 -1
- package/dist/assets/{linear-1X20_EGu.js → linear-U-nKUhyW.js} +1 -1
- package/dist/assets/{map-CCI8WZkS.js → map-BneTM-ri.js} +1 -1
- package/dist/assets/{mcp-servers-dialog-GXXD9K0U.js → mcp-servers-dialog-BUSPvaqI.js} +2 -2
- package/dist/assets/{mermaid-parser.core-Bb8HI_OS.js → mermaid-parser.core-BlKWrEdZ.js} +2 -2
- package/dist/assets/{mermaid-renderer-PIaNiXAz.js → mermaid-renderer-jEbqFaTe.js} +2 -2
- package/dist/assets/{mermaid.core-DUHOIwL5.js → mermaid.core-DWpShXCs.js} +3 -3
- package/dist/assets/{mindmap-definition-LN4V7U3C-Tnbszo7b.js → mindmap-definition-LN4V7U3C-CEVwZD78.js} +1 -1
- package/dist/assets/model-identity-CgA6_Pbm.js +1 -0
- package/dist/assets/model-reference-o41fJ6jQ.js +1 -0
- package/dist/assets/{monaco-BVtCspYZ.js → monaco-D6OhXgjg.js} +1 -1
- package/dist/assets/{ordinal-v4prQcuq.js → ordinal-B2r5L1v4.js} +1 -1
- package/dist/assets/{otel-D1LswXpM.js → otel-BFnphzjt.js} +1 -1
- package/dist/assets/packet-7NZHBO7P-zIioIZVN.js +1 -0
- package/dist/assets/{pegDiagram-2B236MQR-CX824Kd0.js → pegDiagram-2B236MQR-CBLkBdnQ.js} +1 -1
- package/dist/assets/{pi-ai-DAJlO9ZB.js → pi-ai-Cr2ee4a0.js} +2 -2
- package/dist/assets/{pi-web-ui-B-RJSxjR.js → pi-web-ui-DV5jKjSg.js} +1 -1
- package/dist/assets/pie-RZYD4A2V-GGWijBvB.js +1 -0
- package/dist/assets/{pieDiagram-ENE6RG2P-BT04VWPQ.js → pieDiagram-ENE6RG2P-8tCnwtWS.js} +1 -1
- package/dist/assets/{quadrantDiagram-ABIIQ3AL-BvOZxkBr.js → quadrantDiagram-ABIIQ3AL-CWd28cHF.js} +1 -1
- package/dist/assets/radar-I7S5WNFK-yvwFH3RV.js +1 -0
- package/dist/assets/railroad-3IZDKUUU-BVadlswB.js +1 -0
- package/dist/assets/railroad-abnf-AHOZXSZD-B7R-p_2-.js +1 -0
- package/dist/assets/railroad-ebnf-EBAXGLYW-BnbJxPug.js +1 -0
- package/dist/assets/railroad-peg-LSFZ7HO6-Ci3DcEuQ.js +1 -0
- package/dist/assets/{railroadDiagram-RFXS5EU6-DnTU--BV.js → railroadDiagram-RFXS5EU6-CI4ouOBs.js} +1 -1
- package/dist/assets/{react-vendor-eWH0QhNU.js → react-vendor-1KC5PyRx.js} +1 -1
- package/dist/assets/{requirementDiagram-TGXJPOKE--MZX_yEv.js → requirementDiagram-TGXJPOKE-DtFz7sw4.js} +1 -1
- package/dist/assets/{sankeyDiagram-HTMAVEWB-SEZkHhYn.js → sankeyDiagram-HTMAVEWB--VeOwwk9.js} +1 -1
- package/dist/assets/{sequenceDiagram-DBY2YBRQ-BhC2OHiz.js → sequenceDiagram-DBY2YBRQ-B8AHk5Oe.js} +1 -1
- package/dist/assets/{sizeCapture-X5ZJPWSS-Ci5LeToV.js → sizeCapture-X5ZJPWSS-vV_ArM8D.js} +1 -1
- package/dist/assets/{skills-dialog-DDh1h8eH.js → skills-dialog-BThnIUBs.js} +3 -3
- package/dist/assets/{src-CovulcRC.js → src-PYsDme0X.js} +1 -1
- package/dist/assets/{stateDiagram-2N3HPSRC-DKK5tFT4.js → stateDiagram-2N3HPSRC-etXnJ8X8.js} +1 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-Dms3pICj.js +1 -0
- package/dist/assets/{swimlanes-5IMT3BWC-DxxGCk67.js → swimlanes-5IMT3BWC-pabIKAmn.js} +2 -2
- package/dist/assets/swimlanesDiagram-G3AALYLV-B14aWjv6.js +8 -0
- package/dist/assets/{timeline-definition-FHXFAJF6-BPXB3Sue.js → timeline-definition-FHXFAJF6-C55MKm3L.js} +1 -1
- package/dist/assets/treeView-QDETBFTQ-Cru9B2zv.js +1 -0
- package/dist/assets/treemap-6X3UGDF4-DNOVHFaJ.js +1 -0
- package/dist/assets/{vennDiagram-L72KCM5P-CxcBCKye.js → vennDiagram-L72KCM5P-CgNf1Q9W.js} +1 -1
- package/dist/assets/wardley-OPB4EBWU-E3m1BOJQ.js +1 -0
- package/dist/assets/{wardleyDiagram-EHGQE667-DEL6Yes5.js → wardleyDiagram-EHGQE667-Drt5ytec.js} +1 -1
- package/dist/assets/{xychartDiagram-FW5EYKEG-N8cPbcjC.js → xychartDiagram-FW5EYKEG-hhoEo_Ar.js} +1 -1
- package/dist/index.html +9 -8
- package/package.json +3 -1
- package/plugins/{openai-documents → documents}/plugin.json +2 -2
- package/plugins/{openai-presentations → presentations}/plugin.json +2 -2
- package/plugins/{openai-spreadsheets → spreadsheets}/plugin.json +2 -2
- package/server/acp/server.mjs +36 -26
- package/server/agent-manager.mjs +130 -28
- package/server/agent-profile-files.mjs +8 -4
- package/server/agent-profile-schema.mjs +47 -23
- package/server/agent-profiles.mjs +1 -1
- package/server/ai-http-logger.mjs +98 -12
- package/server/cloud/chat-idempotency-store.mjs +96 -0
- package/server/cloud/client.mjs +102 -0
- package/server/cloud/config.mjs +53 -0
- package/server/cloud/credential-store.mjs +193 -0
- package/server/cloud/identity.mjs +355 -0
- package/server/cloud/index.mjs +7 -0
- package/server/cloud/models.mjs +80 -0
- package/server/cloud/runtime.mjs +129 -0
- package/server/cloud/service-config.mjs +77 -0
- package/server/index.mjs +28 -11
- package/server/model-catalog.mjs +262 -0
- package/server/plugins/registry.mjs +29 -5
- package/server/routes/agent-profiles.mjs +41 -7
- package/server/routes/agent.mjs +20 -11
- package/server/routes/backup.mjs +7 -1
- package/server/routes/cloud.mjs +227 -0
- package/server/routes/models.mjs +7 -1
- package/server/routes/scheduled-tasks.mjs +38 -8
- package/server/routes/shared-conversation.mjs +62 -58
- package/server/routes/shares.mjs +76 -1
- package/server/routes/storage.mjs +24 -1
- package/server/routes/workspace.mjs +6 -4
- package/server/share-store.mjs +168 -13
- package/server/skills.mjs +30 -3
- package/server/storage.mjs +7 -1
- package/server/subagents.mjs +3 -3
- package/server/tools/definitions.mjs +1 -1
- package/server/tools/index.mjs +2 -2
- package/server/utils/network.mjs +9 -0
- package/server/utils/response.mjs +8 -1
- package/skills/skill-creator/LICENSE.txt +202 -0
- package/skills/skill-creator/SKILL.md +485 -0
- package/skills/skill-creator/UPSTREAM.md +6 -0
- package/skills/skill-creator/agents/analyzer.md +274 -0
- package/skills/skill-creator/agents/comparator.md +202 -0
- package/skills/skill-creator/agents/grader.md +223 -0
- package/skills/skill-creator/assets/eval_review.html +146 -0
- package/skills/skill-creator/eval-viewer/generate_review.py +471 -0
- package/skills/skill-creator/eval-viewer/viewer.html +1325 -0
- package/skills/skill-creator/references/schemas.md +430 -0
- package/skills/skill-creator/scripts/__init__.py +0 -0
- package/skills/skill-creator/scripts/aggregate_benchmark.py +401 -0
- package/skills/skill-creator/scripts/generate_report.py +326 -0
- package/skills/skill-creator/scripts/improve_description.py +247 -0
- package/skills/skill-creator/scripts/package_skill.py +136 -0
- package/skills/skill-creator/scripts/quick_validate.py +103 -0
- package/skills/skill-creator/scripts/run_eval.py +310 -0
- package/skills/skill-creator/scripts/run_loop.py +328 -0
- package/skills/skill-creator/scripts/utils.py +47 -0
- package/dist/assets/AgentProfilesPage-B84w-r9S.js +0 -1
- package/dist/assets/ChatPanelHost-CyO8fEoj.js +0 -288
- package/dist/assets/PluginsPage-D2862wul.js +0 -1
- package/dist/assets/ScheduledTasksPage-GqbiJDPX.js +0 -2
- package/dist/assets/SharedConversationPage-Cw2QFnbC.js +0 -1
- package/dist/assets/WorkspaceInspector-3uLiu6Bv.js +0 -13
- package/dist/assets/architecture-TIHT7OUA-7FQo5GbP.js +0 -1
- package/dist/assets/channel-DToA8d-4.js +0 -1
- package/dist/assets/chunk-2Q5K7J3B-D_Wxpk-T.js +0 -1
- package/dist/assets/chunk-VAUOI2AC-CIZseNLi.js +0 -1
- package/dist/assets/chunk-XXDRQBXY-Do-XYxat.js +0 -1
- package/dist/assets/classDiagram-OUVF2IWQ-Bu24Sy-k.js +0 -1
- package/dist/assets/classDiagram-v2-EOCWNBFH-DKhh5HSW.js +0 -1
- package/dist/assets/cynefin-VYW2F7L2-oyiAgYC4.js +0 -1
- package/dist/assets/eventmodeling-45OFAUF4-YB_0MefX.js +0 -1
- package/dist/assets/flowDiagram-23GEKE2U-Bc73xdBd.js +0 -1
- package/dist/assets/gitGraph-TEB2WS4Q-Bvp27L0n.js +0 -1
- package/dist/assets/icons-cTkqD_Gi.js +0 -1
- package/dist/assets/index-B48prgLL.js +0 -65
- package/dist/assets/index-DQhwHHer.css +0 -3
- package/dist/assets/info-DKCQHKI2-BsLOivgq.js +0 -1
- package/dist/assets/packet-7NZHBO7P-BKQkXRtk.js +0 -1
- package/dist/assets/pie-RZYD4A2V-BTiTN5Ge.js +0 -1
- package/dist/assets/radar-I7S5WNFK-BU-oVjKM.js +0 -1
- package/dist/assets/railroad-3IZDKUUU-7H2hxNbL.js +0 -1
- package/dist/assets/railroad-abnf-AHOZXSZD-Mx6wf6XQ.js +0 -1
- package/dist/assets/railroad-ebnf-EBAXGLYW-BgXSKhYy.js +0 -1
- package/dist/assets/railroad-peg-LSFZ7HO6-DTEl2rAC.js +0 -1
- package/dist/assets/stateDiagram-v2-6OUMAXLB-D8x3mkni.js +0 -1
- package/dist/assets/swimlanesDiagram-G3AALYLV-C4nOBNp8.js +0 -8
- package/dist/assets/treeView-QDETBFTQ-DOE6NSdf.js +0 -1
- package/dist/assets/treemap-6X3UGDF4-Ca7QD_b4.js +0 -1
- package/dist/assets/wardley-OPB4EBWU-D9O4RKRm.js +0 -1
- /package/dist/assets/{array-DqLCdDFv.js → array-B9UHiPd-.js} +0 -0
- /package/dist/assets/{chunk-KEIR6QF5-s7Qq-R3i.js → chunk-KEIR6QF5-jrz1pRUS.js} +0 -0
- /package/dist/assets/{chunk-Y2CYZVJY-BgISNSiw.js → chunk-Y2CYZVJY-D6N-CrJv.js} +0 -0
- /package/dist/assets/{cytoscape.esm-iekjSZ2n.js → cytoscape.esm-DyfqweF2.js} +0 -0
- /package/dist/assets/{defaultLocale-CrJzLgRD.js → defaultLocale-5eAKkKJC.js} +0 -0
- /package/dist/assets/{dist-zzfqk5hx.js → dist-CLg13NtV.js} +0 -0
- /package/dist/assets/{graphlib-CIz_CfxW.js → graphlib-DJkmx0Cq.js} +0 -0
- /package/dist/assets/{init-C0r9Gk5G.js → init-DlZdxViB.js} +0 -0
- /package/dist/assets/{path-DIKpVbHL.js → path-6uRLdFF7.js} +0 -0
- /package/dist/assets/{plugin-api-C8hMT5W6.js → plugin-api-Uu2xAB4d.js} +0 -0
- /package/dist/assets/{rough.esm-BMOtDaaS.js → rough.esm-Bud4g4fh.js} +0 -0
- /package/dist/assets/{web-RgX7H-OH.js → web-DoV8MSMn.js} +0 -0
- /package/dist/assets/{xterm-BFzZ1FH4.js → xterm-Bm_IbozX.js} +0 -0
- /package/plugins/{openai-documents → documents}/commands/document.md +0 -0
- /package/plugins/{openai-documents → documents}/skills/documents/SKILL.md +0 -0
- /package/plugins/{openai-presentations → presentations}/commands/presentation.md +0 -0
- /package/plugins/{openai-presentations → presentations}/skills/presentations/SKILL.md +0 -0
- /package/plugins/{openai-spreadsheets → spreadsheets}/commands/spreadsheet.md +0 -0
- /package/plugins/{openai-spreadsheets → spreadsheets}/skills/spreadsheets/SKILL.md +0 -0
package/server/agent-manager.mjs
CHANGED
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
formatSubagentTask,
|
|
14
14
|
} from './subagents.mjs'
|
|
15
15
|
import { agentProfileSnapshot, getAgentProfile } from './agent-profiles.mjs'
|
|
16
|
+
import { modelBindingFromModel, resolveImplicitModelPreference, resolveModelBinding } from './model-catalog.mjs'
|
|
16
17
|
import { agentProfileFromMarkdown } from './agent-profile-files.mjs'
|
|
17
18
|
import {
|
|
18
19
|
applyCapabilityPolicy,
|
|
@@ -200,7 +201,7 @@ function hasFullAccess(session) {
|
|
|
200
201
|
|
|
201
202
|
const IDLE_TIMEOUT_MS = 30 * 60 * 1000 // 30 minutes
|
|
202
203
|
const ABORT_IDLE_WAIT_TIMEOUT_MS = 3000
|
|
203
|
-
const SUBAGENT_DEFAULT_TIMEOUT_MS =
|
|
204
|
+
const SUBAGENT_DEFAULT_TIMEOUT_MS = 60 * 60 * 1000
|
|
204
205
|
const SUBAGENT_TRACE_THROTTLE_MS = 150
|
|
205
206
|
|
|
206
207
|
/**
|
|
@@ -515,6 +516,37 @@ function updateSessionMessages(session, messages) {
|
|
|
515
516
|
session.agent.state.messages = messages
|
|
516
517
|
}
|
|
517
518
|
|
|
519
|
+
const CLIENT_MESSAGE_ID_FIELD = 'quickforgeClientMessageId'
|
|
520
|
+
|
|
521
|
+
function isManagedCloudModel(model) {
|
|
522
|
+
return model?.provider === 'quickforge-cloud' && model?.quickforgeModelSource === 'cloud'
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
function objectMetadata(message) {
|
|
526
|
+
const metadata = message?.metadata
|
|
527
|
+
return metadata && typeof metadata === 'object' && !Array.isArray(metadata) ? metadata : {}
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
function logicalMessageId(message) {
|
|
531
|
+
const value = objectMetadata(message)[CLIENT_MESSAGE_ID_FIELD]
|
|
532
|
+
return typeof value === 'string' && /^[A-Za-z0-9._:-]{1,128}$/.test(value) ? value : undefined
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
function messageWithLogicalId(message) {
|
|
536
|
+
if (!message || typeof message !== 'object' || logicalMessageId(message)) return message
|
|
537
|
+
return {
|
|
538
|
+
...message,
|
|
539
|
+
metadata: {
|
|
540
|
+
...objectMetadata(message),
|
|
541
|
+
[CLIENT_MESSAGE_ID_FIELD]: `qfcm_${randomUUID()}`,
|
|
542
|
+
},
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
function prepareCloudUserMessage(session, message) {
|
|
547
|
+
return isManagedCloudModel(session?.model) ? messageWithLogicalId(message) : message
|
|
548
|
+
}
|
|
549
|
+
|
|
518
550
|
function resetSessionCompaction(session) {
|
|
519
551
|
session.contextCompaction = null
|
|
520
552
|
session.lastAutoCompactAt = null
|
|
@@ -627,6 +659,9 @@ async function summarySession(session, initialUserMessage, summaryOptions) {
|
|
|
627
659
|
accessMode: session.accessMode,
|
|
628
660
|
yoloMode: session.yoloMode,
|
|
629
661
|
model: session.model,
|
|
662
|
+
modelRef: session.modelRef,
|
|
663
|
+
modelAccessContext: session.modelAccessContext,
|
|
664
|
+
resolvePersistedModel: true,
|
|
630
665
|
thinkingLevel: session.thinkingLevel,
|
|
631
666
|
messages: compactedMessages,
|
|
632
667
|
title: compactedTitle,
|
|
@@ -1081,7 +1116,7 @@ model:
|
|
|
1081
1116
|
modelId: ${frontmatterString(spec.model.modelId)}${spec.model.api ? `
|
|
1082
1117
|
api: ${frontmatterString(spec.model.api)}` : ''}${spec.model.baseUrl ? `
|
|
1083
1118
|
baseUrl: ${frontmatterString(spec.model.baseUrl)}` : ''}` : ''}
|
|
1084
|
-
max-runtime-ms: ${Math.max(1000, Math.min(Number(spec.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS),
|
|
1119
|
+
max-runtime-ms: ${Math.max(1000, Math.min(Number(spec.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS), 60 * 60 * 1000))}
|
|
1085
1120
|
max-tool-calls: ${Math.max(1, Math.min(Number(spec.maxToolCalls || 300), 300))}
|
|
1086
1121
|
---
|
|
1087
1122
|
${spec.systemPrompt}
|
|
@@ -1135,10 +1170,15 @@ async function runSubagent(parentSession, params, parentSignal, onUpdate) {
|
|
|
1135
1170
|
throw new Error('No active model is configured for the parent session.')
|
|
1136
1171
|
}
|
|
1137
1172
|
|
|
1138
|
-
const timeoutMs = Math.max(1000, Math.min(Number(definition.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS),
|
|
1173
|
+
const timeoutMs = Math.max(1000, Math.min(Number(definition.maxRuntimeMs || SUBAGENT_DEFAULT_TIMEOUT_MS), 60 * 60 * 1000))
|
|
1139
1174
|
definition.capabilityPolicy ||= inferCapabilityPolicy(definition.allowedTools || [])
|
|
1140
1175
|
definition.allowedTools = applyCapabilityPolicy(definition.allowedTools || [], definition.capabilityPolicy)
|
|
1141
|
-
const { model: subagentModel, info: subagentModelInfo } = await resolveAgentProfileModel(
|
|
1176
|
+
const { model: subagentModel, info: subagentModelInfo } = await resolveAgentProfileModel(
|
|
1177
|
+
definition,
|
|
1178
|
+
parentSession.model,
|
|
1179
|
+
readStore,
|
|
1180
|
+
parentSession.modelAccessContext || {},
|
|
1181
|
+
)
|
|
1142
1182
|
const subagentThinkingLevel = resolveAgentProfileThinkingLevel(definition, parentSession.thinkingLevel, subagentModel)
|
|
1143
1183
|
const subagentSessionId = `${parentSession.sessionId}:subagent:${definition.name}:${randomUUID()}`
|
|
1144
1184
|
const startedAt = Date.now()
|
|
@@ -1511,6 +1551,9 @@ export async function createAgent(sessionId, config = {}) {
|
|
|
1511
1551
|
accessMode: rawAccessMode,
|
|
1512
1552
|
yoloMode = false,
|
|
1513
1553
|
model = null,
|
|
1554
|
+
modelRef = null,
|
|
1555
|
+
modelAccessContext = null,
|
|
1556
|
+
resolvePersistedModel = false,
|
|
1514
1557
|
thinkingLevel = 'off',
|
|
1515
1558
|
messages = [],
|
|
1516
1559
|
systemPrompt = null,
|
|
@@ -1555,24 +1598,36 @@ export async function createAgent(sessionId, config = {}) {
|
|
|
1555
1598
|
|
|
1556
1599
|
// Resolve model
|
|
1557
1600
|
let resolvedModel = model
|
|
1601
|
+
let resolvedModelRef = modelRef
|
|
1558
1602
|
if (!resolvedModel) {
|
|
1559
|
-
// Try to load from storage
|
|
1603
|
+
// Try to load the active preference from storage. A stale/hidden implicit
|
|
1604
|
+
// preference may fall back, while an explicit session binding never does.
|
|
1560
1605
|
try {
|
|
1561
1606
|
const settings = await readStore('settings')
|
|
1562
1607
|
const raw = settings?.['active-model']
|
|
1563
|
-
|
|
1608
|
+
resolvedModel = await resolveImplicitModelPreference(raw, modelAccessContext || {})
|
|
1564
1609
|
} catch {
|
|
1565
1610
|
// ignore
|
|
1566
1611
|
}
|
|
1567
1612
|
}
|
|
1568
1613
|
if (agentProfile?.model?.mode === 'fixed') {
|
|
1569
|
-
|
|
1614
|
+
const profileBinding = await resolveAgentProfileModel(agentProfile, resolvedModel, readStore, modelAccessContext || {})
|
|
1615
|
+
resolvedModel = profileBinding.model
|
|
1616
|
+
resolvedModelRef = profileBinding.modelRef || null
|
|
1570
1617
|
resolvedAgentProfile = {
|
|
1571
1618
|
...agentProfile,
|
|
1572
1619
|
model: modelReferenceSnapshot(agentProfile.model),
|
|
1573
1620
|
}
|
|
1574
1621
|
}
|
|
1575
1622
|
if (resolvedAgentProfile && !resolvedModel) throw new Error('No active model is configured for the agent session.')
|
|
1623
|
+
const resolvedBinding = resolvedModel
|
|
1624
|
+
? (resolvedModelRef
|
|
1625
|
+
? { model: resolvedModel, modelRef: resolvedModelRef }
|
|
1626
|
+
: model
|
|
1627
|
+
? { model: resolvedModel, modelRef: null }
|
|
1628
|
+
: await modelBindingFromModel(resolvedModel))
|
|
1629
|
+
: { model: resolvedModel, modelRef: null }
|
|
1630
|
+
resolvedModel = resolvedBinding.model
|
|
1576
1631
|
const resolvedThinkingLevel = agentProfile
|
|
1577
1632
|
? resolveAgentProfileThinkingLevel(agentProfile, thinkingLevel, resolvedModel)
|
|
1578
1633
|
: thinkingLevel
|
|
@@ -1682,6 +1737,9 @@ export async function createAgent(sessionId, config = {}) {
|
|
|
1682
1737
|
accessMode,
|
|
1683
1738
|
yoloMode: resolvedYoloMode,
|
|
1684
1739
|
model: resolvedModel,
|
|
1740
|
+
modelRef: resolvedBinding.modelRef,
|
|
1741
|
+
modelAccessContext: modelAccessContext || null,
|
|
1742
|
+
resolvePersistedModel: resolvePersistedModel === true || Boolean(resolvedBinding.modelRef),
|
|
1685
1743
|
thinkingLevel: resolvedThinkingLevel,
|
|
1686
1744
|
scope,
|
|
1687
1745
|
title,
|
|
@@ -1789,14 +1847,15 @@ export async function createAgent(sessionId, config = {}) {
|
|
|
1789
1847
|
}
|
|
1790
1848
|
|
|
1791
1849
|
if (event.type === 'message_end') {
|
|
1792
|
-
const
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
//
|
|
1850
|
+
const isUserMessage = event.message?.role === 'user' || event.message?.role === 'user-with-attachments'
|
|
1851
|
+
const isInitialUserMessage = isUserMessage && session.agent.state.messages.length === 1
|
|
1852
|
+
const requiresDurableCloudMessage = isUserMessage && isManagedCloudModel(session.model) && Boolean(logicalMessageId(event.message))
|
|
1853
|
+
if (isInitialUserMessage || requiresDurableCloudMessage) {
|
|
1854
|
+
// Persist every managed Cloud user message before the provider stream starts,
|
|
1855
|
+
// so its logical ID survives a process restart and resolves to the same private key.
|
|
1797
1856
|
try {
|
|
1798
1857
|
const metadata = await flushSessionPersist(session)
|
|
1799
|
-
if (metadata) {
|
|
1858
|
+
if (metadata && isInitialUserMessage) {
|
|
1800
1859
|
if (!session.sessionCreatedEmitted) {
|
|
1801
1860
|
session.sessionCreatedEmitted = true
|
|
1802
1861
|
emitSessionEvent(session, { type: 'session_created', metadata })
|
|
@@ -1804,7 +1863,7 @@ export async function createAgent(sessionId, config = {}) {
|
|
|
1804
1863
|
scheduleSessionTitleGeneration(session, event.message)
|
|
1805
1864
|
}
|
|
1806
1865
|
} catch (err) {
|
|
1807
|
-
logger.error(`Failed to persist
|
|
1866
|
+
logger.error(`Failed to persist user message for session ${sessionId}:`, err, { sessionId })
|
|
1808
1867
|
}
|
|
1809
1868
|
} else {
|
|
1810
1869
|
// Debounced persist for crash recovery; coalesces the many message_end
|
|
@@ -1848,7 +1907,7 @@ function sessionLastModifiedFromMessages(messages, fallback) {
|
|
|
1848
1907
|
* Persist session data to storage.
|
|
1849
1908
|
*/
|
|
1850
1909
|
async function persistSessionUnlocked(session) {
|
|
1851
|
-
const { sessionId, agent, scope, projectId, source, channelId, channelName, title, titleSource, createdAt, lastModified: storedLastModified, status, startedAt, finishedAt, model, thinkingLevel, accessMode, yoloMode, contextCompaction } = session
|
|
1910
|
+
const { sessionId, agent, scope, projectId, source, channelId, channelName, title, titleSource, createdAt, lastModified: storedLastModified, status, startedAt, finishedAt, model, modelRef, thinkingLevel, accessMode, yoloMode, contextCompaction } = session
|
|
1852
1911
|
const messages = agent.state.messages
|
|
1853
1912
|
|
|
1854
1913
|
if (messages.length === 0) {
|
|
@@ -1871,6 +1930,7 @@ async function persistSessionUnlocked(session) {
|
|
|
1871
1930
|
title,
|
|
1872
1931
|
titleSource,
|
|
1873
1932
|
model,
|
|
1933
|
+
modelRef: modelRef || undefined,
|
|
1874
1934
|
thinkingLevel,
|
|
1875
1935
|
accessMode,
|
|
1876
1936
|
yoloMode,
|
|
@@ -2063,7 +2123,10 @@ export async function rollbackSessionMessages(sessionId, rollbackMessageIndex) {
|
|
|
2063
2123
|
throw Object.assign(new Error('Session not found'), { statusCode: 404 })
|
|
2064
2124
|
}
|
|
2065
2125
|
if (session.agent.state.isStreaming) {
|
|
2066
|
-
throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes before rolling back.'), {
|
|
2126
|
+
throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes before rolling back.'), {
|
|
2127
|
+
statusCode: 409,
|
|
2128
|
+
errorCode: 'GENERATION_STILL_RUNNING_BEFORE_ROLLBACK',
|
|
2129
|
+
})
|
|
2067
2130
|
}
|
|
2068
2131
|
|
|
2069
2132
|
const messages = Array.isArray(session.agent.state.messages) ? session.agent.state.messages : []
|
|
@@ -2127,18 +2190,42 @@ function scheduleSessionTitleGeneration(session, userMessage) {
|
|
|
2127
2190
|
session.titleGenerationPromiseId = generationId
|
|
2128
2191
|
}
|
|
2129
2192
|
|
|
2193
|
+
async function refreshSessionModelBinding(session) {
|
|
2194
|
+
if (!session?.model || (!session.modelRef && session.resolvePersistedModel !== true)) return session
|
|
2195
|
+
const binding = await resolveModelBinding(
|
|
2196
|
+
session.modelRef ? { modelRef: session.modelRef } : { model: session.model },
|
|
2197
|
+
{
|
|
2198
|
+
context: session.modelAccessContext || {},
|
|
2199
|
+
currentModel: session.model,
|
|
2200
|
+
allowCurrentHidden: true,
|
|
2201
|
+
forExecution: true,
|
|
2202
|
+
legacySnapshot: session.model,
|
|
2203
|
+
},
|
|
2204
|
+
)
|
|
2205
|
+
session.model = binding.model
|
|
2206
|
+
session.modelRef = binding.modelRef
|
|
2207
|
+
session.resolvePersistedModel = true
|
|
2208
|
+
session.agent.state.model = binding.model
|
|
2209
|
+
return session
|
|
2210
|
+
}
|
|
2211
|
+
|
|
2130
2212
|
/**
|
|
2131
2213
|
* Send a user message to the agent and start the agent loop.
|
|
2132
2214
|
* Returns immediately; events are streamed via the event bus.
|
|
2133
2215
|
*/
|
|
2134
|
-
export async function runPrompt(sessionId, message, selectedCapabilities = [], promptCommand = null, transientContextPrompt = null) {
|
|
2216
|
+
export async function runPrompt(sessionId, message, selectedCapabilities = [], promptCommand = null, transientContextPrompt = null, modelAccessContext = null) {
|
|
2135
2217
|
let session = await syncSessionFromStorage(sessionId)
|
|
2136
2218
|
if (!session) {
|
|
2137
2219
|
throw Object.assign(new Error('Session not found'), { statusCode: 404 })
|
|
2138
2220
|
}
|
|
2221
|
+
if (modelAccessContext) session.modelAccessContext = modelAccessContext
|
|
2222
|
+
await refreshSessionModelBinding(session)
|
|
2139
2223
|
|
|
2140
2224
|
if (session.agent.state.isStreaming || session.abortPending) {
|
|
2141
|
-
throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), {
|
|
2225
|
+
throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), {
|
|
2226
|
+
statusCode: 409,
|
|
2227
|
+
errorCode: 'GENERATION_ALREADY_RUNNING',
|
|
2228
|
+
})
|
|
2142
2229
|
}
|
|
2143
2230
|
|
|
2144
2231
|
await refreshMemoryState(session)
|
|
@@ -2149,7 +2236,7 @@ export async function runPrompt(sessionId, message, selectedCapabilities = [], p
|
|
|
2149
2236
|
? { role: 'user', content: message, timestamp: new Date().toISOString() }
|
|
2150
2237
|
: message
|
|
2151
2238
|
const commandState = await resolveCommandState(session, initialUserMessage, promptCommand)
|
|
2152
|
-
const
|
|
2239
|
+
const resolvedUserMessage = commandState.userMessage ?? initialUserMessage
|
|
2153
2240
|
|
|
2154
2241
|
if (commandState.textResponse) {
|
|
2155
2242
|
session.agent.state.messages = [
|
|
@@ -2176,6 +2263,8 @@ export async function runPrompt(sessionId, message, selectedCapabilities = [], p
|
|
|
2176
2263
|
return compactSession(session, initialUserMessage, commandState.compact)
|
|
2177
2264
|
}
|
|
2178
2265
|
|
|
2266
|
+
const userMessage = prepareCloudUserMessage(session, resolvedUserMessage)
|
|
2267
|
+
|
|
2179
2268
|
// Set a meaningful fallback immediately. The AI title request starts only
|
|
2180
2269
|
// after the first user message has been persisted by the message_end handler.
|
|
2181
2270
|
if (session.titleSource === 'default' && session.title === 'New chat') {
|
|
@@ -2221,14 +2310,19 @@ export async function runPrompt(sessionId, message, selectedCapabilities = [], p
|
|
|
2221
2310
|
* Trims messages to keep up to and including the last user message,
|
|
2222
2311
|
* removing the assistant response that follows it.
|
|
2223
2312
|
*/
|
|
2224
|
-
export async function continueSession(sessionId) {
|
|
2313
|
+
export async function continueSession(sessionId, modelAccessContext = null) {
|
|
2225
2314
|
const session = agentSessions.get(sessionId)
|
|
2226
2315
|
if (!session) {
|
|
2227
2316
|
throw Object.assign(new Error('Session not found'), { statusCode: 404 })
|
|
2228
2317
|
}
|
|
2229
2318
|
if (session.agent.state.isStreaming) {
|
|
2230
|
-
throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), {
|
|
2319
|
+
throw Object.assign(new Error('Generation is still running. Stop it or wait until it finishes.'), {
|
|
2320
|
+
statusCode: 409,
|
|
2321
|
+
errorCode: 'GENERATION_ALREADY_RUNNING',
|
|
2322
|
+
})
|
|
2231
2323
|
}
|
|
2324
|
+
if (modelAccessContext) session.modelAccessContext = modelAccessContext
|
|
2325
|
+
await refreshSessionModelBinding(session)
|
|
2232
2326
|
|
|
2233
2327
|
const messages = Array.isArray(session.agent.state.messages) ? session.agent.state.messages : []
|
|
2234
2328
|
|
|
@@ -2246,10 +2340,13 @@ export async function continueSession(sessionId) {
|
|
|
2246
2340
|
|
|
2247
2341
|
const lastUserMessage = messages[lastUserIndex]
|
|
2248
2342
|
const commandState = await resolveCommandState(session, lastUserMessage)
|
|
2249
|
-
const continuedUserMessage = commandState.userMessage ?? lastUserMessage
|
|
2343
|
+
const continuedUserMessage = prepareCloudUserMessage(session, commandState.userMessage ?? lastUserMessage)
|
|
2250
2344
|
const trimmedMessages = messages.slice(0, lastUserIndex).concat(continuedUserMessage)
|
|
2251
2345
|
updateSessionMessages(session, trimmedMessages)
|
|
2252
2346
|
resetSessionCompaction(session)
|
|
2347
|
+
if (isManagedCloudModel(session.model) && logicalMessageId(continuedUserMessage)) {
|
|
2348
|
+
await flushSessionPersist(session)
|
|
2349
|
+
}
|
|
2253
2350
|
|
|
2254
2351
|
resetIdleTimer(session)
|
|
2255
2352
|
session.activeCommandName = commandState.commandName ?? null
|
|
@@ -2334,9 +2431,9 @@ export function steerAgent(sessionId, message) {
|
|
|
2334
2431
|
throw Object.assign(new Error('Session not found'), { statusCode: 404 })
|
|
2335
2432
|
}
|
|
2336
2433
|
|
|
2337
|
-
const agentMessage = typeof message === 'string'
|
|
2434
|
+
const agentMessage = prepareCloudUserMessage(session, typeof message === 'string'
|
|
2338
2435
|
? { role: 'user', content: message, timestamp: Date.now() }
|
|
2339
|
-
: message
|
|
2436
|
+
: message)
|
|
2340
2437
|
|
|
2341
2438
|
session.agent.steer(agentMessage)
|
|
2342
2439
|
return { sessionId, steered: true }
|
|
@@ -2351,9 +2448,9 @@ export function followUpAgent(sessionId, message) {
|
|
|
2351
2448
|
throw Object.assign(new Error('Session not found'), { statusCode: 404 })
|
|
2352
2449
|
}
|
|
2353
2450
|
|
|
2354
|
-
const agentMessage = typeof message === 'string'
|
|
2451
|
+
const agentMessage = prepareCloudUserMessage(session, typeof message === 'string'
|
|
2355
2452
|
? { role: 'user', content: message, timestamp: Date.now() }
|
|
2356
|
-
: message
|
|
2453
|
+
: message)
|
|
2357
2454
|
|
|
2358
2455
|
session.agent.followUp(agentMessage)
|
|
2359
2456
|
return { sessionId, followUp: true }
|
|
@@ -2443,6 +2540,7 @@ export function getSessionState(sessionId) {
|
|
|
2443
2540
|
yoloMode: session.yoloMode,
|
|
2444
2541
|
systemPrompt: session.agent.state.systemPrompt,
|
|
2445
2542
|
model: session.model,
|
|
2543
|
+
modelRef: session.modelRef || undefined,
|
|
2446
2544
|
thinkingLevel: session.thinkingLevel,
|
|
2447
2545
|
title: session.title,
|
|
2448
2546
|
titleSource: session.titleSource,
|
|
@@ -2597,6 +2695,8 @@ export async function restoreAgent(sessionId) {
|
|
|
2597
2695
|
accessMode: normalizeAccessMode(sessionData.accessMode, sessionData.yoloMode),
|
|
2598
2696
|
yoloMode: sessionData.yoloMode || false,
|
|
2599
2697
|
model: sessionData.model,
|
|
2698
|
+
modelRef: sessionData.modelRef || null,
|
|
2699
|
+
resolvePersistedModel: true,
|
|
2600
2700
|
thinkingLevel: sessionData.thinkingLevel || 'off',
|
|
2601
2701
|
messages: sessionData.messages || [],
|
|
2602
2702
|
title: sessionData.title || 'New chat',
|
|
@@ -2752,7 +2852,7 @@ export async function updateSessionYoloMode(sessionId, yoloMode) {
|
|
|
2752
2852
|
* Does NOT force persistence — normal lifecycle events (message_end, agent_end) will persist
|
|
2753
2853
|
* the updated model.
|
|
2754
2854
|
*/
|
|
2755
|
-
export function updateSessionModel(sessionId, model) {
|
|
2855
|
+
export function updateSessionModel(sessionId, model, modelRef = null) {
|
|
2756
2856
|
const session = agentSessions.get(sessionId)
|
|
2757
2857
|
if (!session) {
|
|
2758
2858
|
throw Object.assign(new Error('Session not found'), { statusCode: 404 })
|
|
@@ -2762,9 +2862,11 @@ export function updateSessionModel(sessionId, model) {
|
|
|
2762
2862
|
}
|
|
2763
2863
|
|
|
2764
2864
|
session.model = model
|
|
2865
|
+
session.modelRef = modelRef
|
|
2866
|
+
session.resolvePersistedModel = true
|
|
2765
2867
|
session.agent.state.model = model
|
|
2766
2868
|
|
|
2767
|
-
return { sessionId, model }
|
|
2869
|
+
return { sessionId, model, modelRef: modelRef || undefined }
|
|
2768
2870
|
}
|
|
2769
2871
|
|
|
2770
2872
|
/**
|
|
@@ -6,7 +6,7 @@ import { logger } from './utils/logger.mjs'
|
|
|
6
6
|
import { firstOptionalBoolean, firstString, parseFrontmatter, splitDelimitedList } from './frontmatter.mjs'
|
|
7
7
|
import { normalizeAgentProfileThinkingLevel, normalizeCapabilityPolicy, normalizeModelReference, validateAgentProfileTools, validateModelReference } from './agent-profile-schema.mjs'
|
|
8
8
|
|
|
9
|
-
const DEFAULT_MAX_RUNTIME_MS =
|
|
9
|
+
const DEFAULT_MAX_RUNTIME_MS = 60 * 60 * 1000
|
|
10
10
|
const DEFAULT_MAX_TOOL_CALLS = 300
|
|
11
11
|
const nameRegex = /^[a-z][a-z0-9_-]{1,39}$/
|
|
12
12
|
const allowedToolNames = new Set(['read_file', 'grep_files', 'write_file', 'edit_file', 'run_command'])
|
|
@@ -66,14 +66,18 @@ function quoteFrontmatter(value) {
|
|
|
66
66
|
|
|
67
67
|
function formatModelFrontmatter(model) {
|
|
68
68
|
if (!model || model.mode !== 'fixed') return 'model:\n mode: inherit'
|
|
69
|
-
|
|
69
|
+
const result = [
|
|
70
70
|
'model:',
|
|
71
71
|
' mode: fixed',
|
|
72
|
-
`
|
|
73
|
-
`
|
|
72
|
+
model.source && model.source !== 'legacy-custom' ? ` source: ${quoteFrontmatter(model.source)}` : '',
|
|
73
|
+
model.providerId ? ` providerId: ${quoteFrontmatter(model.providerId)}` : '',
|
|
74
|
+
model.catalogId ? ` catalogId: ${quoteFrontmatter(model.catalogId)}` : '',
|
|
75
|
+
model.provider ? ` provider: ${quoteFrontmatter(model.provider)}` : '',
|
|
76
|
+
model.modelId ? ` modelId: ${quoteFrontmatter(model.modelId)}` : '',
|
|
74
77
|
model.api ? ` api: ${quoteFrontmatter(model.api)}` : '',
|
|
75
78
|
model.baseUrl ? ` baseUrl: ${quoteFrontmatter(model.baseUrl)}` : '',
|
|
76
79
|
].filter(Boolean).join('\n')
|
|
80
|
+
return result
|
|
77
81
|
}
|
|
78
82
|
|
|
79
83
|
export function userAgentProfileFilePath(name) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { resolveModelBinding } from './model-catalog.mjs'
|
|
2
|
+
|
|
1
3
|
export const AGENT_PROFILE_TOOL_NAMES = ['read_file', 'grep_files', 'write_file', 'edit_file', 'run_command']
|
|
2
4
|
export const AGENT_PROFILE_MODEL_INHERIT = { mode: 'inherit' }
|
|
3
5
|
export const AGENT_PROFILE_THINKING_LEVELS = ['inherit', 'off', 'low', 'medium', 'high', 'xhigh']
|
|
@@ -41,10 +43,6 @@ function normalizeString(value) {
|
|
|
41
43
|
return typeof value === 'string' && value.trim() ? value.trim() : undefined
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
function sameBaseUrl(a, b) {
|
|
45
|
-
return String(a || '').trim().replace(/\/$/, '') === String(b || '').trim().replace(/\/$/, '')
|
|
46
|
-
}
|
|
47
|
-
|
|
48
46
|
function readModelField(value, ...keys) {
|
|
49
47
|
if (!value || typeof value !== 'object' || Array.isArray(value)) return undefined
|
|
50
48
|
for (const key of keys) {
|
|
@@ -90,10 +88,16 @@ export function normalizeModelReference(input, metadata = {}) {
|
|
|
90
88
|
const flatModelId = normalizeString(metadata['model-id'] ?? metadata.model_id ?? metadata.modelId)
|
|
91
89
|
const flatApi = normalizeString(metadata['model-api'] ?? metadata.modelApi ?? metadata.api)
|
|
92
90
|
const flatBaseUrl = normalizeString(metadata['model-base-url'] ?? metadata.modelBaseUrl ?? metadata.baseUrl)
|
|
91
|
+
const flatSource = normalizeString(metadata['model-source'] ?? metadata.modelSource)?.toLowerCase()
|
|
92
|
+
const flatProviderId = normalizeString(metadata['model-provider-id'] ?? metadata.modelProviderId ?? metadata.providerId)
|
|
93
|
+
const flatCatalogId = normalizeString(metadata['model-catalog-id'] ?? metadata.modelCatalogId ?? metadata.catalogId)
|
|
93
94
|
|
|
94
|
-
if (flatMode === 'fixed' || flatProvider || flatModelId) {
|
|
95
|
+
if (flatMode === 'fixed' || flatSource || flatProvider || flatModelId || flatProviderId || flatCatalogId) {
|
|
95
96
|
return {
|
|
96
97
|
mode: 'fixed',
|
|
98
|
+
source: flatSource,
|
|
99
|
+
providerId: flatProviderId,
|
|
100
|
+
catalogId: flatCatalogId,
|
|
97
101
|
provider: flatProvider,
|
|
98
102
|
modelId: flatModelId,
|
|
99
103
|
api: flatApi,
|
|
@@ -123,6 +127,9 @@ export function normalizeModelReference(input, metadata = {}) {
|
|
|
123
127
|
|
|
124
128
|
return {
|
|
125
129
|
mode: 'fixed',
|
|
130
|
+
source: readModelField(modelValue, 'source'),
|
|
131
|
+
providerId: readModelField(modelValue, 'providerId', 'provider-id', 'provider_id'),
|
|
132
|
+
catalogId: readModelField(modelValue, 'catalogId', 'catalog-id', 'catalog_id', 'quickforgeCatalogId'),
|
|
126
133
|
provider: readModelField(modelValue, 'provider'),
|
|
127
134
|
modelId: readModelField(modelValue, 'modelId', 'model-id', 'model_id', 'id', 'model'),
|
|
128
135
|
api: readModelField(modelValue, 'api'),
|
|
@@ -133,9 +140,19 @@ export function normalizeModelReference(input, metadata = {}) {
|
|
|
133
140
|
export function validateModelReference(modelRef) {
|
|
134
141
|
const ref = modelRef || AGENT_PROFILE_MODEL_INHERIT
|
|
135
142
|
if (ref.mode !== 'fixed') return { ...AGENT_PROFILE_MODEL_INHERIT }
|
|
143
|
+
if (ref.source === 'cloud') {
|
|
144
|
+
const catalogId = ref.catalogId || ref.modelId
|
|
145
|
+
if (!catalogId) throw requestError('Fixed Cloud agent model requires catalogId')
|
|
146
|
+
return { mode: 'fixed', source: 'cloud', catalogId }
|
|
147
|
+
}
|
|
148
|
+
if (ref.source === 'custom') {
|
|
149
|
+
if (!ref.providerId || !ref.modelId) throw requestError('Fixed custom agent model requires providerId and modelId')
|
|
150
|
+
return { mode: 'fixed', source: 'custom', providerId: ref.providerId, modelId: ref.modelId }
|
|
151
|
+
}
|
|
136
152
|
if (!ref.provider || !ref.modelId) throw requestError('Fixed agent model requires provider and modelId')
|
|
137
153
|
return {
|
|
138
154
|
mode: 'fixed',
|
|
155
|
+
source: 'legacy-custom',
|
|
139
156
|
provider: ref.provider,
|
|
140
157
|
modelId: ref.modelId,
|
|
141
158
|
api: ref.api,
|
|
@@ -164,14 +181,17 @@ export function modelReferenceSnapshot(modelRef) {
|
|
|
164
181
|
if (ref.mode !== 'fixed') return { ...AGENT_PROFILE_MODEL_INHERIT }
|
|
165
182
|
return {
|
|
166
183
|
mode: 'fixed',
|
|
167
|
-
|
|
168
|
-
|
|
184
|
+
...(ref.source && ref.source !== 'legacy-custom' ? { source: ref.source } : {}),
|
|
185
|
+
...(ref.providerId ? { providerId: ref.providerId } : {}),
|
|
186
|
+
...(ref.catalogId ? { catalogId: ref.catalogId } : {}),
|
|
187
|
+
...(ref.provider ? { provider: ref.provider } : {}),
|
|
188
|
+
...(ref.modelId ? { modelId: ref.modelId } : {}),
|
|
169
189
|
...(ref.api ? { api: ref.api } : {}),
|
|
170
190
|
...(ref.baseUrl ? { baseUrl: ref.baseUrl } : {}),
|
|
171
191
|
}
|
|
172
192
|
}
|
|
173
193
|
|
|
174
|
-
export async function resolveAgentProfileModel(profile, parentModel,
|
|
194
|
+
export async function resolveAgentProfileModel(profile, parentModel, _readStore, context = {}) {
|
|
175
195
|
const ref = profile?.model || AGENT_PROFILE_MODEL_INHERIT
|
|
176
196
|
if (!ref || ref.mode !== 'fixed') {
|
|
177
197
|
if (!parentModel) throw requestError('No active model is configured for the parent session.')
|
|
@@ -179,19 +199,23 @@ export async function resolveAgentProfileModel(profile, parentModel, readStore)
|
|
|
179
199
|
}
|
|
180
200
|
|
|
181
201
|
const validRef = validateModelReference(ref)
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
202
|
+
const modelRef = validRef.source === 'cloud'
|
|
203
|
+
? { version: 1, source: 'cloud', catalogId: validRef.catalogId }
|
|
204
|
+
: validRef.source === 'custom'
|
|
205
|
+
? { version: 1, source: 'custom', providerId: validRef.providerId, modelId: validRef.modelId }
|
|
206
|
+
: {
|
|
207
|
+
version: 1,
|
|
208
|
+
source: 'legacy-custom',
|
|
209
|
+
provider: validRef.provider,
|
|
210
|
+
modelId: validRef.modelId,
|
|
211
|
+
...(validRef.api ? { api: validRef.api } : {}),
|
|
212
|
+
...(validRef.baseUrl ? { baseUrl: validRef.baseUrl } : {}),
|
|
213
|
+
}
|
|
214
|
+
const binding = await resolveModelBinding({ modelRef }, {
|
|
215
|
+
context,
|
|
216
|
+
currentModel: parentModel,
|
|
217
|
+
allowCurrentHidden: true,
|
|
218
|
+
forExecution: true,
|
|
219
|
+
})
|
|
220
|
+
return { model: binding.model, modelRef: binding.modelRef, info: { ...modelReferenceSnapshot(validRef), inherited: false } }
|
|
197
221
|
}
|
|
@@ -27,7 +27,7 @@ const BUILTIN_OVERRIDES_STORE = 'agent-profile-overrides'
|
|
|
27
27
|
const RESERVED_NAMES = new Set(subagentDefinitions.map((definition) => definition.name))
|
|
28
28
|
const allowedToolNames = new Set(AGENT_PROFILE_TOOL_NAMES)
|
|
29
29
|
const nameRegex = /^[a-z][a-z0-9_-]{1,39}$/
|
|
30
|
-
const DEFAULT_MAX_RUNTIME_MS =
|
|
30
|
+
const DEFAULT_MAX_RUNTIME_MS = 60 * 60 * 1000
|
|
31
31
|
const DEFAULT_MAX_TOOL_CALLS = 300
|
|
32
32
|
const MIGRATION_MARKER_FILE = path.join(userAgentsDir, '.custom-agents-migrated.json')
|
|
33
33
|
let customAgentMigrationPromise = null
|