@goondocks/myco 0.6.4 → 0.9.0
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/.claude-plugin/marketplace.json +2 -3
- package/.claude-plugin/plugin.json +3 -3
- package/CONTRIBUTING.md +37 -30
- package/README.md +64 -28
- package/bin/myco-run +2 -0
- package/dist/agent-run-EFICNTAU.js +34 -0
- package/dist/agent-run-EFICNTAU.js.map +1 -0
- package/dist/agent-tasks-RXJ7Z5NG.js +180 -0
- package/dist/agent-tasks-RXJ7Z5NG.js.map +1 -0
- package/dist/chunk-2T7RPVPP.js +116 -0
- package/dist/chunk-2T7RPVPP.js.map +1 -0
- package/dist/chunk-3K5WGSJ4.js +165 -0
- package/dist/chunk-3K5WGSJ4.js.map +1 -0
- package/dist/chunk-46PWOKSI.js +26 -0
- package/dist/chunk-46PWOKSI.js.map +1 -0
- package/dist/chunk-4LPQ26CK.js +277 -0
- package/dist/chunk-4LPQ26CK.js.map +1 -0
- package/dist/chunk-5PEUFJ6U.js +92 -0
- package/dist/chunk-5PEUFJ6U.js.map +1 -0
- package/dist/chunk-5VZ52A4T.js +136 -0
- package/dist/chunk-5VZ52A4T.js.map +1 -0
- package/dist/chunk-BUSP3OJB.js +103 -0
- package/dist/chunk-BUSP3OJB.js.map +1 -0
- package/dist/chunk-D7TYRPRM.js +7312 -0
- package/dist/chunk-D7TYRPRM.js.map +1 -0
- package/dist/chunk-DCXRSSBP.js +22 -0
- package/dist/chunk-DCXRSSBP.js.map +1 -0
- package/dist/chunk-E4VLWIJC.js +2 -0
- package/dist/chunk-FFAYUQ5N.js +39 -0
- package/dist/chunk-FFAYUQ5N.js.map +1 -0
- package/dist/chunk-IB76KGBY.js +2 -0
- package/dist/chunk-JMJJEQ3P.js +486 -0
- package/dist/chunk-JMJJEQ3P.js.map +1 -0
- package/dist/{chunk-N33KUCFP.js → chunk-JTYZRPX5.js} +1 -9
- package/dist/chunk-JTYZRPX5.js.map +1 -0
- package/dist/{chunk-NLUE6CYG.js → chunk-JYOOJCPQ.js} +33 -17
- package/dist/chunk-JYOOJCPQ.js.map +1 -0
- package/dist/{chunk-Z74SDEKE.js → chunk-KB4DGYIY.js} +91 -9
- package/dist/chunk-KB4DGYIY.js.map +1 -0
- package/dist/{chunk-ERG2IEWX.js → chunk-KH64DHOY.js} +3 -7413
- package/dist/chunk-KH64DHOY.js.map +1 -0
- package/dist/chunk-KV4OC4H3.js +498 -0
- package/dist/chunk-KV4OC4H3.js.map +1 -0
- package/dist/chunk-KYLDNM7H.js +66 -0
- package/dist/chunk-KYLDNM7H.js.map +1 -0
- package/dist/chunk-LPUQPDC2.js +19 -0
- package/dist/chunk-LPUQPDC2.js.map +1 -0
- package/dist/chunk-M5XWW7UI.js +97 -0
- package/dist/chunk-M5XWW7UI.js.map +1 -0
- package/dist/chunk-MHSCMET3.js +275 -0
- package/dist/chunk-MHSCMET3.js.map +1 -0
- package/dist/chunk-MYX5NCRH.js +45 -0
- package/dist/chunk-MYX5NCRH.js.map +1 -0
- package/dist/chunk-OXZSXYAT.js +877 -0
- package/dist/chunk-OXZSXYAT.js.map +1 -0
- package/dist/chunk-PB6TOLRQ.js +35 -0
- package/dist/chunk-PB6TOLRQ.js.map +1 -0
- package/dist/chunk-PT5IC642.js +162 -0
- package/dist/chunk-PT5IC642.js.map +1 -0
- package/dist/chunk-QIK2XSDQ.js +187 -0
- package/dist/chunk-QIK2XSDQ.js.map +1 -0
- package/dist/chunk-RJ6ZQKG5.js +26 -0
- package/dist/chunk-RJ6ZQKG5.js.map +1 -0
- package/dist/{chunk-YIQLYIHW.js → chunk-TRUJLI6K.js} +29 -43
- package/dist/chunk-TRUJLI6K.js.map +1 -0
- package/dist/chunk-U3IBO3O3.js +41 -0
- package/dist/chunk-U3IBO3O3.js.map +1 -0
- package/dist/{chunk-7WHF2OIZ.js → chunk-UBZPD4HN.js} +25 -7
- package/dist/chunk-UBZPD4HN.js.map +1 -0
- package/dist/{chunk-HIN3UVOG.js → chunk-V7XG6V6C.js} +20 -11
- package/dist/chunk-V7XG6V6C.js.map +1 -0
- package/dist/chunk-WGTCA2NU.js +84 -0
- package/dist/chunk-WGTCA2NU.js.map +1 -0
- package/dist/{chunk-O6PERU7U.js → chunk-XNOCTDHF.js} +2 -2
- package/dist/chunk-YDN4OM33.js +80 -0
- package/dist/chunk-YDN4OM33.js.map +1 -0
- package/dist/cli-ODLFRIYS.js +128 -0
- package/dist/cli-ODLFRIYS.js.map +1 -0
- package/dist/client-EYOTW3JU.js +19 -0
- package/dist/client-MXRNQ5FI.js +13 -0
- package/dist/{config-IBS6KOLQ.js → config-UR5BSGVX.js} +21 -34
- package/dist/config-UR5BSGVX.js.map +1 -0
- package/dist/detect-H5OPI7GD.js +17 -0
- package/dist/detect-H5OPI7GD.js.map +1 -0
- package/dist/detect-providers-Q42OD4OS.js +26 -0
- package/dist/detect-providers-Q42OD4OS.js.map +1 -0
- package/dist/doctor-JLKTXDEH.js +258 -0
- package/dist/doctor-JLKTXDEH.js.map +1 -0
- package/dist/executor-ONSDHPGX.js +1441 -0
- package/dist/executor-ONSDHPGX.js.map +1 -0
- package/dist/init-6GWY345B.js +198 -0
- package/dist/init-6GWY345B.js.map +1 -0
- package/dist/init-wizard-UONLDYLI.js +294 -0
- package/dist/init-wizard-UONLDYLI.js.map +1 -0
- package/dist/llm-BV3QNVRD.js +17 -0
- package/dist/llm-BV3QNVRD.js.map +1 -0
- package/dist/loader-SH67XD54.js +28 -0
- package/dist/loader-SH67XD54.js.map +1 -0
- package/dist/loader-XVXKZZDH.js +18 -0
- package/dist/loader-XVXKZZDH.js.map +1 -0
- package/dist/{chunk-H7PRCVGQ.js → logs-QZVYF6FP.js} +74 -5
- package/dist/logs-QZVYF6FP.js.map +1 -0
- package/dist/main-BMCL7CPO.js +4393 -0
- package/dist/main-BMCL7CPO.js.map +1 -0
- package/dist/openai-embeddings-C265WRNK.js +14 -0
- package/dist/openai-embeddings-C265WRNK.js.map +1 -0
- package/dist/openrouter-U6VFCRX2.js +14 -0
- package/dist/openrouter-U6VFCRX2.js.map +1 -0
- package/dist/post-compact-OWFSOITU.js +26 -0
- package/dist/post-compact-OWFSOITU.js.map +1 -0
- package/dist/post-tool-use-DOUM7CGQ.js +56 -0
- package/dist/post-tool-use-DOUM7CGQ.js.map +1 -0
- package/dist/post-tool-use-failure-SG3C7PE6.js +28 -0
- package/dist/post-tool-use-failure-SG3C7PE6.js.map +1 -0
- package/dist/pre-compact-3J33CHXQ.js +25 -0
- package/dist/pre-compact-3J33CHXQ.js.map +1 -0
- package/dist/provider-check-3WBPZADE.js +12 -0
- package/dist/provider-check-3WBPZADE.js.map +1 -0
- package/dist/registry-J4XTWARS.js +25 -0
- package/dist/registry-J4XTWARS.js.map +1 -0
- package/dist/resolution-events-TFEQPVKS.js +12 -0
- package/dist/resolution-events-TFEQPVKS.js.map +1 -0
- package/dist/resolve-3FEUV462.js +9 -0
- package/dist/resolve-3FEUV462.js.map +1 -0
- package/dist/{restart-XCMILOL5.js → restart-2VM33WOB.js} +10 -6
- package/dist/{restart-XCMILOL5.js.map → restart-2VM33WOB.js.map} +1 -1
- package/dist/search-ZGQR5MDE.js +91 -0
- package/dist/search-ZGQR5MDE.js.map +1 -0
- package/dist/{server-6UDN35QN.js → server-6KMBJCHZ.js} +308 -517
- package/dist/server-6KMBJCHZ.js.map +1 -0
- package/dist/session-Z2FXDDG6.js +68 -0
- package/dist/session-Z2FXDDG6.js.map +1 -0
- package/dist/session-end-FLVX32LE.js +38 -0
- package/dist/session-end-FLVX32LE.js.map +1 -0
- package/dist/session-start-UCLK7PXE.js +169 -0
- package/dist/session-start-UCLK7PXE.js.map +1 -0
- package/dist/setup-digest-4KDSXAIV.js +15 -0
- package/dist/setup-digest-4KDSXAIV.js.map +1 -0
- package/dist/setup-llm-GKMCHURK.js +81 -0
- package/dist/setup-llm-GKMCHURK.js.map +1 -0
- package/dist/src/agent/definitions/agent.yaml +35 -0
- package/dist/src/agent/definitions/tasks/digest-only.yaml +84 -0
- package/dist/src/agent/definitions/tasks/extract-only.yaml +87 -0
- package/dist/src/agent/definitions/tasks/full-intelligence.yaml +472 -0
- package/dist/src/agent/definitions/tasks/graph-maintenance.yaml +92 -0
- package/dist/src/agent/definitions/tasks/review-session.yaml +132 -0
- package/dist/src/agent/definitions/tasks/supersession-sweep.yaml +86 -0
- package/dist/src/agent/definitions/tasks/title-summary.yaml +88 -0
- package/dist/src/agent/prompts/agent.md +121 -0
- package/dist/src/agent/prompts/orchestrator.md +91 -0
- package/dist/src/cli.js +1 -8
- package/dist/src/cli.js.map +1 -1
- package/dist/src/daemon/main.js +1 -8
- package/dist/src/daemon/main.js.map +1 -1
- package/dist/src/hooks/post-tool-use.js +3 -50
- package/dist/src/hooks/post-tool-use.js.map +1 -1
- package/dist/src/hooks/session-end.js +3 -32
- package/dist/src/hooks/session-end.js.map +1 -1
- package/dist/src/hooks/session-start.js +2 -8
- package/dist/src/hooks/session-start.js.map +1 -1
- package/dist/src/hooks/stop.js +3 -42
- package/dist/src/hooks/stop.js.map +1 -1
- package/dist/src/hooks/user-prompt-submit.js +3 -53
- package/dist/src/hooks/user-prompt-submit.js.map +1 -1
- package/dist/src/mcp/server.js +1 -8
- package/dist/src/mcp/server.js.map +1 -1
- package/dist/src/prompts/digest-system.md +1 -1
- package/dist/src/symbionts/manifests/claude-code.yaml +16 -0
- package/dist/src/symbionts/manifests/cursor.yaml +14 -0
- package/dist/stats-IUJPZSVZ.js +94 -0
- package/dist/stats-IUJPZSVZ.js.map +1 -0
- package/dist/stop-XRQLLXST.js +42 -0
- package/dist/stop-XRQLLXST.js.map +1 -0
- package/dist/stop-failure-2CAJJKRG.js +26 -0
- package/dist/stop-failure-2CAJJKRG.js.map +1 -0
- package/dist/subagent-start-MWWQTZMQ.js +26 -0
- package/dist/subagent-start-MWWQTZMQ.js.map +1 -0
- package/dist/subagent-stop-PJXYGRXB.js +28 -0
- package/dist/subagent-stop-PJXYGRXB.js.map +1 -0
- package/dist/task-completed-4LFRJVGI.js +27 -0
- package/dist/task-completed-4LFRJVGI.js.map +1 -0
- package/dist/ui/assets/index-DZrElonz.js +744 -0
- package/dist/ui/assets/index-TkeiYbZB.css +1 -0
- package/dist/ui/favicon.svg +7 -7
- package/dist/ui/fonts/Inter-Variable.woff2 +0 -0
- package/dist/ui/fonts/JetBrainsMono-Variable.woff2 +0 -0
- package/dist/ui/fonts/Newsreader-Italic-Variable.woff2 +0 -0
- package/dist/ui/fonts/Newsreader-Variable.woff2 +0 -0
- package/dist/ui/index.html +2 -2
- package/dist/user-prompt-submit-KSM3AR6P.js +59 -0
- package/dist/user-prompt-submit-KSM3AR6P.js.map +1 -0
- package/dist/{verify-TOWQHPBX.js → verify-UDAYVX37.js} +17 -22
- package/dist/verify-UDAYVX37.js.map +1 -0
- package/dist/{version-36RVCQA6.js → version-KLBN4HZT.js} +3 -4
- package/dist/version-KLBN4HZT.js.map +1 -0
- package/hooks/hooks.json +82 -5
- package/package.json +6 -3
- package/skills/myco/SKILL.md +10 -10
- package/skills/myco/references/cli-usage.md +15 -13
- package/skills/myco/references/vault-status.md +3 -3
- package/skills/myco/references/wisdom.md +4 -4
- package/skills/myco-curate/SKILL.md +86 -0
- package/dist/chunk-2ZIBCEYO.js +0 -113
- package/dist/chunk-2ZIBCEYO.js.map +0 -1
- package/dist/chunk-4RMSHZE4.js +0 -107
- package/dist/chunk-4RMSHZE4.js.map +0 -1
- package/dist/chunk-4XVKZ3WA.js +0 -1078
- package/dist/chunk-4XVKZ3WA.js.map +0 -1
- package/dist/chunk-6FQISQNA.js +0 -61
- package/dist/chunk-6FQISQNA.js.map +0 -1
- package/dist/chunk-7WHF2OIZ.js.map +0 -1
- package/dist/chunk-ERG2IEWX.js.map +0 -1
- package/dist/chunk-FPRXMJLT.js +0 -56
- package/dist/chunk-FPRXMJLT.js.map +0 -1
- package/dist/chunk-GENQ5QGP.js +0 -37
- package/dist/chunk-GENQ5QGP.js.map +0 -1
- package/dist/chunk-H7PRCVGQ.js.map +0 -1
- package/dist/chunk-HIN3UVOG.js.map +0 -1
- package/dist/chunk-HYVT345Y.js +0 -159
- package/dist/chunk-HYVT345Y.js.map +0 -1
- package/dist/chunk-J4D4CROB.js +0 -143
- package/dist/chunk-J4D4CROB.js.map +0 -1
- package/dist/chunk-MDLSAFPP.js +0 -99
- package/dist/chunk-MDLSAFPP.js.map +0 -1
- package/dist/chunk-N33KUCFP.js.map +0 -1
- package/dist/chunk-NL6WQO56.js +0 -65
- package/dist/chunk-NL6WQO56.js.map +0 -1
- package/dist/chunk-NLUE6CYG.js.map +0 -1
- package/dist/chunk-P723N2LP.js +0 -147
- package/dist/chunk-P723N2LP.js.map +0 -1
- package/dist/chunk-QLUE3BUL.js +0 -161
- package/dist/chunk-QLUE3BUL.js.map +0 -1
- package/dist/chunk-QN4W3JUA.js +0 -43
- package/dist/chunk-QN4W3JUA.js.map +0 -1
- package/dist/chunk-RGVBGTD6.js +0 -21
- package/dist/chunk-RGVBGTD6.js.map +0 -1
- package/dist/chunk-TWSTAVLO.js +0 -132
- package/dist/chunk-TWSTAVLO.js.map +0 -1
- package/dist/chunk-UP4P4OAA.js +0 -4423
- package/dist/chunk-UP4P4OAA.js.map +0 -1
- package/dist/chunk-YIQLYIHW.js.map +0 -1
- package/dist/chunk-YTFXA4RX.js +0 -86
- package/dist/chunk-YTFXA4RX.js.map +0 -1
- package/dist/chunk-Z74SDEKE.js.map +0 -1
- package/dist/cli-IHILSS6N.js +0 -97
- package/dist/cli-IHILSS6N.js.map +0 -1
- package/dist/client-AGFNR2S4.js +0 -12
- package/dist/config-IBS6KOLQ.js.map +0 -1
- package/dist/curate-3D4GHKJH.js +0 -78
- package/dist/curate-3D4GHKJH.js.map +0 -1
- package/dist/detect-providers-XEP4QA3R.js +0 -35
- package/dist/detect-providers-XEP4QA3R.js.map +0 -1
- package/dist/digest-7HLJXL77.js +0 -85
- package/dist/digest-7HLJXL77.js.map +0 -1
- package/dist/init-ARQ53JOR.js +0 -109
- package/dist/init-ARQ53JOR.js.map +0 -1
- package/dist/logs-IENORIYR.js +0 -84
- package/dist/logs-IENORIYR.js.map +0 -1
- package/dist/main-6AGPIMH2.js +0 -5715
- package/dist/main-6AGPIMH2.js.map +0 -1
- package/dist/rebuild-Q2ACEB6F.js +0 -64
- package/dist/rebuild-Q2ACEB6F.js.map +0 -1
- package/dist/reprocess-CDEFGQOV.js +0 -79
- package/dist/reprocess-CDEFGQOV.js.map +0 -1
- package/dist/search-7W25SKCB.js +0 -120
- package/dist/search-7W25SKCB.js.map +0 -1
- package/dist/server-6UDN35QN.js.map +0 -1
- package/dist/session-F326AWCH.js +0 -44
- package/dist/session-F326AWCH.js.map +0 -1
- package/dist/session-start-K6IGAC7H.js +0 -192
- package/dist/session-start-K6IGAC7H.js.map +0 -1
- package/dist/setup-digest-X5PN27F4.js +0 -15
- package/dist/setup-llm-S5OHQJXK.js +0 -15
- package/dist/src/prompts/classification.md +0 -43
- package/dist/stats-TTSDXGJV.js +0 -58
- package/dist/stats-TTSDXGJV.js.map +0 -1
- package/dist/templates-XPRBOWCE.js +0 -38
- package/dist/templates-XPRBOWCE.js.map +0 -1
- package/dist/ui/assets/index-08wKT7wS.css +0 -1
- package/dist/ui/assets/index-CMSMi4Jb.js +0 -369
- package/dist/verify-TOWQHPBX.js.map +0 -1
- package/skills/setup/SKILL.md +0 -174
- package/skills/setup/references/model-recommendations.md +0 -83
- /package/dist/{client-AGFNR2S4.js.map → chunk-E4VLWIJC.js.map} +0 -0
- /package/dist/{setup-digest-X5PN27F4.js.map → chunk-IB76KGBY.js.map} +0 -0
- /package/dist/{chunk-O6PERU7U.js.map → chunk-XNOCTDHF.js.map} +0 -0
- /package/dist/{setup-llm-S5OHQJXK.js.map → client-EYOTW3JU.js.map} +0 -0
- /package/dist/{version-36RVCQA6.js.map → client-MXRNQ5FI.js.map} +0 -0
|
@@ -0,0 +1,1441 @@
|
|
|
1
|
+
import { createRequire as __cr } from 'node:module'; const require = __cr(import.meta.url);
|
|
2
|
+
import {
|
|
3
|
+
insertResolutionEvent
|
|
4
|
+
} from "./chunk-YDN4OM33.js";
|
|
5
|
+
import {
|
|
6
|
+
STATUS_COMPLETED,
|
|
7
|
+
STATUS_FAILED,
|
|
8
|
+
STATUS_RUNNING,
|
|
9
|
+
createSporeLineage,
|
|
10
|
+
errorMessage,
|
|
11
|
+
getRunningRun,
|
|
12
|
+
getUnprocessedBatches,
|
|
13
|
+
insertEntity,
|
|
14
|
+
insertGraphEdge,
|
|
15
|
+
insertReport,
|
|
16
|
+
insertRun,
|
|
17
|
+
insertTurn,
|
|
18
|
+
listDigestExtracts,
|
|
19
|
+
listEntities,
|
|
20
|
+
listGraphEdges,
|
|
21
|
+
markBatchProcessed,
|
|
22
|
+
updateRunStatus,
|
|
23
|
+
upsertDigestExtract
|
|
24
|
+
} from "./chunk-OXZSXYAT.js";
|
|
25
|
+
import {
|
|
26
|
+
fullTextSearch
|
|
27
|
+
} from "./chunk-PT5IC642.js";
|
|
28
|
+
import {
|
|
29
|
+
loadAllTasks
|
|
30
|
+
} from "./chunk-BUSP3OJB.js";
|
|
31
|
+
import {
|
|
32
|
+
getAgent,
|
|
33
|
+
getDefaultTask,
|
|
34
|
+
getTask,
|
|
35
|
+
loadAgentDefinition,
|
|
36
|
+
loadSystemPrompt,
|
|
37
|
+
resolveDefinitionsDir,
|
|
38
|
+
resolveEffectiveConfig
|
|
39
|
+
} from "./chunk-JMJJEQ3P.js";
|
|
40
|
+
import "./chunk-IB76KGBY.js";
|
|
41
|
+
import {
|
|
42
|
+
DEFAULT_IMPORTANCE,
|
|
43
|
+
insertSpore,
|
|
44
|
+
listSpores,
|
|
45
|
+
updateSporeStatus
|
|
46
|
+
} from "./chunk-3K5WGSJ4.js";
|
|
47
|
+
import {
|
|
48
|
+
listSessions,
|
|
49
|
+
updateSession
|
|
50
|
+
} from "./chunk-4LPQ26CK.js";
|
|
51
|
+
import {
|
|
52
|
+
createSchema
|
|
53
|
+
} from "./chunk-KV4OC4H3.js";
|
|
54
|
+
import {
|
|
55
|
+
loadConfig
|
|
56
|
+
} from "./chunk-MHSCMET3.js";
|
|
57
|
+
import "./chunk-D7TYRPRM.js";
|
|
58
|
+
import "./chunk-E4VLWIJC.js";
|
|
59
|
+
import {
|
|
60
|
+
external_exports
|
|
61
|
+
} from "./chunk-KH64DHOY.js";
|
|
62
|
+
import {
|
|
63
|
+
getDatabase,
|
|
64
|
+
initDatabase,
|
|
65
|
+
vaultDbPath
|
|
66
|
+
} from "./chunk-MYX5NCRH.js";
|
|
67
|
+
import {
|
|
68
|
+
DEFAULT_AGENT_ID,
|
|
69
|
+
MS_PER_SECOND,
|
|
70
|
+
PHASE_SUMMARY_MAX_CHARS,
|
|
71
|
+
SEARCH_SIMILARITY_THRESHOLD,
|
|
72
|
+
epochSeconds
|
|
73
|
+
} from "./chunk-5VZ52A4T.js";
|
|
74
|
+
import "./chunk-WGTCA2NU.js";
|
|
75
|
+
import {
|
|
76
|
+
getPluginVersion
|
|
77
|
+
} from "./chunk-PB6TOLRQ.js";
|
|
78
|
+
import {
|
|
79
|
+
findPackageRoot
|
|
80
|
+
} from "./chunk-LPUQPDC2.js";
|
|
81
|
+
import "./chunk-PZUWP5VK.js";
|
|
82
|
+
|
|
83
|
+
// src/agent/executor.ts
|
|
84
|
+
import crypto2 from "crypto";
|
|
85
|
+
|
|
86
|
+
// src/agent/tools.ts
|
|
87
|
+
import crypto from "crypto";
|
|
88
|
+
import { tool, createSdkMcpServer } from "@anthropic-ai/claude-agent-sdk";
|
|
89
|
+
|
|
90
|
+
// src/db/queries/agent-state.ts
|
|
91
|
+
var STATE_COLUMNS = [
|
|
92
|
+
"agent_id",
|
|
93
|
+
"key",
|
|
94
|
+
"value",
|
|
95
|
+
"updated_at"
|
|
96
|
+
];
|
|
97
|
+
var SELECT_COLUMNS = STATE_COLUMNS.join(", ");
|
|
98
|
+
function toAgentStateRow(row) {
|
|
99
|
+
return {
|
|
100
|
+
agent_id: row.agent_id,
|
|
101
|
+
key: row.key,
|
|
102
|
+
value: row.value,
|
|
103
|
+
updated_at: row.updated_at
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
function setState(agentId, key, value, updatedAt) {
|
|
107
|
+
const db = getDatabase();
|
|
108
|
+
db.prepare(
|
|
109
|
+
`INSERT INTO agent_state (agent_id, key, value, updated_at)
|
|
110
|
+
VALUES (?, ?, ?, ?)
|
|
111
|
+
ON CONFLICT (agent_id, key) DO UPDATE SET
|
|
112
|
+
value = EXCLUDED.value,
|
|
113
|
+
updated_at = EXCLUDED.updated_at`
|
|
114
|
+
).run(agentId, key, value, updatedAt);
|
|
115
|
+
return toAgentStateRow(
|
|
116
|
+
db.prepare(`SELECT ${SELECT_COLUMNS} FROM agent_state WHERE agent_id = ? AND key = ?`).get(agentId, key)
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
function getStatesForAgent(agentId) {
|
|
120
|
+
const db = getDatabase();
|
|
121
|
+
const rows = db.prepare(
|
|
122
|
+
`SELECT ${SELECT_COLUMNS}
|
|
123
|
+
FROM agent_state
|
|
124
|
+
WHERE agent_id = ?
|
|
125
|
+
ORDER BY key ASC`
|
|
126
|
+
).all(agentId);
|
|
127
|
+
return rows.map(toAgentStateRow);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// src/agent/tools.ts
|
|
131
|
+
var DEFAULT_UNPROCESSED_LIMIT = 50;
|
|
132
|
+
var DEFAULT_SPORES_LIMIT = 50;
|
|
133
|
+
var DEFAULT_SESSIONS_LIMIT = 20;
|
|
134
|
+
var DEFAULT_SEARCH_LIMIT = 10;
|
|
135
|
+
var DEFAULT_ENTITIES_LIMIT = 50;
|
|
136
|
+
var DEFAULT_EDGES_LIMIT = 50;
|
|
137
|
+
function textResult(data) {
|
|
138
|
+
return { content: [{ type: "text", text: JSON.stringify(data) }] };
|
|
139
|
+
}
|
|
140
|
+
function createVaultTools(agentId, runId, turnOffset = 0, embeddingManager) {
|
|
141
|
+
let turnCounter = turnOffset;
|
|
142
|
+
function recordTurn(toolName, toolInput) {
|
|
143
|
+
turnCounter++;
|
|
144
|
+
try {
|
|
145
|
+
insertTurn({
|
|
146
|
+
run_id: runId,
|
|
147
|
+
agent_id: agentId,
|
|
148
|
+
turn_number: turnCounter,
|
|
149
|
+
tool_name: toolName,
|
|
150
|
+
tool_input: JSON.stringify(toolInput),
|
|
151
|
+
started_at: epochSeconds()
|
|
152
|
+
});
|
|
153
|
+
} catch {
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const vaultUnprocessed = tool(
|
|
157
|
+
"vault_unprocessed",
|
|
158
|
+
"Get unprocessed prompt batches, ordered by id ASC. Supports cursor-based pagination.",
|
|
159
|
+
{
|
|
160
|
+
after_id: external_exports.number().optional().describe("Return batches with id greater than this"),
|
|
161
|
+
limit: external_exports.number().optional().describe("Maximum number of batches to return")
|
|
162
|
+
},
|
|
163
|
+
async (args) => {
|
|
164
|
+
recordTurn("vault_unprocessed", args);
|
|
165
|
+
const batches = getUnprocessedBatches({
|
|
166
|
+
after_id: args.after_id,
|
|
167
|
+
limit: args.limit ?? DEFAULT_UNPROCESSED_LIMIT
|
|
168
|
+
});
|
|
169
|
+
return textResult(batches);
|
|
170
|
+
},
|
|
171
|
+
{ annotations: { readOnlyHint: true } }
|
|
172
|
+
);
|
|
173
|
+
const vaultSpores = tool(
|
|
174
|
+
"vault_spores",
|
|
175
|
+
"List spores with optional filters (agent, observation type, status, session).",
|
|
176
|
+
{
|
|
177
|
+
agent_id: external_exports.string().optional().describe("Filter by agent ID"),
|
|
178
|
+
observation_type: external_exports.string().optional().describe("Filter by observation type (e.g., gotcha, decision)"),
|
|
179
|
+
status: external_exports.enum(["active", "superseded", "archived"]).optional().describe("Filter by status"),
|
|
180
|
+
session_id: external_exports.string().optional().describe("Filter by session ID"),
|
|
181
|
+
limit: external_exports.number().optional().describe("Maximum number of spores to return")
|
|
182
|
+
},
|
|
183
|
+
async (args) => {
|
|
184
|
+
recordTurn("vault_spores", args);
|
|
185
|
+
const spores = listSpores({
|
|
186
|
+
agent_id: args.agent_id,
|
|
187
|
+
observation_type: args.observation_type,
|
|
188
|
+
status: args.status,
|
|
189
|
+
session_id: args.session_id,
|
|
190
|
+
limit: args.limit ?? DEFAULT_SPORES_LIMIT
|
|
191
|
+
});
|
|
192
|
+
return textResult(spores);
|
|
193
|
+
},
|
|
194
|
+
{ annotations: { readOnlyHint: true } }
|
|
195
|
+
);
|
|
196
|
+
const vaultSessions = tool(
|
|
197
|
+
"vault_sessions",
|
|
198
|
+
"List sessions with optional status filter, ordered by created_at DESC.",
|
|
199
|
+
{
|
|
200
|
+
limit: external_exports.number().optional().describe("Maximum number of sessions to return"),
|
|
201
|
+
status: external_exports.string().optional().describe("Filter by status (active, completed)")
|
|
202
|
+
},
|
|
203
|
+
async (args) => {
|
|
204
|
+
recordTurn("vault_sessions", args);
|
|
205
|
+
const sessions = listSessions({
|
|
206
|
+
limit: args.limit ?? DEFAULT_SESSIONS_LIMIT,
|
|
207
|
+
status: args.status
|
|
208
|
+
});
|
|
209
|
+
return textResult(sessions);
|
|
210
|
+
},
|
|
211
|
+
{ annotations: { readOnlyHint: true } }
|
|
212
|
+
);
|
|
213
|
+
const vaultSearchFts = tool(
|
|
214
|
+
"vault_search_fts",
|
|
215
|
+
"Full-text search across prompt batches and activities using FTS5. Best for finding specific text, keywords, or session content. Does NOT search spores or entities.",
|
|
216
|
+
{
|
|
217
|
+
query: external_exports.string().describe("Search query text"),
|
|
218
|
+
type: external_exports.string().optional().describe("Restrict to a result type (prompt_batch, activity)"),
|
|
219
|
+
limit: external_exports.number().optional().describe("Maximum number of results to return")
|
|
220
|
+
},
|
|
221
|
+
async (args) => {
|
|
222
|
+
recordTurn("vault_search_fts", args);
|
|
223
|
+
try {
|
|
224
|
+
const results = fullTextSearch(args.query, {
|
|
225
|
+
type: args.type,
|
|
226
|
+
limit: args.limit ?? DEFAULT_SEARCH_LIMIT
|
|
227
|
+
});
|
|
228
|
+
return textResult({ results });
|
|
229
|
+
} catch {
|
|
230
|
+
return textResult({ results: [], message: "Search unavailable" });
|
|
231
|
+
}
|
|
232
|
+
},
|
|
233
|
+
{ annotations: { readOnlyHint: true } }
|
|
234
|
+
);
|
|
235
|
+
const vaultSearchSemantic = tool(
|
|
236
|
+
"vault_search_semantic",
|
|
237
|
+
"Semantic similarity search across embedded vault content (spores, sessions). Best for finding conceptually related content. Returns results ranked by similarity score.",
|
|
238
|
+
{
|
|
239
|
+
query: external_exports.string().describe("Search query text"),
|
|
240
|
+
namespace: external_exports.string().optional().describe("Restrict to a content type: spores, sessions"),
|
|
241
|
+
limit: external_exports.number().optional().describe("Maximum results to return")
|
|
242
|
+
},
|
|
243
|
+
async (args) => {
|
|
244
|
+
recordTurn("vault_search_semantic", args);
|
|
245
|
+
if (!embeddingManager) {
|
|
246
|
+
return textResult({ results: [], message: "Embedding provider unavailable" });
|
|
247
|
+
}
|
|
248
|
+
try {
|
|
249
|
+
const queryVector = await embeddingManager.embedQuery(args.query);
|
|
250
|
+
if (!queryVector) {
|
|
251
|
+
return textResult({ results: [], message: "Embedding provider unavailable" });
|
|
252
|
+
}
|
|
253
|
+
const results = embeddingManager.searchVectors(queryVector, {
|
|
254
|
+
namespace: args.namespace,
|
|
255
|
+
limit: args.limit ?? DEFAULT_SEARCH_LIMIT,
|
|
256
|
+
threshold: SEARCH_SIMILARITY_THRESHOLD
|
|
257
|
+
});
|
|
258
|
+
return textResult({ results });
|
|
259
|
+
} catch {
|
|
260
|
+
return textResult({ results: [], message: "Semantic search unavailable" });
|
|
261
|
+
}
|
|
262
|
+
},
|
|
263
|
+
{ annotations: { readOnlyHint: true } }
|
|
264
|
+
);
|
|
265
|
+
const vaultState = tool(
|
|
266
|
+
"vault_state",
|
|
267
|
+
"Get all state key-value pairs for the current agent.",
|
|
268
|
+
{},
|
|
269
|
+
async () => {
|
|
270
|
+
recordTurn("vault_state", {});
|
|
271
|
+
const states = getStatesForAgent(agentId);
|
|
272
|
+
return textResult(states);
|
|
273
|
+
},
|
|
274
|
+
{ annotations: { readOnlyHint: true } }
|
|
275
|
+
);
|
|
276
|
+
const vaultEntities = tool(
|
|
277
|
+
"vault_entities",
|
|
278
|
+
"List knowledge graph entities with optional filters.",
|
|
279
|
+
{
|
|
280
|
+
type: external_exports.enum(["component", "concept", "person"]).optional().describe("Filter by entity type"),
|
|
281
|
+
name: external_exports.string().optional().describe("Filter by entity name (exact match)"),
|
|
282
|
+
limit: external_exports.number().optional().describe("Maximum entities to return")
|
|
283
|
+
},
|
|
284
|
+
async (args) => {
|
|
285
|
+
recordTurn("vault_entities", args);
|
|
286
|
+
const entities = listEntities({
|
|
287
|
+
agent_id: agentId,
|
|
288
|
+
type: args.type,
|
|
289
|
+
name: args.name,
|
|
290
|
+
limit: args.limit ?? DEFAULT_ENTITIES_LIMIT
|
|
291
|
+
});
|
|
292
|
+
return textResult(entities);
|
|
293
|
+
},
|
|
294
|
+
{ annotations: { readOnlyHint: true } }
|
|
295
|
+
);
|
|
296
|
+
const vaultEdges = tool(
|
|
297
|
+
"vault_edges",
|
|
298
|
+
"List knowledge graph edges with optional filters. Use to check existing relationships before creating new ones.",
|
|
299
|
+
{
|
|
300
|
+
source_id: external_exports.string().optional().describe("Filter by source node ID"),
|
|
301
|
+
target_id: external_exports.string().optional().describe("Filter by target node ID"),
|
|
302
|
+
type: external_exports.string().optional().describe("Filter by edge type (REFERENCES, DEPENDS_ON, AFFECTS, etc.)"),
|
|
303
|
+
limit: external_exports.number().optional().describe("Maximum edges to return")
|
|
304
|
+
},
|
|
305
|
+
async (args) => {
|
|
306
|
+
recordTurn("vault_edges", args);
|
|
307
|
+
const edges = listGraphEdges({
|
|
308
|
+
sourceId: args.source_id,
|
|
309
|
+
targetId: args.target_id,
|
|
310
|
+
type: args.type,
|
|
311
|
+
agentId,
|
|
312
|
+
limit: args.limit ?? DEFAULT_EDGES_LIMIT
|
|
313
|
+
});
|
|
314
|
+
return textResult(edges);
|
|
315
|
+
},
|
|
316
|
+
{ annotations: { readOnlyHint: true } }
|
|
317
|
+
);
|
|
318
|
+
const vaultCreateSpore = tool(
|
|
319
|
+
"vault_create_spore",
|
|
320
|
+
"Create a new spore (observation) in the vault. The agent_id is set automatically.",
|
|
321
|
+
{
|
|
322
|
+
observation_type: external_exports.string().describe("Type of observation (gotcha, decision, discovery, trade-off, bug_fix, etc.)"),
|
|
323
|
+
content: external_exports.string().describe("The observation content in markdown"),
|
|
324
|
+
session_id: external_exports.string().optional().describe("Associated session ID"),
|
|
325
|
+
prompt_batch_id: external_exports.number().optional().describe("Associated prompt batch ID"),
|
|
326
|
+
importance: external_exports.number().optional().describe("Importance score 1-10 (default 5)"),
|
|
327
|
+
tags: external_exports.array(external_exports.string()).optional().describe("Tags for categorization"),
|
|
328
|
+
context: external_exports.string().optional().describe("Additional context about the observation"),
|
|
329
|
+
file_path: external_exports.string().optional().describe("Related file path"),
|
|
330
|
+
properties: external_exports.string().optional().describe('JSON metadata (e.g., {"consolidated_from": [...]} for wisdom spores)')
|
|
331
|
+
},
|
|
332
|
+
async (args) => {
|
|
333
|
+
const id = crypto.randomUUID();
|
|
334
|
+
const now = epochSeconds();
|
|
335
|
+
const spore = insertSpore({
|
|
336
|
+
id,
|
|
337
|
+
agent_id: agentId,
|
|
338
|
+
observation_type: args.observation_type,
|
|
339
|
+
content: args.content,
|
|
340
|
+
session_id: args.session_id ?? null,
|
|
341
|
+
prompt_batch_id: args.prompt_batch_id ?? null,
|
|
342
|
+
importance: args.importance ?? DEFAULT_IMPORTANCE,
|
|
343
|
+
tags: args.tags ? JSON.stringify(args.tags) : null,
|
|
344
|
+
context: args.context ?? null,
|
|
345
|
+
file_path: args.file_path ?? null,
|
|
346
|
+
properties: args.properties ?? null,
|
|
347
|
+
created_at: now
|
|
348
|
+
});
|
|
349
|
+
try {
|
|
350
|
+
createSporeLineage(spore);
|
|
351
|
+
} catch {
|
|
352
|
+
}
|
|
353
|
+
embeddingManager?.onContentWritten("spores", spore.id, args.content, {
|
|
354
|
+
status: "active",
|
|
355
|
+
observation_type: args.observation_type,
|
|
356
|
+
session_id: args.session_id
|
|
357
|
+
}).catch(() => {
|
|
358
|
+
});
|
|
359
|
+
recordTurn("vault_create_spore", args);
|
|
360
|
+
return textResult(spore);
|
|
361
|
+
}
|
|
362
|
+
);
|
|
363
|
+
const vaultCreateEntity = tool(
|
|
364
|
+
"vault_create_entity",
|
|
365
|
+
"Create or update an entity in the knowledge graph. Uses UPSERT on (agent_id, type, name).",
|
|
366
|
+
{
|
|
367
|
+
type: external_exports.enum(["component", "concept", "person"]).describe("Entity type"),
|
|
368
|
+
name: external_exports.string().describe("Entity name (unique within agent + type)"),
|
|
369
|
+
properties: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Additional properties as key-value pairs")
|
|
370
|
+
},
|
|
371
|
+
async (args) => {
|
|
372
|
+
const id = crypto.randomUUID();
|
|
373
|
+
const now = epochSeconds();
|
|
374
|
+
const props = args.properties ? JSON.stringify(args.properties) : null;
|
|
375
|
+
const entity = insertEntity({
|
|
376
|
+
id,
|
|
377
|
+
agent_id: agentId,
|
|
378
|
+
type: args.type,
|
|
379
|
+
name: args.name,
|
|
380
|
+
properties: props,
|
|
381
|
+
first_seen: now,
|
|
382
|
+
last_seen: now
|
|
383
|
+
});
|
|
384
|
+
recordTurn("vault_create_entity", args);
|
|
385
|
+
return textResult(entity);
|
|
386
|
+
}
|
|
387
|
+
);
|
|
388
|
+
const vaultCreateEdge = tool(
|
|
389
|
+
"vault_create_edge",
|
|
390
|
+
"Create a semantic edge in the knowledge graph. Lineage edges (FROM_SESSION, EXTRACTED_FROM, HAS_BATCH, DERIVED_FROM) are created automatically \u2014 do NOT create those.",
|
|
391
|
+
{
|
|
392
|
+
source_id: external_exports.string().describe("Source node ID"),
|
|
393
|
+
source_type: external_exports.enum(["session", "batch", "spore", "entity"]).describe("Source node type"),
|
|
394
|
+
target_id: external_exports.string().describe("Target node ID"),
|
|
395
|
+
target_type: external_exports.enum(["session", "batch", "spore", "entity"]).describe("Target node type"),
|
|
396
|
+
type: external_exports.enum(["RELATES_TO", "SUPERSEDED_BY", "REFERENCES", "DEPENDS_ON", "AFFECTS"]).describe("Semantic edge type"),
|
|
397
|
+
session_id: external_exports.string().optional().describe("Session where this relationship was observed"),
|
|
398
|
+
confidence: external_exports.number().optional().describe("Confidence score 0-1 (default 1.0)"),
|
|
399
|
+
properties: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Additional properties as key-value pairs")
|
|
400
|
+
},
|
|
401
|
+
async (args) => {
|
|
402
|
+
const now = epochSeconds();
|
|
403
|
+
const props = args.properties ? JSON.stringify(args.properties) : void 0;
|
|
404
|
+
const edge = insertGraphEdge({
|
|
405
|
+
agent_id: agentId,
|
|
406
|
+
source_id: args.source_id,
|
|
407
|
+
source_type: args.source_type,
|
|
408
|
+
target_id: args.target_id,
|
|
409
|
+
target_type: args.target_type,
|
|
410
|
+
type: args.type,
|
|
411
|
+
session_id: args.session_id,
|
|
412
|
+
confidence: args.confidence,
|
|
413
|
+
properties: props,
|
|
414
|
+
created_at: now
|
|
415
|
+
});
|
|
416
|
+
recordTurn("vault_create_edge", args);
|
|
417
|
+
return textResult(edge);
|
|
418
|
+
}
|
|
419
|
+
);
|
|
420
|
+
const vaultResolveSpore = tool(
|
|
421
|
+
"vault_resolve_spore",
|
|
422
|
+
"Resolve a spore by updating its status and recording a resolution event.",
|
|
423
|
+
{
|
|
424
|
+
spore_id: external_exports.string().describe("ID of the spore to resolve"),
|
|
425
|
+
action: external_exports.enum(["supersede", "archive", "merge", "split", "consolidate"]).describe("Resolution action"),
|
|
426
|
+
new_spore_id: external_exports.string().optional().describe("ID of the replacement spore (for supersede/merge)"),
|
|
427
|
+
reason: external_exports.string().optional().describe("Explanation for the resolution"),
|
|
428
|
+
session_id: external_exports.string().optional().describe("Session where this resolution occurred")
|
|
429
|
+
},
|
|
430
|
+
async (args) => {
|
|
431
|
+
const now = epochSeconds();
|
|
432
|
+
const statusMap = {
|
|
433
|
+
supersede: "superseded",
|
|
434
|
+
archive: "archived",
|
|
435
|
+
merge: "merged",
|
|
436
|
+
split: "split",
|
|
437
|
+
consolidate: "consolidated"
|
|
438
|
+
};
|
|
439
|
+
const newStatus = statusMap[args.action] ?? args.action;
|
|
440
|
+
const updatedSpore = updateSporeStatus(args.spore_id, newStatus, now);
|
|
441
|
+
const eventId = crypto.randomUUID();
|
|
442
|
+
insertResolutionEvent({
|
|
443
|
+
id: eventId,
|
|
444
|
+
agent_id: agentId,
|
|
445
|
+
spore_id: args.spore_id,
|
|
446
|
+
action: args.action,
|
|
447
|
+
new_spore_id: args.new_spore_id ?? null,
|
|
448
|
+
reason: args.reason ?? null,
|
|
449
|
+
session_id: args.session_id ?? null,
|
|
450
|
+
created_at: now
|
|
451
|
+
});
|
|
452
|
+
if (newStatus !== "active") {
|
|
453
|
+
try {
|
|
454
|
+
embeddingManager?.onStatusChanged("spores", args.spore_id, newStatus);
|
|
455
|
+
} catch {
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
recordTurn("vault_resolve_spore", args);
|
|
459
|
+
return textResult({ spore: updatedSpore, resolution_event_id: eventId });
|
|
460
|
+
}
|
|
461
|
+
);
|
|
462
|
+
const vaultUpdateSession = tool(
|
|
463
|
+
"vault_update_session",
|
|
464
|
+
"Update a session title and/or summary. When generating for the first time, provide BOTH title and summary. Title should be under 80 characters and reflect the full session scope.",
|
|
465
|
+
{
|
|
466
|
+
session_id: external_exports.string().describe("Session ID to update"),
|
|
467
|
+
title: external_exports.string().optional().describe("New session title"),
|
|
468
|
+
summary: external_exports.string().optional().describe("New session summary")
|
|
469
|
+
},
|
|
470
|
+
async (args) => {
|
|
471
|
+
const updates = {};
|
|
472
|
+
if (args.title !== void 0) updates.title = args.title;
|
|
473
|
+
if (args.summary !== void 0) updates.summary = args.summary;
|
|
474
|
+
const session = updateSession(args.session_id, updates);
|
|
475
|
+
if (args.summary) {
|
|
476
|
+
embeddingManager?.onContentWritten("sessions", args.session_id, args.summary, {}).catch(() => {
|
|
477
|
+
});
|
|
478
|
+
}
|
|
479
|
+
recordTurn("vault_update_session", args);
|
|
480
|
+
return textResult(session);
|
|
481
|
+
}
|
|
482
|
+
);
|
|
483
|
+
const vaultSetState = tool(
|
|
484
|
+
"vault_set_state",
|
|
485
|
+
"Set a key-value state pair for the current agent. Used for bookmarks, cursors, and preferences.",
|
|
486
|
+
{
|
|
487
|
+
key: external_exports.string().describe("State key (e.g., last_processed_batch_id, cursor)"),
|
|
488
|
+
value: external_exports.string().describe("State value (stored as text)")
|
|
489
|
+
},
|
|
490
|
+
async (args) => {
|
|
491
|
+
const now = epochSeconds();
|
|
492
|
+
const state = setState(agentId, args.key, args.value, now);
|
|
493
|
+
recordTurn("vault_set_state", args);
|
|
494
|
+
return textResult(state);
|
|
495
|
+
}
|
|
496
|
+
);
|
|
497
|
+
const vaultReadDigest = tool(
|
|
498
|
+
"vault_read_digest",
|
|
499
|
+
"Read current digest extracts. Without a tier parameter, returns a summary of all tiers (content length, generation time). With a tier parameter, returns the full content for that specific tier.",
|
|
500
|
+
{
|
|
501
|
+
tier: external_exports.number().optional().describe("Specific tier to read in full (e.g., 1500, 5000, 10000). Omit to get summary of all tiers.")
|
|
502
|
+
},
|
|
503
|
+
async (args) => {
|
|
504
|
+
recordTurn("vault_read_digest", args);
|
|
505
|
+
const extracts = listDigestExtracts(agentId);
|
|
506
|
+
if (args.tier !== void 0) {
|
|
507
|
+
const extract = extracts.find((e) => e.tier === args.tier);
|
|
508
|
+
if (!extract) return textResult({ tier: args.tier, content: null, message: "No digest at this tier" });
|
|
509
|
+
return textResult({ tier: extract.tier, content: extract.content, generated_at: extract.generated_at });
|
|
510
|
+
}
|
|
511
|
+
return textResult(extracts.map((e) => ({
|
|
512
|
+
tier: e.tier,
|
|
513
|
+
content_length: e.content.length,
|
|
514
|
+
generated_at: e.generated_at
|
|
515
|
+
})));
|
|
516
|
+
},
|
|
517
|
+
{ annotations: { readOnlyHint: true } }
|
|
518
|
+
);
|
|
519
|
+
const vaultWriteDigest = tool(
|
|
520
|
+
"vault_write_digest",
|
|
521
|
+
"Write or update a digest extract at a specific token tier. Uses UPSERT on (agent_id, tier).",
|
|
522
|
+
{
|
|
523
|
+
tier: external_exports.number().describe("Token budget tier (e.g., 1500, 5000, 10000)"),
|
|
524
|
+
content: external_exports.string().describe("The digest extract content in markdown")
|
|
525
|
+
},
|
|
526
|
+
async (args) => {
|
|
527
|
+
const now = epochSeconds();
|
|
528
|
+
const extract = upsertDigestExtract({
|
|
529
|
+
agent_id: agentId,
|
|
530
|
+
tier: args.tier,
|
|
531
|
+
content: args.content,
|
|
532
|
+
generated_at: now
|
|
533
|
+
});
|
|
534
|
+
recordTurn("vault_write_digest", args);
|
|
535
|
+
return textResult(extract);
|
|
536
|
+
}
|
|
537
|
+
);
|
|
538
|
+
const vaultMarkProcessed = tool(
|
|
539
|
+
"vault_mark_processed",
|
|
540
|
+
"Mark a prompt batch as processed so it is not returned by vault_unprocessed.",
|
|
541
|
+
{
|
|
542
|
+
batch_id: external_exports.number().describe("ID of the prompt batch to mark as processed")
|
|
543
|
+
},
|
|
544
|
+
async (args) => {
|
|
545
|
+
const batch = markBatchProcessed(args.batch_id);
|
|
546
|
+
recordTurn("vault_mark_processed", args);
|
|
547
|
+
return textResult(batch);
|
|
548
|
+
}
|
|
549
|
+
);
|
|
550
|
+
const vaultReport = tool(
|
|
551
|
+
"vault_report",
|
|
552
|
+
'Record an observability report for the current run. Use action "skip" when skipping expected operations (e.g., not updating a session summary) with reasoning in the summary field.',
|
|
553
|
+
{
|
|
554
|
+
action: external_exports.string().describe("Action name (e.g., extract, consolidate, digest, skip)"),
|
|
555
|
+
summary: external_exports.string().describe("Human-readable summary of what was done"),
|
|
556
|
+
details: external_exports.record(external_exports.string(), external_exports.unknown()).optional().describe("Structured details as key-value pairs")
|
|
557
|
+
},
|
|
558
|
+
async (args) => {
|
|
559
|
+
recordTurn("vault_report", args);
|
|
560
|
+
const now = epochSeconds();
|
|
561
|
+
const report = insertReport({
|
|
562
|
+
run_id: runId,
|
|
563
|
+
agent_id: agentId,
|
|
564
|
+
action: args.action,
|
|
565
|
+
summary: args.summary,
|
|
566
|
+
details: args.details ? JSON.stringify(args.details) : null,
|
|
567
|
+
created_at: now
|
|
568
|
+
});
|
|
569
|
+
return textResult(report);
|
|
570
|
+
}
|
|
571
|
+
);
|
|
572
|
+
return [
|
|
573
|
+
vaultUnprocessed,
|
|
574
|
+
vaultSpores,
|
|
575
|
+
vaultSessions,
|
|
576
|
+
vaultSearchFts,
|
|
577
|
+
vaultSearchSemantic,
|
|
578
|
+
vaultState,
|
|
579
|
+
vaultEntities,
|
|
580
|
+
vaultEdges,
|
|
581
|
+
vaultCreateSpore,
|
|
582
|
+
vaultCreateEntity,
|
|
583
|
+
vaultCreateEdge,
|
|
584
|
+
vaultResolveSpore,
|
|
585
|
+
vaultUpdateSession,
|
|
586
|
+
vaultSetState,
|
|
587
|
+
vaultReadDigest,
|
|
588
|
+
vaultWriteDigest,
|
|
589
|
+
vaultMarkProcessed,
|
|
590
|
+
vaultReport
|
|
591
|
+
];
|
|
592
|
+
}
|
|
593
|
+
function createVaultToolServer(agentId, runId, embeddingManager) {
|
|
594
|
+
const tools = createVaultTools(agentId, runId, 0, embeddingManager);
|
|
595
|
+
return createSdkMcpServer({
|
|
596
|
+
name: "myco-vault",
|
|
597
|
+
version: getPluginVersion(),
|
|
598
|
+
tools
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
function createScopedVaultToolServer(agentId, runId, toolNames, turnOffset = 0, embeddingManager) {
|
|
602
|
+
const allTools = createVaultTools(agentId, runId, turnOffset, embeddingManager);
|
|
603
|
+
const nameSet = new Set(toolNames);
|
|
604
|
+
const scopedTools = allTools.filter((t) => nameSet.has(t.name));
|
|
605
|
+
return createSdkMcpServer({
|
|
606
|
+
name: "myco-vault",
|
|
607
|
+
version: getPluginVersion(),
|
|
608
|
+
tools: scopedTools
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
// src/agent/context.ts
|
|
613
|
+
var STATE_UNSET = "(unset)";
|
|
614
|
+
var STATE_KEY_LAST_PROCESSED_BATCH = "last_processed_batch_id";
|
|
615
|
+
var SPORE_STATUS_ACTIVE = "active";
|
|
616
|
+
function countRows(table, conditions = []) {
|
|
617
|
+
const db = getDatabase();
|
|
618
|
+
const whereParts = [];
|
|
619
|
+
const params = [];
|
|
620
|
+
for (const { clause, value } of conditions) {
|
|
621
|
+
whereParts.push(clause);
|
|
622
|
+
params.push(value);
|
|
623
|
+
}
|
|
624
|
+
const whereClause = whereParts.length > 0 ? `WHERE ${whereParts.join(" AND ")}` : "";
|
|
625
|
+
const row = db.prepare(
|
|
626
|
+
`SELECT count(*) AS count FROM ${table} ${whereClause}`
|
|
627
|
+
).get(...params);
|
|
628
|
+
return Number(row.count);
|
|
629
|
+
}
|
|
630
|
+
function buildVaultContext(agentId) {
|
|
631
|
+
const states = getStatesForAgent(agentId);
|
|
632
|
+
const totalSessions = countRows("sessions");
|
|
633
|
+
const totalActiveSpores = countRows("spores", [{ clause: "status = ?", value: SPORE_STATUS_ACTIVE }]);
|
|
634
|
+
const totalEntities = countRows("entities");
|
|
635
|
+
const totalEdges = countRows("graph_edges");
|
|
636
|
+
const unprocessedBatches = countRows("prompt_batches", [{ clause: "processed = ?", value: 0 }]);
|
|
637
|
+
const lastDigestAt = getLastDigestTimestamp(agentId);
|
|
638
|
+
const stateMap = new Map(states.map((s) => [s.key, s.value]));
|
|
639
|
+
const lastProcessedBatchId = stateMap.get(STATE_KEY_LAST_PROCESSED_BATCH) ?? STATE_UNSET;
|
|
640
|
+
const lines = [
|
|
641
|
+
"## Current Vault State",
|
|
642
|
+
`agent_id: ${agentId}`,
|
|
643
|
+
`last_processed_batch_id: ${lastProcessedBatchId}`,
|
|
644
|
+
`unprocessed_batches: ${unprocessedBatches}`,
|
|
645
|
+
`total_sessions: ${totalSessions}`,
|
|
646
|
+
`total_active_spores: ${totalActiveSpores}`,
|
|
647
|
+
`total_entities: ${totalEntities}`,
|
|
648
|
+
`total_edges: ${totalEdges}`,
|
|
649
|
+
`last_digest_at: ${lastDigestAt}`
|
|
650
|
+
];
|
|
651
|
+
return lines.join("\n");
|
|
652
|
+
}
|
|
653
|
+
function getLastDigestTimestamp(agentId) {
|
|
654
|
+
const db = getDatabase();
|
|
655
|
+
const row = db.prepare(
|
|
656
|
+
`SELECT MAX(generated_at) AS max_at
|
|
657
|
+
FROM digest_extracts
|
|
658
|
+
WHERE agent_id = ?`
|
|
659
|
+
).get(agentId);
|
|
660
|
+
return row?.max_at ?? 0;
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// src/agent/orchestrator.ts
|
|
664
|
+
import fs from "fs";
|
|
665
|
+
import path from "path";
|
|
666
|
+
import { fileURLToPath } from "url";
|
|
667
|
+
|
|
668
|
+
// src/intelligence/response.ts
|
|
669
|
+
var REASONING_PATTERNS = [
|
|
670
|
+
// <think>...</think>answer (DeepSeek, Qwen, GLM, many others)
|
|
671
|
+
/<think>[\s\S]*?<\/think>\s*/gi,
|
|
672
|
+
// Implicit opening: reasoning...</think>answer (GLM-4.7 observed)
|
|
673
|
+
/^[\s\S]*?<\/think>\s*/i,
|
|
674
|
+
// <reasoning>...</reasoning>answer
|
|
675
|
+
/<reasoning>[\s\S]*?<\/reasoning>\s*/gi,
|
|
676
|
+
// <|thinking|>...<|/thinking|>answer
|
|
677
|
+
/<\|thinking\|>[\s\S]*?<\|\/thinking\|>\s*/gi,
|
|
678
|
+
// Plain-text "Thinking Process:" block followed by actual content
|
|
679
|
+
// (Qwen 3.5 via LM Studio without native thinking mode)
|
|
680
|
+
// Matches from "Thinking Process:" up to the last numbered step, then the synthesis follows
|
|
681
|
+
/^Thinking Process:[\s\S]*?(?=\n(?:## |# |\*\*[A-Z]))/i
|
|
682
|
+
];
|
|
683
|
+
function stripReasoningTokens(text) {
|
|
684
|
+
if (!text) return text;
|
|
685
|
+
for (const pattern of REASONING_PATTERNS) {
|
|
686
|
+
const stripped = text.replace(pattern, "").trim();
|
|
687
|
+
if (stripped && stripped !== text.trim()) {
|
|
688
|
+
return stripped;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
return text;
|
|
692
|
+
}
|
|
693
|
+
function extractJson(text) {
|
|
694
|
+
const cleaned = stripReasoningTokens(text);
|
|
695
|
+
const fenceMatch = cleaned.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
696
|
+
if (fenceMatch) {
|
|
697
|
+
return JSON.parse(fenceMatch[1].trim());
|
|
698
|
+
}
|
|
699
|
+
const objectMatch = cleaned.match(/\{[\s\S]*\}/);
|
|
700
|
+
if (objectMatch) {
|
|
701
|
+
return JSON.parse(objectMatch[0]);
|
|
702
|
+
}
|
|
703
|
+
return JSON.parse(cleaned);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// src/agent/orchestrator.ts
|
|
707
|
+
var DEFAULT_ORCHESTRATOR_MAX_TURNS = 3;
|
|
708
|
+
var ORCHESTRATOR_PROMPT_FILE = "orchestrator.md";
|
|
709
|
+
var PHASE_PROMPT_PREVIEW_CHARS = 100;
|
|
710
|
+
var ORCHESTRATOR_GUIDANCE_HEADER = "## Orchestrator Guidance";
|
|
711
|
+
var NO_CONTEXT_QUERIES_TEXT = "No context queries configured.";
|
|
712
|
+
var FALLBACK_REASONING_PARSE_ERROR = "Orchestrator response could not be parsed \u2014 running all phases with defaults.";
|
|
713
|
+
var FALLBACK_REASONING_MISSING_PHASES = "Orchestrator plan missing phases array \u2014 running all phases with defaults.";
|
|
714
|
+
var PLACEHOLDER_VAULT_STATE = "{{vault_state}}";
|
|
715
|
+
var PLACEHOLDER_PHASE_DEFINITIONS = "{{phase_definitions}}";
|
|
716
|
+
var PLACEHOLDER_CONTEXT_RESULTS = "{{context_results}}";
|
|
717
|
+
var cachedPromptTemplate;
|
|
718
|
+
function loadPromptTemplate() {
|
|
719
|
+
if (!cachedPromptTemplate) {
|
|
720
|
+
const scriptDir = path.dirname(fileURLToPath(import.meta.url));
|
|
721
|
+
const adjacentPath = path.join(scriptDir, "prompts", ORCHESTRATOR_PROMPT_FILE);
|
|
722
|
+
if (fs.existsSync(adjacentPath)) {
|
|
723
|
+
cachedPromptTemplate = fs.readFileSync(adjacentPath, "utf-8");
|
|
724
|
+
return cachedPromptTemplate;
|
|
725
|
+
}
|
|
726
|
+
const root = findPackageRoot(scriptDir);
|
|
727
|
+
if (root) {
|
|
728
|
+
const distPath = path.join(root, "dist", "src", "agent", "prompts", ORCHESTRATOR_PROMPT_FILE);
|
|
729
|
+
if (fs.existsSync(distPath)) {
|
|
730
|
+
cachedPromptTemplate = fs.readFileSync(distPath, "utf-8");
|
|
731
|
+
return cachedPromptTemplate;
|
|
732
|
+
}
|
|
733
|
+
const srcPath = path.join(root, "src", "agent", "prompts", ORCHESTRATOR_PROMPT_FILE);
|
|
734
|
+
cachedPromptTemplate = fs.readFileSync(srcPath, "utf-8");
|
|
735
|
+
return cachedPromptTemplate;
|
|
736
|
+
}
|
|
737
|
+
cachedPromptTemplate = fs.readFileSync(adjacentPath, "utf-8");
|
|
738
|
+
}
|
|
739
|
+
return cachedPromptTemplate;
|
|
740
|
+
}
|
|
741
|
+
function composeOrchestratorPrompt(vaultState, phases, contextResults) {
|
|
742
|
+
const template = loadPromptTemplate();
|
|
743
|
+
const phaseList = formatPhaseList(phases);
|
|
744
|
+
const contextSection = formatContextResults(contextResults);
|
|
745
|
+
return template.replace(PLACEHOLDER_VAULT_STATE, vaultState).replace(PLACEHOLDER_PHASE_DEFINITIONS, phaseList).replace(PLACEHOLDER_CONTEXT_RESULTS, contextSection);
|
|
746
|
+
}
|
|
747
|
+
function parseOrchestratorPlan(response, phases) {
|
|
748
|
+
const trimmed = response.trim();
|
|
749
|
+
if (!trimmed) {
|
|
750
|
+
return buildRunAllPlan(phases, FALLBACK_REASONING_PARSE_ERROR);
|
|
751
|
+
}
|
|
752
|
+
try {
|
|
753
|
+
const parsed = extractJson(trimmed);
|
|
754
|
+
if (!isOrchestratorPlanShape(parsed)) {
|
|
755
|
+
return buildRunAllPlan(phases, FALLBACK_REASONING_MISSING_PHASES);
|
|
756
|
+
}
|
|
757
|
+
return parsed;
|
|
758
|
+
} catch {
|
|
759
|
+
return buildRunAllPlan(phases, FALLBACK_REASONING_PARSE_ERROR);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
function applyDirectives(phases, directives) {
|
|
763
|
+
const directiveMap = new Map(
|
|
764
|
+
directives.map((d) => [d.name, d])
|
|
765
|
+
);
|
|
766
|
+
const result = [];
|
|
767
|
+
for (const phase of phases) {
|
|
768
|
+
const directive = directiveMap.get(phase.name);
|
|
769
|
+
if (!directive) {
|
|
770
|
+
result.push(phase);
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
if (directive.skip) {
|
|
774
|
+
if (phase.required) {
|
|
775
|
+
console.warn(
|
|
776
|
+
`[orchestrator] Cannot skip required phase "${phase.name}" \u2014 keeping it. Reason: ${directive.skipReason ?? "none given"}`
|
|
777
|
+
);
|
|
778
|
+
result.push(applyNonSkipDirective(phase, directive));
|
|
779
|
+
}
|
|
780
|
+
continue;
|
|
781
|
+
}
|
|
782
|
+
result.push(applyNonSkipDirective(phase, directive));
|
|
783
|
+
}
|
|
784
|
+
return result;
|
|
785
|
+
}
|
|
786
|
+
function applyNonSkipDirective(phase, directive) {
|
|
787
|
+
let updated = { ...phase };
|
|
788
|
+
if (directive.maxTurns !== void 0) {
|
|
789
|
+
updated = { ...updated, maxTurns: directive.maxTurns };
|
|
790
|
+
}
|
|
791
|
+
if (directive.contextNotes) {
|
|
792
|
+
updated = {
|
|
793
|
+
...updated,
|
|
794
|
+
prompt: `${updated.prompt}
|
|
795
|
+
|
|
796
|
+
${ORCHESTRATOR_GUIDANCE_HEADER}
|
|
797
|
+
|
|
798
|
+
${directive.contextNotes}`
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
return updated;
|
|
802
|
+
}
|
|
803
|
+
function formatPhaseList(phases) {
|
|
804
|
+
if (phases.length === 0) {
|
|
805
|
+
return "(no phases defined)";
|
|
806
|
+
}
|
|
807
|
+
return phases.map((p) => {
|
|
808
|
+
const preview = p.prompt.slice(0, PHASE_PROMPT_PREVIEW_CHARS);
|
|
809
|
+
const ellipsis = p.prompt.length > PHASE_PROMPT_PREVIEW_CHARS ? "..." : "";
|
|
810
|
+
return `- **${p.name}** (maxTurns: ${p.maxTurns}, required: ${p.required}): ${preview}${ellipsis}`;
|
|
811
|
+
}).join("\n");
|
|
812
|
+
}
|
|
813
|
+
function formatContextResults(results) {
|
|
814
|
+
if (results.length === 0) {
|
|
815
|
+
return NO_CONTEXT_QUERIES_TEXT;
|
|
816
|
+
}
|
|
817
|
+
return results.map((r) => {
|
|
818
|
+
const dataSection = r.error ? `Error: ${r.error}` : JSON.stringify(r.data, null, 2);
|
|
819
|
+
return `### ${r.tool}
|
|
820
|
+
Purpose: ${r.purpose}
|
|
821
|
+
|
|
822
|
+
${dataSection}`;
|
|
823
|
+
}).join("\n\n");
|
|
824
|
+
}
|
|
825
|
+
function isOrchestratorPlanShape(value) {
|
|
826
|
+
if (typeof value !== "object" || value === null) return false;
|
|
827
|
+
const obj = value;
|
|
828
|
+
return Array.isArray(obj["phases"]);
|
|
829
|
+
}
|
|
830
|
+
function buildRunAllPlan(phases, reasoning) {
|
|
831
|
+
return {
|
|
832
|
+
phases: phases.map((p) => ({ name: p.name, skip: false })),
|
|
833
|
+
reasoning
|
|
834
|
+
};
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
// src/agent/context-queries.ts
|
|
838
|
+
var DEFAULT_CONTEXT_QUERY_LIMIT = 10;
|
|
839
|
+
async function executeContextQueries(agentId, queries) {
|
|
840
|
+
for (const query of queries) {
|
|
841
|
+
validateTool(query.tool);
|
|
842
|
+
}
|
|
843
|
+
const settled = await Promise.allSettled(
|
|
844
|
+
queries.map(async (query) => {
|
|
845
|
+
const limit = query.limit ?? DEFAULT_CONTEXT_QUERY_LIMIT;
|
|
846
|
+
const data = await executeQuery(agentId, query.tool, limit);
|
|
847
|
+
return { tool: query.tool, purpose: query.purpose, data };
|
|
848
|
+
})
|
|
849
|
+
);
|
|
850
|
+
const results = [];
|
|
851
|
+
for (let i = 0; i < settled.length; i++) {
|
|
852
|
+
const outcome = settled[i];
|
|
853
|
+
const query = queries[i];
|
|
854
|
+
if (outcome.status === "fulfilled") {
|
|
855
|
+
results.push(outcome.value);
|
|
856
|
+
} else {
|
|
857
|
+
const message = errorMessage(outcome.reason);
|
|
858
|
+
if (query.required) {
|
|
859
|
+
throw new Error(
|
|
860
|
+
`Required context query "${query.tool}" failed: ${message}`
|
|
861
|
+
);
|
|
862
|
+
}
|
|
863
|
+
results.push({
|
|
864
|
+
tool: query.tool,
|
|
865
|
+
purpose: query.purpose,
|
|
866
|
+
data: null,
|
|
867
|
+
error: message
|
|
868
|
+
});
|
|
869
|
+
}
|
|
870
|
+
}
|
|
871
|
+
return results;
|
|
872
|
+
}
|
|
873
|
+
var KNOWN_CONTEXT_QUERY_TOOLS = /* @__PURE__ */ new Set([
|
|
874
|
+
"vault_unprocessed",
|
|
875
|
+
"vault_spores",
|
|
876
|
+
"vault_sessions",
|
|
877
|
+
"vault_state"
|
|
878
|
+
]);
|
|
879
|
+
function validateTool(tool2) {
|
|
880
|
+
if (!KNOWN_CONTEXT_QUERY_TOOLS.has(tool2)) {
|
|
881
|
+
throw new Error(`Unknown context query tool: "${tool2}"`);
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
async function executeQuery(agentId, tool2, limit) {
|
|
885
|
+
switch (tool2) {
|
|
886
|
+
case "vault_unprocessed":
|
|
887
|
+
return getUnprocessedBatches({ limit });
|
|
888
|
+
case "vault_spores":
|
|
889
|
+
return listSpores({ agent_id: agentId, limit });
|
|
890
|
+
case "vault_sessions":
|
|
891
|
+
return listSessions({ limit });
|
|
892
|
+
case "vault_state":
|
|
893
|
+
return getStatesForAgent(agentId);
|
|
894
|
+
default:
|
|
895
|
+
throw new Error(`Unknown context query tool: "${tool2}"`);
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
// src/agent/provider.ts
|
|
900
|
+
var ENV_ANTHROPIC_BASE_URL = "ANTHROPIC_BASE_URL";
|
|
901
|
+
var ENV_ANTHROPIC_AUTH_TOKEN = "ANTHROPIC_AUTH_TOKEN";
|
|
902
|
+
var ENV_ANTHROPIC_API_KEY = "ANTHROPIC_API_KEY";
|
|
903
|
+
var ENV_OLLAMA_NUM_CTX = "OLLAMA_NUM_CTX";
|
|
904
|
+
var DEFAULT_OLLAMA_URL = "http://localhost:11434";
|
|
905
|
+
var DEFAULT_LMSTUDIO_URL = "http://localhost:1234";
|
|
906
|
+
var OLLAMA_AUTH_TOKEN = "ollama";
|
|
907
|
+
var LMSTUDIO_AUTH_TOKEN = "lmstudio";
|
|
908
|
+
function buildPhaseEnv(provider) {
|
|
909
|
+
if (!provider || provider.type === "cloud") return void 0;
|
|
910
|
+
return { ...process.env, ...getProviderEnvVars(provider) };
|
|
911
|
+
}
|
|
912
|
+
function getProviderEnvVars(provider) {
|
|
913
|
+
switch (provider.type) {
|
|
914
|
+
case "cloud":
|
|
915
|
+
return {};
|
|
916
|
+
case "ollama":
|
|
917
|
+
return {
|
|
918
|
+
[ENV_ANTHROPIC_BASE_URL]: provider.baseUrl ?? DEFAULT_OLLAMA_URL,
|
|
919
|
+
[ENV_ANTHROPIC_AUTH_TOKEN]: OLLAMA_AUTH_TOKEN,
|
|
920
|
+
[ENV_ANTHROPIC_API_KEY]: "",
|
|
921
|
+
...provider.contextLength ? { [ENV_OLLAMA_NUM_CTX]: String(provider.contextLength) } : {}
|
|
922
|
+
};
|
|
923
|
+
case "lmstudio":
|
|
924
|
+
return {
|
|
925
|
+
[ENV_ANTHROPIC_BASE_URL]: provider.baseUrl ?? DEFAULT_LMSTUDIO_URL,
|
|
926
|
+
[ENV_ANTHROPIC_AUTH_TOKEN]: provider.apiKey ?? LMSTUDIO_AUTH_TOKEN,
|
|
927
|
+
[ENV_ANTHROPIC_API_KEY]: ""
|
|
928
|
+
};
|
|
929
|
+
default:
|
|
930
|
+
return {};
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
// src/agent/executor.ts
|
|
935
|
+
var STATUS_SKIPPED = "skipped";
|
|
936
|
+
var SKIP_REASON_ALREADY_RUNNING = "already_running";
|
|
937
|
+
var PROMPT_SECTION_TASK = "## Task: ";
|
|
938
|
+
var PROMPT_SECTION_INSTRUCTION = "## User Instruction";
|
|
939
|
+
var PROMPT_SECTION_SEPARATOR = "\n\n";
|
|
940
|
+
var MCP_SERVER_NAME = "myco-vault";
|
|
941
|
+
var PERSIST_SESSION = true;
|
|
942
|
+
var PROMPT_SECTION_PRIOR_PHASES = "## Prior Phase Results";
|
|
943
|
+
var PROMPT_SECTION_CURRENT_PHASE = "## Current Phase: ";
|
|
944
|
+
function composeTaskPrompt(vaultContext, taskDisplayName, taskPrompt, instruction) {
|
|
945
|
+
const sessionIdMatch = instruction?.match(/\b([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\b/i);
|
|
946
|
+
const sessionId = sessionIdMatch?.[1] ?? "";
|
|
947
|
+
let resolvedPrompt = taskPrompt;
|
|
948
|
+
resolvedPrompt = resolvedPrompt.replace(/\{\{session_id\}\}/g, sessionId);
|
|
949
|
+
resolvedPrompt = resolvedPrompt.replace(/\{\{instruction\}\}/g, instruction ?? "");
|
|
950
|
+
const parts = [
|
|
951
|
+
vaultContext,
|
|
952
|
+
`${PROMPT_SECTION_TASK}${taskDisplayName}
|
|
953
|
+
${resolvedPrompt}`
|
|
954
|
+
];
|
|
955
|
+
if (instruction) {
|
|
956
|
+
parts.push(`${PROMPT_SECTION_INSTRUCTION}
|
|
957
|
+
${instruction}`);
|
|
958
|
+
}
|
|
959
|
+
return parts.join(PROMPT_SECTION_SEPARATOR);
|
|
960
|
+
}
|
|
961
|
+
function composePhasePrompt(vaultContext, taskDisplayName, taskOverview, phase, priorPhaseResults, instruction) {
|
|
962
|
+
const parts = [
|
|
963
|
+
vaultContext,
|
|
964
|
+
`${PROMPT_SECTION_TASK}${taskDisplayName}
|
|
965
|
+
${taskOverview}`
|
|
966
|
+
];
|
|
967
|
+
if (instruction) {
|
|
968
|
+
parts.push(`${PROMPT_SECTION_INSTRUCTION}
|
|
969
|
+
${instruction}`);
|
|
970
|
+
}
|
|
971
|
+
if (priorPhaseResults.length > 0 && !phase.skipPriorContext) {
|
|
972
|
+
const summaries = priorPhaseResults.map((pr) => {
|
|
973
|
+
const truncated = pr.summary.length > PHASE_SUMMARY_MAX_CHARS ? pr.summary.slice(0, PHASE_SUMMARY_MAX_CHARS) + "..." : pr.summary;
|
|
974
|
+
return `### ${pr.name} (${pr.status})
|
|
975
|
+
${truncated}`;
|
|
976
|
+
});
|
|
977
|
+
parts.push(`${PROMPT_SECTION_PRIOR_PHASES}
|
|
978
|
+
${summaries.join("\n\n")}`);
|
|
979
|
+
}
|
|
980
|
+
parts.push(`${PROMPT_SECTION_CURRENT_PHASE}${phase.name}
|
|
981
|
+
${phase.prompt}`);
|
|
982
|
+
return parts.join(PROMPT_SECTION_SEPARATOR);
|
|
983
|
+
}
|
|
984
|
+
var OLLAMA_PRELOAD_TIMEOUT_MS = 3e4;
|
|
985
|
+
async function ensureOllamaContextVariant(model, contextLength) {
|
|
986
|
+
const { execFileSync } = await import("child_process");
|
|
987
|
+
const { writeFileSync, unlinkSync } = await import("fs");
|
|
988
|
+
const { tmpdir } = await import("os");
|
|
989
|
+
const { join } = await import("path");
|
|
990
|
+
const baseName = model.replace(/:latest$/, "");
|
|
991
|
+
const variantName = `${baseName}-ctx${contextLength}`;
|
|
992
|
+
try {
|
|
993
|
+
execFileSync("ollama", ["show", variantName], { stdio: "ignore" });
|
|
994
|
+
return variantName;
|
|
995
|
+
} catch {
|
|
996
|
+
}
|
|
997
|
+
try {
|
|
998
|
+
const modelfilePath = join(tmpdir(), `myco-modelfile-${Date.now()}`);
|
|
999
|
+
writeFileSync(modelfilePath, `FROM ${model}
|
|
1000
|
+
PARAMETER num_ctx ${contextLength}
|
|
1001
|
+
`);
|
|
1002
|
+
execFileSync("ollama", ["create", variantName, "-f", modelfilePath], {
|
|
1003
|
+
stdio: "ignore",
|
|
1004
|
+
timeout: OLLAMA_PRELOAD_TIMEOUT_MS
|
|
1005
|
+
});
|
|
1006
|
+
try {
|
|
1007
|
+
unlinkSync(modelfilePath);
|
|
1008
|
+
} catch {
|
|
1009
|
+
}
|
|
1010
|
+
return variantName;
|
|
1011
|
+
} catch {
|
|
1012
|
+
return model;
|
|
1013
|
+
}
|
|
1014
|
+
}
|
|
1015
|
+
function computeWaves(phases) {
|
|
1016
|
+
const nameToPhase = new Map(phases.map((p) => [p.name, p]));
|
|
1017
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
1018
|
+
const dependents = /* @__PURE__ */ new Map();
|
|
1019
|
+
for (const phase of phases) {
|
|
1020
|
+
inDegree.set(phase.name, 0);
|
|
1021
|
+
dependents.set(phase.name, []);
|
|
1022
|
+
}
|
|
1023
|
+
for (const phase of phases) {
|
|
1024
|
+
const deps = phase.dependsOn ?? [];
|
|
1025
|
+
for (const dep of deps) {
|
|
1026
|
+
if (!nameToPhase.has(dep)) continue;
|
|
1027
|
+
inDegree.set(phase.name, (inDegree.get(phase.name) ?? 0) + 1);
|
|
1028
|
+
dependents.get(dep).push(phase.name);
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
const waves = [];
|
|
1032
|
+
const completed = /* @__PURE__ */ new Set();
|
|
1033
|
+
while (completed.size < phases.length) {
|
|
1034
|
+
const wave = [];
|
|
1035
|
+
for (const phase of phases) {
|
|
1036
|
+
if (completed.has(phase.name)) continue;
|
|
1037
|
+
if ((inDegree.get(phase.name) ?? 0) === 0) {
|
|
1038
|
+
wave.push(phase);
|
|
1039
|
+
}
|
|
1040
|
+
}
|
|
1041
|
+
if (wave.length === 0) {
|
|
1042
|
+
const remaining = phases.filter((p) => !completed.has(p.name)).map((p) => p.name);
|
|
1043
|
+
throw new Error(`Circular dependency detected among phases: ${remaining.join(", ")}`);
|
|
1044
|
+
}
|
|
1045
|
+
waves.push(wave);
|
|
1046
|
+
for (const phase of wave) {
|
|
1047
|
+
completed.add(phase.name);
|
|
1048
|
+
for (const dependent of dependents.get(phase.name) ?? []) {
|
|
1049
|
+
inDegree.set(dependent, (inDegree.get(dependent) ?? 0) - 1);
|
|
1050
|
+
}
|
|
1051
|
+
}
|
|
1052
|
+
}
|
|
1053
|
+
return waves;
|
|
1054
|
+
}
|
|
1055
|
+
function phaseSessionId(runId, phaseName) {
|
|
1056
|
+
const hash = crypto2.createHash("sha256").update(`${runId}-${phaseName}`).digest("hex");
|
|
1057
|
+
return [
|
|
1058
|
+
hash.slice(0, 8),
|
|
1059
|
+
hash.slice(8, 12),
|
|
1060
|
+
hash.slice(12, 16),
|
|
1061
|
+
hash.slice(16, 20),
|
|
1062
|
+
hash.slice(20, 32)
|
|
1063
|
+
].join("-");
|
|
1064
|
+
}
|
|
1065
|
+
async function executePhase(query, phasePrompt, phaseModel, systemPrompt, toolServer, phase, env, sessionId, abortController) {
|
|
1066
|
+
let phaseCost = 0;
|
|
1067
|
+
let phaseTokens = 0;
|
|
1068
|
+
let phaseTurns = 0;
|
|
1069
|
+
let phaseSummary = "";
|
|
1070
|
+
try {
|
|
1071
|
+
for await (const message of query({
|
|
1072
|
+
prompt: phasePrompt,
|
|
1073
|
+
options: {
|
|
1074
|
+
model: phaseModel,
|
|
1075
|
+
systemPrompt,
|
|
1076
|
+
mcpServers: { [MCP_SERVER_NAME]: toolServer },
|
|
1077
|
+
maxTurns: phase.maxTurns,
|
|
1078
|
+
permissionMode: "bypassPermissions",
|
|
1079
|
+
allowDangerouslySkipPermissions: true,
|
|
1080
|
+
persistSession: PERSIST_SESSION,
|
|
1081
|
+
env,
|
|
1082
|
+
tools: [],
|
|
1083
|
+
...sessionId ? { sessionId } : {},
|
|
1084
|
+
...abortController ? { abortController } : {}
|
|
1085
|
+
}
|
|
1086
|
+
})) {
|
|
1087
|
+
if (message.type === "result") {
|
|
1088
|
+
phaseCost = message.total_cost_usd ?? 0;
|
|
1089
|
+
phaseTokens = (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0);
|
|
1090
|
+
phaseTurns = message.num_turns ?? 0;
|
|
1091
|
+
if ("result" in message && typeof message.result === "string") {
|
|
1092
|
+
phaseSummary = message.result;
|
|
1093
|
+
}
|
|
1094
|
+
}
|
|
1095
|
+
}
|
|
1096
|
+
if (phase.required && phaseTurns === 0) {
|
|
1097
|
+
console.warn(`[agent] Required phase "${phase.name}" produced 0 turns`);
|
|
1098
|
+
}
|
|
1099
|
+
return {
|
|
1100
|
+
name: phase.name,
|
|
1101
|
+
status: "completed",
|
|
1102
|
+
turnsUsed: phaseTurns,
|
|
1103
|
+
tokensUsed: phaseTokens,
|
|
1104
|
+
costUsd: phaseCost,
|
|
1105
|
+
summary: phaseSummary
|
|
1106
|
+
};
|
|
1107
|
+
} catch (err) {
|
|
1108
|
+
return {
|
|
1109
|
+
name: phase.name,
|
|
1110
|
+
status: "failed",
|
|
1111
|
+
turnsUsed: phaseTurns,
|
|
1112
|
+
tokensUsed: phaseTokens,
|
|
1113
|
+
costUsd: phaseCost,
|
|
1114
|
+
summary: `Error: ${errorMessage(err)}`
|
|
1115
|
+
};
|
|
1116
|
+
}
|
|
1117
|
+
}
|
|
1118
|
+
async function executeSingleQuery(config, systemPrompt, taskPrompt, agentId, runId, provider, embeddingManager, abortController) {
|
|
1119
|
+
const { query } = await import("@anthropic-ai/claude-agent-sdk");
|
|
1120
|
+
const toolServer = createVaultToolServer(agentId, runId, embeddingManager);
|
|
1121
|
+
const env = buildPhaseEnv(provider);
|
|
1122
|
+
const effectiveModel = provider?.model ?? config.model;
|
|
1123
|
+
let resultCostUsd = 0;
|
|
1124
|
+
let resultTokens = 0;
|
|
1125
|
+
for await (const message of query({
|
|
1126
|
+
prompt: taskPrompt,
|
|
1127
|
+
options: {
|
|
1128
|
+
model: effectiveModel,
|
|
1129
|
+
systemPrompt,
|
|
1130
|
+
mcpServers: { [MCP_SERVER_NAME]: toolServer },
|
|
1131
|
+
maxTurns: config.maxTurns,
|
|
1132
|
+
permissionMode: "bypassPermissions",
|
|
1133
|
+
allowDangerouslySkipPermissions: true,
|
|
1134
|
+
persistSession: PERSIST_SESSION,
|
|
1135
|
+
env,
|
|
1136
|
+
tools: [],
|
|
1137
|
+
...abortController ? { abortController } : {}
|
|
1138
|
+
}
|
|
1139
|
+
})) {
|
|
1140
|
+
if (message.type === "result") {
|
|
1141
|
+
resultCostUsd = message.total_cost_usd ?? 0;
|
|
1142
|
+
resultTokens = (message.usage.input_tokens ?? 0) + (message.usage.output_tokens ?? 0);
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
return { tokensUsed: resultTokens, costUsd: resultCostUsd };
|
|
1146
|
+
}
|
|
1147
|
+
async function executePhasedQuery(config, systemPrompt, vaultContext, agentId, runId, taskProviderOverride, phaseProviderOverrides, instruction, embeddingManager, abortController) {
|
|
1148
|
+
const { query } = await import("@anthropic-ai/claude-agent-sdk");
|
|
1149
|
+
const phases = config.phases;
|
|
1150
|
+
const phaseResults = [];
|
|
1151
|
+
let totalTokens = 0;
|
|
1152
|
+
let totalCost = 0;
|
|
1153
|
+
let runningTurnCount = 0;
|
|
1154
|
+
let effectivePhases = [...phases];
|
|
1155
|
+
if (config.orchestrator?.enabled) {
|
|
1156
|
+
const contextQueries = config.contextQueries ? Object.values(config.contextQueries).flat() : [];
|
|
1157
|
+
const contextResults = contextQueries.length > 0 ? await executeContextQueries(agentId, contextQueries) : [];
|
|
1158
|
+
const orchestratorPrompt = composeOrchestratorPrompt(vaultContext, phases, contextResults);
|
|
1159
|
+
const orchestratorModel = config.orchestrator.model ?? config.model;
|
|
1160
|
+
const orchestratorMaxTurns = config.orchestrator.maxTurns ?? DEFAULT_ORCHESTRATOR_MAX_TURNS;
|
|
1161
|
+
let planResponse = "";
|
|
1162
|
+
for await (const message of query({
|
|
1163
|
+
prompt: orchestratorPrompt,
|
|
1164
|
+
options: {
|
|
1165
|
+
model: orchestratorModel,
|
|
1166
|
+
maxTurns: orchestratorMaxTurns,
|
|
1167
|
+
permissionMode: "bypassPermissions",
|
|
1168
|
+
allowDangerouslySkipPermissions: true,
|
|
1169
|
+
persistSession: PERSIST_SESSION,
|
|
1170
|
+
tools: []
|
|
1171
|
+
}
|
|
1172
|
+
})) {
|
|
1173
|
+
if (message.type === "result" && "result" in message && typeof message.result === "string") {
|
|
1174
|
+
planResponse = message.result;
|
|
1175
|
+
}
|
|
1176
|
+
}
|
|
1177
|
+
const plan = parseOrchestratorPlan(planResponse, phases);
|
|
1178
|
+
effectivePhases = applyDirectives(phases, plan.phases);
|
|
1179
|
+
}
|
|
1180
|
+
const declarationOrder = new Map(phases.map((p, i) => [p.name, i]));
|
|
1181
|
+
const waves = computeWaves(effectivePhases);
|
|
1182
|
+
for (const wave of waves) {
|
|
1183
|
+
const executions = wave.map((phase, indexInWave) => {
|
|
1184
|
+
const phasePrompt = composePhasePrompt(
|
|
1185
|
+
vaultContext,
|
|
1186
|
+
config.taskDisplayName,
|
|
1187
|
+
config.taskPrompt,
|
|
1188
|
+
phase,
|
|
1189
|
+
phaseResults,
|
|
1190
|
+
instruction
|
|
1191
|
+
);
|
|
1192
|
+
const phaseOverride = phaseProviderOverrides?.[phase.name];
|
|
1193
|
+
const effectiveMaxTurns = phaseOverride?.maxTurns ?? phase.maxTurns;
|
|
1194
|
+
const phaseModel = phase.model ?? phaseOverride?.provider?.model ?? taskProviderOverride?.model ?? config.model;
|
|
1195
|
+
const toolServer = createScopedVaultToolServer(
|
|
1196
|
+
agentId,
|
|
1197
|
+
runId,
|
|
1198
|
+
phase.tools,
|
|
1199
|
+
runningTurnCount + indexInWave * effectiveMaxTurns,
|
|
1200
|
+
embeddingManager
|
|
1201
|
+
);
|
|
1202
|
+
const phaseProvider = phase.provider ?? phaseOverride?.provider ?? taskProviderOverride ?? config.execution?.provider;
|
|
1203
|
+
const env = buildPhaseEnv(phaseProvider);
|
|
1204
|
+
const sessionId = phaseSessionId(runId, phase.name);
|
|
1205
|
+
const effectivePhase = effectiveMaxTurns !== phase.maxTurns ? { ...phase, maxTurns: effectiveMaxTurns } : phase;
|
|
1206
|
+
return executePhase(query, phasePrompt, phaseModel, systemPrompt, toolServer, effectivePhase, env, sessionId, abortController);
|
|
1207
|
+
});
|
|
1208
|
+
const settled = await Promise.allSettled(executions);
|
|
1209
|
+
const waveResults = settled.map((outcome, i) => {
|
|
1210
|
+
if (outcome.status === "fulfilled") {
|
|
1211
|
+
return outcome.value;
|
|
1212
|
+
}
|
|
1213
|
+
return {
|
|
1214
|
+
name: wave[i].name,
|
|
1215
|
+
status: "failed",
|
|
1216
|
+
turnsUsed: 0,
|
|
1217
|
+
tokensUsed: 0,
|
|
1218
|
+
costUsd: 0,
|
|
1219
|
+
summary: `Error: ${errorMessage(outcome.reason)}`
|
|
1220
|
+
};
|
|
1221
|
+
});
|
|
1222
|
+
waveResults.sort(
|
|
1223
|
+
(a, b) => (declarationOrder.get(a.name) ?? 0) - (declarationOrder.get(b.name) ?? 0)
|
|
1224
|
+
);
|
|
1225
|
+
for (const result of waveResults) {
|
|
1226
|
+
phaseResults.push(result);
|
|
1227
|
+
totalTokens += result.tokensUsed;
|
|
1228
|
+
totalCost += result.costUsd;
|
|
1229
|
+
runningTurnCount += result.turnsUsed;
|
|
1230
|
+
}
|
|
1231
|
+
const shouldStop = wave.some((phase, i) => {
|
|
1232
|
+
if (!phase.required) return false;
|
|
1233
|
+
const outcome = settled[i];
|
|
1234
|
+
if (outcome.status === "rejected") return true;
|
|
1235
|
+
return outcome.value.status === "failed";
|
|
1236
|
+
});
|
|
1237
|
+
if (shouldStop) {
|
|
1238
|
+
break;
|
|
1239
|
+
}
|
|
1240
|
+
}
|
|
1241
|
+
return { tokensUsed: totalTokens, costUsd: totalCost, phases: phaseResults };
|
|
1242
|
+
}
|
|
1243
|
+
async function runAgent(vaultDir, options) {
|
|
1244
|
+
const db = initDatabase(vaultDbPath(vaultDir));
|
|
1245
|
+
createSchema(db);
|
|
1246
|
+
const agentId = options?.agentId ?? DEFAULT_AGENT_ID;
|
|
1247
|
+
const running = getRunningRun(agentId);
|
|
1248
|
+
if (running) {
|
|
1249
|
+
return {
|
|
1250
|
+
runId: running.id,
|
|
1251
|
+
status: STATUS_SKIPPED,
|
|
1252
|
+
reason: SKIP_REASON_ALREADY_RUNNING
|
|
1253
|
+
};
|
|
1254
|
+
}
|
|
1255
|
+
const definitionsDir = resolveDefinitionsDir();
|
|
1256
|
+
const definition = loadAgentDefinition(definitionsDir);
|
|
1257
|
+
const agentRow = getAgent(agentId);
|
|
1258
|
+
const taskRow = options?.task ? getTask(options.task) : getDefaultTask(agentId);
|
|
1259
|
+
const allTasks = loadAllTasks(definitionsDir, vaultDir);
|
|
1260
|
+
const taskName = taskRow?.id ?? options?.task;
|
|
1261
|
+
const yamlTask = taskName ? allTasks.get(taskName) : void 0;
|
|
1262
|
+
const taskOverrides = taskRow ? {
|
|
1263
|
+
name: taskRow.id,
|
|
1264
|
+
displayName: taskRow.display_name ?? taskRow.id,
|
|
1265
|
+
description: taskRow.description ?? "",
|
|
1266
|
+
agent: taskRow.agent_id,
|
|
1267
|
+
prompt: taskRow.prompt,
|
|
1268
|
+
isDefault: taskRow.is_default === 1,
|
|
1269
|
+
...taskRow.tool_overrides ? { toolOverrides: JSON.parse(taskRow.tool_overrides) } : {},
|
|
1270
|
+
// Scalar config from YAML (model, turns, timeout) — DB doesn't store these
|
|
1271
|
+
...yamlTask?.model ? { model: yamlTask.model } : {},
|
|
1272
|
+
...yamlTask?.maxTurns ? { maxTurns: yamlTask.maxTurns } : {},
|
|
1273
|
+
...yamlTask?.timeoutSeconds ? { timeoutSeconds: yamlTask.timeoutSeconds } : {},
|
|
1274
|
+
// Structural config from YAML
|
|
1275
|
+
...yamlTask?.phases ? { phases: yamlTask.phases } : {},
|
|
1276
|
+
...yamlTask?.execution ? { execution: yamlTask.execution } : {},
|
|
1277
|
+
...yamlTask?.contextQueries ? { contextQueries: yamlTask.contextQueries } : {},
|
|
1278
|
+
...yamlTask?.orchestrator ? { orchestrator: yamlTask.orchestrator } : {}
|
|
1279
|
+
} : void 0;
|
|
1280
|
+
const config = resolveEffectiveConfig(definition, agentRow, taskOverrides);
|
|
1281
|
+
let taskProviderOverride;
|
|
1282
|
+
let phaseProviderOverrides = {};
|
|
1283
|
+
try {
|
|
1284
|
+
const mycoConfig = loadConfig(vaultDir);
|
|
1285
|
+
const toProviderConfig = (p) => ({
|
|
1286
|
+
type: p.type,
|
|
1287
|
+
baseUrl: p.base_url,
|
|
1288
|
+
model: p.model,
|
|
1289
|
+
contextLength: p.context_length
|
|
1290
|
+
});
|
|
1291
|
+
const taskConfig = taskName ? mycoConfig.agent.tasks?.[taskName] : void 0;
|
|
1292
|
+
const globalProvider = mycoConfig.agent.provider;
|
|
1293
|
+
if (taskConfig?.provider) {
|
|
1294
|
+
taskProviderOverride = toProviderConfig(taskConfig.provider);
|
|
1295
|
+
} else if (globalProvider) {
|
|
1296
|
+
taskProviderOverride = toProviderConfig(globalProvider);
|
|
1297
|
+
}
|
|
1298
|
+
if (taskConfig?.phases) {
|
|
1299
|
+
for (const [phaseName, phaseConfig] of Object.entries(taskConfig.phases)) {
|
|
1300
|
+
phaseProviderOverrides[phaseName] = {
|
|
1301
|
+
...phaseConfig.provider ? { provider: toProviderConfig(phaseConfig.provider) } : {},
|
|
1302
|
+
...phaseConfig.maxTurns != null ? { maxTurns: phaseConfig.maxTurns } : {}
|
|
1303
|
+
};
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
} catch {
|
|
1307
|
+
}
|
|
1308
|
+
const runId = options?.resumeRunId ?? crypto2.randomUUID();
|
|
1309
|
+
const now = epochSeconds();
|
|
1310
|
+
if (!options?.resumeRunId) {
|
|
1311
|
+
insertRun({
|
|
1312
|
+
id: runId,
|
|
1313
|
+
agent_id: agentId,
|
|
1314
|
+
task: config.taskName,
|
|
1315
|
+
instruction: options?.instruction ?? null,
|
|
1316
|
+
status: STATUS_RUNNING,
|
|
1317
|
+
started_at: now
|
|
1318
|
+
});
|
|
1319
|
+
}
|
|
1320
|
+
const systemPrompt = loadSystemPrompt(definitionsDir, config.systemPromptPath);
|
|
1321
|
+
const vaultContext = buildVaultContext(agentId);
|
|
1322
|
+
const effectiveProvider = taskProviderOverride ?? config.execution?.provider;
|
|
1323
|
+
const effectiveModel = effectiveProvider?.model ?? config.model;
|
|
1324
|
+
const runMeta = {
|
|
1325
|
+
model: effectiveModel,
|
|
1326
|
+
provider: effectiveProvider?.type ?? "cloud",
|
|
1327
|
+
...effectiveProvider?.baseUrl ? { baseUrl: effectiveProvider.baseUrl } : {}
|
|
1328
|
+
};
|
|
1329
|
+
if (effectiveProvider?.type === "ollama" && effectiveProvider.contextLength && effectiveProvider.model) {
|
|
1330
|
+
const variantModel = await ensureOllamaContextVariant(
|
|
1331
|
+
effectiveProvider.model,
|
|
1332
|
+
effectiveProvider.contextLength
|
|
1333
|
+
);
|
|
1334
|
+
taskProviderOverride = { ...taskProviderOverride, model: variantModel };
|
|
1335
|
+
}
|
|
1336
|
+
const taskAbortController = new AbortController();
|
|
1337
|
+
const timeoutMs = config.timeoutSeconds * MS_PER_SECOND;
|
|
1338
|
+
const timeoutId = setTimeout(() => {
|
|
1339
|
+
console.warn(`[agent] Run ${runId} exceeded timeout (${config.timeoutSeconds}s), aborting`);
|
|
1340
|
+
taskAbortController.abort();
|
|
1341
|
+
}, timeoutMs);
|
|
1342
|
+
timeoutId.unref?.();
|
|
1343
|
+
let phaseResults;
|
|
1344
|
+
try {
|
|
1345
|
+
let tokensUsed;
|
|
1346
|
+
let costUsd;
|
|
1347
|
+
if (config.phases && config.phases.length > 0) {
|
|
1348
|
+
const result = await executePhasedQuery(
|
|
1349
|
+
config,
|
|
1350
|
+
systemPrompt,
|
|
1351
|
+
vaultContext,
|
|
1352
|
+
agentId,
|
|
1353
|
+
runId,
|
|
1354
|
+
taskProviderOverride,
|
|
1355
|
+
phaseProviderOverrides,
|
|
1356
|
+
options?.instruction,
|
|
1357
|
+
options?.embeddingManager,
|
|
1358
|
+
taskAbortController
|
|
1359
|
+
);
|
|
1360
|
+
tokensUsed = result.tokensUsed;
|
|
1361
|
+
costUsd = result.costUsd;
|
|
1362
|
+
phaseResults = result.phases;
|
|
1363
|
+
} else {
|
|
1364
|
+
const taskPrompt = composeTaskPrompt(
|
|
1365
|
+
vaultContext,
|
|
1366
|
+
config.taskDisplayName,
|
|
1367
|
+
config.taskPrompt,
|
|
1368
|
+
options?.instruction
|
|
1369
|
+
);
|
|
1370
|
+
const singleProvider = taskProviderOverride ?? config.execution?.provider;
|
|
1371
|
+
const result = await executeSingleQuery(
|
|
1372
|
+
config,
|
|
1373
|
+
systemPrompt,
|
|
1374
|
+
taskPrompt,
|
|
1375
|
+
agentId,
|
|
1376
|
+
runId,
|
|
1377
|
+
singleProvider,
|
|
1378
|
+
options?.embeddingManager,
|
|
1379
|
+
taskAbortController
|
|
1380
|
+
);
|
|
1381
|
+
tokensUsed = result.tokensUsed;
|
|
1382
|
+
costUsd = result.costUsd;
|
|
1383
|
+
}
|
|
1384
|
+
clearTimeout(timeoutId);
|
|
1385
|
+
const completedAt = epochSeconds();
|
|
1386
|
+
updateRunStatus(runId, STATUS_COMPLETED, {
|
|
1387
|
+
completed_at: completedAt,
|
|
1388
|
+
tokens_used: tokensUsed,
|
|
1389
|
+
cost_usd: costUsd,
|
|
1390
|
+
actions_taken: JSON.stringify({ ...runMeta, ...phaseResults ? { phases: phaseResults } : {} })
|
|
1391
|
+
});
|
|
1392
|
+
return {
|
|
1393
|
+
runId,
|
|
1394
|
+
status: STATUS_COMPLETED,
|
|
1395
|
+
tokensUsed,
|
|
1396
|
+
costUsd,
|
|
1397
|
+
...phaseResults ? { phases: phaseResults } : {}
|
|
1398
|
+
};
|
|
1399
|
+
} catch (err) {
|
|
1400
|
+
clearTimeout(timeoutId);
|
|
1401
|
+
let errorMessage2;
|
|
1402
|
+
if (err instanceof Error) {
|
|
1403
|
+
errorMessage2 = err.message || err.constructor.name || "Error (no message)";
|
|
1404
|
+
if (err.stack) errorMessage2 += `
|
|
1405
|
+
${err.stack.split("\n").slice(0, 3).join("\n")}`;
|
|
1406
|
+
} else if (typeof err === "string") {
|
|
1407
|
+
errorMessage2 = err || "Empty string error";
|
|
1408
|
+
} else {
|
|
1409
|
+
try {
|
|
1410
|
+
errorMessage2 = JSON.stringify(err);
|
|
1411
|
+
} catch {
|
|
1412
|
+
errorMessage2 = "Unserializable error";
|
|
1413
|
+
}
|
|
1414
|
+
}
|
|
1415
|
+
const failedAt = epochSeconds();
|
|
1416
|
+
console.error(`[agent] Run ${runId} failed: ${errorMessage2}`);
|
|
1417
|
+
try {
|
|
1418
|
+
updateRunStatus(runId, STATUS_FAILED, {
|
|
1419
|
+
completed_at: failedAt,
|
|
1420
|
+
error: errorMessage2,
|
|
1421
|
+
// Preserve phase results collected before the failure
|
|
1422
|
+
actions_taken: JSON.stringify({ ...runMeta, ...phaseResults ? { phases: phaseResults } : {} })
|
|
1423
|
+
});
|
|
1424
|
+
} catch (dbErr) {
|
|
1425
|
+
console.error(`[agent] Failed to save error to DB:`, dbErr);
|
|
1426
|
+
}
|
|
1427
|
+
return {
|
|
1428
|
+
runId,
|
|
1429
|
+
status: STATUS_FAILED,
|
|
1430
|
+
error: errorMessage2,
|
|
1431
|
+
...phaseResults ? { phases: phaseResults } : {}
|
|
1432
|
+
};
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
export {
|
|
1436
|
+
composePhasePrompt,
|
|
1437
|
+
composeTaskPrompt,
|
|
1438
|
+
computeWaves,
|
|
1439
|
+
runAgent
|
|
1440
|
+
};
|
|
1441
|
+
//# sourceMappingURL=executor-ONSDHPGX.js.map
|