chainlesschain 0.166.127 → 0.166.129
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -1
- package/package.json +1 -1
- package/src/assets/linux-subreaper/linux-arm64/manifest.json +1 -1
- package/src/assets/linux-subreaper/linux-x64/manifest.json +1 -1
- package/src/assets/web-panel/assets/{AIOps-DkSOwKNn.js → AIOps-CjPaaF2r.js} +1 -1
- package/src/assets/web-panel/assets/{ActionButton-CaYSnkeR.js → ActionButton-_zlP_Z6z.js} +1 -1
- package/src/assets/web-panel/assets/{Analytics-D8kEgXLP.js → Analytics-C7X31L8l.js} +2 -2
- package/src/assets/web-panel/assets/{AppLayout-D43FaO4a.js → AppLayout-BmYa34Se.js} +3 -3
- package/src/assets/web-panel/assets/{Artifacts-DfxY2Gqs.js → Artifacts-B_YKNjlp.js} +1 -1
- package/src/assets/web-panel/assets/{Audit-0ogv1Zu5.js → Audit-5JsI67XQ.js} +1 -1
- package/src/assets/web-panel/assets/{BackgroundAgents-BhLnn-Gw.js → BackgroundAgents-BL3QbzvS.js} +1 -1
- package/src/assets/web-panel/assets/{Backup-D4591rlk.js → Backup-BRmg-gTa.js} +1 -1
- package/src/assets/web-panel/assets/{BaseInput-gK1PjPDZ.js → BaseInput-DNE7mT3K.js} +1 -1
- package/src/assets/web-panel/assets/{Chat-CCDmOYwg.js → Chat-OYwAopdM.js} +5 -5
- package/src/assets/web-panel/assets/ChatBubbleRenderer-Dtxw3Wgt.js +1 -0
- package/src/assets/web-panel/assets/{Checkbox-DG4PRH9M.js → Checkbox-nMgYkH8H.js} +1 -1
- package/src/assets/web-panel/assets/{Codegen-DtJxGiSg.js → Codegen-B9G2ngLI.js} +1 -1
- package/src/assets/web-panel/assets/{Col-4wGBC25p.js → Col-i0owJaGP.js} +1 -1
- package/src/assets/web-panel/assets/{Community-dOCSc8t-.js → Community-B3Ta0mI_.js} +1 -1
- package/src/assets/web-panel/assets/{Compact-Du4kXsyN.js → Compact-DDXrvvm-.js} +1 -1
- package/src/assets/web-panel/assets/{Compliance-BbI5XMcz.js → Compliance-Bn4Uq6U1.js} +1 -1
- package/src/assets/web-panel/assets/{Cowork-CbQRpyiK.js → Cowork-CO5NKD6r.js} +2 -2
- package/src/assets/web-panel/assets/{Cron-CtWy2bMC.js → Cron-ByjNese0.js} +2 -2
- package/src/assets/web-panel/assets/{Crosschain-CzdM5hF6.js → Crosschain-BN1FUYyi.js} +1 -1
- package/src/assets/web-panel/assets/{DID-CcBboBJN.js → DID-CUFX5RL3.js} +2 -2
- package/src/assets/web-panel/assets/{Dashboard-I7m0oCeC.js → Dashboard-D_2FDPBP.js} +2 -2
- package/src/assets/web-panel/assets/{Dropdown-CKIy2Ikn.js → Dropdown-lGOMtIzb.js} +1 -1
- package/src/assets/web-panel/assets/{EmailListRenderer-BNuxCq89.js → EmailListRenderer-DA3Qf1S2.js} +1 -1
- package/src/assets/web-panel/assets/{EvolutionSettings-BeBovLZs.js → EvolutionSettings-DLcnicCr.js} +1 -1
- package/src/assets/web-panel/assets/{FamilyGuardDashboard-QThmET-n.js → FamilyGuardDashboard-BPOSaIN1.js} +1 -1
- package/src/assets/web-panel/assets/{Federation-Bqf7YYlV.js → Federation-DzJUCQq8.js} +1 -1
- package/src/assets/web-panel/assets/{FormItemContext-DZAM28ve.js → FormItemContext-DVx1XNKx.js} +1 -1
- package/src/assets/web-panel/assets/{GenericCardRenderer-DunXFYML.js → GenericCardRenderer-BkqzO_lh.js} +1 -1
- package/src/assets/web-panel/assets/{Git-BgwOjaMf.js → Git-Dr_rdT_j.js} +2 -2
- package/src/assets/web-panel/assets/{Governance-B1za4wCP.js → Governance-DyVkZddw.js} +1 -1
- package/src/assets/web-panel/assets/{Inference-DMPqX1oN.js → Inference-IN2YDd4v.js} +1 -1
- package/src/assets/web-panel/assets/{KnowledgeGraph-ChDn3okr.js → KnowledgeGraph-Ceiy4n6N.js} +1 -1
- package/src/assets/web-panel/assets/{Logs-BQoPB6-O.js → Logs-d7pIEAX2.js} +2 -2
- package/src/assets/web-panel/assets/MarkdownRenderer-DmSl0MNI.js +1 -0
- package/src/assets/web-panel/assets/{Marketplace-DZXEaPpe.js → Marketplace-uVE7U14g.js} +1 -1
- package/src/assets/web-panel/assets/{McpTools-CZbVOFaG.js → McpTools-DUfBM--y.js} +3 -3
- package/src/assets/web-panel/assets/{Memory-Cl3T8asu.js → Memory-6gkcR02J.js} +2 -2
- package/src/assets/web-panel/assets/{MobileBridge-DK_ayU9I.js → MobileBridge-Cl6ys2O9.js} +1 -1
- package/src/assets/web-panel/assets/{MobileProjects-DEWAA2gT.js → MobileProjects-5P8jN4gf.js} +1 -1
- package/src/assets/web-panel/assets/{Mtc-z-XAWzMh.js → Mtc-DtiT1Kol.js} +2 -2
- package/src/assets/web-panel/assets/{MtcAudit-CX7qJvQS.js → MtcAudit-DZz8iiTE.js} +4 -4
- package/src/assets/web-panel/assets/{Multisig-DiQlKgxx.js → Multisig-DFH3-fBJ.js} +3 -3
- package/src/assets/web-panel/assets/{NLProgramming-Ciuxcu00.js → NLProgramming-BYNuDOt-.js} +1 -1
- package/src/assets/web-panel/assets/{Notes-BAvqNw_6.js → Notes-BCY4jgYy.js} +3 -3
- package/src/assets/web-panel/assets/{NotificationSettings-DkHDTslA.js → NotificationSettings-Bk2ltghU.js} +1 -1
- package/src/assets/web-panel/assets/{OrderTableRenderer--WZdD2oV.js → OrderTableRenderer-OdeXEGAn.js} +1 -1
- package/src/assets/web-panel/assets/{Organization-Bv6bMLCe.js → Organization-CY4_mSiV.js} +4 -4
- package/src/assets/web-panel/assets/{Overflow-Bwoz_oq1.js → Overflow-CaRUAOY_.js} +1 -1
- package/src/assets/web-panel/assets/{P2P-De7T0ZeB.js → P2P-Bd96rBWQ.js} +2 -2
- package/src/assets/web-panel/assets/{PdhVaultBrowser-Dblr2x25.js → PdhVaultBrowser-JjnExxan.js} +3 -3
- package/src/assets/web-panel/assets/{Permissions-C-jAt-cg.js → Permissions-CW1PUJB0.js} +4 -4
- package/src/assets/web-panel/assets/{PersonalDataHub-yXeXDMgf.js → PersonalDataHub-BNn9alTk.js} +3 -3
- package/src/assets/web-panel/assets/{Pipeline-C8CYoLOa.js → Pipeline-01_PBiUu.js} +1 -1
- package/src/assets/web-panel/assets/{Privacy-B-gwnOGT.js → Privacy-BP4DlVGb.js} +1 -1
- package/src/assets/web-panel/assets/{ProjectInit-CbNjHiBV.js → ProjectInit-CAMnQj4n.js} +2 -2
- package/src/assets/web-panel/assets/{ProjectSettings-BMUY0GCP.js → ProjectSettings-DKxV5On_.js} +2 -2
- package/src/assets/web-panel/assets/Projects-B_4kRnM8.js +1 -0
- package/src/assets/web-panel/assets/{Providers-K_tlWkON.js → Providers-DeqqZyUv.js} +1 -1
- package/src/assets/web-panel/assets/{QrScannerModal-2RSZDzJI.js → QrScannerModal-fFkycCT4.js} +1 -1
- package/src/assets/web-panel/assets/{QuickAsk-mhbcQRMI.js → QuickAsk-Ln6qQidy.js} +1 -1
- package/src/assets/web-panel/assets/{Recommend-BXm0uG0q.js → Recommend-DeENA-y0.js} +1 -1
- package/src/assets/web-panel/assets/{RemoteSession-xhOpmNZG.js → RemoteSession-CRxSYxo4.js} +3 -3
- package/src/assets/web-panel/assets/{Reputation-CwbCWB-3.js → Reputation-B2kU2F0l.js} +1 -1
- package/src/assets/web-panel/assets/{Row-BdAjmDBO.js → Row-lV_nLlFq.js} +1 -1
- package/src/assets/web-panel/assets/{RssFeed-Cq4LZ9WU.js → RssFeed-Df21mCdF.js} +2 -2
- package/src/assets/web-panel/assets/{Search-C_I6B-4l.js → Search-8_Dz4qU9.js} +1 -1
- package/src/assets/web-panel/assets/{Security-CdH6mzL-.js → Security-Cl5-PEcp.js} +3 -3
- package/src/assets/web-panel/assets/{Services-CWu1wqtS.js → Services-C5qgCqA7.js} +2 -2
- package/src/assets/web-panel/assets/{Skeleton-daw9DiVM.js → Skeleton-ASRgSh_Y.js} +1 -1
- package/src/assets/web-panel/assets/{Skills-CmurIxkM.js → Skills-DWx01ZJ7.js} +1 -1
- package/src/assets/web-panel/assets/{Sla-cETA5aPO.js → Sla-I2gbgtW8.js} +1 -1
- package/src/assets/web-panel/assets/{SpeechSettings-B1llZgu3.js → SpeechSettings-BqTikzfe.js} +1 -1
- package/src/assets/web-panel/assets/{SyncSettings-DufZ-B2q.js → SyncSettings-D3zCpBFV.js} +2 -2
- package/src/assets/web-panel/assets/{Tasks-PfRLKTFY.js → Tasks-DjMWII45.js} +1 -1
- package/src/assets/web-panel/assets/{Templates-DGtz-vT8.js → Templates-Cq7qDnHX.js} +1 -1
- package/src/assets/web-panel/assets/{Tenant-JeKYLN0b.js → Tenant-DEasKDpQ.js} +1 -1
- package/src/assets/web-panel/assets/{Terminal-BiMsF2Y0.js → Terminal-J6fLkTzi.js} +2 -2
- package/src/assets/web-panel/assets/{TimelineRenderer-DhcBAGPg.js → TimelineRenderer-CNvWrWN-.js} +1 -1
- package/src/assets/web-panel/assets/{Tokens-DpIg-0ju.js → Tokens-BSgHJCKH.js} +1 -1
- package/src/assets/web-panel/assets/{Trigger-DreKHxyb.js → Trigger-DgGU_D0o.js} +1 -1
- package/src/assets/web-panel/assets/{Trust-D7ByQvBQ.js → Trust-BANlv-uB.js} +1 -1
- package/src/assets/web-panel/assets/{UkeySign-OudyQByy.js → UkeySign-qh8GPRsU.js} +1 -1
- package/src/assets/web-panel/assets/{VideoEditing-BhU6nzCF.js → VideoEditing-DBiGTB4H.js} +1 -1
- package/src/assets/web-panel/assets/{Wallet-BCEpB6E0.js → Wallet-DMUFR7cL.js} +4 -4
- package/src/assets/web-panel/assets/{WebAuthn-DwjAM5Mr.js → WebAuthn-DP9nQQzW.js} +5 -5
- package/src/assets/web-panel/assets/{WorkflowEditor-ChQqlAmY.js → WorkflowEditor-DT_6jDkL.js} +1 -1
- package/src/assets/web-panel/assets/{chat-CzUKWqTy.js → chat-C_kELmV6.js} +1 -1
- package/src/assets/web-panel/assets/{colors-D3Y_Pvu4.js → colors-DE-ZxAv_.js} +1 -1
- package/src/assets/web-panel/assets/{compact-item-ByyPRfkA.js → compact-item-BowulLDi.js} +1 -1
- package/src/assets/web-panel/assets/{createContext-Dt5PF6VI.js → createContext-DCh8oMBQ.js} +1 -1
- package/src/assets/web-panel/assets/devWarning-BVvJAp91.js +1 -0
- package/src/assets/web-panel/assets/{hasIn-BuIaEKuC.js → hasIn-Be7mK-iw.js} +1 -1
- package/src/assets/web-panel/assets/{index-BO29sPX8.js → index-3Ql7xQLn.js} +1 -1
- package/src/assets/web-panel/assets/{index-CFXZ9lbO.js → index-4KkYmFy5.js} +1 -1
- package/src/assets/web-panel/assets/{index-DHzVIQLX.js → index-6OluUVJJ.js} +1 -1
- package/src/assets/web-panel/assets/{index-DxVLI-Iu.js → index-Ao-LXr-d.js} +1 -1
- package/src/assets/web-panel/assets/{index-COsjgjvP.js → index-B-3EDOlf.js} +1 -1
- package/src/assets/web-panel/assets/index-B7IhCfsh.js +1 -0
- package/src/assets/web-panel/assets/{index-CCBm8_o4.js → index-BDIIR8g6.js} +1 -1
- package/src/assets/web-panel/assets/index-BMrbe_Ey.js +1 -0
- package/src/assets/web-panel/assets/{index-BFQGN97S.js → index-BdzVLz-c.js} +1 -1
- package/src/assets/web-panel/assets/{index-CmrfHS36.js → index-BlzMqaWB.js} +1 -1
- package/src/assets/web-panel/assets/{index-GyTOYTFg.js → index-BwY31W-u.js} +1 -1
- package/src/assets/web-panel/assets/{index-CAfX0VyL.js → index-C2pCquZC.js} +1 -1
- package/src/assets/web-panel/assets/{index-BdvZNMNm.js → index-CKmC6ugN.js} +1 -1
- package/src/assets/web-panel/assets/{index-CgPKUSe4.js → index-CL2hAUWh.js} +1 -1
- package/src/assets/web-panel/assets/{index-BmVY2f7I.js → index-CUXfwAhF.js} +1 -1
- package/src/assets/web-panel/assets/{index-Di78LDr8.js → index-CXvy8HrM.js} +1 -1
- package/src/assets/web-panel/assets/{index-DpAqy6Co.js → index-C_VnSUjh.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSXjiZAV.js → index-CecGCLWI.js} +1 -1
- package/src/assets/web-panel/assets/{index-D51wU4q-.js → index-Ck6MYKVN.js} +1 -1
- package/src/assets/web-panel/assets/{index-gg5zO3aD.js → index-Cvy4vdVW.js} +1 -1
- package/src/assets/web-panel/assets/{index-1YgdY0Vq.js → index-CwJfLNqv.js} +1 -1
- package/src/assets/web-panel/assets/{index-NFqKQquS.js → index-D3lOYd9_.js} +1 -1
- package/src/assets/web-panel/assets/{index-CDTS4qJm.js → index-DEDVYN7D.js} +1 -1
- package/src/assets/web-panel/assets/{index-BwlY7Yap.js → index-DLCzaLH4.js} +1 -1
- package/src/assets/web-panel/assets/{index-BcqZAAr5.js → index-DMDaGPxG.js} +1 -1
- package/src/assets/web-panel/assets/{index-DWW5svXU.js → index-DMKo49Um.js} +1 -1
- package/src/assets/web-panel/assets/{index-CByWkXdO.js → index-DN1AT3FH.js} +1 -1
- package/src/assets/web-panel/assets/{index-EtrWRKu2.js → index-DOebEvgn.js} +1 -1
- package/src/assets/web-panel/assets/{index-D7QSTEjb.js → index-DPX3N4T8.js} +1 -1
- package/src/assets/web-panel/assets/{index-F-T8AHeo.js → index-DSRKtgJg.js} +1 -1
- package/src/assets/web-panel/assets/{index-B600riYP.js → index-DSqZBvQM.js} +1 -1
- package/src/assets/web-panel/assets/{index-BSWTyRhI.js → index-DbrQO1p9.js} +1 -1
- package/src/assets/web-panel/assets/{index-huWw0XBb.js → index-DjC2TJeH.js} +1 -1
- package/src/assets/web-panel/assets/{index-Dlec7Sr4.js → index-LVrxqU88.js} +1 -1
- package/src/assets/web-panel/assets/{index-CZX4_hGp.js → index-OH54KMLN.js} +1 -1
- package/src/assets/web-panel/assets/{index-DSgroT-P.js → index-Qx8cTReg.js} +3 -3
- package/src/assets/web-panel/assets/{index-BztqxXMP.js → index-_cYsz4df.js} +1 -1
- package/src/assets/web-panel/assets/{index-Cb7MzML-.js → index-lN916819.js} +1 -1
- package/src/assets/web-panel/assets/{index-_oJnnOnZ.js → index-nLHTuHoT.js} +1 -1
- package/src/assets/web-panel/assets/{initDefaultProps-Bny6G13G.js → initDefaultProps-BNhziAal.js} +1 -1
- package/src/assets/web-panel/assets/{motion-DRhRj_uM.js → motion-fUkbJz38.js} +1 -1
- package/src/assets/web-panel/assets/{move-D0wKnhYr.js → move-rFx211Cl.js} +1 -1
- package/src/assets/web-panel/assets/{mtc-parser-BXXSTJBk.js → mtc-parser-CEP1wN3R.js} +1 -1
- package/src/assets/web-panel/assets/{omit-d8t9Yze4.js → omit-DacHd_Zm.js} +1 -1
- package/src/assets/web-panel/assets/{pickAttrs-nyB6BMe6.js → pickAttrs-Dqp58Ep2.js} +1 -1
- package/src/assets/web-panel/assets/{placementArrow-CSFyBNA2.js → placementArrow-Cv6Rm0pV.js} +1 -1
- package/src/assets/web-panel/assets/{responsiveObserve-DYmiKhJa.js → responsiveObserve-rNE0p9ZW.js} +1 -1
- package/src/assets/web-panel/assets/{slide-D4KZSRmt.js → slide-C97JxD4S.js} +1 -1
- package/src/assets/web-panel/assets/{statusUtils-BcrcPeFm.js → statusUtils-Cxk1gV9M.js} +1 -1
- package/src/assets/web-panel/assets/{styleChecker-BFgOb1vz.js → styleChecker-CbtKKsPo.js} +1 -1
- package/src/assets/web-panel/assets/{useFlexGapSupport-DQ5qSQlN.js → useFlexGapSupport-CQATs2JQ.js} +1 -1
- package/src/assets/web-panel/assets/{useFs-Cafq069l.js → useFs-6c7qrpE_.js} +1 -1
- package/src/assets/web-panel/assets/{usePersonalDataHub-DTma9Ary.js → usePersonalDataHub-OjxtBGe7.js} +1 -1
- package/src/assets/web-panel/assets/{vnode-HvC2-bE9.js → vnode-CSlXfUSh.js} +1 -1
- package/src/assets/web-panel/assets/{zoom-AZxADWXu.js → zoom-Cc1qKiSZ.js} +1 -1
- package/src/assets/web-panel/index.html +1 -1
- package/src/command-help-index.json +1 -1
- package/src/commands/agent.js +29 -0
- package/src/commands/setup.js +35 -10
- package/src/constants.js +15 -89
- package/src/data/changelog.json +27 -1
- package/src/lib/bm25-search.js +6 -3
- package/src/lib/codex-app-server-adapter.js +36 -22
- package/src/lib/codex-app-server-support.js +91 -0
- package/src/lib/coding-change-review-context.js +258 -0
- package/src/lib/coding-task-guidance.js +9 -1
- package/src/lib/context-memory-kernel/memory-query-index.js +35 -17
- package/src/lib/context-memory-kernel/provider-context.js +22 -12
- package/src/lib/goal-check-evidence.js +159 -0
- package/src/lib/goal-condition-engine.js +24 -2
- package/src/lib/llm-connection-probe.js +48 -4
- package/src/lib/llm-onboarding-catalog.json +131 -0
- package/src/lib/skill-retrieval-router.js +2 -1
- package/src/lib/skill-search-tokenizer.js +143 -0
- package/src/repl/agent-repl.js +8 -4
- package/src/runtime/agent-core.js +207 -42
- package/src/runtime/headless-runner.js +138 -66
- package/src/runtime/headless-stream.js +1 -0
- package/src/runtime/mcp-tool-search-ranking.js +142 -0
- package/src/runtime/mcp-tool-search.js +198 -60
- package/src/assets/web-panel/assets/ChatBubbleRenderer-CnpWe3dp.js +0 -1
- package/src/assets/web-panel/assets/MarkdownRenderer-uS1yHX12.js +0 -1
- package/src/assets/web-panel/assets/Projects-DpCaWXv6.js +0 -1
- package/src/assets/web-panel/assets/devWarning-BgSxkkQ3.js +0 -1
- package/src/assets/web-panel/assets/index-D5v6roiB.js +0 -1
- package/src/assets/web-panel/assets/index-DgXZCvH5.js +0 -1
|
@@ -42,7 +42,10 @@ import {
|
|
|
42
42
|
resolvePermissionPromptTool,
|
|
43
43
|
makePermissionPromptConfirmer,
|
|
44
44
|
} from "./mcp-config.js";
|
|
45
|
-
import {
|
|
45
|
+
import {
|
|
46
|
+
maybeApplyToolSearch,
|
|
47
|
+
projectMcpToolDefinitions,
|
|
48
|
+
} from "./mcp-tool-search.js";
|
|
46
49
|
import { IterationBudget } from "../lib/iteration-budget.js";
|
|
47
50
|
import { HostResourceBudget } from "../lib/host-resource-budget.js";
|
|
48
51
|
import {
|
|
@@ -169,6 +172,19 @@ export const _goalProcessDeps = {
|
|
|
169
172
|
export const RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE =
|
|
170
173
|
"CC_RUNTIME_USAGE_LEDGER_FAILED: runtime usage telemetry was not durably persisted";
|
|
171
174
|
|
|
175
|
+
export const GOAL_CHECKPOINT_FAILURE_CODE = "CC_GOAL_CHECKPOINT_FAILED";
|
|
176
|
+
export const GOAL_CHECKPOINT_FAILURE_MESSAGE =
|
|
177
|
+
`${GOAL_CHECKPOINT_FAILURE_CODE}: goal state could not be safely saved or restored; ` +
|
|
178
|
+
"verify prior effects and usage before continuing; for an interrupted goal, " +
|
|
179
|
+
"resume with --goal-recovery-reviewed only after that review";
|
|
180
|
+
|
|
181
|
+
function goalCheckpointFailure(cause, phase) {
|
|
182
|
+
const error = new Error(GOAL_CHECKPOINT_FAILURE_MESSAGE, { cause });
|
|
183
|
+
error.code = GOAL_CHECKPOINT_FAILURE_CODE;
|
|
184
|
+
error.goalCheckpointPhase = phase;
|
|
185
|
+
return error;
|
|
186
|
+
}
|
|
187
|
+
|
|
172
188
|
export function resolveHeadlessMeteredSessionId(persist, sessionId) {
|
|
173
189
|
return persist && sessionId ? sessionId : null;
|
|
174
190
|
}
|
|
@@ -230,6 +246,12 @@ import {
|
|
|
230
246
|
runtimeToolCallId,
|
|
231
247
|
} from "../lib/runtime-usage-ledger.js";
|
|
232
248
|
import { runMeteredDirectModelCall } from "../lib/direct-model-usage.js";
|
|
249
|
+
import {
|
|
250
|
+
GoalCheckEvidence,
|
|
251
|
+
buildGoalJudgePrompt,
|
|
252
|
+
usableGoalEvidence,
|
|
253
|
+
validateGoalJudgeVerdict,
|
|
254
|
+
} from "../lib/goal-check-evidence.js";
|
|
233
255
|
import { resolveTeamMessageToolBundle } from "../lib/agent-team/team-message-tools.js";
|
|
234
256
|
import { normalizeDecisionMode } from "../lib/decision-layer/contracts.js";
|
|
235
257
|
import { createSkillDecisionRuntime } from "../lib/decision-layer/runtime.js";
|
|
@@ -2640,7 +2662,10 @@ async function runAgentHeadlessInWorkspace(
|
|
|
2640
2662
|
}
|
|
2641
2663
|
try {
|
|
2642
2664
|
store.appendEvent(sessionId, "context_sources", {
|
|
2643
|
-
mcp: (
|
|
2665
|
+
mcp: projectMcpToolDefinitions(
|
|
2666
|
+
mcp?.extraToolDefinitions || [],
|
|
2667
|
+
mcp?.externalToolExecutors,
|
|
2668
|
+
).map((definition) => ({
|
|
2644
2669
|
function: {
|
|
2645
2670
|
name: definition?.function?.name || null,
|
|
2646
2671
|
description: definition?.function?.description || "",
|
|
@@ -2970,6 +2995,8 @@ async function runAgentHeadlessInWorkspace(
|
|
|
2970
2995
|
exactToolNames: options.exactToolNames === true,
|
|
2971
2996
|
fileMutationScope,
|
|
2972
2997
|
hermeticExecution,
|
|
2998
|
+
reviewChanges: options.reviewChanges === true,
|
|
2999
|
+
_changeReviewState: { requested: false },
|
|
2973
3000
|
iterationBudget: budget,
|
|
2974
3001
|
toolAdmission: hermeticExecution ? null : options.toolAdmission || null,
|
|
2975
3002
|
unattendedActionPolicy: hermeticExecution
|
|
@@ -3363,17 +3390,25 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3363
3390
|
let _goalHelpers = null;
|
|
3364
3391
|
let _goalTokensSeen = 0; // per-turn usage deltas (engine totals == run total)
|
|
3365
3392
|
let _goalCostSeen = 0;
|
|
3393
|
+
let goalSetupFailure = null;
|
|
3394
|
+
let goalRecoveryReviewed = false;
|
|
3395
|
+
const goalEvidence = options.goalCondition
|
|
3396
|
+
? new GoalCheckEvidence({ readOnlyTools: READ_ONLY_TOOLS })
|
|
3397
|
+
: null;
|
|
3366
3398
|
// Model-judged conditions reuse the run's own model as an independent
|
|
3367
3399
|
// evaluator (mirrors --goal-assess). Overridable via deps for tests.
|
|
3368
3400
|
const _defaultGoalJudge = async (cond, transcript) => {
|
|
3401
|
+
if (!usableGoalEvidence(transcript.goalEvidence).length) {
|
|
3402
|
+
return {
|
|
3403
|
+
met: false,
|
|
3404
|
+
reason:
|
|
3405
|
+
"No current successful tool evidence; run an explicit check for the goal condition",
|
|
3406
|
+
evidence: { kind: "model", source: "current-turn-tools", toolIds: [] },
|
|
3407
|
+
};
|
|
3408
|
+
}
|
|
3369
3409
|
const { chatWithTools } = await import("./agent-core.js");
|
|
3370
3410
|
const { firstBalancedJson } = await import("../lib/json-schema-output.js");
|
|
3371
|
-
const judgePrompt =
|
|
3372
|
-
`You are judging whether a coding session met a completion condition.\n` +
|
|
3373
|
-
`Condition: ${cond.text || cond.source}\n\n` +
|
|
3374
|
-
`Latest assistant output:\n${String(transcript.finalText || "").slice(0, 2000)}\n\n` +
|
|
3375
|
-
`Reply with STRICT JSON only, for example: {"met": false, "reason": "<short>"}. ` +
|
|
3376
|
-
`Set met to true only when the condition is satisfied; otherwise false.`;
|
|
3411
|
+
const judgePrompt = buildGoalJudgePrompt(cond, transcript);
|
|
3377
3412
|
const r = await runMeteredDirectModelCall({
|
|
3378
3413
|
sessionId: resolveHeadlessMeteredSessionId(persist, sessionId),
|
|
3379
3414
|
persist: persist
|
|
@@ -3394,37 +3429,33 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3394
3429
|
}),
|
|
3395
3430
|
});
|
|
3396
3431
|
const text = r?.message?.content || "";
|
|
3397
|
-
let
|
|
3398
|
-
let reason = "model judge returned no verdict";
|
|
3432
|
+
let verdict = null;
|
|
3399
3433
|
const block = firstBalancedJson(text, "{");
|
|
3400
3434
|
if (block) {
|
|
3401
3435
|
try {
|
|
3402
|
-
|
|
3403
|
-
met = parsed.met === true;
|
|
3404
|
-
if (typeof parsed.reason === "string" && parsed.reason.trim())
|
|
3405
|
-
reason = parsed.reason.trim();
|
|
3406
|
-
else reason = met ? "condition met" : "condition not met";
|
|
3436
|
+
verdict = JSON.parse(block);
|
|
3407
3437
|
} catch {
|
|
3408
3438
|
/* tolerant: a non-JSON verdict stays unmet */
|
|
3409
3439
|
}
|
|
3410
3440
|
}
|
|
3411
|
-
return
|
|
3412
|
-
met,
|
|
3413
|
-
reason,
|
|
3414
|
-
evidence: { kind: "model", raw: text.slice(0, 200) },
|
|
3415
|
-
};
|
|
3441
|
+
return validateGoalJudgeVerdict(verdict, transcript.goalEvidence);
|
|
3416
3442
|
};
|
|
3417
|
-
//
|
|
3418
|
-
//
|
|
3419
|
-
//
|
|
3420
|
-
|
|
3421
|
-
// context. Defined here so the outer loop can call it after each evaluate().
|
|
3422
|
-
const persistGoalSnapshot = () => {
|
|
3443
|
+
// A running checkpoint precedes model/tool effects; an evaluated checkpoint
|
|
3444
|
+
// precedes publishing the decision. An interrupted running phase requires
|
|
3445
|
+
// reconciliation on resume instead of silently replaying the old goal state.
|
|
3446
|
+
const persistGoalSnapshot = (phase, failurePhase = "after-model") => {
|
|
3423
3447
|
if (!persist || !goalEngine) return;
|
|
3424
3448
|
try {
|
|
3425
|
-
store.appendEvent(sessionId, "goal_snapshot",
|
|
3426
|
-
|
|
3427
|
-
|
|
3449
|
+
store.appendEvent(sessionId, "goal_snapshot", {
|
|
3450
|
+
...goalEngine.snapshot(),
|
|
3451
|
+
checkpoint: {
|
|
3452
|
+
schema: "chainlesschain.goal-checkpoint/v1",
|
|
3453
|
+
phase,
|
|
3454
|
+
...(goalRecoveryReviewed ? { recoveryReviewed: true } : {}),
|
|
3455
|
+
},
|
|
3456
|
+
});
|
|
3457
|
+
} catch (error) {
|
|
3458
|
+
throw goalCheckpointFailure(error, failurePhase);
|
|
3428
3459
|
}
|
|
3429
3460
|
};
|
|
3430
3461
|
if (options.goalCondition) {
|
|
@@ -3442,17 +3473,41 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3442
3473
|
try {
|
|
3443
3474
|
const event = store.findLatestEvent(resumeId, "goal_snapshot");
|
|
3444
3475
|
const snap = event?.data;
|
|
3476
|
+
if (
|
|
3477
|
+
event &&
|
|
3478
|
+
(!snap?.state ||
|
|
3479
|
+
typeof snap.state.done !== "boolean" ||
|
|
3480
|
+
(snap.checkpoint != null &&
|
|
3481
|
+
(snap.checkpoint.schema !==
|
|
3482
|
+
"chainlesschain.goal-checkpoint/v1" ||
|
|
3483
|
+
!["ready", "running", "evaluated"].includes(
|
|
3484
|
+
snap.checkpoint.phase,
|
|
3485
|
+
))))
|
|
3486
|
+
) {
|
|
3487
|
+
throw goalCheckpointFailure(null, "before-model");
|
|
3488
|
+
}
|
|
3489
|
+
if (snap?.checkpoint?.phase === "running") {
|
|
3490
|
+
if (options.goalRecoveryReviewed !== true)
|
|
3491
|
+
throw goalCheckpointFailure(null, "before-model");
|
|
3492
|
+
goalRecoveryReviewed = true;
|
|
3493
|
+
}
|
|
3445
3494
|
if (snap && snap.state && snap.state.done !== true) {
|
|
3446
3495
|
restoredSnap = snap;
|
|
3447
3496
|
}
|
|
3448
|
-
} catch {
|
|
3449
|
-
|
|
3497
|
+
} catch (error) {
|
|
3498
|
+
throw error?.code === GOAL_CHECKPOINT_FAILURE_CODE
|
|
3499
|
+
? error
|
|
3500
|
+
: goalCheckpointFailure(error, "before-model");
|
|
3450
3501
|
}
|
|
3451
3502
|
}
|
|
3452
3503
|
if (restoredSnap) {
|
|
3453
|
-
|
|
3454
|
-
|
|
3455
|
-
|
|
3504
|
+
try {
|
|
3505
|
+
goalEngine = eng.GoalConditionEngine.fromSnapshot(restoredSnap, {
|
|
3506
|
+
now: goalNow,
|
|
3507
|
+
});
|
|
3508
|
+
} catch (error) {
|
|
3509
|
+
throw goalCheckpointFailure(error, "before-model");
|
|
3510
|
+
}
|
|
3456
3511
|
} else {
|
|
3457
3512
|
goalEngine = new eng.GoalConditionEngine({
|
|
3458
3513
|
condition: options.goalCondition,
|
|
@@ -3471,13 +3526,14 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3471
3526
|
GOAL_DECISION: eng.GOAL_DECISION,
|
|
3472
3527
|
};
|
|
3473
3528
|
const started = goalEngine.start();
|
|
3529
|
+
persistGoalSnapshot("ready", "before-model");
|
|
3474
3530
|
emitStream({
|
|
3475
3531
|
type: started.type,
|
|
3476
3532
|
condition: started.condition,
|
|
3477
3533
|
budget: started.budget,
|
|
3478
3534
|
resumed: Boolean(restoredSnap),
|
|
3535
|
+
...(goalRecoveryReviewed ? { recovery_reviewed: true } : {}),
|
|
3479
3536
|
});
|
|
3480
|
-
persistGoalSnapshot(); // checkpoint the starting/restored state
|
|
3481
3537
|
if (isText)
|
|
3482
3538
|
writeErr(
|
|
3483
3539
|
` ◎ goal-condition ${restoredSnap ? "resumed" : "active"}: ` +
|
|
@@ -3486,10 +3542,15 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3486
3542
|
`${goalEngine.budget.maxOuterTurns})\n`,
|
|
3487
3543
|
);
|
|
3488
3544
|
} catch (err) {
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3545
|
+
if (err?.code === GOAL_CHECKPOINT_FAILURE_CODE) {
|
|
3546
|
+
// Surface through the main failure/cleanup path before any agent call.
|
|
3547
|
+
goalSetupFailure = err;
|
|
3548
|
+
} else {
|
|
3549
|
+
// A bad spec should have been rejected at the command layer; fail-open so
|
|
3550
|
+
// a malformed condition never aborts an otherwise-valid run.
|
|
3551
|
+
goalEngine = null;
|
|
3552
|
+
if (isText) writeErr(` goal-condition ignored: ${err.message}\n`);
|
|
3553
|
+
}
|
|
3493
3554
|
}
|
|
3494
3555
|
}
|
|
3495
3556
|
|
|
@@ -3522,8 +3583,11 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3522
3583
|
let loopFailureOutcome = null;
|
|
3523
3584
|
let cleanupFailure = null;
|
|
3524
3585
|
try {
|
|
3586
|
+
if (goalSetupFailure) throw goalSetupFailure;
|
|
3525
3587
|
while (true) {
|
|
3526
3588
|
sessionHostLease?.assert?.();
|
|
3589
|
+
persistGoalSnapshot("running", "before-model");
|
|
3590
|
+
goalEvidence?.beginTurn();
|
|
3527
3591
|
// P1 turn→checkpoint binding: one drain of the loop = one turn. Anchor
|
|
3528
3592
|
// the conversation offset before the model sees the new user turn. A
|
|
3529
3593
|
// `--worktree` run stamps its isolation worktree (branch name, threaded
|
|
@@ -3586,6 +3650,7 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3586
3650
|
args: event.args,
|
|
3587
3651
|
};
|
|
3588
3652
|
toolCalls.push(toolCall);
|
|
3653
|
+
goalEvidence?.started(toolCall);
|
|
3589
3654
|
toolStartedAt.set(
|
|
3590
3655
|
telemetryToolId,
|
|
3591
3656
|
deps.now ? deps.now() : Date.now(),
|
|
@@ -3713,6 +3778,7 @@ async function runAgentHeadlessInWorkspace(
|
|
|
3713
3778
|
if (policyEvent) emitStream(policyEvent);
|
|
3714
3779
|
}
|
|
3715
3780
|
if (settledCall) {
|
|
3781
|
+
goalEvidence?.settled(settledCall, event.result, Boolean(err));
|
|
3716
3782
|
settledCall.is_error = Boolean(err);
|
|
3717
3783
|
settledCall.durationMs =
|
|
3718
3784
|
event.result?.toolTelemetryRecord?.durationMs ??
|
|
@@ -4069,6 +4135,7 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4069
4135
|
prompt: options.prompt,
|
|
4070
4136
|
finalText,
|
|
4071
4137
|
toolCalls,
|
|
4138
|
+
goalEvidence: goalEvidence.snapshot(),
|
|
4072
4139
|
});
|
|
4073
4140
|
}
|
|
4074
4141
|
} catch (err) {
|
|
@@ -4082,6 +4149,8 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4082
4149
|
}
|
|
4083
4150
|
|
|
4084
4151
|
const { decision, events } = goalEngine.evaluate(evaluation);
|
|
4152
|
+
// Publish only after the decision and accumulated usage are durable.
|
|
4153
|
+
persistGoalSnapshot("evaluated");
|
|
4085
4154
|
for (const ev of events) {
|
|
4086
4155
|
emitStream(ev);
|
|
4087
4156
|
if (isText) {
|
|
@@ -4097,10 +4166,6 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4097
4166
|
);
|
|
4098
4167
|
}
|
|
4099
4168
|
}
|
|
4100
|
-
// Checkpoint the post-evaluate state (outerTurns incremented, and
|
|
4101
|
-
// done/outcome on a terminal decision) so a crash or Ctrl-C between here
|
|
4102
|
-
// and the next turn still resumes at the right point.
|
|
4103
|
-
persistGoalSnapshot();
|
|
4104
4169
|
if (decision === _goalHelpers.GOAL_DECISION.CONTINUE) {
|
|
4105
4170
|
messages.push(
|
|
4106
4171
|
markRuntimeOnlySessionMessage({
|
|
@@ -4119,6 +4184,8 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4119
4184
|
);
|
|
4120
4185
|
continue; // re-drive: run another outer turn
|
|
4121
4186
|
}
|
|
4187
|
+
if (decision === _goalHelpers.GOAL_DECISION.EXHAUSTED)
|
|
4188
|
+
endReason = "goal-exhausted";
|
|
4122
4189
|
// complete | exhausted → fall through to the break below.
|
|
4123
4190
|
}
|
|
4124
4191
|
break;
|
|
@@ -4126,13 +4193,16 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4126
4193
|
} catch (err) {
|
|
4127
4194
|
const runtimeLedgerPersistenceFailed =
|
|
4128
4195
|
err?.runtimeLedgerPersistence === true;
|
|
4129
|
-
const
|
|
4196
|
+
const goalCheckpointFailed = err?.code === GOAL_CHECKPOINT_FAILURE_CODE;
|
|
4197
|
+
const persistenceFailed =
|
|
4198
|
+
runtimeLedgerPersistenceFailed || goalCheckpointFailed;
|
|
4199
|
+
const persistence = persistenceFailed
|
|
4130
4200
|
? projectSessionPersistenceFailure(
|
|
4131
4201
|
createSessionPersistenceFailure(err, {
|
|
4132
4202
|
sessionId,
|
|
4133
4203
|
operation: "append-event",
|
|
4134
4204
|
}),
|
|
4135
|
-
{ phase: "after-model" },
|
|
4205
|
+
{ phase: err.goalCheckpointPhase || "after-model" },
|
|
4136
4206
|
)
|
|
4137
4207
|
: null;
|
|
4138
4208
|
if (persistence) {
|
|
@@ -4146,17 +4216,19 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4146
4216
|
err?.code === "CC_SESSION_BUDGET_EXHAUSTED" ||
|
|
4147
4217
|
err?.code === "CC_SESSION_BUDGET_USAGE_UNKNOWN" ||
|
|
4148
4218
|
options.sessionBudget?.signal?.aborted === true;
|
|
4149
|
-
const message =
|
|
4150
|
-
?
|
|
4151
|
-
:
|
|
4152
|
-
?
|
|
4153
|
-
:
|
|
4154
|
-
?
|
|
4155
|
-
|
|
4156
|
-
|
|
4157
|
-
|
|
4158
|
-
|
|
4159
|
-
|
|
4219
|
+
const message = goalCheckpointFailed
|
|
4220
|
+
? GOAL_CHECKPOINT_FAILURE_MESSAGE
|
|
4221
|
+
: runtimeLedgerPersistenceFailed
|
|
4222
|
+
? RUNTIME_LEDGER_PERSISTENCE_FAILURE_MESSAGE
|
|
4223
|
+
: err?.code === "CC_SESSION_BUDGET_USAGE_UNKNOWN"
|
|
4224
|
+
? err.message
|
|
4225
|
+
: sessionBudgetFailed
|
|
4226
|
+
? sessionBudgetAdmissionError(
|
|
4227
|
+
options.sessionBudget?.reason?.() || err?.budgetReason,
|
|
4228
|
+
"run",
|
|
4229
|
+
).message
|
|
4230
|
+
: err?.message || String(err);
|
|
4231
|
+
const errorSubtype = persistenceFailed
|
|
4160
4232
|
? "error_persistence"
|
|
4161
4233
|
: sessionBudgetFailed
|
|
4162
4234
|
? "error_session_budget"
|
|
@@ -4166,9 +4238,7 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4166
4238
|
const diagnosticFields = transportDetails
|
|
4167
4239
|
? { error_details: transportDetails }
|
|
4168
4240
|
: {
|
|
4169
|
-
...(
|
|
4170
|
-
? { code: err.code }
|
|
4171
|
-
: {}),
|
|
4241
|
+
...(persistenceFailed && err.code ? { code: err.code } : {}),
|
|
4172
4242
|
...(persistence ? { persistence } : {}),
|
|
4173
4243
|
};
|
|
4174
4244
|
if (isStream) {
|
|
@@ -4204,13 +4274,11 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4204
4274
|
// "the model call failed" from "the run itself errored" (1).
|
|
4205
4275
|
loopFailureOutcome = {
|
|
4206
4276
|
exitCode:
|
|
4207
|
-
|
|
4208
|
-
? 1
|
|
4209
|
-
: classifyLoopError(err),
|
|
4277
|
+
persistenceFailed || sessionBudgetFailed ? 1 : classifyLoopError(err),
|
|
4210
4278
|
result: message,
|
|
4211
4279
|
isError: true,
|
|
4212
4280
|
...(persistence ? { persistence } : {}),
|
|
4213
|
-
...(
|
|
4281
|
+
...(persistenceFailed && err.code ? { code: err.code } : {}),
|
|
4214
4282
|
};
|
|
4215
4283
|
} finally {
|
|
4216
4284
|
// Capture body-cache hits/misses caused by list_skills/run_skill during the
|
|
@@ -4380,18 +4448,22 @@ async function runAgentHeadlessInWorkspace(
|
|
|
4380
4448
|
const exhausted =
|
|
4381
4449
|
endReason === "budget-exhausted" || endReason === "max_turns";
|
|
4382
4450
|
const costStopped = endReason === "cost-budget-exhausted";
|
|
4451
|
+
const goalExhausted = endReason === "goal-exhausted";
|
|
4383
4452
|
let isError =
|
|
4384
4453
|
exhausted ||
|
|
4385
4454
|
costStopped ||
|
|
4455
|
+
goalExhausted ||
|
|
4386
4456
|
endReason === "no-response" ||
|
|
4387
4457
|
endReason === "deferred-mutation-unresolved";
|
|
4388
4458
|
let subtype = exhausted
|
|
4389
4459
|
? "error_max_turns"
|
|
4390
4460
|
: costStopped
|
|
4391
4461
|
? "error_max_budget"
|
|
4392
|
-
:
|
|
4393
|
-
? "
|
|
4394
|
-
:
|
|
4462
|
+
: goalExhausted
|
|
4463
|
+
? "error_goal_condition"
|
|
4464
|
+
: isError
|
|
4465
|
+
? "error"
|
|
4466
|
+
: "success";
|
|
4395
4467
|
const durationMs = (deps.now ? deps.now() : Date.now()) - startedAt;
|
|
4396
4468
|
let persistenceFailure = null;
|
|
4397
4469
|
let sessionPersistenceCode = null;
|
|
@@ -3862,6 +3862,7 @@ async function runAgentHeadlessStreamInWorkspace(
|
|
|
3862
3862
|
};
|
|
3863
3863
|
const loopOptionsBase = {
|
|
3864
3864
|
...(evolutionIngress === null ? {} : { evolutionIngress }),
|
|
3865
|
+
reviewChanges: options.reviewChanges === true,
|
|
3865
3866
|
model,
|
|
3866
3867
|
provider,
|
|
3867
3868
|
// Extended thinking (Anthropic; opt-in via --think/--ultrathink).
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
// Keyword ranking only: admission, schema loading and executor generations
|
|
2
|
+
// remain owned by mcp-tool-search.js. No provider or embedding calls.
|
|
3
|
+
const segmenter = new Intl.Segmenter("zh", { granularity: "word" });
|
|
4
|
+
const documents = new WeakMap();
|
|
5
|
+
const stopWords = new Set([
|
|
6
|
+
"a",
|
|
7
|
+
"an",
|
|
8
|
+
"the",
|
|
9
|
+
"to",
|
|
10
|
+
"of",
|
|
11
|
+
"for",
|
|
12
|
+
"in",
|
|
13
|
+
"on",
|
|
14
|
+
"with",
|
|
15
|
+
"and",
|
|
16
|
+
"please",
|
|
17
|
+
"help",
|
|
18
|
+
"me",
|
|
19
|
+
"how",
|
|
20
|
+
"can",
|
|
21
|
+
"i",
|
|
22
|
+
"请",
|
|
23
|
+
"请问",
|
|
24
|
+
"帮",
|
|
25
|
+
"帮我",
|
|
26
|
+
"我",
|
|
27
|
+
"我要",
|
|
28
|
+
"需要",
|
|
29
|
+
"如何",
|
|
30
|
+
"怎么",
|
|
31
|
+
"一下",
|
|
32
|
+
"一个",
|
|
33
|
+
"的",
|
|
34
|
+
"在",
|
|
35
|
+
"中",
|
|
36
|
+
"和",
|
|
37
|
+
"并",
|
|
38
|
+
"给",
|
|
39
|
+
"为",
|
|
40
|
+
"从",
|
|
41
|
+
"将",
|
|
42
|
+
"把",
|
|
43
|
+
"进行",
|
|
44
|
+
"可以",
|
|
45
|
+
"使用",
|
|
46
|
+
]);
|
|
47
|
+
|
|
48
|
+
const normalize = (text) => text.normalize("NFKC").toLowerCase();
|
|
49
|
+
|
|
50
|
+
export function compileMcpToolSearchQuery(query) {
|
|
51
|
+
const scoring = new Set();
|
|
52
|
+
const required = new Set();
|
|
53
|
+
const chunks = normalize(query)
|
|
54
|
+
.split(/[\s,,、;;!?!?。::]+/u)
|
|
55
|
+
.filter(Boolean);
|
|
56
|
+
for (const chunk of chunks) {
|
|
57
|
+
if (!chunk) continue;
|
|
58
|
+
if (chunk.startsWith("+") && chunk.length > 1) {
|
|
59
|
+
// A required name fragment is literal, never split or stop-word filtered.
|
|
60
|
+
required.add(chunk.slice(1));
|
|
61
|
+
scoring.add(chunk.slice(1));
|
|
62
|
+
} else if (/\p{Script=Han}/u.test(chunk)) {
|
|
63
|
+
for (const part of segmenter.segment(chunk)) {
|
|
64
|
+
if (part.isWordLike && !stopWords.has(part.segment))
|
|
65
|
+
scoring.add(part.segment);
|
|
66
|
+
}
|
|
67
|
+
} else if (
|
|
68
|
+
(!stopWords.has(chunk) || chunks.length === 1) &&
|
|
69
|
+
/[\p{L}\p{N}]/u.test(chunk)
|
|
70
|
+
) {
|
|
71
|
+
scoring.add(chunk);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { scoring: [...scoring], required: [...required] };
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function documentFor(name, entry) {
|
|
78
|
+
const description = String(entry.definition?.function?.description || "");
|
|
79
|
+
const cached = documents.get(entry);
|
|
80
|
+
if (cached?.name === name && cached.description === description)
|
|
81
|
+
return cached;
|
|
82
|
+
// Preserve exact identifier fragments and expose camel-case word boundaries
|
|
83
|
+
// for natural-language queries such as "read file" against readFile.
|
|
84
|
+
const words = name.replace(/([a-z0-9])([A-Z])/g, "$1 $2");
|
|
85
|
+
const document = {
|
|
86
|
+
name,
|
|
87
|
+
description,
|
|
88
|
+
lowerName: normalize(name),
|
|
89
|
+
nameWords: words === name ? null : normalize(words),
|
|
90
|
+
lowerDescription: normalize(description),
|
|
91
|
+
};
|
|
92
|
+
documents.set(entry, document);
|
|
93
|
+
return document;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function compare(left, right) {
|
|
97
|
+
return (
|
|
98
|
+
right.score - left.score ||
|
|
99
|
+
(left.name < right.name ? -1 : left.name > right.name ? 1 : 0)
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function rankMcpToolSearchEntries(entries, query, maxResults) {
|
|
104
|
+
const { scoring, required } = compileMcpToolSearchQuery(query);
|
|
105
|
+
if (!scoring.length) return [];
|
|
106
|
+
const results = [];
|
|
107
|
+
for (const [name, entry] of entries) {
|
|
108
|
+
if (entry.stale === true) continue;
|
|
109
|
+
const doc = documentFor(name, entry);
|
|
110
|
+
if (required.some((term) => !doc.lowerName.includes(term))) continue;
|
|
111
|
+
let coverage = 0,
|
|
112
|
+
nameHits = 0,
|
|
113
|
+
descriptionHits = 0;
|
|
114
|
+
for (const term of scoring) {
|
|
115
|
+
const inName =
|
|
116
|
+
doc.lowerName.includes(term) || Boolean(doc.nameWords?.includes(term));
|
|
117
|
+
const inDescription = doc.lowerDescription.includes(term);
|
|
118
|
+
if (inName || inDescription) coverage++;
|
|
119
|
+
if (inName) nameHits++;
|
|
120
|
+
if (inDescription) descriptionHits++;
|
|
121
|
+
}
|
|
122
|
+
if (!coverage) continue;
|
|
123
|
+
// Intent coverage wins over repetition of one broad word. At equal
|
|
124
|
+
// coverage retain the existing 3:1 name/description preference.
|
|
125
|
+
const score =
|
|
126
|
+
coverage * (scoring.length * 4 + 1) + nameHits * 3 + descriptionHits;
|
|
127
|
+
const result = { name, entry, score };
|
|
128
|
+
// Keep only top K, rather than allocating and sorting every matching tool.
|
|
129
|
+
let low = 0,
|
|
130
|
+
high = results.length;
|
|
131
|
+
while (low < high) {
|
|
132
|
+
const mid = (low + high) >>> 1;
|
|
133
|
+
if (compare(result, results[mid]) < 0) high = mid;
|
|
134
|
+
else low = mid + 1;
|
|
135
|
+
}
|
|
136
|
+
if (low < maxResults) {
|
|
137
|
+
results.splice(low, 0, result);
|
|
138
|
+
if (results.length > maxResults) results.pop();
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return results;
|
|
142
|
+
}
|