chainlesschain 0.166.112 → 0.166.115
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/README.md +16 -6
- package/package.json +1 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/.build-hash +1 -1
- package/src/assets/web-panel/assets/{AIOps-sOceeExN.js → AIOps-BsoSoDNb.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-BQs-vRUr.js → ActionButton-Dcx7Gm5t.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-sfAHHMhA.js → Analytics-S1hsBIz3.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-0gAvE0c8.js → AppLayout-B2j067qM.js} +4 -4
- package/src/assets/web-panel/assets/{Artifacts-Dh9s2Qmd.js → Artifacts-D5iGV9ic.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-CITm26SU.js → Audit-C8ChVvXu.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BiMbBOh0.js → BackgroundAgents-Cg97AAJS.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CNpnhI3h.js → Backup-CyxU9IUg.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-BI_lltkp.js → BaseInput-CKlWjA8I.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BgfB88xY.js → Chat-C-EqZza6.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BRFiXKPX.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-4xy9rS3j.js → Checkbox-kkI13tSJ.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-D93h9ihS.js → Codegen-NlqEDwHK.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BRf3STY-.js → Col-CfepEu79.js} +1 -1
- package/src/assets/web-panel/assets/{Community-f187ziSL.js → Community-BRo0qLXM.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-D4hXWuo1.js → Compact-BMu8TP0E.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-C6cYKI6H.js → Compliance-B7Q3Moef.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-C1i1f8LD.js → Cowork-BVwt7Xmc.js} +3 -3
- package/src/assets/web-panel/assets/{Cron-BacCE4LA.js → Cron-CgBv20Qy.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DXztxOoH.js → Crosschain-CwcSBJk2.js} +1 -1
- package/src/assets/web-panel/assets/{DID-rpf4HN8x.js → DID-d20rCiIm.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-h4bgtH7L.js → Dashboard-PpZaUYpS.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CyQnoHmu.js → Dropdown-DjsLdX_Z.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-FCtp4AcB.js → EmailListRenderer-CaPkrtxn.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-JbISHTWR.js → EvolutionSettings-DDY8cQnE.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-DCIQLyfK.js → FamilyGuardDashboard-VQavMjyj.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-DDbFpwja.js → Federation-D0GvKQgI.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-CXF0jtXb.js → FormItemContext-Dl_TWHmb.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-CUaNfAM0.js → GenericCardRenderer-Bny2uagG.js} +1 -1
- package/src/assets/web-panel/assets/{Git-Bhoz2gDf.js → Git-B01KXq47.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-FiiXHe8e.js → Governance-F4c4Vwo1.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-brpTW2Q3.js → Inference-_025Q-8K.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-BCWP-f6k.js → KnowledgeGraph-DwbTmQb1.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-CxYcduoK.js → Logs-CnNo0hCm.js} +2 -2
- package/src/assets/web-panel/assets/{MarkdownRenderer-12vD1nC1.js → MarkdownRenderer-D8_iZief.js} +1 -1
- package/src/assets/web-panel/assets/{Marketplace-DANdmW7l.js → Marketplace-Dkz5bv7F.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-Bi_EKkb5.js → McpTools-CBtRwDW_.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-DecoMbYw.js → Memory-Y9jnyTb7.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DrOhFKp0.js → MobileBridge-Br1urkOz.js} +1 -1
- package/src/assets/web-panel/assets/MobileProjects-DnsyuerX.js +1 -0
- package/src/assets/web-panel/assets/{Mtc-SLPII1iw.js → Mtc-he3ZzieF.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-DWoVORYy.js → MtcAudit-BadphAuN.js} +2 -2
- package/src/assets/web-panel/assets/{Multisig-Dxpnmq-m.js → Multisig-3_pVLymK.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-kNTpNqCP.js → NLProgramming-DmtmHfsI.js} +1 -1
- package/src/assets/web-panel/assets/Notes-CE4L2O55.js +7 -0
- package/src/assets/web-panel/assets/{NotificationSettings-D3Qt8Gkl.js → NotificationSettings-B7QmfJn9.js} +1 -1
- package/src/assets/web-panel/assets/OrderTableRenderer-O0wRSyJ0.js +1 -0
- package/src/assets/web-panel/assets/{Organization-EhRl4JoJ.js → Organization-BrlMSsyT.js} +2 -2
- package/src/assets/web-panel/assets/{Overflow-BTt5C_5W.js → Overflow-CY4ULPrZ.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-CeR2jyb0.js → P2P-kIANZYKd.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BzD3OHWq.js → PdhVaultBrowser-DEgB4rvF.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-BOPyeRlz.js → Permissions-CWxywRp5.js} +3 -3
- package/src/assets/web-panel/assets/{PersonalDataHub-DcmNNsfO.js → PersonalDataHub-DAg7iCbr.js} +4 -4
- package/src/assets/web-panel/assets/{Pipeline-DuL3kwWC.js → Pipeline-Brc6ONnR.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CkQRdlSU.js → Privacy-CcinYTL8.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-moE_vQ1P.js → ProjectInit-Bz8XEsom.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-PnTWi4NQ.js → ProjectSettings-CsOMlSTZ.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-DZvbT3D7.js → Projects-BeSOM6wi.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-CkcrHYy9.js → Providers-CeunOQiH.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-nYNFGf_H.js → QrScannerModal-CN2a2_Fb.js} +1 -1
- package/src/assets/web-panel/assets/QuickAsk-CVeLif3e.js +1 -0
- package/src/assets/web-panel/assets/{Recommend-CmYN_NaS.js → Recommend-1k9WOEGM.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-BuOdNEjA.js → RemoteSession-Q8UCqIMw.js} +2 -2
- package/src/assets/web-panel/assets/{Reputation-BgkheZou.js → Reputation-CkrCgXKM.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DvA3klj1.js → Row-JFdvuTzi.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-CgkIL3PG.js → RssFeed-C74JHCmk.js} +3 -3
- package/src/assets/web-panel/assets/{Search-Cv2twJdL.js → Search-DrJiVO1T.js} +1 -1
- package/src/assets/web-panel/assets/{Security-XrD2UNU6.js → Security-BJzNlSJq.js} +3 -3
- package/src/assets/web-panel/assets/{Services-LujCntCK.js → Services-D4TLMnJm.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-ZZCOsxPX.js → Skeleton-cswTDqhh.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-BEXGkOrU.js → Skills-Bv0rM1BS.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-CIqmCgdD.js → Sla-D9rE7hNh.js} +1 -1
- package/src/assets/web-panel/assets/SpeechSettings-Bfhvin8B.js +1 -0
- package/src/assets/web-panel/assets/{SyncSettings-BVGgUs0p.js → SyncSettings-BwnMG8kq.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-C1lh68l5.js → Tasks-wJvU24cB.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-BG4zNAFx.js → Templates-CZbRU3tN.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-t2o6i5fY.js → Tenant-_jbpFJPZ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-CH8UDdVO.js → Terminal-BzNm5WKZ.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-B5sYY1IO.js → TimelineRenderer-bmybWjuS.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-D0y7QkG5.js → Tokens-o1WDcqVQ.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-BA2nKko0.js → Trigger-BB1D6sIB.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-CrFKCQIs.js → Trust-CLxdCfy2.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-B3x_-Zun.js → UkeySign-B9LS6vS0.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-TEwxbLH6.js → VideoEditing-Bg0-wxjz.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Larp5rrt.js → Wallet-Bw0G2F6P.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DfWbEIZe.js → WebAuthn-irEiNY9b.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-8LKiKExY.js → WorkflowEditor-Bh08FbJs.js} +1 -1
- package/src/assets/web-panel/assets/{chat-ByxYOvYW.js → chat-De-FPjVT.js} +1 -1
- package/src/assets/web-panel/assets/{colors-Dh4yAClh.js → colors-ygdyvinU.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-f5n2j1WZ.js → compact-item-BQ9jH9KV.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-DIprYuXL.js → createContext-BFuVSyox.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-c2I2Rn4_.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-CvYeap2I.js → hasIn-i19GtR1P.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlTwZIeX.js → index-28DjsABm.js} +1 -1
- package/src/assets/web-panel/assets/{index-CJjc8ObW.js → index-4HoFz1MA.js} +1 -1
- package/src/assets/web-panel/assets/{index-xU0eHLIH.js → index-B1IsP_JO.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bk8oWRk6.js → index-B2LieObB.js} +1 -1
- package/src/assets/web-panel/assets/{index-BlImvgb7.js → index-BBYiCI1d.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlJCDpeN.js → index-BGMxK155.js} +1 -1
- package/src/assets/web-panel/assets/{index-Du435yzt.js → index-BKblSCL9.js} +1 -1
- package/src/assets/web-panel/assets/{index-BS_dpgzu.js → index-BKlU5VZy.js} +1 -1
- package/src/assets/web-panel/assets/{index-CTqJNul4.js → index-BLMtCKAY.js} +1 -1
- package/src/assets/web-panel/assets/{index-BvyFQF8I.js → index-BPUCvc8i.js} +1 -1
- package/src/assets/web-panel/assets/{index-CzabQZ7I.js → index-BVhtukYX.js} +1 -1
- package/src/assets/web-panel/assets/{index-BsU46c7D.js → index-BaaydJcC.js} +1 -1
- package/src/assets/web-panel/assets/{index-DshB3-Up.js → index-Bhf-MuUh.js} +25 -25
- package/src/assets/web-panel/assets/{index-uDiVjYrS.js → index-Bw5pTpnI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CcvA1nae.js → index-C61w3omz.js} +1 -1
- package/src/assets/web-panel/assets/{index-7eG1J-GT.js → index-CBVcGaxk.js} +1 -1
- package/src/assets/web-panel/assets/{index-BoayvJ48.js → index-CMNjaSir.js} +1 -1
- package/src/assets/web-panel/assets/index-CTs4dYcV.js +1 -0
- package/src/assets/web-panel/assets/{index-CD0s5ESV.js → index-CWfgeaG4.js} +1 -1
- package/src/assets/web-panel/assets/{index-B0AXUhiJ.js → index-CXrk8OYO.js} +1 -1
- package/src/assets/web-panel/assets/{index-BaXSBxy-.js → index-CgoSgmjK.js} +1 -1
- package/src/assets/web-panel/assets/{index-DaZVtafQ.js → index-CpdXhhMY.js} +1 -1
- package/src/assets/web-panel/assets/{index-bt-0zMmH.js → index-Cq9k4-Ws.js} +1 -1
- package/src/assets/web-panel/assets/{index-C5aH2Pj2.js → index-DAboGZTw.js} +1 -1
- package/src/assets/web-panel/assets/{index-DGyTzElU.js → index-DL7ewjD2.js} +1 -1
- package/src/assets/web-panel/assets/{index-DI8jC7gQ.js → index-DS1IwwGL.js} +1 -1
- package/src/assets/web-panel/assets/{index-c_CxUQl3.js → index-DTY20pWu.js} +1 -1
- package/src/assets/web-panel/assets/{index-DlULGx8u.js → index-DVnFgasM.js} +1 -1
- package/src/assets/web-panel/assets/index-DeuvaW15.js +1 -0
- package/src/assets/web-panel/assets/{index-6VEWxOyC.js → index-DgjLaB7k.js} +1 -1
- package/src/assets/web-panel/assets/{index-DjvON8oh.js → index-DlwxUZQL.js} +1 -1
- package/src/assets/web-panel/assets/{index-CpR0zD38.js → index-DuuOX5u3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DUj-sL9U.js → index-IXkif6J_.js} +1 -1
- package/src/assets/web-panel/assets/{index-hwbaD3Nk.js → index-We2nK3ju.js} +1 -1
- package/src/assets/web-panel/assets/{index-CIZQtz8G.js → index-_9tUBcLm.js} +1 -1
- package/src/assets/web-panel/assets/{index-fpWv4u3Z.js → index-cDJsyAkI.js} +1 -1
- package/src/assets/web-panel/assets/{index-3ROY-lYB.js → index-l5-J0jHx.js} +1 -1
- package/src/assets/web-panel/assets/{index-C2RGykST.js → index-m8waSAyv.js} +1 -1
- package/src/assets/web-panel/assets/{index-DmcAL4hd.js → index-vXtH3o6O.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-DRuE92W6.js → initDefaultProps-B_EZHeqN.js} +1 -1
- package/src/assets/web-panel/assets/{motion-6Sgma5Vd.js → motion-BrVb_Gy1.js} +1 -1
- package/src/assets/web-panel/assets/{move-BbQsH8sb.js → move-CKxVRL_J.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BdC4INal.js → mtc-parser-C80rvQ1J.js} +1 -1
- package/src/assets/web-panel/assets/{omit-DeC5m_bi.js → omit-De5vD7BR.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-DuehpBws.js → pickAttrs-BTyEDjth.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CJEhv2ij.js → placementArrow-BWR94AjR.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-Dyw3lDGr.js → responsiveObserve-1g-Vnibk.js} +1 -1
- package/src/assets/web-panel/assets/{slide-BMaLXTbS.js → slide-Dmg6dYuF.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-c1K_SdJH.js → statusUtils-Ddj6rSab.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-CefBry8k.js → styleChecker-DyP1mPDf.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Dj2IsZpo.js → useFlexGapSupport-D3d_0YuY.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-RLfB3yqb.js → useFs-M3vq-gE2.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DbRVH_NA.js → usePersonalDataHub-GtP2TgtK.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-DTn_QVJz.js → vnode-BurE2ATQ.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DuFR0E7i.js → zoom-Ch-ViiDe.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/data/changelog.json +42 -3
- package/src/gateways/ws/llm-chat-protocol.js +124 -41
- package/src/gateways/ws/message-dispatcher.js +2 -0
- package/src/lib/evolution/evolution-deployment-config.js +15 -6
- package/src/lib/evolution/evolution-deployment-loader.js +63 -5
- package/src/lib/evolution/evolution-evidence-projector.js +48 -10
- package/src/lib/evolution/governed-model-turn.js +2 -2
- package/src/lib/evolution/local-ui-evolution-deployment.js +141 -55
- package/src/lib/evolution/local-ui-evolution-host.mjs +26 -8
- package/src/lib/evolution/local-ui-evolution-runtime.js +46 -23
- package/src/lib/evolution/opaque-hex-id.js +8 -0
- package/src/lib/read-file-loop-guard.js +2 -2
- package/src/runtime/agent-core.js +28 -19
- package/src/assets/web-panel/assets/ChatBubbleRenderer-BDP3fGoz.js +0 -1
- package/src/assets/web-panel/assets/MobileProjects-rRwP16dN.js +0 -1
- package/src/assets/web-panel/assets/Notes-D1uXCfVd.js +0 -7
- package/src/assets/web-panel/assets/OrderTableRenderer-qvaah2-m.js +0 -1
- package/src/assets/web-panel/assets/QuickAsk-53WNo7xT.js +0 -1
- package/src/assets/web-panel/assets/SpeechSettings-DkVbwJox.js +0 -1
- package/src/assets/web-panel/assets/devWarning-DRIge35Z.js +0 -1
- package/src/assets/web-panel/assets/index-Bq24rTYx.js +0 -1
- package/src/assets/web-panel/assets/index-D2f18WsK.js +0 -1
|
@@ -38,12 +38,35 @@ import {
|
|
|
38
38
|
streamOpenAI,
|
|
39
39
|
streamAnthropic,
|
|
40
40
|
streamGemini,
|
|
41
|
+
STREAM_STALL_MS,
|
|
41
42
|
} from "../../lib/chat-core.js";
|
|
42
43
|
import { BUILT_IN_PROVIDERS } from "../../lib/llm-providers.js";
|
|
43
44
|
import { resolveLlmCreds } from "./llm-creds.js";
|
|
44
45
|
import { prepareGovernedModelTurn } from "../../lib/evolution/governed-model-turn.js";
|
|
45
46
|
import { normalizeOllamaBaseUrl } from "../../lib/ollama-base-url.js";
|
|
46
47
|
import { normalizeProviderBaseUrl } from "../../lib/provider-protocol.js";
|
|
48
|
+
import { raceWithAbort } from "../../lib/abort-utils.js";
|
|
49
|
+
|
|
50
|
+
const activeChats = new WeakMap();
|
|
51
|
+
const CHAT_SETUP_TIMEOUT_MS = 60_000;
|
|
52
|
+
|
|
53
|
+
/** A request id is scoped to its originating socket, never another client. */
|
|
54
|
+
export function cancelLlmChat(ws, id) {
|
|
55
|
+
activeChats.get(ws)?.get(id)?.abort(new Error("Chat cancelled"));
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function waitForChatPhase(operation, controller, phase) {
|
|
59
|
+
const timer = setTimeout(
|
|
60
|
+
() => controller.abort(new Error(`Chat ${phase} timed out after 60s`)),
|
|
61
|
+
CHAT_SETUP_TIMEOUT_MS,
|
|
62
|
+
);
|
|
63
|
+
timer.unref?.();
|
|
64
|
+
try {
|
|
65
|
+
return await raceWithAbort(operation, controller.signal);
|
|
66
|
+
} finally {
|
|
67
|
+
clearTimeout(timer);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
47
70
|
|
|
48
71
|
function validateMessages(messages) {
|
|
49
72
|
if (!Array.isArray(messages) || messages.length === 0)
|
|
@@ -77,7 +100,17 @@ export async function handleLlmChat(server, id, ws, message) {
|
|
|
77
100
|
return;
|
|
78
101
|
}
|
|
79
102
|
|
|
80
|
-
|
|
103
|
+
let creds;
|
|
104
|
+
try {
|
|
105
|
+
creds = resolveLlmCreds(server, message);
|
|
106
|
+
} catch (error) {
|
|
107
|
+
send({
|
|
108
|
+
type: `${topic}.result`,
|
|
109
|
+
ok: false,
|
|
110
|
+
error: error?.message || String(error),
|
|
111
|
+
});
|
|
112
|
+
return;
|
|
113
|
+
}
|
|
81
114
|
if (!creds || !creds.provider) {
|
|
82
115
|
send({
|
|
83
116
|
type: `${topic}.result`,
|
|
@@ -100,6 +133,7 @@ export async function handleLlmChat(server, id, ws, message) {
|
|
|
100
133
|
|
|
101
134
|
let accumulator = "";
|
|
102
135
|
const onToken = (token) => {
|
|
136
|
+
controller.signal.throwIfAborted();
|
|
103
137
|
if (typeof token !== "string" || token.length === 0) return;
|
|
104
138
|
accumulator += token;
|
|
105
139
|
send({
|
|
@@ -114,59 +148,99 @@ export async function handleLlmChat(server, id, ws, message) {
|
|
|
114
148
|
};
|
|
115
149
|
|
|
116
150
|
const controller = new AbortController();
|
|
151
|
+
let requests = null;
|
|
152
|
+
if (ws && (typeof ws === "object" || typeof ws === "function")) {
|
|
153
|
+
requests = activeChats.get(ws);
|
|
154
|
+
if (!requests) activeChats.set(ws, (requests = new Map()));
|
|
155
|
+
if (requests.has(id)) {
|
|
156
|
+
send({
|
|
157
|
+
type: `${topic}.result`,
|
|
158
|
+
ok: false,
|
|
159
|
+
error: "Chat request is already active",
|
|
160
|
+
});
|
|
161
|
+
return;
|
|
162
|
+
}
|
|
163
|
+
requests.set(id, controller);
|
|
164
|
+
}
|
|
117
165
|
const disconnect = () =>
|
|
118
166
|
controller.abort(new Error("Chat connection closed"));
|
|
167
|
+
const onStall = (elapsedMs, timeoutMs) => {
|
|
168
|
+
if (controller.signal.aborted) return;
|
|
169
|
+
send({
|
|
170
|
+
type: `${topic}.status`,
|
|
171
|
+
status: {
|
|
172
|
+
stage: "waiting",
|
|
173
|
+
provider: creds.provider,
|
|
174
|
+
model: creds.model,
|
|
175
|
+
elapsedMs,
|
|
176
|
+
timeoutMs,
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
};
|
|
119
180
|
ws?.once?.("close", disconnect);
|
|
120
181
|
try {
|
|
121
|
-
const turn = await
|
|
122
|
-
server.evolutionCompositionFactory ?? null,
|
|
123
|
-
{
|
|
182
|
+
const turn = await waitForChatPhase(
|
|
183
|
+
prepareGovernedModelTurn(server.evolutionCompositionFactory ?? null, {
|
|
124
184
|
mode: "ws-llm-chat",
|
|
125
185
|
messages: message.messages,
|
|
126
186
|
signal: controller.signal,
|
|
127
|
-
},
|
|
187
|
+
}),
|
|
188
|
+
controller,
|
|
189
|
+
"initialization",
|
|
128
190
|
);
|
|
129
191
|
const streamOptions = {
|
|
130
192
|
requireCompletion: turn.governed,
|
|
131
193
|
signal: controller.signal,
|
|
132
194
|
};
|
|
195
|
+
// Tell the browser the configured deadline even when waiting hints are
|
|
196
|
+
// disabled, so a slow local model gets its full loading budget.
|
|
197
|
+
onStall(0, STREAM_STALL_MS);
|
|
133
198
|
const baseUrl =
|
|
134
199
|
creds.provider === "ollama"
|
|
135
200
|
? normalizeOllamaBaseUrl(creds.baseUrl)
|
|
136
201
|
: normalizeProviderBaseUrl(creds.baseUrl);
|
|
137
202
|
if (creds.provider === "ollama") {
|
|
138
|
-
await
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
203
|
+
await raceWithAbort(
|
|
204
|
+
streamOllama(
|
|
205
|
+
turn.messages,
|
|
206
|
+
creds.model,
|
|
207
|
+
baseUrl,
|
|
208
|
+
onToken,
|
|
209
|
+
onUsage,
|
|
210
|
+
onStall,
|
|
211
|
+
streamOptions,
|
|
212
|
+
),
|
|
213
|
+
controller.signal,
|
|
146
214
|
);
|
|
147
215
|
} else if (creds.provider === "anthropic") {
|
|
148
216
|
const url = baseUrl;
|
|
149
|
-
await
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
217
|
+
await raceWithAbort(
|
|
218
|
+
streamAnthropic(
|
|
219
|
+
turn.messages,
|
|
220
|
+
creds.model,
|
|
221
|
+
url,
|
|
222
|
+
creds.apiKey,
|
|
223
|
+
onToken,
|
|
224
|
+
onUsage,
|
|
225
|
+
onStall,
|
|
226
|
+
streamOptions,
|
|
227
|
+
),
|
|
228
|
+
controller.signal,
|
|
158
229
|
);
|
|
159
230
|
} else if (creds.provider === "gemini") {
|
|
160
231
|
const url = baseUrl;
|
|
161
|
-
await
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
232
|
+
await raceWithAbort(
|
|
233
|
+
streamGemini(
|
|
234
|
+
turn.messages,
|
|
235
|
+
creds.model,
|
|
236
|
+
url,
|
|
237
|
+
creds.apiKey,
|
|
238
|
+
onToken,
|
|
239
|
+
onUsage,
|
|
240
|
+
onStall,
|
|
241
|
+
streamOptions,
|
|
242
|
+
),
|
|
243
|
+
controller.signal,
|
|
170
244
|
);
|
|
171
245
|
} else {
|
|
172
246
|
// OpenAI-compatible — covers openai / volcengine / deepseek / dashscope /
|
|
@@ -174,19 +248,26 @@ export async function handleLlmChat(server, id, ws, message) {
|
|
|
174
248
|
// BUILT_IN_PROVIDERS already applied above.
|
|
175
249
|
const def = BUILT_IN_PROVIDERS[creds.provider];
|
|
176
250
|
const url = baseUrl || def?.baseUrl;
|
|
177
|
-
await
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
251
|
+
await raceWithAbort(
|
|
252
|
+
streamOpenAI(
|
|
253
|
+
turn.messages,
|
|
254
|
+
creds.model,
|
|
255
|
+
url,
|
|
256
|
+
creds.apiKey,
|
|
257
|
+
onToken,
|
|
258
|
+
onUsage,
|
|
259
|
+
onStall,
|
|
260
|
+
streamOptions,
|
|
261
|
+
),
|
|
262
|
+
controller.signal,
|
|
186
263
|
);
|
|
187
264
|
}
|
|
188
265
|
|
|
189
|
-
await
|
|
266
|
+
await waitForChatPhase(
|
|
267
|
+
turn.complete(accumulator),
|
|
268
|
+
controller,
|
|
269
|
+
"completion",
|
|
270
|
+
);
|
|
190
271
|
send({
|
|
191
272
|
type: `${topic}.result`,
|
|
192
273
|
ok: true,
|
|
@@ -205,6 +286,8 @@ export async function handleLlmChat(server, id, ws, message) {
|
|
|
205
286
|
error: err?.message || String(err),
|
|
206
287
|
});
|
|
207
288
|
} finally {
|
|
289
|
+
requests?.delete(id);
|
|
290
|
+
if (requests?.size === 0) activeChats.delete(ws);
|
|
208
291
|
ws?.removeListener?.("close", disconnect);
|
|
209
292
|
}
|
|
210
293
|
}
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
handleRemoteSessionTerminal,
|
|
31
31
|
} from "./remote-session-protocol.js";
|
|
32
32
|
import { RemoteCommandLedger } from "../../harness/remote-command-ledger.js";
|
|
33
|
+
import { cancelLlmChat } from "./llm-chat-protocol.js";
|
|
33
34
|
|
|
34
35
|
/**
|
|
35
36
|
* Reconnect-safe command execution. When a message carries a stable
|
|
@@ -293,6 +294,7 @@ export function createWsMessageDispatcher(server) {
|
|
|
293
294
|
"chat.intent.classify-followup": () =>
|
|
294
295
|
server._handleChatIntentClassifyFollowup(id, ws, message),
|
|
295
296
|
"llm.chat": () => server._handleLlmChat(id, ws, message),
|
|
297
|
+
"llm.chat.cancel": () => cancelLlmChat(ws, id),
|
|
296
298
|
};
|
|
297
299
|
|
|
298
300
|
// Static core routes take precedence and are dispatched directly. The
|
|
@@ -200,6 +200,16 @@ export async function configureEvolutionDeployment(
|
|
|
200
200
|
options,
|
|
201
201
|
);
|
|
202
202
|
updateEvolutionDeploymentProfile((current) => {
|
|
203
|
+
if (
|
|
204
|
+
options.expectedProfile &&
|
|
205
|
+
JSON.stringify(current) !== JSON.stringify(options.expectedProfile)
|
|
206
|
+
) {
|
|
207
|
+
const error = new Error(
|
|
208
|
+
"Evolution deployment profile changed during local migration",
|
|
209
|
+
);
|
|
210
|
+
error.code = "EVOLUTION_DEPLOYMENT_PROFILE_CHANGED";
|
|
211
|
+
throw error;
|
|
212
|
+
}
|
|
203
213
|
if (options.expectedProfileAbsent === true && current) {
|
|
204
214
|
const error = new Error(
|
|
205
215
|
"Evolution deployment profile was configured during local initialization",
|
|
@@ -272,12 +282,11 @@ export async function configureEvolutionDeployment(
|
|
|
272
282
|
revisionFloors,
|
|
273
283
|
activeTrustRootDigest: verified.descriptor.trustRootDigest,
|
|
274
284
|
revokedDescriptorRevisions,
|
|
275
|
-
deploymentMode:
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
: deploymentMode || "managed",
|
|
285
|
+
deploymentMode: preserveLocalMode
|
|
286
|
+
? "local"
|
|
287
|
+
: preserveTestMode
|
|
288
|
+
? "test"
|
|
289
|
+
: deploymentMode || "managed",
|
|
281
290
|
testPrivateKeyPath:
|
|
282
291
|
deploymentMode === "test"
|
|
283
292
|
? testPrivateKeyPath || null
|
|
@@ -622,7 +622,9 @@ async function loadBuiltInFactories(commandName) {
|
|
|
622
622
|
import("./evolution-eval-process-supervisor.js"),
|
|
623
623
|
import("./governed-skill-synthesis-attestor-trust-approval-client.js"),
|
|
624
624
|
import("./governed-skill-synthesis-attestor-trust-operations-client.js"),
|
|
625
|
-
import(
|
|
625
|
+
import(
|
|
626
|
+
"./governed-skill-synthesis-attestor-trust-operations-cli-host.js"
|
|
627
|
+
),
|
|
626
628
|
]);
|
|
627
629
|
factories.createEvolutionWorkbenchCliHost = createEvolutionWorkbenchCliHost;
|
|
628
630
|
factories.createEvolutionWorkbenchReviewRuntime =
|
|
@@ -1027,9 +1029,39 @@ export async function loadEvolutionDeploymentCommandDependencies(
|
|
|
1027
1029
|
importModule = (url) => import(url),
|
|
1028
1030
|
additionalFactories = {},
|
|
1029
1031
|
initializeDefaultLocalUi = false,
|
|
1032
|
+
initializeDefaultLocalModels = true,
|
|
1030
1033
|
} = {},
|
|
1031
1034
|
) {
|
|
1032
1035
|
if (!SUPPORTED_COMMANDS.has(commandName)) return null;
|
|
1036
|
+
const localModelDependencies = () =>
|
|
1037
|
+
dependencies(
|
|
1038
|
+
{
|
|
1039
|
+
evolutionCompositionFactory: async (context) => {
|
|
1040
|
+
const { initializeDefaultLocalUiEvolutionDeployment } = await import(
|
|
1041
|
+
"./local-ui-evolution-deployment.js"
|
|
1042
|
+
);
|
|
1043
|
+
await initializeDefaultLocalUiEvolutionDeployment({ env, cwd });
|
|
1044
|
+
const admitted = await loadEvolutionDeploymentCommandDependencies(
|
|
1045
|
+
commandName,
|
|
1046
|
+
{
|
|
1047
|
+
env,
|
|
1048
|
+
cwd,
|
|
1049
|
+
read,
|
|
1050
|
+
resolveRealPath,
|
|
1051
|
+
importModule,
|
|
1052
|
+
additionalFactories,
|
|
1053
|
+
initializeDefaultLocalModels: false,
|
|
1054
|
+
},
|
|
1055
|
+
);
|
|
1056
|
+
if (typeof admitted?.evolutionCompositionFactory !== "function")
|
|
1057
|
+
throw new Error(
|
|
1058
|
+
"Local model command requires an authenticated Evolution deployment",
|
|
1059
|
+
);
|
|
1060
|
+
return admitted.evolutionCompositionFactory(context);
|
|
1061
|
+
},
|
|
1062
|
+
},
|
|
1063
|
+
commandName,
|
|
1064
|
+
);
|
|
1033
1065
|
let descriptorPath = env.CHAINLESSCHAIN_EVOLUTION_DEPLOYMENT_DESCRIPTOR;
|
|
1034
1066
|
let trustRootPath = env.CHAINLESSCHAIN_EVOLUTION_DEPLOYMENT_TRUST_ROOT;
|
|
1035
1067
|
if (
|
|
@@ -1061,6 +1093,15 @@ export async function loadEvolutionDeploymentCommandDependencies(
|
|
|
1061
1093
|
"Saved evolution deployment profile is disabled",
|
|
1062
1094
|
);
|
|
1063
1095
|
}
|
|
1096
|
+
if (
|
|
1097
|
+
initializeDefaultLocalModels &&
|
|
1098
|
+
["agent", "ask", "chat"].includes(commandName) &&
|
|
1099
|
+
!saved.profile
|
|
1100
|
+
) {
|
|
1101
|
+
// Registration/help is read-only. Bootstrap only when a real command
|
|
1102
|
+
// requests its authenticated composition, then re-read current policy.
|
|
1103
|
+
return localModelDependencies();
|
|
1104
|
+
}
|
|
1064
1105
|
if (!saved.error && saved.profile?.enabled) {
|
|
1065
1106
|
descriptorPath = saved.profile.descriptorPath;
|
|
1066
1107
|
trustRootPath = saved.profile.trustRootPath;
|
|
@@ -1111,19 +1152,35 @@ export async function loadEvolutionDeploymentCommandDependencies(
|
|
|
1111
1152
|
const localProfile =
|
|
1112
1153
|
fromSavedProfile && saved.profile.deploymentMode === "local";
|
|
1113
1154
|
if (localProfile) {
|
|
1155
|
+
const generation = saved.profile.descriptorPath.endsWith(
|
|
1156
|
+
"deployment-v2.json",
|
|
1157
|
+
)
|
|
1158
|
+
? 2
|
|
1159
|
+
: 1;
|
|
1114
1160
|
const localHostPath = join(
|
|
1115
1161
|
dirname(saved.filePath),
|
|
1116
1162
|
"local-ui-host",
|
|
1117
|
-
"ui-host.mjs",
|
|
1163
|
+
generation === 2 ? "ui-host-v2.mjs" : "ui-host.mjs",
|
|
1118
1164
|
);
|
|
1119
1165
|
const canonicalLocalHostPath = await realpath(localHostPath);
|
|
1120
1166
|
if (
|
|
1121
|
-
|
|
1122
|
-
|
|
1167
|
+
!(
|
|
1168
|
+
["ui"].join(",") === descriptor.commands.join(",") ||
|
|
1169
|
+
"agent,ask,chat,ui" === descriptor.commands.join(",")
|
|
1170
|
+
) ||
|
|
1123
1171
|
verified.modulePath !== canonicalLocalHostPath
|
|
1124
1172
|
) {
|
|
1125
|
-
throw new Error(
|
|
1173
|
+
throw new Error(
|
|
1174
|
+
"Local Evolution deployment is not the protected UI host",
|
|
1175
|
+
);
|
|
1126
1176
|
}
|
|
1177
|
+
if (
|
|
1178
|
+
initializeDefaultLocalModels &&
|
|
1179
|
+
["agent", "ask", "chat", "ui"].includes(commandName) &&
|
|
1180
|
+
descriptor.commands.length === 1 &&
|
|
1181
|
+
descriptor.commands[0] === "ui"
|
|
1182
|
+
)
|
|
1183
|
+
return localModelDependencies();
|
|
1127
1184
|
}
|
|
1128
1185
|
if (!descriptor.commands.includes(commandName)) {
|
|
1129
1186
|
return deniedAgentDependencies(
|
|
@@ -1154,6 +1211,7 @@ export async function loadEvolutionDeploymentCommandDependencies(
|
|
|
1154
1211
|
createLocalUiEvolutionComposition: (options = {}) =>
|
|
1155
1212
|
createLocalUiEvolutionComposition({
|
|
1156
1213
|
...options,
|
|
1214
|
+
commandName,
|
|
1157
1215
|
localDirectory: join(dirname(saved.filePath), "local-ui-host"),
|
|
1158
1216
|
env,
|
|
1159
1217
|
cwd,
|
|
@@ -93,6 +93,8 @@ const TRUSTED_PAYLOAD_COMMITMENT_PURPOSE =
|
|
|
93
93
|
const LEGACY_LOCAL_UI_TENANT_ID_PATTERN = /^local-ui-[a-f0-9]{32}$/u;
|
|
94
94
|
const FORMATTED_LOCAL_UI_TENANT_ID_PATTERN =
|
|
95
95
|
/^local-ui-(?:[a-f0-9]{8}-){3}[a-f0-9]{8}$/u;
|
|
96
|
+
const ENCODED_LOCAL_UI_TENANT_ID_PATTERN =
|
|
97
|
+
/^local-ui-(?:[a-p]{8}-){3}[a-p]{8}$/u;
|
|
96
98
|
|
|
97
99
|
const INPUT_KEYS = new Set(["sourceEnvelope", "payload"]);
|
|
98
100
|
const SOURCE_VERIFICATION_KEYS = new Set([
|
|
@@ -877,17 +879,32 @@ function normalizeId(value, label, maximum = 256) {
|
|
|
877
879
|
return value;
|
|
878
880
|
}
|
|
879
881
|
|
|
880
|
-
function
|
|
881
|
-
|
|
882
|
+
function isLocalUiTenantId(value) {
|
|
883
|
+
return (
|
|
882
884
|
typeof value === "string" &&
|
|
883
885
|
(LEGACY_LOCAL_UI_TENANT_ID_PATTERN.test(value) ||
|
|
884
|
-
FORMATTED_LOCAL_UI_TENANT_ID_PATTERN.test(value)
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
886
|
+
FORMATTED_LOCAL_UI_TENANT_ID_PATTERN.test(value) ||
|
|
887
|
+
ENCODED_LOCAL_UI_TENANT_ID_PATTERN.test(value))
|
|
888
|
+
);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
function normalizeTenantId(value, label) {
|
|
892
|
+
if (isLocalUiTenantId(value)) return value;
|
|
888
893
|
return normalizeId(value, label);
|
|
889
894
|
}
|
|
890
895
|
|
|
896
|
+
function normalizeLocalAttestationId(value, label, tenantId, suffix) {
|
|
897
|
+
// A bound local identity is already admitted as tenant metadata. Inspect its
|
|
898
|
+
// fixed reference structure without treating its random digits as content;
|
|
899
|
+
// preserve the original signed bytes and scan every other identifier fully.
|
|
900
|
+
const scanValue =
|
|
901
|
+
isLocalUiTenantId(tenantId) && value === `local-ui-${tenantId}-${suffix}`
|
|
902
|
+
? `local-ui-local-identity-${suffix}`
|
|
903
|
+
: value;
|
|
904
|
+
normalizeId(scanValue, label);
|
|
905
|
+
return value;
|
|
906
|
+
}
|
|
907
|
+
|
|
891
908
|
function normalizeDigest(
|
|
892
909
|
value,
|
|
893
910
|
label,
|
|
@@ -946,7 +963,6 @@ function normalizeOpaqueUri(value, { label, schemes, tenantId }) {
|
|
|
946
963
|
`${label} is invalid`,
|
|
947
964
|
);
|
|
948
965
|
}
|
|
949
|
-
assertNoKnownSecrets(value);
|
|
950
966
|
if (
|
|
951
967
|
/[?#@\\%\s]/u.test(value) ||
|
|
952
968
|
hasUriControlOrWhitespace(value) ||
|
|
@@ -985,7 +1001,11 @@ function normalizeOpaqueUri(value, { label, schemes, tenantId }) {
|
|
|
985
1001
|
parsed.port ||
|
|
986
1002
|
parsed.search ||
|
|
987
1003
|
parsed.hash ||
|
|
988
|
-
parsed.hostname !== formatLocalUiTenantReferenceId(tenantId)
|
|
1004
|
+
(parsed.hostname !== formatLocalUiTenantReferenceId(tenantId) &&
|
|
1005
|
+
!(
|
|
1006
|
+
LEGACY_LOCAL_UI_TENANT_ID_PATTERN.test(tenantId) &&
|
|
1007
|
+
parsed.hostname === tenantId
|
|
1008
|
+
)) ||
|
|
989
1009
|
!decodedPath.startsWith("/") ||
|
|
990
1010
|
decodedPath
|
|
991
1011
|
.split("/")
|
|
@@ -996,6 +1016,14 @@ function normalizeOpaqueUri(value, { label, schemes, tenantId }) {
|
|
|
996
1016
|
`${label} is outside the tenant-scoped URI policy`,
|
|
997
1017
|
);
|
|
998
1018
|
}
|
|
1019
|
+
// Only the exact, bound local host is identity metadata. Keep the complete
|
|
1020
|
+
// original path in the scan, and never rewrite persisted URI/digest bytes.
|
|
1021
|
+
const localPrefix = `${scheme}://${parsed.hostname}`;
|
|
1022
|
+
const scanValue =
|
|
1023
|
+
isLocalUiTenantId(tenantId) && value.startsWith(`${localPrefix}/`)
|
|
1024
|
+
? `${scheme}://local-ui-identity${value.slice(localPrefix.length)}`
|
|
1025
|
+
: value;
|
|
1026
|
+
assertNoKnownSecrets(scanValue);
|
|
999
1027
|
return value;
|
|
1000
1028
|
}
|
|
1001
1029
|
|
|
@@ -2291,8 +2319,18 @@ function validateAttestation(value, receipt) {
|
|
|
2291
2319
|
"projection attestation is invalid or unbound",
|
|
2292
2320
|
);
|
|
2293
2321
|
}
|
|
2294
|
-
|
|
2295
|
-
|
|
2322
|
+
normalizeLocalAttestationId(
|
|
2323
|
+
value.keyId,
|
|
2324
|
+
"attestation keyId",
|
|
2325
|
+
receipt.tenantId,
|
|
2326
|
+
"attestation",
|
|
2327
|
+
);
|
|
2328
|
+
normalizeLocalAttestationId(
|
|
2329
|
+
value.issuer,
|
|
2330
|
+
"attestation issuer",
|
|
2331
|
+
receipt.tenantId,
|
|
2332
|
+
"evolution-projector",
|
|
2333
|
+
);
|
|
2296
2334
|
return deepFreeze(cloneCanonical(value));
|
|
2297
2335
|
}
|
|
2298
2336
|
|
|
@@ -2,7 +2,7 @@ import { randomUUID } from "node:crypto";
|
|
|
2
2
|
import { types } from "node:util";
|
|
3
3
|
import { captureAgentEvolutionRuntimeComposition } from "./agent-evolution-runtime-composition-brand.js";
|
|
4
4
|
import { captureAgentEvolutionIngress } from "./agent-evolution-ingress.js";
|
|
5
|
-
import {
|
|
5
|
+
import { encodeOpaqueHexId } from "./opaque-hex-id.js";
|
|
6
6
|
|
|
7
7
|
export function readEvolutionCompositionFactory(dependencies = {}) {
|
|
8
8
|
if (
|
|
@@ -44,7 +44,7 @@ export async function prepareGovernedModelTurn(
|
|
|
44
44
|
}
|
|
45
45
|
if (typeof factory !== "function")
|
|
46
46
|
throw new TypeError("Invalid evolution composition factory");
|
|
47
|
-
const runId = `${mode}-${
|
|
47
|
+
const runId = `${mode}-${encodeOpaqueHexId(
|
|
48
48
|
randomUUID().replaceAll("-", ""),
|
|
49
49
|
)}`;
|
|
50
50
|
const composition = captureAgentEvolutionRuntimeComposition(
|