@ai-agent-forge/agent-forge 0.86.1 → 0.86.3
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/CHANGELOG.md +34 -0
- package/dist/bundle/.build-manifest.json +158 -152
- package/dist/bundle/chunks/{anthropic-messages-RJYU4TCY.js → anthropic-messages-EVFQ6MLR.js} +3 -3
- package/dist/bundle/chunks/{azure-openai-responses-LESTCUL7.js → azure-openai-responses-WQCZWFAH.js} +1 -1
- package/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/dist/bundle/chunks/{chunk-MDOTREMR.js → chunk-3WE3W52L.js} +2 -2
- package/dist/bundle/chunks/chunk-F6SBZUJG.js +141 -0
- package/dist/bundle/chunks/{chunk-SER2HCLE.js → chunk-N6BQJSGH.js} +1 -1
- package/dist/bundle/chunks/chunk-RK2X2KU2.js +1442 -0
- package/dist/bundle/chunks/chunk-TBPTHASB.js +2 -0
- package/dist/bundle/chunks/github-copilot.js +1 -1
- package/dist/bundle/chunks/{google-generative-ai-NZ66X6K7.js → google-generative-ai-ISTTUZMW.js} +1 -1
- package/dist/bundle/chunks/{google-vertex-2ZZOFBNQ.js → google-vertex-NS7ZF7DK.js} +1 -1
- package/dist/bundle/chunks/jiti-static-loader-CDSTNEDU.js +2 -0
- package/dist/bundle/chunks/{mistral-conversations-B6DZRMEK.js → mistral-conversations-GINO6Z4I.js} +1 -1
- package/dist/bundle/chunks/{openai-codex-responses-UFH6O5K6.js → openai-codex-responses-YDJSZOIH.js} +1 -1
- package/dist/bundle/chunks/{openai-completions-A55GHA4O.js → openai-completions-UPRWTQPT.js} +3 -3
- package/dist/bundle/chunks/openai-responses-O63W6HQ3.js +2 -0
- package/dist/bundle/chunks/virtual-modules-O72ICTMQ.js +2 -0
- package/dist/bundle/cli.js +1 -1
- package/dist/bundle/index.js +1 -1
- package/dist/bundle/rpc-entry.js +1 -1
- package/dist/cli/args.d.ts.map +1 -1
- package/dist/cli/args.js +14 -4
- package/dist/cli/args.js.map +1 -1
- package/dist/cli/session-picker.d.ts +1 -1
- package/dist/cli/session-picker.d.ts.map +1 -1
- package/dist/cli/session-picker.js +8 -2
- package/dist/cli/session-picker.js.map +1 -1
- package/dist/core/agent-session-compaction.d.ts +7 -2
- package/dist/core/agent-session-compaction.d.ts.map +1 -1
- package/dist/core/agent-session-compaction.js +137 -43
- package/dist/core/agent-session-compaction.js.map +1 -1
- package/dist/core/agent-session-internal.d.ts +6 -0
- package/dist/core/agent-session-internal.d.ts.map +1 -1
- package/dist/core/agent-session-internal.js.map +1 -1
- package/dist/core/agent-session-runtime.d.ts.map +1 -1
- package/dist/core/agent-session-runtime.js +1 -1
- package/dist/core/agent-session-runtime.js.map +1 -1
- package/dist/core/agent-session.d.ts +21 -4
- package/dist/core/agent-session.d.ts.map +1 -1
- package/dist/core/agent-session.js +104 -93
- package/dist/core/agent-session.js.map +1 -1
- package/dist/core/compaction/compaction.d.ts +15 -0
- package/dist/core/compaction/compaction.d.ts.map +1 -1
- package/dist/core/compaction/compaction.js +20 -1
- package/dist/core/compaction/compaction.js.map +1 -1
- package/dist/core/export-html/template.css +10 -0
- package/dist/core/export-html/template.js +50 -17
- package/dist/core/extensions/bootstrap-compaction-policy.d.ts.map +1 -1
- package/dist/core/extensions/bootstrap-compaction-policy.js +3 -1
- package/dist/core/extensions/bootstrap-compaction-policy.js.map +1 -1
- package/dist/core/extensions/capability-plugin.d.ts.map +1 -1
- package/dist/core/extensions/capability-plugin.js +25 -30
- package/dist/core/extensions/capability-plugin.js.map +1 -1
- package/dist/core/extensions/jiti-static-loader.d.ts +2 -0
- package/dist/core/extensions/jiti-static-loader.d.ts.map +1 -0
- package/dist/core/extensions/jiti-static-loader.js +5 -0
- package/dist/core/extensions/jiti-static-loader.js.map +1 -0
- package/dist/core/extensions/microcompact.d.ts +3 -2
- package/dist/core/extensions/microcompact.d.ts.map +1 -1
- package/dist/core/extensions/microcompact.js +14 -5
- package/dist/core/extensions/microcompact.js.map +1 -1
- package/dist/core/extensions/virtual-modules.d.ts +3 -0
- package/dist/core/extensions/virtual-modules.d.ts.map +1 -0
- package/dist/core/extensions/virtual-modules.js +32 -0
- package/dist/core/extensions/virtual-modules.js.map +1 -0
- package/dist/core/facade/coding-agent-facade.d.ts +3 -3
- package/dist/core/facade/coding-agent-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-facade.js.map +1 -1
- package/dist/core/facade/coding-agent-runtime-facade.d.ts +2 -2
- package/dist/core/facade/coding-agent-runtime-facade.d.ts.map +1 -1
- package/dist/core/facade/coding-agent-runtime-facade.js +4 -4
- package/dist/core/facade/coding-agent-runtime-facade.js.map +1 -1
- package/dist/core/model-resolver.d.ts.map +1 -1
- package/dist/core/model-resolver.js +2 -2
- package/dist/core/model-resolver.js.map +1 -1
- package/dist/core/package-install-host.d.ts +1 -1
- package/dist/core/package-install-host.d.ts.map +1 -1
- package/dist/core/package-install-host.js +4 -3
- package/dist/core/package-install-host.js.map +1 -1
- package/dist/core/prompt-templates.d.ts +6 -1
- package/dist/core/prompt-templates.d.ts.map +1 -1
- package/dist/core/prompt-templates.js +61 -35
- package/dist/core/prompt-templates.js.map +1 -1
- package/dist/core/resource-loader.d.ts.map +1 -1
- package/dist/core/resource-loader.js +6 -2
- package/dist/core/resource-loader.js.map +1 -1
- package/dist/core/session-manager.d.ts +23 -4
- package/dist/core/session-manager.d.ts.map +1 -1
- package/dist/core/session-manager.js +146 -108
- package/dist/core/session-manager.js.map +1 -1
- package/dist/core/settings-manager.d.ts +3 -0
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +4 -0
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/tools/bash.d.ts +2 -1
- package/dist/core/tools/bash.d.ts.map +1 -1
- package/dist/core/tools/bash.js +18 -3
- package/dist/core/tools/bash.js.map +1 -1
- package/dist/main.d.ts.map +1 -1
- package/dist/main.js +6 -7
- package/dist/main.js.map +1 -1
- package/dist/modes/interactive/components/session-selector.d.ts +5 -5
- package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
- package/dist/modes/interactive/components/session-selector.js +74 -50
- package/dist/modes/interactive/components/session-selector.js.map +1 -1
- package/dist/modes/interactive/components/tool-execution.d.ts.map +1 -1
- package/dist/modes/interactive/components/tool-execution.js +18 -9
- package/dist/modes/interactive/components/tool-execution.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +2 -2
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +35 -32
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-client.d.ts +14 -6
- package/dist/modes/rpc/rpc-client.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-client.js +47 -10
- package/dist/modes/rpc/rpc-client.js.map +1 -1
- package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-mode.js +9 -10
- package/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/dist/modes/rpc/rpc-types.d.ts +10 -1
- package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
- package/dist/modes/rpc/rpc-types.js.map +1 -1
- package/dist/remote/server-assembly.d.ts.map +1 -1
- package/dist/remote/server-assembly.js +1 -1
- package/dist/remote/server-assembly.js.map +1 -1
- package/dist/utils/clipboard-image.d.ts.map +1 -1
- package/dist/utils/clipboard-image.js +1 -12
- package/dist/utils/clipboard-image.js.map +1 -1
- package/dist/utils/clipboard.d.ts.map +1 -1
- package/dist/utils/clipboard.js +88 -13
- package/dist/utils/clipboard.js.map +1 -1
- package/dist/utils/mime.d.ts.map +1 -1
- package/dist/utils/mime.js +1 -1
- package/dist/utils/mime.js.map +1 -1
- package/dist/utils/wsl.d.ts +3 -0
- package/dist/utils/wsl.d.ts.map +1 -0
- package/dist/utils/wsl.js +15 -0
- package/dist/utils/wsl.js.map +1 -0
- package/docs/rpc.md +7 -5
- package/docs/sdk.md +9 -8
- package/package.json +1 -1
- package/dist/bundle/chunks/chunk-KQEGUM34.js +0 -2
- package/dist/bundle/chunks/chunk-S3YLY4MG.js +0 -1581
- package/dist/bundle/chunks/openai-responses-TJLXRAXR.js +0 -2
|
@@ -1306,9 +1306,10 @@
|
|
|
1306
1306
|
</div>`;
|
|
1307
1307
|
}
|
|
1308
1308
|
|
|
1309
|
-
if (entry.type === 'custom_message'
|
|
1310
|
-
|
|
1311
|
-
|
|
1309
|
+
if (entry.type === 'custom_message') {
|
|
1310
|
+
const hidden = entry.display === false;
|
|
1311
|
+
return `<div class="hook-message${hidden ? ' hook-message-hidden' : ''}" id="${entryDomId}">${tsHtml}
|
|
1312
|
+
<div class="hook-type">[${escapeHtml(entry.customType)}]${hidden ? ' · Hidden in terminal' : ''}</div>
|
|
1312
1313
|
<div class="markdown-content">${safeMarkedParse(typeof entry.content === 'string' ? entry.content : JSON.stringify(entry.content))}</div>
|
|
1313
1314
|
</div>`;
|
|
1314
1315
|
}
|
|
@@ -1384,10 +1385,11 @@
|
|
|
1384
1385
|
<div class="header">
|
|
1385
1386
|
<h1>Session: ${escapeHtml(header?.id || 'unknown')}</h1>
|
|
1386
1387
|
<div class="help-bar">
|
|
1387
|
-
<span class="help-hint">T toggle thinking · O toggle tools</span>
|
|
1388
|
+
<span class="help-hint">T toggle thinking · O toggle tools · H toggle hidden messages</span>
|
|
1388
1389
|
<div class="help-actions">
|
|
1389
|
-
<button type="button" class="header-toggle-btn" data-action="toggle-thinking" title="Toggle thinking (T)">Toggle thinking</button>
|
|
1390
|
-
<button type="button" class="header-toggle-btn" data-action="toggle-tools" title="Toggle tools (O)">Toggle tools</button>
|
|
1390
|
+
<button type="button" class="header-toggle-btn" data-action="toggle-thinking" aria-pressed="${thinkingExpanded}" title="Toggle thinking (T)">Toggle thinking</button>
|
|
1391
|
+
<button type="button" class="header-toggle-btn" data-action="toggle-tools" aria-pressed="${toolOutputsExpanded}" title="Toggle tools (O)">Toggle tools</button>
|
|
1392
|
+
<button type="button" class="header-toggle-btn" data-action="toggle-hidden-messages" aria-pressed="${showHiddenMessages}" title="Show custom messages marked as hidden in the terminal (H).">${showHiddenMessages ? 'Hide hidden messages' : 'Show hidden messages'}</button>
|
|
1391
1393
|
<button type="button" class="download-json-btn" onclick="downloadSessionJson()" title="Download session as JSONL">↓ JSONL</button>
|
|
1392
1394
|
</div>
|
|
1393
1395
|
</div>
|
|
@@ -1495,6 +1497,10 @@
|
|
|
1495
1497
|
function navigateTo(targetId, scrollMode = 'target', scrollToEntryId = null) {
|
|
1496
1498
|
currentLeafId = targetId;
|
|
1497
1499
|
currentTargetId = scrollToEntryId || targetId;
|
|
1500
|
+
const targetEntry = byId.get(currentTargetId);
|
|
1501
|
+
if (scrollMode === 'target' && targetEntry?.type === 'custom_message' && targetEntry.display === false) {
|
|
1502
|
+
setHiddenMessagesVisible(true);
|
|
1503
|
+
}
|
|
1498
1504
|
const path = getPath(targetId);
|
|
1499
1505
|
|
|
1500
1506
|
renderTree();
|
|
@@ -1516,6 +1522,10 @@
|
|
|
1516
1522
|
messagesEl.innerHTML = '';
|
|
1517
1523
|
messagesEl.appendChild(fragment);
|
|
1518
1524
|
|
|
1525
|
+
// Cached nodes contain their initial presentation; reapply the viewer's toggle states.
|
|
1526
|
+
setThinkingExpanded(thinkingExpanded);
|
|
1527
|
+
setToolOutputsExpanded(toolOutputsExpanded);
|
|
1528
|
+
|
|
1519
1529
|
// Attach click handlers for copy-link buttons
|
|
1520
1530
|
messagesEl.querySelectorAll('.copy-link-btn').forEach(btn => {
|
|
1521
1531
|
btn.addEventListener('click', (e) => {
|
|
@@ -1788,19 +1798,32 @@
|
|
|
1788
1798
|
// Toggle states
|
|
1789
1799
|
let thinkingExpanded = true;
|
|
1790
1800
|
let toolOutputsExpanded = false;
|
|
1801
|
+
let showHiddenMessages = false;
|
|
1802
|
+
|
|
1803
|
+
function setHiddenMessagesVisible(visible) {
|
|
1804
|
+
showHiddenMessages = visible;
|
|
1805
|
+
document.body.classList.toggle('show-hidden-messages', visible);
|
|
1806
|
+
const button = document.querySelector('[data-action="toggle-hidden-messages"]');
|
|
1807
|
+
if (button) {
|
|
1808
|
+
button.setAttribute('aria-pressed', String(visible));
|
|
1809
|
+
button.textContent = visible ? 'Hide hidden messages' : 'Show hidden messages';
|
|
1810
|
+
}
|
|
1811
|
+
}
|
|
1791
1812
|
|
|
1792
|
-
|
|
1793
|
-
thinkingExpanded =
|
|
1813
|
+
function setThinkingExpanded(expanded) {
|
|
1814
|
+
thinkingExpanded = expanded;
|
|
1815
|
+
document.querySelector('[data-action="toggle-thinking"]')?.setAttribute('aria-pressed', String(expanded));
|
|
1794
1816
|
document.querySelectorAll('.thinking-text').forEach(el => {
|
|
1795
1817
|
el.style.display = thinkingExpanded ? '' : 'none';
|
|
1796
1818
|
});
|
|
1797
1819
|
document.querySelectorAll('.thinking-collapsed').forEach(el => {
|
|
1798
1820
|
el.style.display = thinkingExpanded ? 'none' : 'block';
|
|
1799
1821
|
});
|
|
1800
|
-
}
|
|
1822
|
+
}
|
|
1801
1823
|
|
|
1802
|
-
|
|
1803
|
-
toolOutputsExpanded =
|
|
1824
|
+
function setToolOutputsExpanded(expanded) {
|
|
1825
|
+
toolOutputsExpanded = expanded;
|
|
1826
|
+
document.querySelector('[data-action="toggle-tools"]')?.setAttribute('aria-pressed', String(expanded));
|
|
1804
1827
|
document.querySelectorAll('.tool-output.expandable').forEach(el => {
|
|
1805
1828
|
el.classList.toggle('expanded', toolOutputsExpanded);
|
|
1806
1829
|
});
|
|
@@ -1810,11 +1833,18 @@
|
|
|
1810
1833
|
document.querySelectorAll('.skill-invocation').forEach(el => {
|
|
1811
1834
|
el.classList.toggle('expanded', toolOutputsExpanded);
|
|
1812
1835
|
});
|
|
1813
|
-
}
|
|
1836
|
+
}
|
|
1814
1837
|
|
|
1815
1838
|
const attachHeaderHandlers = () => {
|
|
1816
|
-
document.querySelector('[data-action="toggle-thinking"]')?.addEventListener('click',
|
|
1817
|
-
|
|
1839
|
+
document.querySelector('[data-action="toggle-thinking"]')?.addEventListener('click', () => {
|
|
1840
|
+
setThinkingExpanded(!thinkingExpanded);
|
|
1841
|
+
});
|
|
1842
|
+
document.querySelector('[data-action="toggle-tools"]')?.addEventListener('click', () => {
|
|
1843
|
+
setToolOutputsExpanded(!toolOutputsExpanded);
|
|
1844
|
+
});
|
|
1845
|
+
document.querySelector('[data-action="toggle-hidden-messages"]')?.addEventListener('click', () => {
|
|
1846
|
+
setHiddenMessagesVisible(!showHiddenMessages);
|
|
1847
|
+
});
|
|
1818
1848
|
};
|
|
1819
1849
|
|
|
1820
1850
|
const isEditableTarget = (element) => {
|
|
@@ -1834,17 +1864,20 @@
|
|
|
1834
1864
|
navigateTo(leafId, 'bottom');
|
|
1835
1865
|
}
|
|
1836
1866
|
|
|
1837
|
-
if (isEditableTarget(document.activeElement)) {
|
|
1867
|
+
if (e.ctrlKey || e.metaKey || e.altKey || isEditableTarget(document.activeElement)) {
|
|
1838
1868
|
return;
|
|
1839
1869
|
}
|
|
1840
1870
|
|
|
1841
1871
|
const key = e.key.toLowerCase();
|
|
1842
1872
|
if (key === 't') {
|
|
1843
1873
|
e.preventDefault();
|
|
1844
|
-
|
|
1874
|
+
setThinkingExpanded(!thinkingExpanded);
|
|
1845
1875
|
} else if (key === 'o') {
|
|
1846
1876
|
e.preventDefault();
|
|
1847
|
-
|
|
1877
|
+
setToolOutputsExpanded(!toolOutputsExpanded);
|
|
1878
|
+
} else if (key === 'h') {
|
|
1879
|
+
e.preventDefault();
|
|
1880
|
+
setHiddenMessagesVisible(!showHiddenMessages);
|
|
1848
1881
|
}
|
|
1849
1882
|
});
|
|
1850
1883
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap-compaction-policy.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/bootstrap-compaction-policy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,sBAAsB,EAA4B,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAUjE,eAAO,MAAM,8BAA8B,qCAAqC,CAAC;AACjF,eAAO,MAAM,8BAA8B,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap-compaction-policy.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/bootstrap-compaction-policy.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,sBAAsB,EAA4B,MAAM,wBAAwB,CAAC;AAC/F,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAUjE,eAAO,MAAM,8BAA8B,qCAAqC,CAAC;AACjF,eAAO,MAAM,8BAA8B,YAAY,CAAC;AASxD,8FAA8F;AAC9F,wBAAgB,gCAAgC,CAAC,OAAO,EAAE,iBAAiB,GAAG,sBAAsB,CAmFnG","sourcesContent":["import { type CompactionPreparation, compact, prepareCompaction } from \"../compaction/index.ts\";\nimport { type CapabilityPluginHandle, loadCapabilityPluginSync } from \"./capability-plugin.ts\";\nimport type { CapabilityRuntime } from \"./capability-runtime.ts\";\nimport {\n\tapplyMicrocompactElision,\n\tDEFAULT_MIN_ELIDE_CHARS,\n\tMICROCOMPACT_CUSTOM_TYPE,\n\tplanMicrocompact,\n} from \"./microcompact.ts\";\nimport type { CompactionPolicyRequest, CompactionSummaryRequest } from \"./public-api.ts\";\nimport { EXPERIMENTAL_PUBLIC_API_VERSION } from \"./public-api.ts\";\n\nexport const BOOTSTRAP_COMPACTION_PLUGIN_ID = \"agent-forge.bootstrap-compaction\";\nexport const DEFAULT_COMPACTION_POLICY_NAME = \"default\";\n\n/**\n * 会话宿主经 threshold decide 请求透传的 microcompact 门控事实(settings 的\n * `compaction.microcompactEnabled` 与会话冷却的合取)。请求缺省视为 true,\n * 旧调用方与第三方宿主保持既有行为。\n */\ntype DecisionRequestWithMicrocompact = CompactionPolicyRequest & { microcompactEnabled?: boolean };\n\n/** Register the current automatic-compaction decision as a replaceable first-party policy. */\nexport function installBootstrapCompactionPolicy(runtime: CapabilityRuntime): CapabilityPluginHandle {\n\treturn loadCapabilityPluginSync(\n\t\truntime,\n\t\t{\n\t\t\tid: BOOTSTRAP_COMPACTION_PLUGIN_ID,\n\t\t\tversion: \"0.0.0\",\n\t\t\tapiVersion: EXPERIMENTAL_PUBLIC_API_VERSION,\n\t\t\tentry: \"<embedded:bootstrap-compaction>\",\n\t\t\trequiredCapabilities: [\"compaction-policy\"],\n\t\t},\n\t\t(api) => {\n\t\t\t// Microcompact 投影(宪法 §4/§5):经公共 registerEntryProjection 通道\n\t\t\t// 注册——内核按注册顺序应用投影、不解释语义;第三方上下文策略走同一\n\t\t\t// 通道。策略被禁用/替换时,本投影随插件卸载一并消失。\n\t\t\tapi.registerEntryProjection({\n\t\t\t\tcustomType: MICROCOMPACT_CUSTOM_TYPE,\n\t\t\t\tproject: (entries) => applyMicrocompactElision(entries as never) as never,\n\t\t\t});\n\t\t\tapi.registerCompactionPolicy(DEFAULT_COMPACTION_POLICY_NAME, {\n\t\t\t\tprepare: (request) =>\n\t\t\t\t\tprepareCompaction(\n\t\t\t\t\t\trequest.entries as Parameters<typeof prepareCompaction>[0],\n\t\t\t\t\t\trequest.settings as Parameters<typeof prepareCompaction>[1],\n\t\t\t\t\t),\n\t\t\t\tdecide: (request) => {\n\t\t\t\t\tif (!request.enabled) return { compact: false };\n\t\t\t\t\tif (request.reason === \"threshold\") {\n\t\t\t\t\t\tconst usage = request.contextUsage;\n\t\t\t\t\t\tconst overBudget =\n\t\t\t\t\t\t\tusage !== undefined &&\n\t\t\t\t\t\t\tusage.contextWindow > 0 &&\n\t\t\t\t\t\t\tusage.contextTokens > usage.contextWindow - usage.reserveTokens;\n\t\t\t\t\t\t// 便宜缓解优先(microcompact):阈值命中先尝试零成本的本地\n\t\t\t\t\t\t// 变换——把老的粗大 tool result 从模型可见上下文中替换为占位\n\t\t\t\t\t\t// 符——释放达标则以 relief 条目落地并跳过 LLM 摘要;不足则照常\n\t\t\t\t\t\t// 走全量压缩。条目语义完全属于本策略,投影也由本策略注册。\n\t\t\t\t\t\t// 宿主在设置关闭或会话冷却期内传 microcompactEnabled:false,\n\t\t\t\t\t\t// planMicrocompact 据此拒绝规划,自然落到下方全量压缩分支。\n\t\t\t\t\t\tif (overBudget && request.branchEntries !== undefined) {\n\t\t\t\t\t\t\tconst plan = planMicrocompact(request.branchEntries as Parameters<typeof planMicrocompact>[0], {\n\t\t\t\t\t\t\t\tenabled: (request as DecisionRequestWithMicrocompact).microcompactEnabled !== false,\n\t\t\t\t\t\t\t\treserveTokens: usage.reserveTokens,\n\t\t\t\t\t\t\t\tkeepRecentTokens: request.keepRecentTokens ?? 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (plan) {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tcompact: false,\n\t\t\t\t\t\t\t\t\trelief: {\n\t\t\t\t\t\t\t\t\t\tcustomType: MICROCOMPACT_CUSTOM_TYPE,\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\telideBeforeEntryId: plan.elideBeforeEntryId,\n\t\t\t\t\t\t\t\t\t\t\tminChars: DEFAULT_MIN_ELIDE_CHARS,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { compact: overBudget, retry: false };\n\t\t\t\t\t}\n\t\t\t\t\tif (request.recoveryAttempted) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcompact: false,\n\t\t\t\t\t\t\tfailureMessage: request.contextOverflow\n\t\t\t\t\t\t\t\t? \"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\"\n\t\t\t\t\t\t\t\t: \"Truncated response recovery failed after one compact-and-retry attempt.\",\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcompact: request.contextOverflow || request.recoverableLength,\n\t\t\t\t\t\tretry: request.canContinue,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tsummarize: async (request: CompactionSummaryRequest) =>\n\t\t\t\t\tcompact(request.preparation as CompactionPreparation, {\n\t\t\t\t\t\tinvocation: request.invocation,\n\t\t\t\t\t\tmodel: request.model,\n\t\t\t\t\t\tcustomInstructions: request.customInstructions,\n\t\t\t\t\t\tthinkingLevel: request.thinkingLevel,\n\t\t\t\t\t\tsignal: request.signal,\n\t\t\t\t\t}),\n\t\t\t});\n\t\t},\n\t);\n}\n"]}
|
|
@@ -34,9 +34,11 @@ export function installBootstrapCompactionPolicy(runtime) {
|
|
|
34
34
|
// 变换——把老的粗大 tool result 从模型可见上下文中替换为占位
|
|
35
35
|
// 符——释放达标则以 relief 条目落地并跳过 LLM 摘要;不足则照常
|
|
36
36
|
// 走全量压缩。条目语义完全属于本策略,投影也由本策略注册。
|
|
37
|
+
// 宿主在设置关闭或会话冷却期内传 microcompactEnabled:false,
|
|
38
|
+
// planMicrocompact 据此拒绝规划,自然落到下方全量压缩分支。
|
|
37
39
|
if (overBudget && request.branchEntries !== undefined) {
|
|
38
40
|
const plan = planMicrocompact(request.branchEntries, {
|
|
39
|
-
enabled:
|
|
41
|
+
enabled: request.microcompactEnabled !== false,
|
|
40
42
|
reserveTokens: usage.reserveTokens,
|
|
41
43
|
keepRecentTokens: request.keepRecentTokens ?? 0,
|
|
42
44
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bootstrap-compaction-policy.js","sourceRoot":"","sources":["../../../src/core/extensions/bootstrap-compaction-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAA+B,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EACN,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAElE,MAAM,CAAC,MAAM,8BAA8B,GAAG,kCAAkC,CAAC;AACjF,MAAM,CAAC,MAAM,8BAA8B,GAAG,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"bootstrap-compaction-policy.js","sourceRoot":"","sources":["../../../src/core/extensions/bootstrap-compaction-policy.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,OAAO,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAChG,OAAO,EAA+B,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAE/F,OAAO,EACN,wBAAwB,EACxB,uBAAuB,EACvB,wBAAwB,EACxB,gBAAgB,GAChB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,+BAA+B,EAAE,MAAM,iBAAiB,CAAC;AAElE,MAAM,CAAC,MAAM,8BAA8B,GAAG,kCAAkC,CAAC;AACjF,MAAM,CAAC,MAAM,8BAA8B,GAAG,SAAS,CAAC;AASxD,8FAA8F;AAC9F,MAAM,UAAU,gCAAgC,CAAC,OAA0B,EAA0B;IACpG,OAAO,wBAAwB,CAC9B,OAAO,EACP;QACC,EAAE,EAAE,8BAA8B;QAClC,OAAO,EAAE,OAAO;QAChB,UAAU,EAAE,+BAA+B;QAC3C,KAAK,EAAE,iCAAiC;QACxC,oBAAoB,EAAE,CAAC,mBAAmB,CAAC;KAC3C,EACD,CAAC,GAAG,EAAE,EAAE,CAAC;QACR,qFAA2D;QAC3D,sGAAoC;QACpC,+EAA6B;QAC7B,GAAG,CAAC,uBAAuB,CAAC;YAC3B,UAAU,EAAE,wBAAwB;YACpC,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,wBAAwB,CAAC,OAAgB,CAAU;SACzE,CAAC,CAAC;QACH,GAAG,CAAC,wBAAwB,CAAC,8BAA8B,EAAE;YAC5D,OAAO,EAAE,CAAC,OAAO,EAAE,EAAE,CACpB,iBAAiB,CAChB,OAAO,CAAC,OAAkD,EAC1D,OAAO,CAAC,QAAmD,CAC3D;YACF,MAAM,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC;gBACpB,IAAI,CAAC,OAAO,CAAC,OAAO;oBAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;gBAChD,IAAI,OAAO,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;oBACpC,MAAM,KAAK,GAAG,OAAO,CAAC,YAAY,CAAC;oBACnC,MAAM,UAAU,GACf,KAAK,KAAK,SAAS;wBACnB,KAAK,CAAC,aAAa,GAAG,CAAC;wBACvB,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,GAAG,KAAK,CAAC,aAAa,CAAC;oBACjE,iFAAqC;oBACrC,qFAAuC;oBACvC,wFAAwC;oBACxC,uFAA+B;oBAC/B,6EAA6C;oBAC7C,gFAAwC;oBACxC,IAAI,UAAU,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,EAAE,CAAC;wBACvD,MAAM,IAAI,GAAG,gBAAgB,CAAC,OAAO,CAAC,aAAuD,EAAE;4BAC9F,OAAO,EAAG,OAA2C,CAAC,mBAAmB,KAAK,KAAK;4BACnF,aAAa,EAAE,KAAK,CAAC,aAAa;4BAClC,gBAAgB,EAAE,OAAO,CAAC,gBAAgB,IAAI,CAAC;yBAC/C,CAAC,CAAC;wBACH,IAAI,IAAI,EAAE,CAAC;4BACV,OAAO;gCACN,OAAO,EAAE,KAAK;gCACd,MAAM,EAAE;oCACP,UAAU,EAAE,wBAAwB;oCACpC,IAAI,EAAE;wCACL,kBAAkB,EAAE,IAAI,CAAC,kBAAkB;wCAC3C,QAAQ,EAAE,uBAAuB;qCACjC;iCACD;6BACD,CAAC;wBACH,CAAC;oBACF,CAAC;oBACD,OAAO,EAAE,OAAO,EAAE,UAAU,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;gBAC9C,CAAC;gBACD,IAAI,OAAO,CAAC,iBAAiB,EAAE,CAAC;oBAC/B,OAAO;wBACN,OAAO,EAAE,KAAK;wBACd,cAAc,EAAE,OAAO,CAAC,eAAe;4BACtC,CAAC,CAAC,oIAAoI;4BACtI,CAAC,CAAC,yEAAyE;qBAC5E,CAAC;gBACH,CAAC;gBACD,OAAO;oBACN,OAAO,EAAE,OAAO,CAAC,eAAe,IAAI,OAAO,CAAC,iBAAiB;oBAC7D,KAAK,EAAE,OAAO,CAAC,WAAW;iBAC1B,CAAC;YAAA,CACF;YACD,SAAS,EAAE,KAAK,EAAE,OAAiC,EAAE,EAAE,CACtD,OAAO,CAAC,OAAO,CAAC,WAAoC,EAAE;gBACrD,UAAU,EAAE,OAAO,CAAC,UAAU;gBAC9B,KAAK,EAAE,OAAO,CAAC,KAAK;gBACpB,kBAAkB,EAAE,OAAO,CAAC,kBAAkB;gBAC9C,aAAa,EAAE,OAAO,CAAC,aAAa;gBACpC,MAAM,EAAE,OAAO,CAAC,MAAM;aACtB,CAAC;SACH,CAAC,CAAC;IAAA,CACH,CACD,CAAC;AAAA,CACF","sourcesContent":["import { type CompactionPreparation, compact, prepareCompaction } from \"../compaction/index.ts\";\nimport { type CapabilityPluginHandle, loadCapabilityPluginSync } from \"./capability-plugin.ts\";\nimport type { CapabilityRuntime } from \"./capability-runtime.ts\";\nimport {\n\tapplyMicrocompactElision,\n\tDEFAULT_MIN_ELIDE_CHARS,\n\tMICROCOMPACT_CUSTOM_TYPE,\n\tplanMicrocompact,\n} from \"./microcompact.ts\";\nimport type { CompactionPolicyRequest, CompactionSummaryRequest } from \"./public-api.ts\";\nimport { EXPERIMENTAL_PUBLIC_API_VERSION } from \"./public-api.ts\";\n\nexport const BOOTSTRAP_COMPACTION_PLUGIN_ID = \"agent-forge.bootstrap-compaction\";\nexport const DEFAULT_COMPACTION_POLICY_NAME = \"default\";\n\n/**\n * 会话宿主经 threshold decide 请求透传的 microcompact 门控事实(settings 的\n * `compaction.microcompactEnabled` 与会话冷却的合取)。请求缺省视为 true,\n * 旧调用方与第三方宿主保持既有行为。\n */\ntype DecisionRequestWithMicrocompact = CompactionPolicyRequest & { microcompactEnabled?: boolean };\n\n/** Register the current automatic-compaction decision as a replaceable first-party policy. */\nexport function installBootstrapCompactionPolicy(runtime: CapabilityRuntime): CapabilityPluginHandle {\n\treturn loadCapabilityPluginSync(\n\t\truntime,\n\t\t{\n\t\t\tid: BOOTSTRAP_COMPACTION_PLUGIN_ID,\n\t\t\tversion: \"0.0.0\",\n\t\t\tapiVersion: EXPERIMENTAL_PUBLIC_API_VERSION,\n\t\t\tentry: \"<embedded:bootstrap-compaction>\",\n\t\t\trequiredCapabilities: [\"compaction-policy\"],\n\t\t},\n\t\t(api) => {\n\t\t\t// Microcompact 投影(宪法 §4/§5):经公共 registerEntryProjection 通道\n\t\t\t// 注册——内核按注册顺序应用投影、不解释语义;第三方上下文策略走同一\n\t\t\t// 通道。策略被禁用/替换时,本投影随插件卸载一并消失。\n\t\t\tapi.registerEntryProjection({\n\t\t\t\tcustomType: MICROCOMPACT_CUSTOM_TYPE,\n\t\t\t\tproject: (entries) => applyMicrocompactElision(entries as never) as never,\n\t\t\t});\n\t\t\tapi.registerCompactionPolicy(DEFAULT_COMPACTION_POLICY_NAME, {\n\t\t\t\tprepare: (request) =>\n\t\t\t\t\tprepareCompaction(\n\t\t\t\t\t\trequest.entries as Parameters<typeof prepareCompaction>[0],\n\t\t\t\t\t\trequest.settings as Parameters<typeof prepareCompaction>[1],\n\t\t\t\t\t),\n\t\t\t\tdecide: (request) => {\n\t\t\t\t\tif (!request.enabled) return { compact: false };\n\t\t\t\t\tif (request.reason === \"threshold\") {\n\t\t\t\t\t\tconst usage = request.contextUsage;\n\t\t\t\t\t\tconst overBudget =\n\t\t\t\t\t\t\tusage !== undefined &&\n\t\t\t\t\t\t\tusage.contextWindow > 0 &&\n\t\t\t\t\t\t\tusage.contextTokens > usage.contextWindow - usage.reserveTokens;\n\t\t\t\t\t\t// 便宜缓解优先(microcompact):阈值命中先尝试零成本的本地\n\t\t\t\t\t\t// 变换——把老的粗大 tool result 从模型可见上下文中替换为占位\n\t\t\t\t\t\t// 符——释放达标则以 relief 条目落地并跳过 LLM 摘要;不足则照常\n\t\t\t\t\t\t// 走全量压缩。条目语义完全属于本策略,投影也由本策略注册。\n\t\t\t\t\t\t// 宿主在设置关闭或会话冷却期内传 microcompactEnabled:false,\n\t\t\t\t\t\t// planMicrocompact 据此拒绝规划,自然落到下方全量压缩分支。\n\t\t\t\t\t\tif (overBudget && request.branchEntries !== undefined) {\n\t\t\t\t\t\t\tconst plan = planMicrocompact(request.branchEntries as Parameters<typeof planMicrocompact>[0], {\n\t\t\t\t\t\t\t\tenabled: (request as DecisionRequestWithMicrocompact).microcompactEnabled !== false,\n\t\t\t\t\t\t\t\treserveTokens: usage.reserveTokens,\n\t\t\t\t\t\t\t\tkeepRecentTokens: request.keepRecentTokens ?? 0,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t\tif (plan) {\n\t\t\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\t\t\tcompact: false,\n\t\t\t\t\t\t\t\t\trelief: {\n\t\t\t\t\t\t\t\t\t\tcustomType: MICROCOMPACT_CUSTOM_TYPE,\n\t\t\t\t\t\t\t\t\t\tdata: {\n\t\t\t\t\t\t\t\t\t\t\telideBeforeEntryId: plan.elideBeforeEntryId,\n\t\t\t\t\t\t\t\t\t\t\tminChars: DEFAULT_MIN_ELIDE_CHARS,\n\t\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t};\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\treturn { compact: overBudget, retry: false };\n\t\t\t\t\t}\n\t\t\t\t\tif (request.recoveryAttempted) {\n\t\t\t\t\t\treturn {\n\t\t\t\t\t\t\tcompact: false,\n\t\t\t\t\t\t\tfailureMessage: request.contextOverflow\n\t\t\t\t\t\t\t\t? \"Context overflow recovery failed after one compact-and-retry attempt. Try reducing context or switching to a larger-context model.\"\n\t\t\t\t\t\t\t\t: \"Truncated response recovery failed after one compact-and-retry attempt.\",\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\treturn {\n\t\t\t\t\t\tcompact: request.contextOverflow || request.recoverableLength,\n\t\t\t\t\t\tretry: request.canContinue,\n\t\t\t\t\t};\n\t\t\t\t},\n\t\t\t\tsummarize: async (request: CompactionSummaryRequest) =>\n\t\t\t\t\tcompact(request.preparation as CompactionPreparation, {\n\t\t\t\t\t\tinvocation: request.invocation,\n\t\t\t\t\t\tmodel: request.model,\n\t\t\t\t\t\tcustomInstructions: request.customInstructions,\n\t\t\t\t\t\tthinkingLevel: request.thinkingLevel,\n\t\t\t\t\t\tsignal: request.signal,\n\t\t\t\t\t}),\n\t\t\t});\n\t\t},\n\t);\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/capability-plugin.ts"],"names":[],"mappings":"AAMA,OAAO,EACN,KAAK,uBAAuB,EAE5B,KAAK,2BAA2B,EAGhC,MAAM,yBAAyB,CAAC;AAUjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAQjE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAInF,YAAY,EACX,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,EACxB,2BAA2B,EAC3B,4BAA4B,GAC5B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAExE,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AA+BD;;;;;;;;GAQG;AACH,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAOD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACzC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,MAAM,EAAE,EACnD,UAAU,EAAE,6BAA6B,GACvC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBxB;AAoGD;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAoFhG;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CA6DjC;AAED,mEAAmE;AACnE,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,2BAA2B,GAClC,sBAAsB,CAyFxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gCAAgC,CACrD,OAAO,EAAE,iBAAiB,EAC1B,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,YAAY,CAAA;CAAE,GAClD,OAAO,CAAC,sBAAsB,CAAC,CAiEjC","sourcesContent":["import type { Dirent } from \"node:fs\";\nimport { lstatSync, readdirSync, realpathSync, statSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport * as pluginSdk from \"@agent-forge/plugin-sdk\";\nimport {\n\ttype CapabilityPluginFactory,\n\ttype CapabilityPluginInstance,\n\ttype CapabilityPluginSyncFactory,\n\ttype CapabilityPluginSyncInstance,\n\tparseCapabilityPluginManifest,\n} from \"@agent-forge/plugin-sdk\";\nimport * as pluginSdkSessionLineage from \"@agent-forge/plugin-sdk/session-lineage\";\nimport * as protocolSubagent from \"@agent-forge/protocol/subagent\";\nimport { createJiti } from \"jiti/static\";\nimport * as typebox from \"typebox\";\nimport * as typeboxValue from \"typebox/value\";\n// Same undici copy the http-dispatcher already bundles: plugin packages\n// declare it pinned but installed tarballs carry no node_modules, so the\n// image-generation plugin's proxy-aware fetch resolves to this namespace.\nimport * as undici from \"undici\";\nimport type { CapabilityRuntime } from \"./capability-runtime.ts\";\nimport {\n\tPLUGIN_DISPOSE_EVENT_ID,\n\tPLUGIN_DISPOSE_EVENT_VERSION,\n\tPLUGIN_READY_EVENT_ID,\n\tPLUGIN_READY_EVENT_VERSION,\n\ttype PluginDisposeEventDataV1,\n} from \"./lifecycle-catalog.ts\";\nimport type { CapabilityAPI, PluginConfig, PluginManifest } from \"./public-api.ts\";\n\n// Authoring-surface symbols moved to @agent-forge/plugin-sdk (D-075 S2);\n// re-exported here so existing host imports keep resolving.\nexport type {\n\tCapabilityPluginFactory,\n\tCapabilityPluginFactoryResult,\n\tCapabilityPluginInstance,\n\tCapabilityPluginSyncFactory,\n\tCapabilityPluginSyncInstance,\n} from \"@agent-forge/plugin-sdk\";\nexport { parseCapabilityPluginManifest } from \"@agent-forge/plugin-sdk\";\n\nexport interface CapabilityPluginHandle {\n\treadonly manifest: PluginManifest;\n\treadonly api: CapabilityAPI;\n\t/** Resolves once the plugin.ready lifecycle delivery has settled. */\n\treadonly ready: Promise<void>;\n\tdispose(): Promise<void>;\n}\n\nconst activePlugins = new WeakMap<CapabilityRuntime, Map<string, symbol>>();\n\n// Host-resolved heavy-dependency aliases (D-075 S4 fourth batch, installed-\n// code-loading): the memory plugin package carries its vector stack pinned in\n// its own package.json, but an npm-installed tarball ships no node_modules —\n// the same void the SDK/protocol virtual modules below fill. Unlike those,\n// lancedb/transformers are NATIVE/lazy packages the host must not bundle or\n// import here: they stay host dependencies, and each specifier is resolved\n// ONCE (module-level cache, successes only) to the host's own entry file\n// path and handed to jiti as an alias. The alias reliably intercepts only\n// STATIC imports on the entry chain of files jiti transforms — lazy\n// `await import()` calls inside an installed ESM dist bypass the transform\n// pipeline and hit the native resolver, so those lazy paths are supplied by\n// the hostDependencyPaths absolute-path channel instead (hostDependencyPaths-\n// Config below plus the plugin-side host-module-import). Resolution failures\n// are tolerated on both channels: the alias table is a best-effort supply\n// path, and heavy-dependency failures must surface at the plugin's point of\n// use, where the memory plugin reports structured failures with an action\n// list.\nconst hostHeavyDependencyAliases: ReadonlySet<string> = new Set([\n\t\"@lancedb/lancedb\",\n\t\"@huggingface/transformers\",\n\t// memory 的 onnxruntime 预检(nativeBinaryCheck)在插件内直接 resolve 该传递\n\t// 依赖;安装店副本无 node_modules,必须与 transformers 同走宿主 alias 通道。\n\t\"onnxruntime-node\",\n]);\n\nconst resolvedHeavyDependencyAliases: Map<string, string> = new Map();\n\n/**\n * Explicit injection object for {@link buildHostDependencyAliases}. Both fields\n * are required on purpose: with optional positional parameters a test could\n * inject only `resolve` and silently write its fake results into the\n * module-level production cache (`resolvedHeavyDependencyAliases`), hijacking\n * every later real plugin load in the same vitest worker. Making the object\n * mandatory means a test cannot supply a resolver without also supplying the\n * cache it pollutes.\n */\nexport interface HostDependencyAliasResolution {\n\treadonly resolve: (specifier: string) => string;\n\treadonly cache: Map<string, string>;\n}\n\nconst defaultHostDependencyAliasResolution: HostDependencyAliasResolution = {\n\tresolve: (specifier) => createRequire(import.meta.url).resolve(specifier),\n\tcache: resolvedHeavyDependencyAliases,\n};\n\n/**\n * Tolerant heavy-dependency resolution shared by the jiti alias channel and\n * the hostDependencyPaths config channel: each specifier is resolved against\n * the host installation (successes cached module-level), and a specifier that\n * fails to resolve is simply absent from the result. The alias table is a\n * best-effort supply path — heavy-dependency failures must surface at the\n * plugin's point of use, where the memory plugin reports structured failures\n * with an action list. Exported for deterministic tests; production callers\n * pass {@link defaultHostDependencyAliasResolution} explicitly.\n */\nexport function buildHostDependencyAliases(\n\tspecifiers: ReadonlySet<string> | readonly string[],\n\tresolution: HostDependencyAliasResolution,\n): Record<string, string> {\n\tconst aliases: Record<string, string> = {};\n\tfor (const specifier of specifiers) {\n\t\tconst cached = resolution.cache.get(specifier);\n\t\tif (cached !== undefined) {\n\t\t\taliases[specifier] = cached;\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst resolved = resolution.resolve(specifier);\n\t\t\tresolution.cache.set(specifier, resolved);\n\t\t\taliases[specifier] = resolved;\n\t\t} catch {\n\t\t\t// Tolerant by contract: absent entry = plugin-side fallback.\n\t\t}\n\t}\n\treturn aliases;\n}\n\n/**\n * Host-resolved heavy-dependency entry paths (specifier → absolute path) for\n * the config channel that feeds the lazy `await import()` paths the jiti\n * alias channel cannot reach (installed ESM dists bypass the transform\n * pipeline). Tolerant like the alias table: a specifier the host installation\n * cannot resolve is simply absent, and plugin code falls back to its own\n * resolution (or reports the structured failure). camelCase keys keep the\n * JSON config channel idiomatic for plugin consumers.\n */\nfunction hostDependencyPathsConfig(): Record<string, string> {\n\tconst paths: Record<string, string> = {};\n\tfor (const [specifier, entryPath] of Object.entries(\n\t\tbuildHostDependencyAliases(hostHeavyDependencyAliases, defaultHostDependencyAliasResolution),\n\t)) {\n\t\tpaths[camelCaseDependencyKey(specifier)] = entryPath;\n\t}\n\treturn paths;\n}\n\nfunction camelCaseDependencyKey(specifier: string): string {\n\tconst scoped = specifier.replace(/^@[^/]+\\//, \"\");\n\treturn scoped.replace(/[-.](.)/g, (_, character: string) => character.toUpperCase());\n}\n\nfunction isPluginInstance(value: unknown): value is CapabilityPluginInstance {\n\treturn typeof value === \"object\" && value !== null && typeof (value as { dispose?: unknown }).dispose === \"function\";\n}\n\nfunction normalizePluginInstance(value: unknown, manifest: PluginManifest): CapabilityPluginInstance | undefined {\n\tif (value === undefined) return undefined;\n\tif (!isPluginInstance(value)) {\n\t\tthrow new Error(`Capability plugin factory must return void or an instance with dispose(): ${manifest.id}`);\n\t}\n\treturn value;\n}\n\nfunction normalizePluginSyncInstance(\n\tvalue: unknown,\n\tmanifest: PluginManifest,\n): CapabilityPluginSyncInstance | undefined {\n\tif (value === undefined) return undefined;\n\tif (!isPluginInstance(value)) {\n\t\tthrow new Error(\n\t\t\t`Synchronous capability plugin factory must return void or an instance with dispose(): ${manifest.id}`,\n\t\t);\n\t}\n\treturn value as CapabilityPluginSyncInstance;\n}\n\nfunction throwCleanupErrors(errors: unknown[], manifestId: string): void {\n\tif (errors.length === 0) return;\n\tif (errors.length === 1) throw errors[0];\n\tthrow new AggregateError(errors, `Capability plugin cleanup failed: ${manifestId}`);\n}\n\nasync function dispatchPluginDisposeEvent(\n\truntime: CapabilityRuntime,\n\tmanifest: PluginManifest,\n\tstatus: PluginDisposeEventDataV1[\"status\"],\n): Promise<void> {\n\tif (!runtime.hasLifecycleEvent(PLUGIN_DISPOSE_EVENT_ID, PLUGIN_DISPOSE_EVENT_VERSION)) return;\n\tawait runtime.dispatchLifecycle({\n\t\ttype: PLUGIN_DISPOSE_EVENT_ID,\n\t\tversion: PLUGIN_DISPOSE_EVENT_VERSION,\n\t\tphase: \"committed\",\n\t\tdata: {\n\t\t\tversion: 1,\n\t\t\tpluginId: manifest.id,\n\t\t\tpluginVersion: manifest.version,\n\t\t\tstatus,\n\t\t},\n\t\tsource: \"capability-plugin\",\n\t});\n}\n\nasync function dispatchPluginReadyEvent(runtime: CapabilityRuntime, manifest: PluginManifest): Promise<void> {\n\tif (!runtime.hasLifecycleEvent(PLUGIN_READY_EVENT_ID, PLUGIN_READY_EVENT_VERSION)) return;\n\tawait runtime.dispatchLifecycle({\n\t\ttype: PLUGIN_READY_EVENT_ID,\n\t\tversion: PLUGIN_READY_EVENT_VERSION,\n\t\tphase: \"committed\",\n\t\tdata: {\n\t\t\tversion: 1,\n\t\t\tpluginId: manifest.id,\n\t\t\tpluginVersion: manifest.version,\n\t\t},\n\t\tsource: \"capability-plugin\",\n\t});\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nfunction compareNames(left: string, right: string): number {\n\treturn left < right ? -1 : left > right ? 1 : 0;\n}\n\n/**\n * Find installed capability manifests below the given plugin directories.\n *\n * Directories are visited in caller order; entries in each directory use a\n * stable lexical order. Missing roots are normal for a first-run host.\n * Existing unreadable or malformed filesystem paths fail explicitly rather\n * than silently changing the loaded plugin set. Dependency and hidden\n * directories are never traversed.\n */\nexport function discoverCapabilityPluginManifests(pluginDirectories: readonly string[]): string[] {\n\tconst manifests: string[] = [];\n\tconst seenDirectories = new Set<string>();\n\tconst seenManifests = new Set<string>();\n\n\tconst visit = (directory: string, optional: boolean): void => {\n\t\tconst resolvedDirectory = path.resolve(directory);\n\t\tlet stats: ReturnType<typeof statSync>;\n\t\ttry {\n\t\t\tstats = statSync(resolvedDirectory);\n\t\t} catch (error) {\n\t\t\tif (optional && isMissingPathError(error)) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!lstatSync(resolvedDirectory).isSymbolicLink()) return;\n\t\t\t\t} catch (linkError) {\n\t\t\t\t\tif (isMissingPathError(linkError)) return;\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to inspect capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\t\t\tlinkError instanceof Error ? linkError.message : String(linkError)\n\t\t\t\t\t\t}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to inspect capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tif (!stats.isDirectory()) {\n\t\t\tthrow new Error(`Capability plugin path must be a directory: ${resolvedDirectory}`);\n\t\t}\n\n\t\tlet canonicalDirectory: string;\n\t\ttry {\n\t\t\tcanonicalDirectory = realpathSync(resolvedDirectory);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to resolve capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tif (seenDirectories.has(canonicalDirectory)) return;\n\t\tseenDirectories.add(canonicalDirectory);\n\n\t\tlet entries: Dirent<string>[];\n\t\ttry {\n\t\t\tentries = readdirSync(resolvedDirectory, { withFileTypes: true, encoding: \"utf8\" });\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to read capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const entry of entries.sort((left, right) => compareNames(left.name, right.name))) {\n\t\t\tif (entry.name === \"node_modules\" || entry.name.startsWith(\".\")) continue;\n\t\t\tconst entryPath = path.join(resolvedDirectory, entry.name);\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tvisit(entryPath, false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!entry.isFile() || entry.name !== \"plugin.json\") continue;\n\n\t\t\tlet canonicalManifest: string;\n\t\t\ttry {\n\t\t\t\tcanonicalManifest = realpathSync(entryPath);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to resolve capability plugin manifest ${entryPath}: ${\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (seenManifests.has(canonicalManifest)) continue;\n\t\t\tseenManifests.add(canonicalManifest);\n\t\t\tmanifests.push(canonicalManifest);\n\t\t}\n\t};\n\n\tfor (const pluginDirectory of pluginDirectories) visit(pluginDirectory, true);\n\treturn manifests;\n}\n\n/**\n * Load a capability plugin through the public facade only.\n * Filesystem discovery and package installation stay outside this mechanism.\n */\nexport async function loadCapabilityPlugin(\n\truntime: CapabilityRuntime,\n\tmanifest: PluginManifest,\n\tfactory: CapabilityPluginFactory,\n): Promise<CapabilityPluginHandle> {\n\tconst active = activePlugins.get(runtime) ?? new Map<string, symbol>();\n\tif (active.has(manifest.id)) throw new Error(`Capability plugin is already loaded: ${manifest.id}`);\n\tconst ownerToken = Symbol(manifest.id);\n\tactive.set(manifest.id, ownerToken);\n\tactivePlugins.set(runtime, active);\n\tlet api: CapabilityAPI | undefined;\n\tlet instance: CapabilityPluginInstance | undefined;\n\tconst cleanup = async (notifyDispose: boolean): Promise<void> => {\n\t\tconst errors: unknown[] = [];\n\t\tif (api) runtime.revokeAPI(api);\n\t\ttry {\n\t\t\tawait runtime.disposePlugin(manifest.id);\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\ttry {\n\t\t\tawait instance?.dispose();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (notifyDispose) {\n\t\t\ttry {\n\t\t\t\tawait dispatchPluginDisposeEvent(runtime, manifest, errors.length === 0 ? \"disposed\" : \"failed\");\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error);\n\t\t\t}\n\t\t}\n\t\tthrowCleanupErrors(errors, manifest.id);\n\t};\n\ttry {\n\t\tapi = runtime.createAPI(manifest);\n\t\tinstance = normalizePluginInstance(await factory(api), manifest);\n\t\tawait dispatchPluginReadyEvent(runtime, manifest);\n\t\tconst pluginApi = api;\n\t\tlet disposePromise: Promise<void> | undefined;\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tapi: pluginApi,\n\t\t\tready: Promise.resolve(),\n\t\t\tdispose: async () => {\n\t\t\t\tdisposePromise ??= (async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait cleanup(true);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t\treturn disposePromise;\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait cleanup(false);\n\t\t} catch (cleanupError) {\n\t\t\tthrow new AggregateError([error, cleanupError], `Capability plugin startup cleanup failed: ${manifest.id}`);\n\t\t} finally {\n\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Load a synchronous embedded plugin during host construction. */\nexport function loadCapabilityPluginSync(\n\truntime: CapabilityRuntime,\n\tmanifest: PluginManifest,\n\tfactory: CapabilityPluginSyncFactory,\n): CapabilityPluginHandle {\n\tconst active = activePlugins.get(runtime) ?? new Map<string, symbol>();\n\tif (active.has(manifest.id)) throw new Error(`Capability plugin is already loaded: ${manifest.id}`);\n\tconst ownerToken = Symbol(manifest.id);\n\tactive.set(manifest.id, ownerToken);\n\tactivePlugins.set(runtime, active);\n\tlet api: CapabilityAPI | undefined;\n\tlet instance: CapabilityPluginSyncInstance | undefined;\n\tconst cleanupRegistrationsSync = (): unknown[] => {\n\t\tconst errors: unknown[] = [];\n\t\tif (api) runtime.revokeAPI(api);\n\t\ttry {\n\t\t\truntime.disposePluginSync(manifest.id);\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\treturn errors;\n\t};\n\tconst cleanupSync = async (): Promise<void> => {\n\t\tconst errors = cleanupRegistrationsSync();\n\t\tlet result: unknown;\n\t\ttry {\n\t\t\tresult = instance?.dispose();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (result && typeof (result as PromiseLike<void>).then === \"function\") {\n\t\t\tconst contractError = new Error(\n\t\t\t\t`Synchronous capability plugin disposer must not return a Promise: ${manifest.id}`,\n\t\t\t);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error);\n\t\t\t}\n\t\t\terrors.push(contractError);\n\t\t}\n\t\ttry {\n\t\t\tawait dispatchPluginDisposeEvent(runtime, manifest, errors.length === 0 ? \"disposed\" : \"failed\");\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tthrowCleanupErrors(errors, manifest.id);\n\t};\n\ttry {\n\t\tapi = runtime.createAPI(manifest);\n\t\tinstance = normalizePluginSyncInstance(factory(api), manifest);\n\t} catch (error) {\n\t\ttry {\n\t\t\tthrowCleanupErrors(cleanupRegistrationsSync(), manifest.id);\n\t\t} catch (cleanupError) {\n\t\t\tthrow new AggregateError([error, cleanupError], `Capability plugin startup cleanup failed: ${manifest.id}`);\n\t\t} finally {\n\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t}\n\t\tthrow error;\n\t}\n\tconst ready = dispatchPluginReadyEvent(runtime, manifest);\n\t// The embedded constructor API is synchronous; retain a handled promise so\n\t// hosts may explicitly await lifecycle delivery without risking an unhandled rejection.\n\tvoid ready.catch(() => undefined);\n\tlet disposePromise: Promise<void> | undefined;\n\treturn {\n\t\tmanifest,\n\t\tapi: api!,\n\t\tready,\n\t\tdispose: async () => {\n\t\t\tdisposePromise ??= (async () => {\n\t\t\t\tlet readyError: unknown;\n\t\t\t\ttry {\n\t\t\t\t\tawait ready;\n\t\t\t\t} catch (error) {\n\t\t\t\t\treadyError = error;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait cleanupSync();\n\t\t\t\t\tif (readyError !== undefined) throw readyError;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (readyError !== undefined && error !== readyError) {\n\t\t\t\t\t\tthrow new AggregateError([readyError, error], `Capability plugin cleanup failed: ${manifest.id}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t} finally {\n\t\t\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t\t\t}\n\t\t\t})();\n\t\t\treturn disposePromise;\n\t\t},\n\t};\n}\n\n/**\n * Load a plugin from its JSON manifest. This is intentionally separate from\n * legacy extension discovery until both systems share the same public facade.\n *\n * `options.configOverride` (D-075 S4 third batch) merges host-declared values\n * over the manifest's own `config` defaults before the plugin API is built —\n * a public channel (first-party and third-party plugins alike) for hosts that\n * vouch for facts the manifest cannot know, e.g. the CLI declaring its own\n * process entry trustworthy so the subagent-delegate package auto-pools. It\n * stays below any plugin-side config channel: the agent-dir config file the\n * plugin entry reads merges over whatever the host injected here.\n */\nexport async function loadCapabilityPluginFromManifest(\n\truntime: CapabilityRuntime,\n\tmanifestPath: string,\n\toptions?: { readonly configOverride?: PluginConfig },\n): Promise<CapabilityPluginHandle> {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(await readFile(manifestPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to read capability plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tconst parsed = parseCapabilityPluginManifest(raw, manifestPath);\n\t// hostDependencyPaths (安装店重依赖可见性): 宿主已解析的重依赖入口绝对路径\n\t// 并进 manifest config——安装店副本无 node_modules, 插件内 createRequire 自\n\t// 解析不可达 (memory 的 onnxruntime native 预检实证); 与 jiti alias 通道互补\n\t// (alias 拦截 import, 本通道喂插件内的路径式消费)。公共同道: 第一方与第三方\n\t// 插件同样可读。仍低于插件侧 config 文件通道 (agent-dir 配置合并在其上)。\n\tconst hostDependencyOverride = { hostDependencyPaths: hostDependencyPathsConfig() };\n\tconst callerOverride = options?.configOverride;\n\tconst manifest =\n\t\tcallerOverride === undefined || Object.keys(callerOverride).length === 0\n\t\t\t? { ...parsed, config: { ...parsed.config, ...hostDependencyOverride } }\n\t\t\t: { ...parsed, config: { ...parsed.config, ...hostDependencyOverride, ...callerOverride } };\n\tconst entryPath = path.resolve(path.dirname(manifestPath), manifest.entry);\n\t// Host-resolved authoring dependencies (D-075 §4.1): installed plugin\n\t// packages live in the install store, which carries no node_modules (npm\n\t// tarballs never include dependencies), so their bare imports of the SDK\n\t// and the pinned typebox dependency resolve against the host's own copies\n\t// through jiti virtual modules. Works identically in the bundle and Bun\n\t// binaries where no source-tree node_modules exists at all. D-075 S4 third\n\t// batch: the protocol package joins — the subagent-delegate package's\n\t// runtime imports (`@agent-forge/protocol`) resolve the same way. S4 fourth\n\t// batch: the memory package's native vector stack (`@lancedb/lancedb`,\n\t// `@huggingface/transformers`) resolves through the jiti alias channel\n\t// instead — those stay real host node_modules entries, so plugins load the\n\t// host's native builds rather than a virtual copy.\n\tconst jiti = createJiti(import.meta.url, {\n\t\tmoduleCache: false,\n\t\ttsconfigPaths: true,\n\t\talias: buildHostDependencyAliases(hostHeavyDependencyAliases, defaultHostDependencyAliasResolution),\n\t\tvirtualModules: {\n\t\t\t\"@agent-forge/plugin-sdk\": pluginSdk,\n\t\t\t\"@agent-forge/plugin-sdk/session-lineage\": pluginSdkSessionLineage,\n\t\t\t\"@agent-forge/protocol/subagent\": protocolSubagent,\n\t\t\ttypebox,\n\t\t\t\"typebox/value\": typeboxValue,\n\t\t\t// 0.85.13 regression fix (0.85.14): the image-generation plugin's\n\t\t\t// undici dependency (EnvHttpProxyAgent proxy support) resolved to\n\t\t\t// nowhere in the install-store shape and the plugin failed to load\n\t\t\t// (\"Cannot find module 'undici'\"). Virtual module = the host's own\n\t\t\t// copy, identical in the bundle and Bun binary forms; red-verified\n\t\t\t// by test/plugin-virtual-undici.test.ts.\n\t\t\tundici,\n\t\t},\n\t});\n\tlet factory: unknown;\n\ttry {\n\t\tfactory = await jiti.import(entryPath, { default: true });\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to import capability plugin entry ${entryPath}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tif (typeof factory !== \"function\") {\n\t\tthrow new Error(`Capability plugin entry must default-export a factory function: ${entryPath}`);\n\t}\n\treturn loadCapabilityPlugin(runtime, manifest, factory as CapabilityPluginFactory);\n}\n"]}
|
|
1
|
+
{"version":3,"file":"capability-plugin.d.ts","sourceRoot":"","sources":["../../../src/core/extensions/capability-plugin.ts"],"names":[],"mappings":"AAKA,OAAO,EACN,KAAK,uBAAuB,EAE5B,KAAK,2BAA2B,EAGhC,MAAM,yBAAyB,CAAC;AAIjC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAQjE,OAAO,KAAK,EAAE,aAAa,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAInF,YAAY,EACX,uBAAuB,EACvB,6BAA6B,EAC7B,wBAAwB,EACxB,2BAA2B,EAC3B,4BAA4B,GAC5B,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,6BAA6B,EAAE,MAAM,yBAAyB,CAAC;AAExE,MAAM,WAAW,sBAAsB;IACtC,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,aAAa,CAAC;IAC5B,qEAAqE;IACrE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9B,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;CACzB;AAmDD;;;;;;;;GAQG;AACH,MAAM,WAAW,6BAA6B;IAC7C,QAAQ,CAAC,OAAO,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,MAAM,CAAC;IAChD,QAAQ,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACpC;AAOD;;;;;;;;;GASG;AACH,wBAAgB,0BAA0B,CACzC,UAAU,EAAE,WAAW,CAAC,MAAM,CAAC,GAAG,SAAS,MAAM,EAAE,EACnD,UAAU,EAAE,6BAA6B,GACvC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAiBxB;AAoGD;;;;;;;;GAQG;AACH,wBAAgB,iCAAiC,CAAC,iBAAiB,EAAE,SAAS,MAAM,EAAE,GAAG,MAAM,EAAE,CAoFhG;AAED;;;GAGG;AACH,wBAAsB,oBAAoB,CACzC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,uBAAuB,GAC9B,OAAO,CAAC,sBAAsB,CAAC,CA6DjC;AAED,mEAAmE;AACnE,wBAAgB,wBAAwB,CACvC,OAAO,EAAE,iBAAiB,EAC1B,QAAQ,EAAE,cAAc,EACxB,OAAO,EAAE,2BAA2B,GAClC,sBAAsB,CAyFxB;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,gCAAgC,CACrD,OAAO,EAAE,iBAAiB,EAC1B,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE;IAAE,QAAQ,CAAC,cAAc,CAAC,EAAE,YAAY,CAAA;CAAE,GAClD,OAAO,CAAC,sBAAsB,CAAC,CAsDjC","sourcesContent":["import type { Dirent } from \"node:fs\";\nimport { lstatSync, readdirSync, realpathSync, statSync } from \"node:fs\";\nimport { readFile } from \"node:fs/promises\";\nimport { createRequire } from \"node:module\";\nimport * as path from \"node:path\";\nimport {\n\ttype CapabilityPluginFactory,\n\ttype CapabilityPluginInstance,\n\ttype CapabilityPluginSyncFactory,\n\ttype CapabilityPluginSyncInstance,\n\tparseCapabilityPluginManifest,\n} from \"@agent-forge/plugin-sdk\";\n// Type-only: the runtime dependency stays deferred until the first plugin\n// load (getCreateJiti below).\nimport type { createJiti } from \"jiti/static\";\nimport type { CapabilityRuntime } from \"./capability-runtime.ts\";\nimport {\n\tPLUGIN_DISPOSE_EVENT_ID,\n\tPLUGIN_DISPOSE_EVENT_VERSION,\n\tPLUGIN_READY_EVENT_ID,\n\tPLUGIN_READY_EVENT_VERSION,\n\ttype PluginDisposeEventDataV1,\n} from \"./lifecycle-catalog.ts\";\nimport type { CapabilityAPI, PluginConfig, PluginManifest } from \"./public-api.ts\";\n\n// Authoring-surface symbols moved to @agent-forge/plugin-sdk (D-075 S2);\n// re-exported here so existing host imports keep resolving.\nexport type {\n\tCapabilityPluginFactory,\n\tCapabilityPluginFactoryResult,\n\tCapabilityPluginInstance,\n\tCapabilityPluginSyncFactory,\n\tCapabilityPluginSyncInstance,\n} from \"@agent-forge/plugin-sdk\";\nexport { parseCapabilityPluginManifest } from \"@agent-forge/plugin-sdk\";\n\nexport interface CapabilityPluginHandle {\n\treadonly manifest: PluginManifest;\n\treadonly api: CapabilityAPI;\n\t/** Resolves once the plugin.ready lifecycle delivery has settled. */\n\treadonly ready: Promise<void>;\n\tdispose(): Promise<void>;\n}\n\nconst activePlugins = new WeakMap<CapabilityRuntime, Map<string, symbol>>();\n\n// Upstream pi 40c256ccc parity: importing this module sits on every startup\n// path, so the jiti transform pipeline (Babel included) and the bundled\n// virtual modules stay deferred until the first plugin actually loads. The\n// dynamic imports below are deliberate lazy-load points; the thin\n// jiti-static-loader entry keeps jiti/static statically reachable for the\n// Bun and Node bundlers that must embed it.\nlet createJitiPromise: Promise<typeof createJiti> | undefined;\n\nfunction getCreateJiti(): Promise<typeof createJiti> {\n\tcreateJitiPromise ??= import(\"./jiti-static-loader.ts\").then((module) => module.createJiti);\n\treturn createJitiPromise;\n}\n\nlet virtualModulesPromise: Promise<Record<string, unknown>> | undefined;\n\nfunction getVirtualModules(): Promise<Record<string, unknown>> {\n\tvirtualModulesPromise ??= import(\"./virtual-modules.ts\").then((module) => module.VIRTUAL_MODULES);\n\treturn virtualModulesPromise;\n}\n\n// Host-resolved heavy-dependency aliases (D-075 S4 fourth batch, installed-\n// code-loading): the memory plugin package carries its vector stack pinned in\n// its own package.json, but an npm-installed tarball ships no node_modules —\n// the same void the SDK/protocol virtual modules below fill. Unlike those,\n// lancedb/transformers are NATIVE/lazy packages the host must not bundle or\n// import here: they stay host dependencies, and each specifier is resolved\n// ONCE (module-level cache, successes only) to the host's own entry file\n// path and handed to jiti as an alias. The alias reliably intercepts only\n// STATIC imports on the entry chain of files jiti transforms — lazy\n// `await import()` calls inside an installed ESM dist bypass the transform\n// pipeline and hit the native resolver, so those lazy paths are supplied by\n// the hostDependencyPaths absolute-path channel instead (hostDependencyPaths-\n// Config below plus the plugin-side host-module-import). Resolution failures\n// are tolerated on both channels: the alias table is a best-effort supply\n// path, and heavy-dependency failures must surface at the plugin's point of\n// use, where the memory plugin reports structured failures with an action\n// list.\nconst hostHeavyDependencyAliases: ReadonlySet<string> = new Set([\n\t\"@lancedb/lancedb\",\n\t\"@huggingface/transformers\",\n\t// memory 的 onnxruntime 预检(nativeBinaryCheck)在插件内直接 resolve 该传递\n\t// 依赖;安装店副本无 node_modules,必须与 transformers 同走宿主 alias 通道。\n\t\"onnxruntime-node\",\n]);\n\nconst resolvedHeavyDependencyAliases: Map<string, string> = new Map();\n\n/**\n * Explicit injection object for {@link buildHostDependencyAliases}. Both fields\n * are required on purpose: with optional positional parameters a test could\n * inject only `resolve` and silently write its fake results into the\n * module-level production cache (`resolvedHeavyDependencyAliases`), hijacking\n * every later real plugin load in the same vitest worker. Making the object\n * mandatory means a test cannot supply a resolver without also supplying the\n * cache it pollutes.\n */\nexport interface HostDependencyAliasResolution {\n\treadonly resolve: (specifier: string) => string;\n\treadonly cache: Map<string, string>;\n}\n\nconst defaultHostDependencyAliasResolution: HostDependencyAliasResolution = {\n\tresolve: (specifier) => createRequire(import.meta.url).resolve(specifier),\n\tcache: resolvedHeavyDependencyAliases,\n};\n\n/**\n * Tolerant heavy-dependency resolution shared by the jiti alias channel and\n * the hostDependencyPaths config channel: each specifier is resolved against\n * the host installation (successes cached module-level), and a specifier that\n * fails to resolve is simply absent from the result. The alias table is a\n * best-effort supply path — heavy-dependency failures must surface at the\n * plugin's point of use, where the memory plugin reports structured failures\n * with an action list. Exported for deterministic tests; production callers\n * pass {@link defaultHostDependencyAliasResolution} explicitly.\n */\nexport function buildHostDependencyAliases(\n\tspecifiers: ReadonlySet<string> | readonly string[],\n\tresolution: HostDependencyAliasResolution,\n): Record<string, string> {\n\tconst aliases: Record<string, string> = {};\n\tfor (const specifier of specifiers) {\n\t\tconst cached = resolution.cache.get(specifier);\n\t\tif (cached !== undefined) {\n\t\t\taliases[specifier] = cached;\n\t\t\tcontinue;\n\t\t}\n\t\ttry {\n\t\t\tconst resolved = resolution.resolve(specifier);\n\t\t\tresolution.cache.set(specifier, resolved);\n\t\t\taliases[specifier] = resolved;\n\t\t} catch {\n\t\t\t// Tolerant by contract: absent entry = plugin-side fallback.\n\t\t}\n\t}\n\treturn aliases;\n}\n\n/**\n * Host-resolved heavy-dependency entry paths (specifier → absolute path) for\n * the config channel that feeds the lazy `await import()` paths the jiti\n * alias channel cannot reach (installed ESM dists bypass the transform\n * pipeline). Tolerant like the alias table: a specifier the host installation\n * cannot resolve is simply absent, and plugin code falls back to its own\n * resolution (or reports the structured failure). camelCase keys keep the\n * JSON config channel idiomatic for plugin consumers.\n */\nfunction hostDependencyPathsConfig(): Record<string, string> {\n\tconst paths: Record<string, string> = {};\n\tfor (const [specifier, entryPath] of Object.entries(\n\t\tbuildHostDependencyAliases(hostHeavyDependencyAliases, defaultHostDependencyAliasResolution),\n\t)) {\n\t\tpaths[camelCaseDependencyKey(specifier)] = entryPath;\n\t}\n\treturn paths;\n}\n\nfunction camelCaseDependencyKey(specifier: string): string {\n\tconst scoped = specifier.replace(/^@[^/]+\\//, \"\");\n\treturn scoped.replace(/[-.](.)/g, (_, character: string) => character.toUpperCase());\n}\n\nfunction isPluginInstance(value: unknown): value is CapabilityPluginInstance {\n\treturn typeof value === \"object\" && value !== null && typeof (value as { dispose?: unknown }).dispose === \"function\";\n}\n\nfunction normalizePluginInstance(value: unknown, manifest: PluginManifest): CapabilityPluginInstance | undefined {\n\tif (value === undefined) return undefined;\n\tif (!isPluginInstance(value)) {\n\t\tthrow new Error(`Capability plugin factory must return void or an instance with dispose(): ${manifest.id}`);\n\t}\n\treturn value;\n}\n\nfunction normalizePluginSyncInstance(\n\tvalue: unknown,\n\tmanifest: PluginManifest,\n): CapabilityPluginSyncInstance | undefined {\n\tif (value === undefined) return undefined;\n\tif (!isPluginInstance(value)) {\n\t\tthrow new Error(\n\t\t\t`Synchronous capability plugin factory must return void or an instance with dispose(): ${manifest.id}`,\n\t\t);\n\t}\n\treturn value as CapabilityPluginSyncInstance;\n}\n\nfunction throwCleanupErrors(errors: unknown[], manifestId: string): void {\n\tif (errors.length === 0) return;\n\tif (errors.length === 1) throw errors[0];\n\tthrow new AggregateError(errors, `Capability plugin cleanup failed: ${manifestId}`);\n}\n\nasync function dispatchPluginDisposeEvent(\n\truntime: CapabilityRuntime,\n\tmanifest: PluginManifest,\n\tstatus: PluginDisposeEventDataV1[\"status\"],\n): Promise<void> {\n\tif (!runtime.hasLifecycleEvent(PLUGIN_DISPOSE_EVENT_ID, PLUGIN_DISPOSE_EVENT_VERSION)) return;\n\tawait runtime.dispatchLifecycle({\n\t\ttype: PLUGIN_DISPOSE_EVENT_ID,\n\t\tversion: PLUGIN_DISPOSE_EVENT_VERSION,\n\t\tphase: \"committed\",\n\t\tdata: {\n\t\t\tversion: 1,\n\t\t\tpluginId: manifest.id,\n\t\t\tpluginVersion: manifest.version,\n\t\t\tstatus,\n\t\t},\n\t\tsource: \"capability-plugin\",\n\t});\n}\n\nasync function dispatchPluginReadyEvent(runtime: CapabilityRuntime, manifest: PluginManifest): Promise<void> {\n\tif (!runtime.hasLifecycleEvent(PLUGIN_READY_EVENT_ID, PLUGIN_READY_EVENT_VERSION)) return;\n\tawait runtime.dispatchLifecycle({\n\t\ttype: PLUGIN_READY_EVENT_ID,\n\t\tversion: PLUGIN_READY_EVENT_VERSION,\n\t\tphase: \"committed\",\n\t\tdata: {\n\t\t\tversion: 1,\n\t\t\tpluginId: manifest.id,\n\t\t\tpluginVersion: manifest.version,\n\t\t},\n\t\tsource: \"capability-plugin\",\n\t});\n}\n\nfunction isMissingPathError(error: unknown): boolean {\n\treturn typeof error === \"object\" && error !== null && \"code\" in error && error.code === \"ENOENT\";\n}\n\nfunction compareNames(left: string, right: string): number {\n\treturn left < right ? -1 : left > right ? 1 : 0;\n}\n\n/**\n * Find installed capability manifests below the given plugin directories.\n *\n * Directories are visited in caller order; entries in each directory use a\n * stable lexical order. Missing roots are normal for a first-run host.\n * Existing unreadable or malformed filesystem paths fail explicitly rather\n * than silently changing the loaded plugin set. Dependency and hidden\n * directories are never traversed.\n */\nexport function discoverCapabilityPluginManifests(pluginDirectories: readonly string[]): string[] {\n\tconst manifests: string[] = [];\n\tconst seenDirectories = new Set<string>();\n\tconst seenManifests = new Set<string>();\n\n\tconst visit = (directory: string, optional: boolean): void => {\n\t\tconst resolvedDirectory = path.resolve(directory);\n\t\tlet stats: ReturnType<typeof statSync>;\n\t\ttry {\n\t\t\tstats = statSync(resolvedDirectory);\n\t\t} catch (error) {\n\t\t\tif (optional && isMissingPathError(error)) {\n\t\t\t\ttry {\n\t\t\t\t\tif (!lstatSync(resolvedDirectory).isSymbolicLink()) return;\n\t\t\t\t} catch (linkError) {\n\t\t\t\t\tif (isMissingPathError(linkError)) return;\n\t\t\t\t\tthrow new Error(\n\t\t\t\t\t\t`Failed to inspect capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\t\t\tlinkError instanceof Error ? linkError.message : String(linkError)\n\t\t\t\t\t\t}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t}\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to inspect capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tif (!stats.isDirectory()) {\n\t\t\tthrow new Error(`Capability plugin path must be a directory: ${resolvedDirectory}`);\n\t\t}\n\n\t\tlet canonicalDirectory: string;\n\t\ttry {\n\t\t\tcanonicalDirectory = realpathSync(resolvedDirectory);\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to resolve capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\t\tif (seenDirectories.has(canonicalDirectory)) return;\n\t\tseenDirectories.add(canonicalDirectory);\n\n\t\tlet entries: Dirent<string>[];\n\t\ttry {\n\t\t\tentries = readdirSync(resolvedDirectory, { withFileTypes: true, encoding: \"utf8\" });\n\t\t} catch (error) {\n\t\t\tthrow new Error(\n\t\t\t\t`Failed to read capability plugin directory ${resolvedDirectory}: ${\n\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t}`,\n\t\t\t);\n\t\t}\n\n\t\tfor (const entry of entries.sort((left, right) => compareNames(left.name, right.name))) {\n\t\t\tif (entry.name === \"node_modules\" || entry.name.startsWith(\".\")) continue;\n\t\t\tconst entryPath = path.join(resolvedDirectory, entry.name);\n\t\t\tif (entry.isDirectory()) {\n\t\t\t\tvisit(entryPath, false);\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tif (!entry.isFile() || entry.name !== \"plugin.json\") continue;\n\n\t\t\tlet canonicalManifest: string;\n\t\t\ttry {\n\t\t\t\tcanonicalManifest = realpathSync(entryPath);\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(\n\t\t\t\t\t`Failed to resolve capability plugin manifest ${entryPath}: ${\n\t\t\t\t\t\terror instanceof Error ? error.message : String(error)\n\t\t\t\t\t}`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tif (seenManifests.has(canonicalManifest)) continue;\n\t\t\tseenManifests.add(canonicalManifest);\n\t\t\tmanifests.push(canonicalManifest);\n\t\t}\n\t};\n\n\tfor (const pluginDirectory of pluginDirectories) visit(pluginDirectory, true);\n\treturn manifests;\n}\n\n/**\n * Load a capability plugin through the public facade only.\n * Filesystem discovery and package installation stay outside this mechanism.\n */\nexport async function loadCapabilityPlugin(\n\truntime: CapabilityRuntime,\n\tmanifest: PluginManifest,\n\tfactory: CapabilityPluginFactory,\n): Promise<CapabilityPluginHandle> {\n\tconst active = activePlugins.get(runtime) ?? new Map<string, symbol>();\n\tif (active.has(manifest.id)) throw new Error(`Capability plugin is already loaded: ${manifest.id}`);\n\tconst ownerToken = Symbol(manifest.id);\n\tactive.set(manifest.id, ownerToken);\n\tactivePlugins.set(runtime, active);\n\tlet api: CapabilityAPI | undefined;\n\tlet instance: CapabilityPluginInstance | undefined;\n\tconst cleanup = async (notifyDispose: boolean): Promise<void> => {\n\t\tconst errors: unknown[] = [];\n\t\tif (api) runtime.revokeAPI(api);\n\t\ttry {\n\t\t\tawait runtime.disposePlugin(manifest.id);\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\ttry {\n\t\t\tawait instance?.dispose();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (notifyDispose) {\n\t\t\ttry {\n\t\t\t\tawait dispatchPluginDisposeEvent(runtime, manifest, errors.length === 0 ? \"disposed\" : \"failed\");\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error);\n\t\t\t}\n\t\t}\n\t\tthrowCleanupErrors(errors, manifest.id);\n\t};\n\ttry {\n\t\tapi = runtime.createAPI(manifest);\n\t\tinstance = normalizePluginInstance(await factory(api), manifest);\n\t\tawait dispatchPluginReadyEvent(runtime, manifest);\n\t\tconst pluginApi = api;\n\t\tlet disposePromise: Promise<void> | undefined;\n\t\treturn {\n\t\t\tmanifest,\n\t\t\tapi: pluginApi,\n\t\t\tready: Promise.resolve(),\n\t\t\tdispose: async () => {\n\t\t\t\tdisposePromise ??= (async () => {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tawait cleanup(true);\n\t\t\t\t\t} finally {\n\t\t\t\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t\t\t\t}\n\t\t\t\t})();\n\t\t\t\treturn disposePromise;\n\t\t\t},\n\t\t};\n\t} catch (error) {\n\t\ttry {\n\t\t\tawait cleanup(false);\n\t\t} catch (cleanupError) {\n\t\t\tthrow new AggregateError([error, cleanupError], `Capability plugin startup cleanup failed: ${manifest.id}`);\n\t\t} finally {\n\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t}\n\t\tthrow error;\n\t}\n}\n\n/** Load a synchronous embedded plugin during host construction. */\nexport function loadCapabilityPluginSync(\n\truntime: CapabilityRuntime,\n\tmanifest: PluginManifest,\n\tfactory: CapabilityPluginSyncFactory,\n): CapabilityPluginHandle {\n\tconst active = activePlugins.get(runtime) ?? new Map<string, symbol>();\n\tif (active.has(manifest.id)) throw new Error(`Capability plugin is already loaded: ${manifest.id}`);\n\tconst ownerToken = Symbol(manifest.id);\n\tactive.set(manifest.id, ownerToken);\n\tactivePlugins.set(runtime, active);\n\tlet api: CapabilityAPI | undefined;\n\tlet instance: CapabilityPluginSyncInstance | undefined;\n\tconst cleanupRegistrationsSync = (): unknown[] => {\n\t\tconst errors: unknown[] = [];\n\t\tif (api) runtime.revokeAPI(api);\n\t\ttry {\n\t\t\truntime.disposePluginSync(manifest.id);\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\treturn errors;\n\t};\n\tconst cleanupSync = async (): Promise<void> => {\n\t\tconst errors = cleanupRegistrationsSync();\n\t\tlet result: unknown;\n\t\ttry {\n\t\t\tresult = instance?.dispose();\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tif (result && typeof (result as PromiseLike<void>).then === \"function\") {\n\t\t\tconst contractError = new Error(\n\t\t\t\t`Synchronous capability plugin disposer must not return a Promise: ${manifest.id}`,\n\t\t\t);\n\t\t\ttry {\n\t\t\t\tawait result;\n\t\t\t} catch (error) {\n\t\t\t\terrors.push(error);\n\t\t\t}\n\t\t\terrors.push(contractError);\n\t\t}\n\t\ttry {\n\t\t\tawait dispatchPluginDisposeEvent(runtime, manifest, errors.length === 0 ? \"disposed\" : \"failed\");\n\t\t} catch (error) {\n\t\t\terrors.push(error);\n\t\t}\n\t\tthrowCleanupErrors(errors, manifest.id);\n\t};\n\ttry {\n\t\tapi = runtime.createAPI(manifest);\n\t\tinstance = normalizePluginSyncInstance(factory(api), manifest);\n\t} catch (error) {\n\t\ttry {\n\t\t\tthrowCleanupErrors(cleanupRegistrationsSync(), manifest.id);\n\t\t} catch (cleanupError) {\n\t\t\tthrow new AggregateError([error, cleanupError], `Capability plugin startup cleanup failed: ${manifest.id}`);\n\t\t} finally {\n\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t}\n\t\tthrow error;\n\t}\n\tconst ready = dispatchPluginReadyEvent(runtime, manifest);\n\t// The embedded constructor API is synchronous; retain a handled promise so\n\t// hosts may explicitly await lifecycle delivery without risking an unhandled rejection.\n\tvoid ready.catch(() => undefined);\n\tlet disposePromise: Promise<void> | undefined;\n\treturn {\n\t\tmanifest,\n\t\tapi: api!,\n\t\tready,\n\t\tdispose: async () => {\n\t\t\tdisposePromise ??= (async () => {\n\t\t\t\tlet readyError: unknown;\n\t\t\t\ttry {\n\t\t\t\t\tawait ready;\n\t\t\t\t} catch (error) {\n\t\t\t\t\treadyError = error;\n\t\t\t\t}\n\t\t\t\ttry {\n\t\t\t\t\tawait cleanupSync();\n\t\t\t\t\tif (readyError !== undefined) throw readyError;\n\t\t\t\t} catch (error) {\n\t\t\t\t\tif (readyError !== undefined && error !== readyError) {\n\t\t\t\t\t\tthrow new AggregateError([readyError, error], `Capability plugin cleanup failed: ${manifest.id}`);\n\t\t\t\t\t}\n\t\t\t\t\tthrow error;\n\t\t\t\t} finally {\n\t\t\t\t\tif (active.get(manifest.id) === ownerToken) active.delete(manifest.id);\n\t\t\t\t}\n\t\t\t})();\n\t\t\treturn disposePromise;\n\t\t},\n\t};\n}\n\n/**\n * Load a plugin from its JSON manifest. This is intentionally separate from\n * legacy extension discovery until both systems share the same public facade.\n *\n * `options.configOverride` (D-075 S4 third batch) merges host-declared values\n * over the manifest's own `config` defaults before the plugin API is built —\n * a public channel (first-party and third-party plugins alike) for hosts that\n * vouch for facts the manifest cannot know, e.g. the CLI declaring its own\n * process entry trustworthy so the subagent-delegate package auto-pools. It\n * stays below any plugin-side config channel: the agent-dir config file the\n * plugin entry reads merges over whatever the host injected here.\n */\nexport async function loadCapabilityPluginFromManifest(\n\truntime: CapabilityRuntime,\n\tmanifestPath: string,\n\toptions?: { readonly configOverride?: PluginConfig },\n): Promise<CapabilityPluginHandle> {\n\tlet raw: unknown;\n\ttry {\n\t\traw = JSON.parse(await readFile(manifestPath, \"utf8\"));\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to read capability plugin manifest ${manifestPath}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tconst parsed = parseCapabilityPluginManifest(raw, manifestPath);\n\t// hostDependencyPaths (安装店重依赖可见性): 宿主已解析的重依赖入口绝对路径\n\t// 并进 manifest config——安装店副本无 node_modules, 插件内 createRequire 自\n\t// 解析不可达 (memory 的 onnxruntime native 预检实证); 与 jiti alias 通道互补\n\t// (alias 拦截 import, 本通道喂插件内的路径式消费)。公共同道: 第一方与第三方\n\t// 插件同样可读。仍低于插件侧 config 文件通道 (agent-dir 配置合并在其上)。\n\tconst hostDependencyOverride = { hostDependencyPaths: hostDependencyPathsConfig() };\n\tconst callerOverride = options?.configOverride;\n\tconst manifest =\n\t\tcallerOverride === undefined || Object.keys(callerOverride).length === 0\n\t\t\t? { ...parsed, config: { ...parsed.config, ...hostDependencyOverride } }\n\t\t\t: { ...parsed, config: { ...parsed.config, ...hostDependencyOverride, ...callerOverride } };\n\tconst entryPath = path.resolve(path.dirname(manifestPath), manifest.entry);\n\t// Host-resolved authoring dependencies (D-075 §4.1): installed plugin\n\t// packages live in the install store, which carries no node_modules (npm\n\t// tarballs never include dependencies), so their bare imports of the SDK\n\t// and the pinned typebox dependency resolve against the host's own copies\n\t// through jiti virtual modules (./virtual-modules.ts, lazy). Works\n\t// identically in the bundle and Bun binaries where no source-tree\n\t// node_modules exists at all. D-075 S4 third batch: the protocol package\n\t// joins — the subagent-delegate package's runtime imports\n\t// (`@agent-forge/protocol`) resolve the same way. S4 fourth batch: the\n\t// memory package's native vector stack (`@lancedb/lancedb`,\n\t// `@huggingface/transformers`) resolves through the jiti alias channel\n\t// instead — those stay real host node_modules entries, so plugins load the\n\t// host's native builds rather than a virtual copy.\n\tconst [createJitiImpl, virtualModules] = await Promise.all([getCreateJiti(), getVirtualModules()]);\n\tconst jiti = createJitiImpl(import.meta.url, {\n\t\tmoduleCache: false,\n\t\ttsconfigPaths: true,\n\t\talias: buildHostDependencyAliases(hostHeavyDependencyAliases, defaultHostDependencyAliasResolution),\n\t\tvirtualModules,\n\t});\n\tlet factory: unknown;\n\ttry {\n\t\tfactory = await jiti.import(entryPath, { default: true });\n\t} catch (error) {\n\t\tthrow new Error(\n\t\t\t`Failed to import capability plugin entry ${entryPath}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t);\n\t}\n\tif (typeof factory !== \"function\") {\n\t\tthrow new Error(`Capability plugin entry must default-export a factory function: ${entryPath}`);\n\t}\n\treturn loadCapabilityPlugin(runtime, manifest, factory as CapabilityPluginFactory);\n}\n"]}
|
|
@@ -2,20 +2,26 @@ import { lstatSync, readdirSync, realpathSync, statSync } from "node:fs";
|
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import * as path from "node:path";
|
|
5
|
-
import * as pluginSdk from "@agent-forge/plugin-sdk";
|
|
6
5
|
import { parseCapabilityPluginManifest, } from "@agent-forge/plugin-sdk";
|
|
7
|
-
import * as pluginSdkSessionLineage from "@agent-forge/plugin-sdk/session-lineage";
|
|
8
|
-
import * as protocolSubagent from "@agent-forge/protocol/subagent";
|
|
9
|
-
import { createJiti } from "jiti/static";
|
|
10
|
-
import * as typebox from "typebox";
|
|
11
|
-
import * as typeboxValue from "typebox/value";
|
|
12
|
-
// Same undici copy the http-dispatcher already bundles: plugin packages
|
|
13
|
-
// declare it pinned but installed tarballs carry no node_modules, so the
|
|
14
|
-
// image-generation plugin's proxy-aware fetch resolves to this namespace.
|
|
15
|
-
import * as undici from "undici";
|
|
16
6
|
import { PLUGIN_DISPOSE_EVENT_ID, PLUGIN_DISPOSE_EVENT_VERSION, PLUGIN_READY_EVENT_ID, PLUGIN_READY_EVENT_VERSION, } from "./lifecycle-catalog.js";
|
|
17
7
|
export { parseCapabilityPluginManifest } from "@agent-forge/plugin-sdk";
|
|
18
8
|
const activePlugins = new WeakMap();
|
|
9
|
+
// Upstream pi 40c256ccc parity: importing this module sits on every startup
|
|
10
|
+
// path, so the jiti transform pipeline (Babel included) and the bundled
|
|
11
|
+
// virtual modules stay deferred until the first plugin actually loads. The
|
|
12
|
+
// dynamic imports below are deliberate lazy-load points; the thin
|
|
13
|
+
// jiti-static-loader entry keeps jiti/static statically reachable for the
|
|
14
|
+
// Bun and Node bundlers that must embed it.
|
|
15
|
+
let createJitiPromise;
|
|
16
|
+
function getCreateJiti() {
|
|
17
|
+
createJitiPromise ??= import("./jiti-static-loader.js").then((module) => module.createJiti);
|
|
18
|
+
return createJitiPromise;
|
|
19
|
+
}
|
|
20
|
+
let virtualModulesPromise;
|
|
21
|
+
function getVirtualModules() {
|
|
22
|
+
virtualModulesPromise ??= import("./virtual-modules.js").then((module) => module.VIRTUAL_MODULES);
|
|
23
|
+
return virtualModulesPromise;
|
|
24
|
+
}
|
|
19
25
|
// Host-resolved heavy-dependency aliases (D-075 S4 fourth batch, installed-
|
|
20
26
|
// code-loading): the memory plugin package carries its vector stack pinned in
|
|
21
27
|
// its own package.json, but an npm-installed tarball ships no node_modules —
|
|
@@ -454,32 +460,21 @@ export async function loadCapabilityPluginFromManifest(runtime, manifestPath, op
|
|
|
454
460
|
// packages live in the install store, which carries no node_modules (npm
|
|
455
461
|
// tarballs never include dependencies), so their bare imports of the SDK
|
|
456
462
|
// and the pinned typebox dependency resolve against the host's own copies
|
|
457
|
-
// through jiti virtual modules. Works
|
|
458
|
-
// binaries where no source-tree
|
|
459
|
-
//
|
|
460
|
-
//
|
|
461
|
-
//
|
|
463
|
+
// through jiti virtual modules (./virtual-modules.ts, lazy). Works
|
|
464
|
+
// identically in the bundle and Bun binaries where no source-tree
|
|
465
|
+
// node_modules exists at all. D-075 S4 third batch: the protocol package
|
|
466
|
+
// joins — the subagent-delegate package's runtime imports
|
|
467
|
+
// (`@agent-forge/protocol`) resolve the same way. S4 fourth batch: the
|
|
468
|
+
// memory package's native vector stack (`@lancedb/lancedb`,
|
|
462
469
|
// `@huggingface/transformers`) resolves through the jiti alias channel
|
|
463
470
|
// instead — those stay real host node_modules entries, so plugins load the
|
|
464
471
|
// host's native builds rather than a virtual copy.
|
|
465
|
-
const
|
|
472
|
+
const [createJitiImpl, virtualModules] = await Promise.all([getCreateJiti(), getVirtualModules()]);
|
|
473
|
+
const jiti = createJitiImpl(import.meta.url, {
|
|
466
474
|
moduleCache: false,
|
|
467
475
|
tsconfigPaths: true,
|
|
468
476
|
alias: buildHostDependencyAliases(hostHeavyDependencyAliases, defaultHostDependencyAliasResolution),
|
|
469
|
-
virtualModules
|
|
470
|
-
"@agent-forge/plugin-sdk": pluginSdk,
|
|
471
|
-
"@agent-forge/plugin-sdk/session-lineage": pluginSdkSessionLineage,
|
|
472
|
-
"@agent-forge/protocol/subagent": protocolSubagent,
|
|
473
|
-
typebox,
|
|
474
|
-
"typebox/value": typeboxValue,
|
|
475
|
-
// 0.85.13 regression fix (0.85.14): the image-generation plugin's
|
|
476
|
-
// undici dependency (EnvHttpProxyAgent proxy support) resolved to
|
|
477
|
-
// nowhere in the install-store shape and the plugin failed to load
|
|
478
|
-
// ("Cannot find module 'undici'"). Virtual module = the host's own
|
|
479
|
-
// copy, identical in the bundle and Bun binary forms; red-verified
|
|
480
|
-
// by test/plugin-virtual-undici.test.ts.
|
|
481
|
-
undici,
|
|
482
|
-
},
|
|
477
|
+
virtualModules,
|
|
483
478
|
});
|
|
484
479
|
let factory;
|
|
485
480
|
try {
|