chainlesschain 0.162.82 → 0.162.84
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/package.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-C1dEj8Gv.js → AIOps-CUPGM_Kx.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CzXXDnBr.js → ActionButton-Gpo_8hNk.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-hdY26dTn.js → Analytics-gUz2I_9P.js} +3 -3
- package/src/assets/web-panel/assets/{AppLayout-D6vzt_W0.js → AppLayout-8S6XH1S0.js} +3 -3
- package/src/assets/web-panel/assets/{Audit-CyavCkKh.js → Audit-DspRXpoj.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-CN26lWvD.js → Backup-CrO4UCdI.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-DuztEFOJ.js → BaseInput-BkEVF4o4.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-BtR0IxAD.js → Chat-B9EvII6G.js} +5 -5
- package/src/assets/web-panel/assets/{ChatBubbleRenderer-3Fqx4Hr2.js → ChatBubbleRenderer-BfXGm9lb.js} +1 -1
- package/src/assets/web-panel/assets/{Checkbox-DpZIx_RE.js → Checkbox-BrDQRcU4.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-CHTbeOJl.js → Codegen-CqBoplXd.js} +1 -1
- package/src/assets/web-panel/assets/{Col-BpLy4N8M.js → Col-CbQa3Dci.js} +1 -1
- package/src/assets/web-panel/assets/{Community-Bjj8jRSr.js → Community-C03LI8ue.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-JRM5b_T8.js → Compact-D_XPXg9d.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BhgyZEaK.js → Compliance-B5sBpZMO.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-DptkLSOO.js → Cowork-WnDWZ2l6.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-DnKASPO9.js → Cron-CMIJXLkp.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-DyutKwBT.js → Crosschain-DLptM6-5.js} +1 -1
- package/src/assets/web-panel/assets/{DID-26hGyWNl.js → DID-svP2FmRz.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-TR0q4qh-.js → Dashboard-CO5hKuwh.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-xvwRnUkx.js → Dropdown-CQIK5Gf6.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-FMmTGI6O.js → EmailListRenderer-CBBq-Mwz.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-BZA7U05u.js → FamilyGuardDashboard-DgcxYtqz.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-CyDZU8Vb.js → Federation-Di9NPJ6Y.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-Bwpx_qG1.js → FormItemContext-CwjF4P1N.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-BOmjGKYM.js → GenericCardRenderer-BZRv0AD7.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BnAkhaIF.js → Git-BUpxPamc.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-C47Eochw.js → Governance-D-RKals0.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-CFUir5Av.js → Inference-CEoHP1e3.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-C-rgIKPB.js → KnowledgeGraph-Bzb02Le2.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-B2ECWeOD.js → Logs-C80J5aHm.js} +2 -2
- package/src/assets/web-panel/assets/{Marketplace-Bd24otS-.js → Marketplace-CLeqc86x.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-BEh50uI4.js → McpTools-C6_3jvji.js} +5 -5
- package/src/assets/web-panel/assets/{Memory-ClE1QgWc.js → Memory-CB1VmvbL.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DMsIqebF.js → MobileBridge-PPO8M2EY.js} +2 -2
- package/src/assets/web-panel/assets/{MobileProjects-yFLjy9f4.js → MobileProjects-Bu-ul-bk.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-lnmQdmxN.js → Mtc-CY0506vU.js} +4 -4
- package/src/assets/web-panel/assets/{MtcAudit-DEdi9KlB.js → MtcAudit-BV-IqDNO.js} +6 -6
- package/src/assets/web-panel/assets/{Multisig-EMtJxjIi.js → Multisig-8YiHk7pd.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-BiUmSSO5.js → NLProgramming-DCFi8iuv.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-3lpy_K7F.js → Notes-pcK3qdfo.js} +4 -4
- package/src/assets/web-panel/assets/{NotificationSettings-DdV8KQ2W.js → NotificationSettings-DrU6Ac_p.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer-RiYZWIrY.js → OrderTableRenderer-tCu7jh7L.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-D4pXjOf7.js → Organization-r7rkShQ7.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bgiby6WK.js → Overflow-DGOBthyf.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-BHxhcSMm.js → P2P-DalC-NnK.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-BdUjqoZX.js → PdhVaultBrowser-4xxODAFn.js} +5 -5
- package/src/assets/web-panel/assets/{Permissions-DiT7TAuH.js → Permissions-C15WSlI2.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-yX_ynMWf.js → PersonalDataHub-DAGK05sL.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-DSqiTMMR.js → Pipeline-NAji3Ktw.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-CEqDwNuF.js → Privacy-CCRUEGFK.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-5QUyd1ln.js → ProjectInit-DVmQTOeF.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-CC6VlFAp.js → ProjectSettings-1NVdULNr.js} +2 -2
- package/src/assets/web-panel/assets/{Projects-CxRagMyT.js → Projects-ws0_zzCP.js} +1 -1
- package/src/assets/web-panel/assets/{Providers-MmzWjI1Z.js → Providers-Bsi5PeyG.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-BvC_QGmG.js → QuickAsk-Teh85bAz.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend--uuUiAeR.js → Recommend-CnBrDiNE.js} +1 -1
- package/src/assets/web-panel/assets/{Reputation-D4mGDQhe.js → Reputation-BRuy4vvz.js} +1 -1
- package/src/assets/web-panel/assets/{Row-DEHR17nP.js → Row-AknoXYnV.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Dhd5LlvJ.js → RssFeed-BYhR3Mr1.js} +2 -2
- package/src/assets/web-panel/assets/{Search-BKKaAsdv.js → Search-CCVNTHhz.js} +1 -1
- package/src/assets/web-panel/assets/{Security-BNEZq_5G.js → Security-DtxuRS8f.js} +3 -3
- package/src/assets/web-panel/assets/{Services-DnnD83Th.js → Services-CH9pcUuR.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-DRN2nuYV.js → Skeleton-BVCIpTSu.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CZ8v6lET.js → Skills-Bh0_27fL.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-fWXby0dV.js → Sla-Dt2ZjTIC.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-W3mT-TCc.js → SpeechSettings-3oB4vztB.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-Cf6KahGB.js → SyncSettings-3EakfvY5.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-2y3yFyI7.js → Tasks-DrkWRRuK.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-C35-32qQ.js → Templates-bJMb7OuJ.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-BmdzuATF.js → Tenant-9T-oGFha.js} +1 -1
- package/src/assets/web-panel/assets/Terminal-CPZGmFF2.js +3 -0
- package/src/assets/web-panel/assets/{TimelineRenderer-5tp0WznW.js → TimelineRenderer-C6IcefQF.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DirT8R87.js → Tokens-DRBbMZ6n.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DYnzdL_p.js → Trigger-CfBK_gR2.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-C_q6P5WI.js → Trust-Csi86O_m.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-BUeK4hfx.js → UkeySign-Dh0RMWm3.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BS_--Xsn.js → VideoEditing-CGVRp-xp.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-Bq_HZQqC.js → Wallet-ul6ZpClL.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-CY3WJ6nC.js → WebAuthn-B96-wm1H.js} +4 -4
- package/src/assets/web-panel/assets/{WorkflowEditor-DlPUi0YB.js → WorkflowEditor-CHvvdMYl.js} +1 -1
- package/src/assets/web-panel/assets/{chat-jQtA2Ab3.js → chat-CrmxJLgQ.js} +1 -1
- package/src/assets/web-panel/assets/{colors-ooTwaBud.js → colors-iw0H0UBl.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-BO5q8ejQ.js → compact-item-BoP3ciR6.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-CQEFxH8G.js → createContext-CerRGWSU.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-Cjez93XF.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-Bfh8ym7j.js → hasIn-DsatQYJx.js} +1 -1
- package/src/assets/web-panel/assets/{index-BLFFfptZ.js → index-0GW7IL2K.js} +1 -1
- package/src/assets/web-panel/assets/{index-vz2NGSmb.js → index-4IhKBZK7.js} +1 -1
- package/src/assets/web-panel/assets/{index-B_jRn2qu.js → index-7l1rmyaN.js} +1 -1
- package/src/assets/web-panel/assets/{index-ttHp-hXj.js → index-8jD5bKYd.js} +1 -1
- package/src/assets/web-panel/assets/{index-BDu0C8OQ.js → index-B19YcZYT.js} +1 -1
- package/src/assets/web-panel/assets/{index-BRAE0gub.js → index-BMbuAe5D.js} +1 -1
- package/src/assets/web-panel/assets/{index-CWHoylCz.js → index-BP_JGTE7.js} +1 -1
- package/src/assets/web-panel/assets/{index-DIdJ8ejc.js → index-BWZD_xU3.js} +1 -1
- package/src/assets/web-panel/assets/{index-DYXirELz.js → index-BXvqWNro.js} +1 -1
- package/src/assets/web-panel/assets/{index-_8VdJDx9.js → index-BbSrbGp1.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSySRvTm.js → index-BcyvEERG.js} +1 -1
- package/src/assets/web-panel/assets/{index-B4g0hyRy.js → index-BgHjBX0-.js} +1 -1
- package/src/assets/web-panel/assets/{index-D-TuIKgh.js → index-Boik4lkC.js} +1 -1
- package/src/assets/web-panel/assets/{index-wEzQ3n0H.js → index-BuhW7RGq.js} +1 -1
- package/src/assets/web-panel/assets/{index-D67wRcX7.js → index-C1GAAh9I.js} +1 -1
- package/src/assets/web-panel/assets/{index-Vq5_4yRG.js → index-C1Ve7k2T.js} +1 -1
- package/src/assets/web-panel/assets/{index-D184_rN5.js → index-C5r1VXhR.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dplghama.js → index-CDkkLejB.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpvBCXK2.js → index-CIKm0ljX.js} +1 -1
- package/src/assets/web-panel/assets/index-CN5J59xo.js +1 -0
- package/src/assets/web-panel/assets/{index-DenLVGTu.js → index-CSNbpxSb.js} +1 -1
- package/src/assets/web-panel/assets/{index-CXiTomlG.js → index-CSbZKYQE.js} +1 -1
- package/src/assets/web-panel/assets/{index-Bqd69z-n.js → index-CWjQpi8r.js} +1 -1
- package/src/assets/web-panel/assets/{index-oEHdC_uw.js → index-Cxc0hflR.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHKvkxN7.js → index-D0IzrHb1.js} +1 -1
- package/src/assets/web-panel/assets/{index-U6Qz-HCH.js → index-D97QUify.js} +1 -1
- package/src/assets/web-panel/assets/{index-B8GMkcIp.js → index-D9Sygqi9.js} +3 -3
- package/src/assets/web-panel/assets/{index-DBY9StK5.js → index-DAGrtlTV.js} +1 -1
- package/src/assets/web-panel/assets/{index-B28q3m82.js → index-DDrhbD6H.js} +1 -1
- package/src/assets/web-panel/assets/{index-kkC2JCE-.js → index-DKuaBG68.js} +1 -1
- package/src/assets/web-panel/assets/{index-D_geVHb2.js → index-Dbpu7Y9S.js} +1 -1
- package/src/assets/web-panel/assets/{index-DBfaQNOv.js → index-DnQ7-JQY.js} +1 -1
- package/src/assets/web-panel/assets/{index-wAc5u7Y-.js → index-DvQd5rvA.js} +1 -1
- package/src/assets/web-panel/assets/{index-BouXFnjK.js → index-Dx4n5tpI.js} +1 -1
- package/src/assets/web-panel/assets/{index-CnMG8pdx.js → index-KTJ86cMc.js} +1 -1
- package/src/assets/web-panel/assets/{index-iknCkh9p.js → index-QwRb8Iww.js} +1 -1
- package/src/assets/web-panel/assets/index-RnzfY85C.js +1 -0
- package/src/assets/web-panel/assets/{index-CtbbCXw9.js → index-b43zAH3v.js} +1 -1
- package/src/assets/web-panel/assets/{index-0InkUerO.js → index-ykZB3IUq.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-C0lDjMFG.js → initDefaultProps-C_C9YePV.js} +1 -1
- package/src/assets/web-panel/assets/{motion-CKqarhmp.js → motion-DsRTNcag.js} +1 -1
- package/src/assets/web-panel/assets/{move-DU_4DXfe.js → move-CNQpgGaU.js} +1 -1
- package/src/assets/web-panel/assets/{omit-C486jH10.js → omit-B_C8ne12.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-Sivz4zN9.js → pickAttrs-D95no1kz.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-Ca2RquTa.js → placementArrow-CqoJQLBC.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-BvwPauMH.js → responsiveObserve-BvxPjVzY.js} +1 -1
- package/src/assets/web-panel/assets/{slide-B9onHJLI.js → slide-C1PZ8gjQ.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-b_AgBw9w.js → statusUtils-CXlmu_Qa.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-EtdQYqac.js → styleChecker-Yeh5dWMi.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-Cp_Cx5AB.js → useFlexGapSupport-BA1uUeeV.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Dwp7AWMH.js → useFs-TCL7sk7I.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-BjHr52Az.js → usePersonalDataHub-DD0yPkw9.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-CJkJ5hJu.js → vnode-Cxw9uvFj.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-DJEBPq5j.js → zoom-DPRJdorO.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/lib/image-input.js +90 -0
- package/src/repl/agent-repl.js +50 -5
- package/src/runtime/headless-stream.js +18 -2
- package/src/assets/web-panel/assets/Terminal-B6R_Mv2d.js +0 -3
- package/src/assets/web-panel/assets/devWarning-cfHzirPw.js +0 -1
- package/src/assets/web-panel/assets/index-CWB8kLmE.js +0 -1
- package/src/assets/web-panel/assets/index-DtaI9LEB.js +0 -1
package/src/lib/image-input.js
CHANGED
|
@@ -44,6 +44,96 @@ export function resolveImages(paths, deps = {}) {
|
|
|
44
44
|
});
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
+
/**
|
|
48
|
+
* Claude-Code-style auto-detection: find local image-file paths mentioned in a
|
|
49
|
+
* prompt so the turn can attach them as vision input. A token is treated as an
|
|
50
|
+
* image only when (a) its extension is one we support and (b) the file actually
|
|
51
|
+
* exists on disk — so prose like "I edited a.png" attaches only when a.png is
|
|
52
|
+
* really there, and a typo'd/remote path stays as plain text. Matched path
|
|
53
|
+
* tokens are stripped from the returned text ("describe ./a.png" → "describe" +
|
|
54
|
+
* an attachment); an all-path message leaves empty text, which the caller turns
|
|
55
|
+
* into an image-only turn. URLs / data: URIs are never auto-attached (local
|
|
56
|
+
* files only). Pure except for the existence check (inject `deps.existsSync`).
|
|
57
|
+
*
|
|
58
|
+
* @param {string} text
|
|
59
|
+
* @param {object} deps { existsSync }
|
|
60
|
+
* @returns {{ images: string[], text: string }}
|
|
61
|
+
*/
|
|
62
|
+
export function detectImagePaths(text, deps = {}) {
|
|
63
|
+
const existsSync = deps.existsSync || fs.existsSync;
|
|
64
|
+
if (typeof text !== "string" || !text.trim()) {
|
|
65
|
+
return { images: [], text: typeof text === "string" ? text : "" };
|
|
66
|
+
}
|
|
67
|
+
const exts = Object.keys(EXT_MEDIA)
|
|
68
|
+
.map((e) => e.slice(1))
|
|
69
|
+
.join("|"); // png|jpg|jpeg|gif|webp
|
|
70
|
+
// Quoted ("…"/'…') paths first (may contain spaces), then bare
|
|
71
|
+
// whitespace-delimited tokens ending in a supported image extension.
|
|
72
|
+
const re = new RegExp(
|
|
73
|
+
`"([^"]+?\\.(?:${exts}))"|'([^']+?\\.(?:${exts}))'|(\\S+?\\.(?:${exts}))(?=$|[\\s)\\]'",])`,
|
|
74
|
+
"gi",
|
|
75
|
+
);
|
|
76
|
+
const images = [];
|
|
77
|
+
const seen = new Set();
|
|
78
|
+
const ranges = [];
|
|
79
|
+
let m;
|
|
80
|
+
while ((m = re.exec(text)) !== null) {
|
|
81
|
+
const raw = m[1] || m[2] || m[3];
|
|
82
|
+
if (!raw) continue;
|
|
83
|
+
// Local files only — never auto-attach URLs / data: URIs.
|
|
84
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(raw) || /^data:/i.test(raw)) continue;
|
|
85
|
+
let exists = false;
|
|
86
|
+
try {
|
|
87
|
+
exists = existsSync(raw);
|
|
88
|
+
} catch {
|
|
89
|
+
exists = false;
|
|
90
|
+
}
|
|
91
|
+
if (!exists) continue;
|
|
92
|
+
if (!seen.has(raw)) {
|
|
93
|
+
seen.add(raw);
|
|
94
|
+
images.push(raw);
|
|
95
|
+
}
|
|
96
|
+
ranges.push([m.index, m.index + m[0].length]);
|
|
97
|
+
}
|
|
98
|
+
if (!images.length) return { images: [], text };
|
|
99
|
+
let out = text;
|
|
100
|
+
for (let i = ranges.length - 1; i >= 0; i--) {
|
|
101
|
+
out = out.slice(0, ranges[i][0]) + out.slice(ranges[i][1]);
|
|
102
|
+
}
|
|
103
|
+
out = out.replace(/ {2,}/g, " ").trim();
|
|
104
|
+
return { images, text: out };
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Compose a REPL/interactive turn from raw typed text: auto-detect local image
|
|
109
|
+
* paths, build the user-message content, and (on an image turn) the per-turn
|
|
110
|
+
* vision-LLM override. Pure orchestration over detectImagePaths/resolveImages/
|
|
111
|
+
* buildUserContent/resolveVisionLlm so the interactive wiring is unit-testable
|
|
112
|
+
* (the REPL itself forces a terminal and can't be driven headlessly).
|
|
113
|
+
*
|
|
114
|
+
* @param {string} text the user's typed message
|
|
115
|
+
* @param {object} llm { provider, baseUrl, apiKey, visionModel } current LLM
|
|
116
|
+
* @param {object} deps { existsSync, fs } injected for tests
|
|
117
|
+
* @returns {{ content, images: string[], visionLlm: object|null, text: string }}
|
|
118
|
+
* content is a plain string when no image is detected, else a multimodal
|
|
119
|
+
* array; visionLlm is the per-turn provider/model/baseUrl/apiKey override
|
|
120
|
+
* (null when there are no images); text is the path-stripped prompt.
|
|
121
|
+
*/
|
|
122
|
+
export function prepareVisionTurn(text, llm = {}, deps = {}) {
|
|
123
|
+
const detected = detectImagePaths(text, deps);
|
|
124
|
+
if (!detected.images.length) {
|
|
125
|
+
return { content: text, images: [], visionLlm: null, text };
|
|
126
|
+
}
|
|
127
|
+
const finalText = detected.text || "Please look at the attached image(s).";
|
|
128
|
+
const resolved = resolveImages(detected.images, deps); // throws on bad ext
|
|
129
|
+
return {
|
|
130
|
+
content: buildUserContent(finalText, resolved),
|
|
131
|
+
images: detected.images,
|
|
132
|
+
visionLlm: resolveVisionLlm({ hasImage: true, flags: {}, llm }),
|
|
133
|
+
text: finalText,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
47
137
|
/**
|
|
48
138
|
* Build a user-message `content`: the plain string when there are no images,
|
|
49
139
|
* else an OpenAI-style multimodal array (the internal representation).
|
package/src/repl/agent-repl.js
CHANGED
|
@@ -81,6 +81,7 @@ import {
|
|
|
81
81
|
} from "../runtime/agent-core.js";
|
|
82
82
|
import { formatBackgroundTasks } from "./tasks-status.js";
|
|
83
83
|
import { expandFileRefsAsync } from "../runtime/file-ref-expander.js";
|
|
84
|
+
import { prepareVisionTurn } from "../lib/image-input.js";
|
|
84
85
|
import { composeSystemPrompt } from "../runtime/system-prompt.js";
|
|
85
86
|
import {
|
|
86
87
|
makeFallbackChatFn,
|
|
@@ -279,6 +280,16 @@ export async function startAgentRepl(options = {}) {
|
|
|
279
280
|
let _sessionTier = "strict";
|
|
280
281
|
const baseUrl = options.baseUrl || "http://localhost:11434";
|
|
281
282
|
const apiKey = options.apiKey || null;
|
|
283
|
+
// Configured vision model (config.llm.visionModel) — used when a turn carries
|
|
284
|
+
// an auto-detected image path so the REPL switches to a vision-capable model
|
|
285
|
+
// for that turn only (resolveVisionLlm falls back to the default when unset).
|
|
286
|
+
let _visionModel;
|
|
287
|
+
try {
|
|
288
|
+
const { loadConfig } = await import("../lib/config-manager.js");
|
|
289
|
+
_visionModel = loadConfig()?.llm?.visionModel || undefined;
|
|
290
|
+
} catch {
|
|
291
|
+
/* optional — resolveVisionLlm falls back to DEFAULT_VISION_MODEL */
|
|
292
|
+
}
|
|
282
293
|
// Extra workspace roots (--add-dir): advertised in the system prompt and
|
|
283
294
|
// spanned by search_files.
|
|
284
295
|
const additionalDirectories = Array.isArray(options.additionalDirectories)
|
|
@@ -3075,8 +3086,40 @@ export async function startAgentRepl(options = {}) {
|
|
|
3075
3086
|
// optional polish — never fail the turn over it
|
|
3076
3087
|
}
|
|
3077
3088
|
|
|
3089
|
+
// Claude-Code-style: auto-attach local image paths typed in the message so
|
|
3090
|
+
// "describe ./shot.png" reads the image via the vision model (same as the
|
|
3091
|
+
// chat panels). CC_AUTO_IMAGE=0 opts out. `_visionLlm` (truthy on an image
|
|
3092
|
+
// turn) overrides this turn's provider/model/baseUrl/apiKey below. The
|
|
3093
|
+
// composition is the unit-tested `prepareVisionTurn` helper.
|
|
3094
|
+
let _visionLlm = null;
|
|
3095
|
+
let _userMessageContent = userContent;
|
|
3096
|
+
if (process.env.CC_AUTO_IMAGE !== "0") {
|
|
3097
|
+
try {
|
|
3098
|
+
const turn = prepareVisionTurn(userContent, {
|
|
3099
|
+
provider,
|
|
3100
|
+
baseUrl,
|
|
3101
|
+
apiKey,
|
|
3102
|
+
visionModel: _visionModel,
|
|
3103
|
+
});
|
|
3104
|
+
if (turn.visionLlm) {
|
|
3105
|
+
_userMessageContent = turn.content;
|
|
3106
|
+
_visionLlm = turn.visionLlm;
|
|
3107
|
+
logger.info(
|
|
3108
|
+
chalk.gray(
|
|
3109
|
+
`[image] ${turn.images.length} attached → vision model ${turn.visionLlm.model}`,
|
|
3110
|
+
),
|
|
3111
|
+
);
|
|
3112
|
+
}
|
|
3113
|
+
} catch (e) {
|
|
3114
|
+
// Bad attachment (e.g. unreadable file) → send as plain text.
|
|
3115
|
+
_visionLlm = null;
|
|
3116
|
+
_userMessageContent = userContent;
|
|
3117
|
+
logger.info(chalk.yellow(`[image] ${e.message} — sending as text`));
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
|
|
3078
3121
|
// Add user message
|
|
3079
|
-
messages.push({ role: "user", content:
|
|
3122
|
+
messages.push({ role: "user", content: _userMessageContent });
|
|
3080
3123
|
|
|
3081
3124
|
// Slot-filling: detect intent and fill missing parameters interactively
|
|
3082
3125
|
try {
|
|
@@ -3202,12 +3245,14 @@ export async function startAgentRepl(options = {}) {
|
|
|
3202
3245
|
),
|
|
3203
3246
|
),
|
|
3204
3247
|
signal: _turnAbort.signal,
|
|
3205
|
-
|
|
3206
|
-
model
|
|
3248
|
+
// On an auto-detected image turn, switch to the vision LLM for this
|
|
3249
|
+
// turn only (provider/baseUrl/apiKey unchanged, model → vision model).
|
|
3250
|
+
provider: _visionLlm ? _visionLlm.provider : provider,
|
|
3251
|
+
model: _visionLlm ? _visionLlm.model : activeModel,
|
|
3207
3252
|
thinking,
|
|
3208
3253
|
thinkingBudget,
|
|
3209
|
-
baseUrl,
|
|
3210
|
-
apiKey,
|
|
3254
|
+
baseUrl: _visionLlm ? _visionLlm.baseUrl : baseUrl,
|
|
3255
|
+
apiKey: _visionLlm ? _visionLlm.apiKey : apiKey,
|
|
3211
3256
|
contextEngine,
|
|
3212
3257
|
iterationBudget,
|
|
3213
3258
|
sessionId,
|
|
@@ -20,6 +20,7 @@ import { bootstrap } from "./bootstrap.js";
|
|
|
20
20
|
import { buildSystemPrompt, agentLoop as coreAgentLoop } from "./agent-core.js";
|
|
21
21
|
import { composeSystemPrompt } from "./system-prompt.js";
|
|
22
22
|
import { expandFileRefsAsync } from "./file-ref-expander.js";
|
|
23
|
+
import { detectImagePaths } from "../lib/image-input.js";
|
|
23
24
|
import {
|
|
24
25
|
resolveAgentMcp,
|
|
25
26
|
resolvePermissionPromptTool,
|
|
@@ -113,9 +114,24 @@ export function parseInputEvent(line) {
|
|
|
113
114
|
// the same image-input pipeline as `cc agent --image`.
|
|
114
115
|
const rawImages =
|
|
115
116
|
obj && typeof obj === "object" ? obj.images || msg.images : null;
|
|
116
|
-
|
|
117
|
-
? rawImages.filter((p) => typeof p === "string" && p.trim())
|
|
117
|
+
let images = Array.isArray(rawImages)
|
|
118
|
+
? rawImages.filter((p) => typeof p === "string" && p.trim())
|
|
118
119
|
: [];
|
|
120
|
+
// Claude-Code-style: auto-attach local image-file paths the user typed into
|
|
121
|
+
// the message (so "describe ./shot.png" reads the image, like Claude Code).
|
|
122
|
+
// Opt out with CC_AUTO_IMAGE=0. Explicit `images` (paste) still win.
|
|
123
|
+
if (
|
|
124
|
+
typeof content === "string" &&
|
|
125
|
+
content.trim() &&
|
|
126
|
+
process.env.CC_AUTO_IMAGE !== "0"
|
|
127
|
+
) {
|
|
128
|
+
const detected = detectImagePaths(content);
|
|
129
|
+
if (detected.images.length) {
|
|
130
|
+
images = [...images, ...detected.images];
|
|
131
|
+
content = detected.text;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
images = [...new Set(images)].slice(0, 8);
|
|
119
135
|
if (typeof content !== "string" || !content.trim()) {
|
|
120
136
|
// An image-only turn is valid — give the model something to act on.
|
|
121
137
|
if (images.length)
|
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["./xterm-BZcWGsqw.js","./markdown-CsiA8-E5.js","./markdown-Dfs9RUU9.css","./addon-fit-CK6X9sAG.js","./xterm-DFuMZ0ql.css"])))=>i.map(i=>d[i]);
|
|
2
|
-
import{u as fe,_ as me,d as U,e as V}from"./index-B8GMkcIp.js";import{I as z,J as x,U as _,Q as q,S as K,K as T,V as R,c as A,F as Q,Z as Y,R as E,o as Z,f as G,w as $,n as D,b as ee,r as S,P as y,_ as ve,a2 as we,a3 as he,a4 as _e}from"./vendor-BvqAck49.js";import{R as ye,b as pe,as as ge}from"./icons-DP3uiYxy.js";const k=new Map,C=new Map,I=new Set,N=new Set;let te=!1;function xe(c){te||(te=!0,c.onMessage(o=>{if(!(!o||typeof o.type!="string")){if(o.type==="terminal.stdout"){const{sessionId:s,data:e,seq:i}=o.payload||{};if(!s)return;let w;try{const d=atob(e||""),f=new Uint8Array(d.length);for(let n=0;n<d.length;n++)f[n]=d.charCodeAt(n);w=new TextDecoder("utf-8").decode(f)}catch{w=""}const u={sessionId:s,data:w,seq:i};k.get(s)?.forEach(d=>d(u)),I.forEach(d=>d(u))}else if(o.type==="terminal.exit"){const{sessionId:s,exitCode:e,signal:i}=o.payload||{};if(!s)return;const w={sessionId:s,exitCode:e,signal:i};C.get(s)?.forEach(u=>u(w)),N.forEach(u=>u(w))}}}))}function ne(c){const o=new TextEncoder().encode(c);let s="";for(let e=0;e<o.length;e++)s+=String.fromCharCode(o[e]);return btoa(s)}function ae(c){const o=atob(c||""),s=new Uint8Array(o.length);for(let e=0;e<o.length;e++)s[e]=o.charCodeAt(e);return new TextDecoder("utf-8").decode(s)}function oe(){const c=fe();xe(c);async function o(n={}){const a=await c.sendRaw({type:"terminal.create",payload:{shell:n.shell,cwd:n.cwd,env:n.env,cols:n.cols,rows:n.rows}});if(a.ok===!1)throw new Error(a.error||"terminal_create_failed");return a.result??a}async function s(){const n=await c.sendRaw({type:"terminal.list",payload:{}});if(n.ok===!1)throw new Error(n.error||"terminal_list_failed");const a=n.result??n;return Array.isArray(a.sessions)?a.sessions:[]}async function e(n,a){const r=await c.sendRaw({type:"terminal.stdin",payload:{sessionId:n,data:ne(String(a))}});if(r.ok===!1)throw new Error(r.error||"terminal_stdin_failed");return r.result??r}async function i(n,a,r){const h=await c.sendRaw({type:"terminal.resize",payload:{sessionId:n,cols:a,rows:r}});if(h.ok===!1)throw new Error(h.error||"terminal_resize_failed");return h.result??h}async function w(n){const a=await c.sendRaw({type:"terminal.close",payload:{sessionId:n}});if(a.ok===!1)throw new Error(a.error||"terminal_close_failed");return a.result??a}async function u(n,a=0){const r=await c.sendRaw({type:"terminal.history",payload:{sessionId:n,fromSeq:a}});if(r.ok===!1)throw new Error(r.error||"terminal_history_failed");const h=r.result??r;return{truncated:!!h.truncated,chunks:(h.chunks||[]).map(L=>({seq:L.seq,data:ae(L.data)}))}}function d(n,a){return n?(k.has(n)||k.set(n,new Set),k.get(n).add(a),()=>{k.get(n)?.delete(a),k.get(n)?.size===0&&k.delete(n)}):(I.add(a),()=>I.delete(a))}function f(n,a){return n?(C.has(n)||C.set(n,new Set),C.get(n).add(a),()=>{C.get(n)?.delete(a),C.get(n)?.size===0&&C.delete(n)}):(N.add(a),()=>N.delete(a))}return{create:o,list:s,stdin:e,resize:i,close:w,history:u,onStdout:d,onExit:f,_internal:{stdoutSubs:k,exitSubs:C,toBase64Utf8:ne,fromBase64Utf8:ae}}}const Se={__name:"Terminal",setup(c,{expose:o}){o();const s=oe(),e=S([]),i=S(null),w=S("pwsh"),u=S(!1),d=S(!1),f=S(""),n=S(""),a=S([]),r=[{value:"pwsh",label:"PowerShell"},{value:"cmd",label:"CMD"},{value:"bash",label:"Bash"},{value:"wsl",label:"WSL"}],h=ee(()=>e.value.find(t=>t.id===i.value));function L(t){return t?t.slice(0,8):""}let O=null,M=null;async function F(){if(O)return{xtermMod:O,fitAddonMod:M};try{O=await V(()=>import("./xterm-BZcWGsqw.js").then(t=>t.x),__vite__mapDeps([0,1,2]),import.meta.url),M=await V(()=>import("./addon-fit-CK6X9sAG.js").then(t=>t.a),__vite__mapDeps([3,1,2]),import.meta.url),await V(()=>Promise.resolve({}),__vite__mapDeps([4]),import.meta.url)}catch(t){throw n.value="xterm 资源加载失败:"+(t?.message||"未知错误"),t}return{xtermMod:O,fitAddonMod:M}}async function B(t){await D();const{xtermMod:l,fitAddonMod:p}=await F(),b=a.value.find(v=>v?.dataset?.sessionId===t.id);if(!b)return;const m=new l.Terminal({cursorBlink:!0,fontFamily:'Consolas, "Courier New", monospace',fontSize:13,theme:{background:"#1e1e1e",foreground:"#d4d4d4"},convertEol:!1}),P=new p.FitAddon;m.loadAddon(P),m.open(b);try{P.fit()}catch{}t.xterm=m,t.fitAddon=P;const ie=m.onData(v=>{s.stdin(t.id,v).catch(g=>{String(g?.message||"").includes("dangerous_keyword_blocked")?U.warning("该命令被桌面端拦截(高危关键字)"):U.error("stdin 失败: "+(g?.message||g))})}),ce=s.onStdout(t.id,({data:v,seq:g})=>{t.lastSeq=g,m.write(v)}),de=s.onExit(t.id,({exitCode:v,signal:g})=>{t.alive=!1,t.exitCode=v,t.signal=g,m.writeln(`\r
|
|
3
|
-
\x1B[33m[session exited, code=${v}, signal=${g??"-"}]\x1B[0m`)});t.offs=()=>{try{ie.dispose?.()}catch{}ce(),de()};try{const{chunks:v,truncated:g}=await s.history(t.id,0);g&&m.writeln("\x1B[2m[history truncated — earlier output was evicted]\x1B[0m");for(const J of v)m.write(J.data),t.lastSeq=J.seq}catch(v){m.writeln(`\x1B[31m[history fetch failed: ${v?.message||v}]\x1B[0m`)}const H=new ResizeObserver(()=>{try{P.fit(),s.resize(t.id,m.cols,m.rows).catch(()=>{})}catch{}});H.observe(b);const ue=t.offs;t.offs=()=>{try{H.disconnect()}catch{}ue()}}async function re(){u.value=!0,f.value="";try{const t=await s.create({shell:w.value,cols:80,rows:24}),l={id:t.sessionId,shell:t.shell,cwd:"",alive:!0,lastSeq:0,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(l),i.value=l.id,await B(l)}catch(t){f.value=t?.message||String(t)}finally{u.value=!1}}async function se(t){try{await s.close(t)}catch(l){f.value=l?.message||String(l)}setTimeout(()=>W(t),500)}function W(t){const l=e.value.findIndex(b=>b.id===t);if(l===-1)return;const p=e.value[l];try{p.offs?.()}catch{}try{p.xterm?.dispose?.()}catch{}e.value.splice(l,1),i.value===t&&(i.value=e.value[0]?.id||null)}function le(t){i.value=t,D(()=>{const l=e.value.find(p=>p.id===t);try{l?.fitAddon?.fit()}catch{}})}async function X(){d.value=!0,f.value="";try{const t=await s.list();for(const l of t){const p=e.value.find(m=>m.id===l.id);if(p){p.alive=l.alive,p.lastSeq=l.lastSeq;continue}const b={id:l.id,shell:l.shell,cwd:l.cwd,alive:l.alive,lastSeq:l.lastSeq,exitCode:null,xterm:null,fitAddon:null,offs:()=>{}};e.value.push(b),await B(b)}!i.value&&e.value.length>0&&(i.value=e.value[0].id)}catch(t){f.value=t?.message||String(t)}finally{d.value=!1}}Z(async()=>{await X()}),G(()=>{for(const t of e.value){try{t.offs?.()}catch{}try{t.xterm?.dispose?.()}catch{}}}),$(i,()=>{D(()=>{const t=h.value;try{t?.fitAddon?.fit()}catch{}})});const j={term:s,sessions:e,activeId:i,newShell:w,creating:u,loadingList:d,error:f,warning:n,xtermContainers:a,shellOptions:r,active:h,shortId:L,get xtermMod(){return O},set xtermMod(t){O=t},get fitAddonMod(){return M},set fitAddonMod(t){M=t},loadXterm:F,mountXterm:B,onCreate:re,onClose:se,removeSession:W,activate:le,refreshList:X,ref:S,computed:ee,onMounted:Z,onBeforeUnmount:G,nextTick:D,watch:$,get message(){return U},get PlusOutlined(){return ge},get CloseOutlined(){return pe},get ReloadOutlined(){return ye},get useTerminal(){return oe}};return Object.defineProperty(j,"__isScriptSetup",{enumerable:!1,value:!0}),j}},be={class:"terminal-page"},ke={class:"terminal-header"},Ce={class:"page-sub"},Ae={class:"terminal-body"},Ee={class:"session-tabs"},Oe=["onClick"],Te={class:"session-shell"},Re={class:"session-id"},Me={key:0,class:"session-empty"},ze={class:"xterm-host"},Le=["data-session-id"],Pe={key:0,class:"xterm-placeholder"},qe={key:1,class:"terminal-footer"},De={key:0,class:"footer-exit"};function Be(c,o,s,e,i,w){const u=z("a-tag"),d=z("a-select"),f=z("a-button"),n=z("a-space"),a=z("a-alert");return y(),x("div",be,[_("div",ke,[_("div",null,[o[3]||(o[3]=_("h2",{class:"page-title"},"远程终端",-1)),_("p",Ce,[o[2]||(o[2]=q(" 桌面端托管的 PTY 会话;Android 端可远程操控同一通道 ",-1)),e.warning?(y(),K(u,{key:0,color:"orange",style:{"margin-left":"8px"}},{default:T(()=>[q(E(e.warning),1)]),_:1})):R("v-if",!0)])]),A(n,null,{default:T(()=>[A(d,{value:e.newShell,"onUpdate:value":o[0]||(o[0]=r=>e.newShell=r),style:{width:"130px"},size:"small",options:e.shellOptions},null,8,["value"]),A(f,{type:"primary",size:"small",loading:e.creating,onClick:e.onCreate},{icon:T(()=>[A(e.PlusOutlined)]),default:T(()=>[o[4]||(o[4]=q(" 新会话 ",-1))]),_:1},8,["loading"]),A(f,{size:"small",loading:e.loadingList,onClick:e.refreshList},{icon:T(()=>[A(e.ReloadOutlined)]),default:T(()=>[o[5]||(o[5]=q(" 刷新 ",-1))]),_:1},8,["loading"])]),_:1})]),e.error?(y(),K(a,{key:0,message:e.error,type:"error","show-icon":"",closable:"",style:{"margin-bottom":"12px"},onClose:o[1]||(o[1]=r=>e.error="")},null,8,["message"])):R("v-if",!0),_("div",Ae,[_("div",Ee,[(y(!0),x(Q,null,Y(e.sessions,r=>(y(),x("div",{key:r.id,class:ve(["session-tab",{active:r.id===e.activeId,dead:!r.alive}]),onClick:h=>e.activate(r.id)},[_("span",Te,E(r.shell),1),_("span",Re,E(e.shortId(r.id)),1),A(e.CloseOutlined,{class:"session-close",onClick:we(h=>e.onClose(r.id),["stop"])},null,8,["onClick"])],10,Oe))),128)),e.sessions.length===0?(y(),x("div",Me,' 点击 "新会话" 创建第一个终端 ')):R("v-if",!0)]),_("div",ze,[(y(!0),x(Q,null,Y(e.sessions,r=>he((y(),x("div",{key:r.id,ref_for:!0,ref:"xtermContainers","data-session-id":r.id,class:"xterm-container"},null,8,Le)),[[_e,r.id===e.activeId]])),128)),e.sessions.length===0?(y(),x("div",Pe,[...o[6]||(o[6]=[_("span",null,"无活跃会话",-1)])])):R("v-if",!0)])]),e.active?(y(),x("div",qe,[_("span",null,E(e.active.shell)+" · "+E(e.active.cwd||"(默认 cwd)")+" · seq "+E(e.active.lastSeq),1),e.active.alive?R("v-if",!0):(y(),x("span",De,"已退出 (code="+E(e.active.exitCode??"-")+")",1))])):R("v-if",!0)])}const Ne=me(Se,[["render",Be],["__scopeId","data-v-65366a29"],["__file","/tmp/cc-web-panel-dUwIHq/repo/packages/web-panel/src/views/Terminal.vue"]]);export{Ne as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{O as r}from"./index-B8GMkcIp.js";const o=((n,a,e)=>{r(n,`[ant-design-vue: ${a}] ${e}`)});export{o as d};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as o}from"./Row-DEHR17nP.js";import{U as t}from"./index-B8GMkcIp.js";import"./vendor-BvqAck49.js";import"./responsiveObserve-BvwPauMH.js";import"./useFlexGapSupport-Cp_Cx5AB.js";import"./styleChecker-EtdQYqac.js";import"./index-DBfaQNOv.js";import"./icons-DP3uiYxy.js";const l=t(o);export{l as default};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{C as o}from"./Col-BpLy4N8M.js";import{U as t}from"./index-B8GMkcIp.js";import"./vendor-BvqAck49.js";import"./index-DBfaQNOv.js";import"./icons-DP3uiYxy.js";const s=t(o);export{s as default};
|