@goondocks/myco 0.21.0 → 0.21.2
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/bin/myco-run +68 -7
- package/dist/{agent-eval-RJSQI5S2.js → agent-eval-2MQKTXX3.js} +7 -6
- package/dist/{agent-eval-RJSQI5S2.js.map → agent-eval-2MQKTXX3.js.map} +1 -1
- package/dist/{agent-run-2JSYFOKU.js → agent-run-XJBTSVJR.js} +5 -5
- package/dist/{agent-tasks-APFJIM2T.js → agent-tasks-7MWBZOC7.js} +5 -5
- package/dist/{chunk-75Z7UKDY.js → chunk-4D22KTXY.js} +2 -2
- package/dist/{chunk-P66DLD6G.js → chunk-6FBLL7MD.js} +8 -2
- package/dist/chunk-6FBLL7MD.js.map +1 -0
- package/dist/{chunk-JZS6GZ6T.js → chunk-AUIXX33A.js} +10 -3
- package/dist/chunk-AUIXX33A.js.map +1 -0
- package/dist/{chunk-F3OEQYLS.js → chunk-DBBO6FHE.js} +33 -30
- package/dist/{chunk-F3OEQYLS.js.map → chunk-DBBO6FHE.js.map} +1 -1
- package/dist/{chunk-CESKJD44.js → chunk-DMPCC7V6.js} +19 -11
- package/dist/chunk-DMPCC7V6.js.map +1 -0
- package/dist/{chunk-RL5R4CQU.js → chunk-DTWUHHFI.js} +39 -2
- package/dist/{chunk-RL5R4CQU.js.map → chunk-DTWUHHFI.js.map} +1 -1
- package/dist/{chunk-XL75KZGI.js → chunk-EKZG2MCD.js} +7 -3
- package/dist/chunk-EKZG2MCD.js.map +1 -0
- package/dist/{chunk-NGH7U6A3.js → chunk-HCT7RMM2.js} +487 -98
- package/dist/chunk-HCT7RMM2.js.map +1 -0
- package/dist/{chunk-G6QIBNZM.js → chunk-IMW5TJ3O.js} +7 -6
- package/dist/chunk-IMW5TJ3O.js.map +1 -0
- package/dist/chunk-LQIPXVDH.js +17 -0
- package/dist/chunk-LQIPXVDH.js.map +1 -0
- package/dist/{chunk-5ZG4RMUH.js → chunk-N2DGFACQ.js} +2 -2
- package/dist/{chunk-VHNRMM4O.js → chunk-OTQH5KZW.js} +87 -37
- package/dist/chunk-OTQH5KZW.js.map +1 -0
- package/dist/{chunk-6LB7XELY.js → chunk-QATYARI5.js} +15 -13
- package/dist/chunk-QATYARI5.js.map +1 -0
- package/dist/{chunk-LVIY7P35.js → chunk-QLLBJEM7.js} +5 -1
- package/dist/chunk-QLLBJEM7.js.map +1 -0
- package/dist/{chunk-DJ3IHNYO.js → chunk-TFRUDNLI.js} +2 -2
- package/dist/{chunk-R2JIJBCL.js → chunk-TMAXWERS.js} +87 -4
- package/dist/chunk-TMAXWERS.js.map +1 -0
- package/dist/chunk-TSM6VESW.js +25 -0
- package/dist/chunk-TSM6VESW.js.map +1 -0
- package/dist/{chunk-ILJPRYES.js → chunk-USVFEWYL.js} +2 -2
- package/dist/{chunk-JR54LTPP.js → chunk-W5L5IHP5.js} +3 -3
- package/dist/{chunk-BUTL6IFS.js → chunk-Z55WGA2J.js} +2 -2
- package/dist/{chunk-NGROSFOH.js → chunk-Z66IT5KL.js} +14 -9
- package/dist/chunk-Z66IT5KL.js.map +1 -0
- package/dist/{cli-LNYSTDQM.js → cli-DDHTHU2J.js} +37 -37
- package/dist/{client-NWE4TCNO.js → client-PQU53UQU.js} +5 -3
- package/dist/{detect-PXNM6TA7.js → detect-7NUD5B5R.js} +2 -2
- package/dist/{doctor-TI7EZ3RW.js → doctor-QK6KFY6H.js} +6 -6
- package/dist/{executor-F2YU7HXJ.js → executor-FJCMNSXM.js} +11 -10
- package/dist/{init-KG3TYVGE.js → init-GQPD6HHX.js} +9 -9
- package/dist/{installer-UMH7OJ5A.js → installer-N4UTEACX.js} +2 -2
- package/dist/{loader-NAVVZK63.js → loader-UDNUMEDA.js} +3 -2
- package/dist/{main-5PRQNEEE.js → main-4HKTZFIM.js} +469 -187
- package/dist/main-4HKTZFIM.js.map +1 -0
- package/dist/{open-5A27BCSB.js → open-3P3DDAOA.js} +5 -5
- package/dist/{post-compact-USAODKPQ.js → post-compact-QA5LME2J.js} +7 -7
- package/dist/{post-tool-use-GMMSYBII.js → post-tool-use-QRZMPNYL.js} +6 -6
- package/dist/{post-tool-use-failure-NZVSL2PO.js → post-tool-use-failure-XNHIKBZG.js} +7 -7
- package/dist/{pre-compact-LZ57DLUS.js → pre-compact-HDV6X5QM.js} +7 -7
- package/dist/{registry-M2Z5QBWH.js → registry-F3THYC5M.js} +4 -3
- package/dist/{remove-T3KE6C5N.js → remove-USQDLGTJ.js} +7 -7
- package/dist/{restart-YWDEVZUJ.js → restart-FQLZE2TW.js} +6 -6
- package/dist/{search-GKFDGELR.js → search-5COKV6TD.js} +6 -6
- package/dist/{server-AHUR6CWF.js → server-KRMBRW4T.js} +23 -7
- package/dist/{server-AHUR6CWF.js.map → server-KRMBRW4T.js.map} +1 -1
- package/dist/{session-2ZEPLWW6.js → session-NJCUW3OX.js} +5 -5
- package/dist/{session-end-LWJYQAXX.js → session-end-XD27GRYF.js} +6 -6
- package/dist/{session-start-WTA6GCOQ.js → session-start-RDTXUSYL.js} +11 -11
- package/dist/{setup-llm-E7UU5IO7.js → setup-llm-FYPPJI6W.js} +5 -5
- package/dist/src/agent/definitions/tasks/cortex-instructions.yaml +63 -41
- package/dist/src/agent/definitions/tasks/skill-evolve.yaml +178 -22
- package/dist/src/agent/definitions/tasks/skill-generate.yaml +20 -6
- package/dist/src/agent/definitions/tasks/vault-evolve.yaml +65 -55
- package/dist/src/cli.js +1 -1
- package/dist/src/daemon/main.js +1 -1
- package/dist/src/hooks/post-tool-use.js +1 -1
- package/dist/src/hooks/session-end.js +1 -1
- package/dist/src/hooks/session-start.js +1 -1
- package/dist/src/hooks/stop.js +1 -1
- package/dist/src/hooks/user-prompt-submit.js +1 -1
- package/dist/src/mcp/server.js +1 -1
- package/dist/src/symbionts/manifests/opencode.yaml +7 -0
- package/dist/src/symbionts/templates/agents-starter.md +1 -1
- package/dist/src/symbionts/templates/opencode/plugin.ts +41 -1
- package/dist/src/symbionts/templates/pi/plugin.ts +12 -1
- package/dist/{stats-DFG6S23S.js → stats-JCLZLA5G.js} +6 -6
- package/dist/{stop-WRBTXEVT.js → stop-B7XCXEM5.js} +6 -6
- package/dist/{stop-failure-32MGIG2Q.js → stop-failure-R6QZCUOZ.js} +7 -7
- package/dist/{subagent-start-VFGHQFVL.js → subagent-start-N7A622F3.js} +7 -7
- package/dist/{subagent-stop-663FXG3P.js → subagent-stop-SVOG5MZJ.js} +7 -7
- package/dist/{task-completed-ZCQYEFMZ.js → task-completed-3DL5LJXF.js} +7 -7
- package/dist/{team-JTI5CDUO.js → team-VJ3M263F.js} +3 -3
- package/dist/ui/assets/{index-DGf1h-Ha.js → index-O1kNWlWM.js} +119 -119
- package/dist/ui/assets/index-z2Jm8i4A.css +1 -0
- package/dist/ui/index.html +2 -2
- package/dist/{update-3NBQTG32.js → update-TVXAUJMZ.js} +45 -11
- package/dist/update-TVXAUJMZ.js.map +1 -0
- package/dist/{user-prompt-submit-ME2TBKOS.js → user-prompt-submit-KYO2VGLB.js} +10 -9
- package/dist/user-prompt-submit-KYO2VGLB.js.map +1 -0
- package/dist/{version-GQAFBBPX.js → version-LDFEALUJ.js} +2 -2
- package/package.json +1 -1
- package/skills/myco-rules/SKILL.md +94 -0
- package/skills/{rules → myco-rules}/references/rules-bad-example.md +1 -1
- package/skills/{rules → myco-rules}/references/rules-good-example.md +1 -1
- package/dist/chunk-6LB7XELY.js.map +0 -1
- package/dist/chunk-CESKJD44.js.map +0 -1
- package/dist/chunk-CUDIZJY7.js +0 -36
- package/dist/chunk-CUDIZJY7.js.map +0 -1
- package/dist/chunk-G6QIBNZM.js.map +0 -1
- package/dist/chunk-JZS6GZ6T.js.map +0 -1
- package/dist/chunk-LVIY7P35.js.map +0 -1
- package/dist/chunk-NGH7U6A3.js.map +0 -1
- package/dist/chunk-NGROSFOH.js.map +0 -1
- package/dist/chunk-P66DLD6G.js.map +0 -1
- package/dist/chunk-R2JIJBCL.js.map +0 -1
- package/dist/chunk-VHNRMM4O.js.map +0 -1
- package/dist/chunk-XL75KZGI.js.map +0 -1
- package/dist/main-5PRQNEEE.js.map +0 -1
- package/dist/ui/assets/index-_OP4ifzH.css +0 -1
- package/dist/update-3NBQTG32.js.map +0 -1
- package/dist/user-prompt-submit-ME2TBKOS.js.map +0 -1
- package/skills/myco-curate/SKILL.md +0 -86
- package/skills/rules/SKILL.md +0 -214
- /package/dist/{agent-run-2JSYFOKU.js.map → agent-run-XJBTSVJR.js.map} +0 -0
- /package/dist/{agent-tasks-APFJIM2T.js.map → agent-tasks-7MWBZOC7.js.map} +0 -0
- /package/dist/{chunk-75Z7UKDY.js.map → chunk-4D22KTXY.js.map} +0 -0
- /package/dist/{chunk-5ZG4RMUH.js.map → chunk-N2DGFACQ.js.map} +0 -0
- /package/dist/{chunk-DJ3IHNYO.js.map → chunk-TFRUDNLI.js.map} +0 -0
- /package/dist/{chunk-ILJPRYES.js.map → chunk-USVFEWYL.js.map} +0 -0
- /package/dist/{chunk-JR54LTPP.js.map → chunk-W5L5IHP5.js.map} +0 -0
- /package/dist/{chunk-BUTL6IFS.js.map → chunk-Z55WGA2J.js.map} +0 -0
- /package/dist/{cli-LNYSTDQM.js.map → cli-DDHTHU2J.js.map} +0 -0
- /package/dist/{client-NWE4TCNO.js.map → client-PQU53UQU.js.map} +0 -0
- /package/dist/{detect-PXNM6TA7.js.map → detect-7NUD5B5R.js.map} +0 -0
- /package/dist/{doctor-TI7EZ3RW.js.map → doctor-QK6KFY6H.js.map} +0 -0
- /package/dist/{executor-F2YU7HXJ.js.map → executor-FJCMNSXM.js.map} +0 -0
- /package/dist/{init-KG3TYVGE.js.map → init-GQPD6HHX.js.map} +0 -0
- /package/dist/{installer-UMH7OJ5A.js.map → installer-N4UTEACX.js.map} +0 -0
- /package/dist/{loader-NAVVZK63.js.map → loader-UDNUMEDA.js.map} +0 -0
- /package/dist/{open-5A27BCSB.js.map → open-3P3DDAOA.js.map} +0 -0
- /package/dist/{post-compact-USAODKPQ.js.map → post-compact-QA5LME2J.js.map} +0 -0
- /package/dist/{post-tool-use-GMMSYBII.js.map → post-tool-use-QRZMPNYL.js.map} +0 -0
- /package/dist/{post-tool-use-failure-NZVSL2PO.js.map → post-tool-use-failure-XNHIKBZG.js.map} +0 -0
- /package/dist/{pre-compact-LZ57DLUS.js.map → pre-compact-HDV6X5QM.js.map} +0 -0
- /package/dist/{registry-M2Z5QBWH.js.map → registry-F3THYC5M.js.map} +0 -0
- /package/dist/{remove-T3KE6C5N.js.map → remove-USQDLGTJ.js.map} +0 -0
- /package/dist/{restart-YWDEVZUJ.js.map → restart-FQLZE2TW.js.map} +0 -0
- /package/dist/{search-GKFDGELR.js.map → search-5COKV6TD.js.map} +0 -0
- /package/dist/{session-2ZEPLWW6.js.map → session-NJCUW3OX.js.map} +0 -0
- /package/dist/{session-end-LWJYQAXX.js.map → session-end-XD27GRYF.js.map} +0 -0
- /package/dist/{session-start-WTA6GCOQ.js.map → session-start-RDTXUSYL.js.map} +0 -0
- /package/dist/{setup-llm-E7UU5IO7.js.map → setup-llm-FYPPJI6W.js.map} +0 -0
- /package/dist/{stats-DFG6S23S.js.map → stats-JCLZLA5G.js.map} +0 -0
- /package/dist/{stop-WRBTXEVT.js.map → stop-B7XCXEM5.js.map} +0 -0
- /package/dist/{stop-failure-32MGIG2Q.js.map → stop-failure-R6QZCUOZ.js.map} +0 -0
- /package/dist/{subagent-start-VFGHQFVL.js.map → subagent-start-N7A622F3.js.map} +0 -0
- /package/dist/{subagent-stop-663FXG3P.js.map → subagent-stop-SVOG5MZJ.js.map} +0 -0
- /package/dist/{task-completed-ZCQYEFMZ.js.map → task-completed-3DL5LJXF.js.map} +0 -0
- /package/dist/{team-JTI5CDUO.js.map → team-VJ3M263F.js.map} +0 -0
- /package/dist/{version-GQAFBBPX.js.map → version-LDFEALUJ.js.map} +0 -0
|
@@ -8,21 +8,22 @@ import {
|
|
|
8
8
|
buildRunAccountingUpdate,
|
|
9
9
|
buildUsageData,
|
|
10
10
|
checkpointResultsForResume,
|
|
11
|
-
errorMessage,
|
|
12
11
|
inferRuntimeFromProviderType,
|
|
12
|
+
isExpiredSessionError,
|
|
13
13
|
isSessionResumeFailure,
|
|
14
14
|
parseCheckpointState,
|
|
15
15
|
resolveProviderForResume,
|
|
16
16
|
serializeCheckpointState,
|
|
17
17
|
summarizePhaseCosts
|
|
18
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-QATYARI5.js";
|
|
19
19
|
import {
|
|
20
20
|
fullTextSearch,
|
|
21
|
-
hydrateSearchResults
|
|
22
|
-
|
|
21
|
+
hydrateSearchResults,
|
|
22
|
+
sanitizeFtsQuery
|
|
23
|
+
} from "./chunk-QLLBJEM7.js";
|
|
23
24
|
import {
|
|
24
25
|
loadAllTasks
|
|
25
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-USVFEWYL.js";
|
|
26
27
|
import {
|
|
27
28
|
getAgent,
|
|
28
29
|
getDefaultTask,
|
|
@@ -31,7 +32,10 @@ import {
|
|
|
31
32
|
loadSystemPrompt,
|
|
32
33
|
resolveDefinitionsDir,
|
|
33
34
|
resolveEffectiveConfig
|
|
34
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-AUIXX33A.js";
|
|
36
|
+
import {
|
|
37
|
+
errorMessage
|
|
38
|
+
} from "./chunk-LQIPXVDH.js";
|
|
35
39
|
import {
|
|
36
40
|
countToolCallsByRun,
|
|
37
41
|
insertTurn,
|
|
@@ -59,12 +63,11 @@ import {
|
|
|
59
63
|
getSpore,
|
|
60
64
|
insertSpore,
|
|
61
65
|
listDigestExtracts,
|
|
62
|
-
listSporeIdsSince,
|
|
63
66
|
listSpores,
|
|
64
67
|
updateSporeStatus,
|
|
65
68
|
upsertCortexInstructions,
|
|
66
69
|
upsertDigestExtract
|
|
67
|
-
} from "./chunk-
|
|
70
|
+
} from "./chunk-DBBO6FHE.js";
|
|
68
71
|
import {
|
|
69
72
|
countSessions,
|
|
70
73
|
getActiveSessionIds,
|
|
@@ -78,7 +81,7 @@ import {
|
|
|
78
81
|
AGENT_SETTABLE_STATUSES,
|
|
79
82
|
CANDIDATE_STATUS,
|
|
80
83
|
createSchema
|
|
81
|
-
} from "./chunk-
|
|
84
|
+
} from "./chunk-DTWUHHFI.js";
|
|
82
85
|
import {
|
|
83
86
|
loadMergedConfig
|
|
84
87
|
} from "./chunk-53RPGOEN.js";
|
|
@@ -89,7 +92,7 @@ import {
|
|
|
89
92
|
} from "./chunk-MYX5NCRH.js";
|
|
90
93
|
import {
|
|
91
94
|
getPluginVersion
|
|
92
|
-
} from "./chunk-
|
|
95
|
+
} from "./chunk-Z55WGA2J.js";
|
|
93
96
|
import {
|
|
94
97
|
findPackageRoot
|
|
95
98
|
} from "./chunk-LPUQPDC2.js";
|
|
@@ -97,6 +100,7 @@ import {
|
|
|
97
100
|
CONTENT_HASH_ALGORITHM,
|
|
98
101
|
DEFAULT_AGENT_ID,
|
|
99
102
|
DEFAULT_LIST_LIMIT,
|
|
103
|
+
DIGEST_TIERS,
|
|
100
104
|
EDGE_TYPE_DERIVED_FROM,
|
|
101
105
|
EDGE_TYPE_EXTRACTED_FROM,
|
|
102
106
|
EDGE_TYPE_FROM_SESSION,
|
|
@@ -197,6 +201,7 @@ var STATUS_RUNNING = "running";
|
|
|
197
201
|
var STATUS_COMPLETED = "completed";
|
|
198
202
|
var STATUS_FAILED = "failed";
|
|
199
203
|
var RESUME_STATUS_READY = "ready";
|
|
204
|
+
var RESUME_STATUS_SESSION_EXPIRED = "session_expired";
|
|
200
205
|
var RUN_COLUMNS = [
|
|
201
206
|
"id",
|
|
202
207
|
"agent_id",
|
|
@@ -1251,6 +1256,32 @@ function deleteSkillRecordCascade(idOrName) {
|
|
|
1251
1256
|
return { id: record.id, name: record.name };
|
|
1252
1257
|
}
|
|
1253
1258
|
|
|
1259
|
+
// src/agent/semantic-shortlist.ts
|
|
1260
|
+
async function shortlistSemanticIds(options) {
|
|
1261
|
+
const {
|
|
1262
|
+
provider,
|
|
1263
|
+
namespace,
|
|
1264
|
+
query: query2,
|
|
1265
|
+
candidateIds,
|
|
1266
|
+
maxResults,
|
|
1267
|
+
overFetch,
|
|
1268
|
+
threshold,
|
|
1269
|
+
filters
|
|
1270
|
+
} = options;
|
|
1271
|
+
if (!provider || maxResults <= 0) return [];
|
|
1272
|
+
const queryVector = await provider.embedQuery(query2);
|
|
1273
|
+
if (!queryVector) return [];
|
|
1274
|
+
const results = provider.searchVectors(queryVector, {
|
|
1275
|
+
namespace,
|
|
1276
|
+
limit: Math.max(maxResults, maxResults * overFetch),
|
|
1277
|
+
threshold,
|
|
1278
|
+
filters
|
|
1279
|
+
});
|
|
1280
|
+
const shortlisted = candidateIds ? results.filter((result) => candidateIds.has(result.id)) : results;
|
|
1281
|
+
shortlisted.sort((a, b) => b.similarity - a.similarity);
|
|
1282
|
+
return shortlisted.slice(0, maxResults).map((result) => result.id);
|
|
1283
|
+
}
|
|
1284
|
+
|
|
1254
1285
|
// src/agent/tools/skill-validator.ts
|
|
1255
1286
|
var import_yaml = __toESM(require_dist(), 1);
|
|
1256
1287
|
var MAX_SKILL_LINES = 800;
|
|
@@ -1706,7 +1737,57 @@ function buildSkillSurveyInstruction(agentId) {
|
|
|
1706
1737
|
return { instruction: parts.join("\n") };
|
|
1707
1738
|
}
|
|
1708
1739
|
var SKILL_EVOLVE_DEFAULT_ASSESS_INTERVAL_HOURS = 24;
|
|
1709
|
-
var SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN =
|
|
1740
|
+
var SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN = 3;
|
|
1741
|
+
var SKILL_EVOLVE_RECENT_SPORE_SCAN_LIMIT = 40;
|
|
1742
|
+
var SKILL_EVOLVE_RELEVANT_SPORE_LIMIT = 10;
|
|
1743
|
+
var SKILL_EVOLVE_SEMANTIC_OVERFETCH = 4;
|
|
1744
|
+
var SKILL_EVOLVE_SEMANTIC_THRESHOLD = 0;
|
|
1745
|
+
function normalizeSkillName(name) {
|
|
1746
|
+
return name.replace(/[-_:]+/g, " ");
|
|
1747
|
+
}
|
|
1748
|
+
function buildSporeSearchText(spore) {
|
|
1749
|
+
return [spore.observation_type, spore.content, spore.context, spore.tags, spore.file_path].filter(Boolean).join(" ");
|
|
1750
|
+
}
|
|
1751
|
+
function selectRelevantSporeIdsByLexicalOverlap(skill, recentSpores) {
|
|
1752
|
+
if (recentSpores.length === 0) return [];
|
|
1753
|
+
const skillName = normalizeSkillName(skill.name);
|
|
1754
|
+
const skillQuery = `${skillName} ${skill.description}`;
|
|
1755
|
+
return recentSpores.map((spore) => {
|
|
1756
|
+
const sporeText = buildSporeSearchText(spore);
|
|
1757
|
+
const descriptionScore = descriptionSimilarity(skillQuery, sporeText);
|
|
1758
|
+
const nameScore = descriptionSimilarity(skillName, sporeText);
|
|
1759
|
+
const totalScore = descriptionScore + nameScore * 1.5;
|
|
1760
|
+
return { id: spore.id, totalScore, createdAt: spore.created_at, importance: spore.importance };
|
|
1761
|
+
}).filter((candidate) => candidate.totalScore > 0).sort((a, b) => {
|
|
1762
|
+
if (b.totalScore !== a.totalScore) return b.totalScore - a.totalScore;
|
|
1763
|
+
if (b.importance !== a.importance) return b.importance - a.importance;
|
|
1764
|
+
return b.createdAt - a.createdAt;
|
|
1765
|
+
}).slice(0, SKILL_EVOLVE_RELEVANT_SPORE_LIMIT).map((candidate) => candidate.id);
|
|
1766
|
+
}
|
|
1767
|
+
async function selectRelevantSporeIdsForSkill(skill, sinceEpoch, retrievalProvider) {
|
|
1768
|
+
const recentSpores = listSpores({
|
|
1769
|
+
status: "active",
|
|
1770
|
+
since: sinceEpoch,
|
|
1771
|
+
includeActive: false,
|
|
1772
|
+
limit: SKILL_EVOLVE_RECENT_SPORE_SCAN_LIMIT
|
|
1773
|
+
});
|
|
1774
|
+
if (recentSpores.length === 0) return [];
|
|
1775
|
+
const semanticIds = await shortlistSemanticIds({
|
|
1776
|
+
provider: retrievalProvider,
|
|
1777
|
+
namespace: "spores",
|
|
1778
|
+
query: `${normalizeSkillName(skill.name)} ${skill.description}`,
|
|
1779
|
+
candidateIds: new Set(recentSpores.map((spore) => spore.id)),
|
|
1780
|
+
maxResults: SKILL_EVOLVE_RELEVANT_SPORE_LIMIT,
|
|
1781
|
+
overFetch: SKILL_EVOLVE_SEMANTIC_OVERFETCH,
|
|
1782
|
+
threshold: SKILL_EVOLVE_SEMANTIC_THRESHOLD,
|
|
1783
|
+
filters: {
|
|
1784
|
+
status: "active",
|
|
1785
|
+
created_at_gte: sinceEpoch
|
|
1786
|
+
}
|
|
1787
|
+
});
|
|
1788
|
+
if (semanticIds.length > 0) return semanticIds;
|
|
1789
|
+
return selectRelevantSporeIdsByLexicalOverlap(skill, recentSpores);
|
|
1790
|
+
}
|
|
1710
1791
|
var MIN_SECTIONS_FOR_STANDALONE = 2;
|
|
1711
1792
|
function extractHeadings(content) {
|
|
1712
1793
|
const bodyMatch = content.match(/^---[\s\S]*?---\n([\s\S]*)$/);
|
|
@@ -1733,7 +1814,7 @@ function headingOverlap(headingsA, headingsB) {
|
|
|
1733
1814
|
const smaller = Math.min(headingsA.length, headingsB.length);
|
|
1734
1815
|
return { score: smaller > 0 ? shared.length / smaller : 0, shared };
|
|
1735
1816
|
}
|
|
1736
|
-
function buildSkillEvolveInstruction(params, projectRoot,
|
|
1817
|
+
async function buildSkillEvolveInstruction(params, projectRoot, retrievalProvider) {
|
|
1737
1818
|
const assessIntervalHours = Number(params?.assess_interval_hours ?? SKILL_EVOLVE_DEFAULT_ASSESS_INTERVAL_HOURS);
|
|
1738
1819
|
const maxSkillsPerRun = Number(params?.max_skills_per_run ?? SKILL_EVOLVE_DEFAULT_MAX_SKILLS_PER_RUN);
|
|
1739
1820
|
const now = epochSeconds();
|
|
@@ -1750,20 +1831,20 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
|
|
|
1750
1831
|
const lastAssessedAt = typeof props.last_assessed_at === "number" ? props.last_assessed_at : 0;
|
|
1751
1832
|
const knowledgeWatermark = typeof props.knowledge_watermark === "number" ? props.knowledge_watermark : 0;
|
|
1752
1833
|
if (lastAssessedAt > 0 && now - lastAssessedAt < intervalSeconds) continue;
|
|
1753
|
-
const newSporeIds =
|
|
1834
|
+
const newSporeIds = await selectRelevantSporeIdsForSkill(skill, knowledgeWatermark, retrievalProvider);
|
|
1754
1835
|
if (newSporeIds.length === 0) continue;
|
|
1755
1836
|
needsAssessment.push({
|
|
1756
1837
|
id: skill.id,
|
|
1757
1838
|
name: skill.name,
|
|
1758
1839
|
generation: skill.generation,
|
|
1759
1840
|
description: skill.description,
|
|
1760
|
-
newSporeIds
|
|
1841
|
+
newSporeIds,
|
|
1842
|
+
lastAssessedAt
|
|
1761
1843
|
});
|
|
1762
|
-
if (needsAssessment.length >= maxSkillsPerRun) {
|
|
1763
|
-
break;
|
|
1764
|
-
}
|
|
1765
1844
|
}
|
|
1766
|
-
|
|
1845
|
+
needsAssessment.sort((a, b) => a.lastAssessedAt - b.lastAssessedAt);
|
|
1846
|
+
const selectedSkills = needsAssessment.slice(0, maxSkillsPerRun);
|
|
1847
|
+
if (selectedSkills.length === 0) {
|
|
1767
1848
|
return "No skills need assessment. All active skills are current or were recently assessed. Report skip via vault_report and finish.";
|
|
1768
1849
|
}
|
|
1769
1850
|
const structures = [];
|
|
@@ -1809,11 +1890,11 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
|
|
|
1809
1890
|
}
|
|
1810
1891
|
}
|
|
1811
1892
|
const parts = [
|
|
1812
|
-
`${
|
|
1893
|
+
`${selectedSkills.length} skill(s) need assessment.`,
|
|
1813
1894
|
`assess_interval_hours: ${assessIntervalHours}`,
|
|
1814
1895
|
`max_skills_per_run: ${maxSkillsPerRun}`
|
|
1815
1896
|
];
|
|
1816
|
-
for (const skill of
|
|
1897
|
+
for (const skill of selectedSkills) {
|
|
1817
1898
|
parts.push("");
|
|
1818
1899
|
parts.push("---");
|
|
1819
1900
|
parts.push(`## Skill: ${skill.name} (gen ${skill.generation})`);
|
|
@@ -1852,10 +1933,10 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
|
|
|
1852
1933
|
}
|
|
1853
1934
|
}
|
|
1854
1935
|
}
|
|
1855
|
-
if (
|
|
1936
|
+
if (retrievalProvider) {
|
|
1856
1937
|
const idToName = new Map(allSkills.map((s) => [s.id, s.name]));
|
|
1857
1938
|
try {
|
|
1858
|
-
const semanticPairs =
|
|
1939
|
+
const semanticPairs = retrievalProvider.pairwiseSimilarity("skill_records", 0.65);
|
|
1859
1940
|
if (semanticPairs.length > 0) {
|
|
1860
1941
|
parts.push("");
|
|
1861
1942
|
parts.push("## Semantic Similarity (embedding cosine distance)");
|
|
@@ -1872,14 +1953,14 @@ function buildSkillEvolveInstruction(params, projectRoot, similarityProvider) {
|
|
|
1872
1953
|
}
|
|
1873
1954
|
return parts.join("\n");
|
|
1874
1955
|
}
|
|
1875
|
-
async function buildTaskInstruction(taskName, taskParams, agentId, projectRoot,
|
|
1956
|
+
async function buildTaskInstruction(taskName, taskParams, agentId, projectRoot, retrievalProvider, config, getTeamClient) {
|
|
1876
1957
|
switch (taskName) {
|
|
1877
1958
|
case SKILL_GENERATE_TASK:
|
|
1878
1959
|
return buildSkillGenerateInstruction();
|
|
1879
1960
|
case SKILL_SURVEY_TASK:
|
|
1880
1961
|
return agentId ? buildSkillSurveyInstruction(agentId) : void 0;
|
|
1881
1962
|
case SKILL_EVOLVE_TASK: {
|
|
1882
|
-
const instruction = buildSkillEvolveInstruction(taskParams, projectRoot,
|
|
1963
|
+
const instruction = await buildSkillEvolveInstruction(taskParams, projectRoot, retrievalProvider);
|
|
1883
1964
|
return instruction ? { instruction } : void 0;
|
|
1884
1965
|
}
|
|
1885
1966
|
case CORTEX_INSTRUCTIONS_TASK: {
|
|
@@ -2403,6 +2484,7 @@ var ORCHESTRATOR_GUIDANCE_HEADER = "## Orchestrator Guidance";
|
|
|
2403
2484
|
var NO_CONTEXT_QUERIES_TEXT = "No context queries configured.";
|
|
2404
2485
|
var FALLBACK_REASONING_PARSE_ERROR = "Orchestrator response could not be parsed \u2014 running all phases with defaults.";
|
|
2405
2486
|
var FALLBACK_REASONING_MISSING_PHASES = "Orchestrator plan missing phases array \u2014 running all phases with defaults.";
|
|
2487
|
+
var ORCHESTRATOR_PARSE_ERROR_PREVIEW_CHARS = 200;
|
|
2406
2488
|
var PLACEHOLDER_VAULT_STATE = "{{vault_state}}";
|
|
2407
2489
|
var PLACEHOLDER_PHASE_DEFINITIONS = "{{phase_definitions}}";
|
|
2408
2490
|
var PLACEHOLDER_CONTEXT_RESULTS = "{{context_results}}";
|
|
@@ -2436,7 +2518,7 @@ function composeOrchestratorPrompt(vaultState, phases, contextResults) {
|
|
|
2436
2518
|
const contextSection = formatContextResults(contextResults);
|
|
2437
2519
|
return template.replace(PLACEHOLDER_VAULT_STATE, vaultState).replace(PLACEHOLDER_PHASE_DEFINITIONS, phaseList).replace(PLACEHOLDER_CONTEXT_RESULTS, contextSection);
|
|
2438
2520
|
}
|
|
2439
|
-
function parseOrchestratorPlan(response, phases) {
|
|
2521
|
+
function parseOrchestratorPlan(response, phases, logger) {
|
|
2440
2522
|
const trimmed = response.trim();
|
|
2441
2523
|
if (!trimmed) {
|
|
2442
2524
|
return buildRunAllPlan(phases, FALLBACK_REASONING_PARSE_ERROR);
|
|
@@ -2447,8 +2529,14 @@ function parseOrchestratorPlan(response, phases) {
|
|
|
2447
2529
|
return buildRunAllPlan(phases, FALLBACK_REASONING_MISSING_PHASES);
|
|
2448
2530
|
}
|
|
2449
2531
|
return parsed;
|
|
2450
|
-
} catch {
|
|
2451
|
-
|
|
2532
|
+
} catch (err) {
|
|
2533
|
+
const detail = errorMessage(err);
|
|
2534
|
+
const truncated = detail.length > ORCHESTRATOR_PARSE_ERROR_PREVIEW_CHARS ? `${detail.slice(0, ORCHESTRATOR_PARSE_ERROR_PREVIEW_CHARS)}\u2026` : detail;
|
|
2535
|
+
logger?.warn("agent.orchestrator.parse-failed", "Orchestrator plan parse failed", {
|
|
2536
|
+
error: detail,
|
|
2537
|
+
responsePreview: trimmed.slice(0, 200)
|
|
2538
|
+
});
|
|
2539
|
+
return buildRunAllPlan(phases, `${FALLBACK_REASONING_PARSE_ERROR} (${truncated})`);
|
|
2452
2540
|
}
|
|
2453
2541
|
}
|
|
2454
2542
|
function applyDirectives(phases, directives) {
|
|
@@ -3055,6 +3143,27 @@ function countWriteIntentsByToolForEvaluation(evaluationId) {
|
|
|
3055
3143
|
// src/agent/tools/read-tools.ts
|
|
3056
3144
|
import { tool } from "@anthropic-ai/claude-agent-sdk";
|
|
3057
3145
|
|
|
3146
|
+
// src/semantic-search-filters.ts
|
|
3147
|
+
function hasSemanticSearchFilters(filters) {
|
|
3148
|
+
if (!filters) return false;
|
|
3149
|
+
return Object.values(filters).some((value) => value !== void 0);
|
|
3150
|
+
}
|
|
3151
|
+
function matchesSemanticSearchFilters(metadata, filters) {
|
|
3152
|
+
if (!filters) return true;
|
|
3153
|
+
if (filters.status !== void 0 && metadata?.status !== filters.status) return false;
|
|
3154
|
+
if (filters.session_id !== void 0 && metadata?.session_id !== filters.session_id) return false;
|
|
3155
|
+
if (filters.observation_type !== void 0 && metadata?.observation_type !== filters.observation_type) return false;
|
|
3156
|
+
if (filters.project_root !== void 0 && metadata?.project_root !== filters.project_root) return false;
|
|
3157
|
+
if (filters.name !== void 0 && metadata?.name !== filters.name) return false;
|
|
3158
|
+
if (filters.source_path !== void 0 && metadata?.source_path !== filters.source_path) return false;
|
|
3159
|
+
const createdAt = typeof metadata?.created_at === "number" ? metadata.created_at : void 0;
|
|
3160
|
+
if (filters.created_at_gte !== void 0 && (createdAt === void 0 || createdAt < filters.created_at_gte)) return false;
|
|
3161
|
+
if (filters.created_at_lte !== void 0 && (createdAt === void 0 || createdAt > filters.created_at_lte)) return false;
|
|
3162
|
+
if (filters.created_at_gt !== void 0 && (createdAt === void 0 || createdAt <= filters.created_at_gt)) return false;
|
|
3163
|
+
if (filters.created_at_lt !== void 0 && (createdAt === void 0 || createdAt >= filters.created_at_lt)) return false;
|
|
3164
|
+
return true;
|
|
3165
|
+
}
|
|
3166
|
+
|
|
3058
3167
|
// src/db/queries/graph-edges.ts
|
|
3059
3168
|
import crypto3 from "crypto";
|
|
3060
3169
|
var DEFAULT_BFS_DEPTH = 2;
|
|
@@ -3355,23 +3464,36 @@ function createReadTools(deps) {
|
|
|
3355
3464
|
);
|
|
3356
3465
|
const vaultSearchFts = tool(
|
|
3357
3466
|
"vault_search_fts",
|
|
3358
|
-
|
|
3467
|
+
'Full-text search across sessions, spores, prompt batches, and activities using FTS5. Best for finding exact keywords, file paths, function names, and specific text. You can pass natural-language queries containing hyphens, slashes, dots, etc. \u2014 the tool auto-quotes tokens with non-word characters so file paths and hyphenated identifiers (e.g., "skill-evolve-inventory", "packages/myco/src/loader.ts") are treated as literal phrases instead of being rejected by FTS5 MATCH syntax. Plain alphanumeric/underscore tokens are left unquoted so they AND together normally. Results from in-flight sessions are hidden by default so intelligence tasks only see settled work; pass include_active=true to bypass.',
|
|
3359
3468
|
{
|
|
3360
|
-
query: external_exports.string().describe("Search query text"),
|
|
3469
|
+
query: external_exports.string().describe("Search query text. Special characters (hyphens, slashes, dots, colons) are auto-quoted \u2014 no manual escaping needed."),
|
|
3361
3470
|
type: external_exports.string().optional().describe("Restrict to a result type (session, spore, prompt_batch, activity)"),
|
|
3362
3471
|
limit: external_exports.number().optional().describe("Maximum number of results to return"),
|
|
3363
3472
|
include_active: external_exports.boolean().optional().describe("Include results from sessions still in active status (default: false)")
|
|
3364
3473
|
},
|
|
3365
3474
|
async (args) => {
|
|
3475
|
+
const sanitizedQuery = sanitizeFtsQuery(args.query);
|
|
3366
3476
|
try {
|
|
3367
|
-
const results = fullTextSearch(
|
|
3477
|
+
const results = fullTextSearch(sanitizedQuery, {
|
|
3368
3478
|
type: args.type,
|
|
3369
3479
|
limit: args.limit ?? DEFAULT_SEARCH_LIMIT,
|
|
3370
3480
|
includeActive: args.include_active === true
|
|
3371
3481
|
});
|
|
3372
|
-
return textResult({ results });
|
|
3373
|
-
} catch {
|
|
3374
|
-
|
|
3482
|
+
return textResult({ results, sanitized_query: sanitizedQuery !== args.query ? sanitizedQuery : void 0 });
|
|
3483
|
+
} catch (err) {
|
|
3484
|
+
const message = errorMessage(err);
|
|
3485
|
+
let hint;
|
|
3486
|
+
if (/no such table|no such module: fts5/i.test(message)) {
|
|
3487
|
+
hint = "FTS index missing \u2014 the searched table may not have an FTS5 mirror. Check the type parameter.";
|
|
3488
|
+
} else if (/syntax error|malformed MATCH/i.test(message)) {
|
|
3489
|
+
hint = 'FTS5 query syntax rejected. Quote special characters (e.g., wrap file paths in double quotes: "packages/myco/src/loader.ts").';
|
|
3490
|
+
}
|
|
3491
|
+
return textResult({
|
|
3492
|
+
error: `vault_search_fts failed: ${message}${hint ? ` \u2014 ${hint}` : ""}`,
|
|
3493
|
+
results: [],
|
|
3494
|
+
query: args.query,
|
|
3495
|
+
type: args.type ?? null
|
|
3496
|
+
});
|
|
3375
3497
|
}
|
|
3376
3498
|
},
|
|
3377
3499
|
{ annotations: { readOnlyHint: true } }
|
|
@@ -3383,7 +3505,12 @@ function createReadTools(deps) {
|
|
|
3383
3505
|
query: external_exports.string().describe("Search query text"),
|
|
3384
3506
|
namespace: external_exports.string().optional().describe("Restrict to a content type: spores, sessions, plans, artifacts, skill_records. Omit to search all."),
|
|
3385
3507
|
limit: external_exports.number().optional().describe("Maximum results to return"),
|
|
3386
|
-
include_active: external_exports.boolean().optional().describe("Include results from sessions still in active status (default: false)")
|
|
3508
|
+
include_active: external_exports.boolean().optional().describe("Include results from sessions still in active status (default: false)"),
|
|
3509
|
+
status: external_exports.string().optional().describe("Optional metadata filter, e.g. active/superseded for spores and skill_records."),
|
|
3510
|
+
session_id: external_exports.string().optional().describe("Optional metadata filter for a linked session id."),
|
|
3511
|
+
observation_type: external_exports.string().optional().describe("Optional metadata filter for spore observation type."),
|
|
3512
|
+
since: external_exports.number().optional().describe("Optional created_at lower bound (epoch seconds)."),
|
|
3513
|
+
until: external_exports.number().optional().describe("Optional created_at upper bound (epoch seconds).")
|
|
3387
3514
|
},
|
|
3388
3515
|
async (args) => {
|
|
3389
3516
|
if (!embeddingManager) {
|
|
@@ -3397,21 +3524,39 @@ function createReadTools(deps) {
|
|
|
3397
3524
|
const searchLimit = args.limit ?? DEFAULT_SEARCH_LIMIT;
|
|
3398
3525
|
const excludeActive = args.include_active !== true;
|
|
3399
3526
|
const activeIds = excludeActive ? getActiveSessionIds() : /* @__PURE__ */ new Set();
|
|
3527
|
+
const metadataFilters = {
|
|
3528
|
+
...args.status !== void 0 ? { status: args.status } : {},
|
|
3529
|
+
...args.session_id !== void 0 ? { session_id: args.session_id } : {},
|
|
3530
|
+
...args.observation_type !== void 0 ? { observation_type: args.observation_type } : {},
|
|
3531
|
+
...args.since !== void 0 ? { created_at_gte: args.since } : {},
|
|
3532
|
+
...args.until !== void 0 ? { created_at_lte: args.until } : {}
|
|
3533
|
+
};
|
|
3534
|
+
const vectorFilters = hasSemanticSearchFilters(metadataFilters) ? metadataFilters : void 0;
|
|
3400
3535
|
const [rawLocalResults, teamResults] = await Promise.all([
|
|
3401
3536
|
Promise.resolve(
|
|
3402
3537
|
embeddingManager.searchVectors(queryVector, {
|
|
3403
3538
|
namespace: args.namespace,
|
|
3404
3539
|
limit: searchLimit,
|
|
3405
|
-
threshold: SEARCH_SIMILARITY_THRESHOLD
|
|
3540
|
+
threshold: SEARCH_SIMILARITY_THRESHOLD,
|
|
3541
|
+
filters: vectorFilters
|
|
3406
3542
|
}).map((r) => ({ ...r, source: "local" }))
|
|
3407
3543
|
),
|
|
3408
|
-
teamClient ? teamClient.search(args.query, {
|
|
3544
|
+
teamClient ? teamClient.search(args.query, {
|
|
3545
|
+
limit: searchLimit,
|
|
3546
|
+
tables: args.namespace ? [args.namespace] : void 0,
|
|
3547
|
+
status: args.status,
|
|
3548
|
+
observation_type: args.observation_type,
|
|
3549
|
+
since: args.since,
|
|
3550
|
+
until: args.until,
|
|
3551
|
+
session_id: args.session_id
|
|
3552
|
+
}).then((res) => res.results.map((r) => ({ ...r, source: `${TEAM_SOURCE_PREFIX}${r.machine_id}` }))).catch(() => []) : Promise.resolve([])
|
|
3409
3553
|
]);
|
|
3410
3554
|
const localResults = activeIds.size > 0 ? rawLocalResults.filter((r) => {
|
|
3411
3555
|
const sid = r.metadata?.session_id;
|
|
3412
3556
|
return typeof sid !== "string" || !activeIds.has(sid);
|
|
3413
3557
|
}) : rawLocalResults;
|
|
3414
|
-
const
|
|
3558
|
+
const filteredLocalResults = vectorFilters ? localResults.filter((r) => matchesSemanticSearchFilters(r.metadata, metadataFilters)) : localResults;
|
|
3559
|
+
const hydratedLocalResults = hydrateSearchResults(filteredLocalResults).map((r) => ({
|
|
3415
3560
|
...r,
|
|
3416
3561
|
source: "local"
|
|
3417
3562
|
}));
|
|
@@ -3422,13 +3567,33 @@ function createReadTools(deps) {
|
|
|
3422
3567
|
return typeof sid !== "string" || !activeIds.has(sid);
|
|
3423
3568
|
});
|
|
3424
3569
|
}
|
|
3570
|
+
if (vectorFilters) {
|
|
3571
|
+
dedupedTeam = dedupedTeam.filter((r) => matchesSemanticSearchFilters(
|
|
3572
|
+
r.metadata,
|
|
3573
|
+
metadataFilters
|
|
3574
|
+
));
|
|
3575
|
+
}
|
|
3425
3576
|
const merged = [
|
|
3426
3577
|
...hydratedLocalResults,
|
|
3427
3578
|
...dedupedTeam
|
|
3428
3579
|
].sort((a, b) => (b.score ?? 0) - (a.score ?? 0)).slice(0, searchLimit);
|
|
3429
3580
|
return textResult({ results: merged });
|
|
3430
|
-
} catch {
|
|
3431
|
-
|
|
3581
|
+
} catch (err) {
|
|
3582
|
+
const message = errorMessage(err);
|
|
3583
|
+
let hint;
|
|
3584
|
+
if (/timeout|ETIMEDOUT|AbortError/i.test(message)) {
|
|
3585
|
+
hint = "Embedding provider timed out. Retry once or reduce query length.";
|
|
3586
|
+
} else if (/ECONNREFUSED|fetch failed|network/i.test(message)) {
|
|
3587
|
+
hint = "Embedding provider unreachable. Check that the configured provider (Ollama/LM Studio/Anthropic) is running.";
|
|
3588
|
+
} else if (/no such table|no such column/i.test(message)) {
|
|
3589
|
+
hint = "Vector table missing or schema mismatch. Run `myco rebuild` or check migrations.";
|
|
3590
|
+
}
|
|
3591
|
+
return textResult({
|
|
3592
|
+
error: `vault_search_semantic failed: ${message}${hint ? ` \u2014 ${hint}` : ""}`,
|
|
3593
|
+
results: [],
|
|
3594
|
+
query: args.query,
|
|
3595
|
+
namespace: args.namespace ?? null
|
|
3596
|
+
});
|
|
3432
3597
|
}
|
|
3433
3598
|
},
|
|
3434
3599
|
{ annotations: { readOnlyHint: true, openWorldHint: true } }
|
|
@@ -3636,7 +3801,8 @@ function createWriteTools(deps) {
|
|
|
3636
3801
|
embeddingManager?.onContentWritten("spores", spore.id, args.content, {
|
|
3637
3802
|
status: "active",
|
|
3638
3803
|
observation_type: args.observation_type,
|
|
3639
|
-
session_id: args.session_id
|
|
3804
|
+
session_id: args.session_id,
|
|
3805
|
+
created_at: now
|
|
3640
3806
|
}).catch(() => {
|
|
3641
3807
|
});
|
|
3642
3808
|
return textResult(spore);
|
|
@@ -3726,12 +3892,54 @@ function createWriteTools(deps) {
|
|
|
3726
3892
|
);
|
|
3727
3893
|
const vaultReadDigest = tool2(
|
|
3728
3894
|
"vault_read_digest",
|
|
3729
|
-
|
|
3895
|
+
'Read current digest extracts. Three modes: (1) no args \u2192 summary metadata for all tiers; (2) tier \u2192 full content for that tier; (3) pick: "rotate_oldest" \u2192 the digest-rotation decision, returning the tier whose generated_at is oldest plus its full content (or skip:true when all tiers are fresher than min_staleness_seconds). The rotation mode lets callers outsource the "which tier should we update this run" choice to a deterministic tool decision instead of prompting the LLM to compare timestamps.',
|
|
3730
3896
|
{
|
|
3731
|
-
tier: external_exports.number().optional().describe("Specific tier to read in full (e.g., 1500, 5000, 10000). Omit to get summary of all tiers.")
|
|
3897
|
+
tier: external_exports.number().optional().describe("Specific tier to read in full (e.g., 1500, 5000, 10000). Omit to get summary of all tiers. Ignored when pick is set."),
|
|
3898
|
+
pick: external_exports.enum(["rotate_oldest"]).optional().describe('Rotation mode. "rotate_oldest" picks the tier with the oldest generated_at (missing tiers count as never-generated and sort first). The response includes the selected tier, its full content, a rotation_reason explaining the choice, and metadata for all tiers so the caller can audit the decision.'),
|
|
3899
|
+
min_staleness_seconds: external_exports.number().optional().describe(`Used with pick="rotate_oldest". If every tier's generated_at is newer than (now - min_staleness_seconds), the tool returns {skip: true, reason, all_tiers} instead of selecting a tier. Defaults to 0 (never skip).`)
|
|
3732
3900
|
},
|
|
3733
3901
|
async (args) => {
|
|
3734
3902
|
const extracts = listDigestExtracts(agentId);
|
|
3903
|
+
if (args.pick === "rotate_oldest") {
|
|
3904
|
+
const now = epochSeconds();
|
|
3905
|
+
const canonical = DIGEST_TIERS.map((tier) => {
|
|
3906
|
+
const existing = extracts.find((e) => e.tier === tier);
|
|
3907
|
+
return {
|
|
3908
|
+
tier,
|
|
3909
|
+
generated_at: existing?.generated_at ?? 0,
|
|
3910
|
+
content_length: existing?.content.length ?? 0,
|
|
3911
|
+
content: existing?.content ?? null
|
|
3912
|
+
};
|
|
3913
|
+
});
|
|
3914
|
+
const minStale = args.min_staleness_seconds ?? 0;
|
|
3915
|
+
if (minStale > 0) {
|
|
3916
|
+
const allPresent = canonical.every((t) => t.generated_at > 0);
|
|
3917
|
+
const cutoff = now - minStale;
|
|
3918
|
+
const allFresh = canonical.every((t) => t.generated_at > cutoff);
|
|
3919
|
+
if (allPresent && allFresh) {
|
|
3920
|
+
return textResult({
|
|
3921
|
+
mode: "rotate_oldest",
|
|
3922
|
+
skip: true,
|
|
3923
|
+
reason: `All ${canonical.length} tiers were generated within the last ${minStale} seconds (cutoff=${cutoff}).`,
|
|
3924
|
+
all_tiers: canonical.map((t) => ({ tier: t.tier, generated_at: t.generated_at, content_length: t.content_length }))
|
|
3925
|
+
});
|
|
3926
|
+
}
|
|
3927
|
+
}
|
|
3928
|
+
const sorted = [...canonical].sort((a, b) => {
|
|
3929
|
+
if (a.generated_at !== b.generated_at) return a.generated_at - b.generated_at;
|
|
3930
|
+
return b.tier - a.tier;
|
|
3931
|
+
});
|
|
3932
|
+
const selected = sorted[0];
|
|
3933
|
+
const reason = selected.generated_at === 0 ? `Tier ${selected.tier} has never been generated \u2014 seeding.` : `Tier ${selected.tier} has the oldest generated_at (${selected.generated_at}); next oldest is tier ${sorted[1]?.tier} at ${sorted[1]?.generated_at}.`;
|
|
3934
|
+
return textResult({
|
|
3935
|
+
mode: "rotate_oldest",
|
|
3936
|
+
selected_tier: selected.tier,
|
|
3937
|
+
selected_generated_at: selected.generated_at,
|
|
3938
|
+
selected_content: selected.content,
|
|
3939
|
+
rotation_reason: reason,
|
|
3940
|
+
all_tiers: canonical.map((t) => ({ tier: t.tier, generated_at: t.generated_at, content_length: t.content_length }))
|
|
3941
|
+
});
|
|
3942
|
+
}
|
|
3735
3943
|
if (args.tier !== void 0) {
|
|
3736
3944
|
const extract = extracts.find((e) => e.tier === args.tier);
|
|
3737
3945
|
if (!extract) return textResult({ tier: args.tier, content: null, message: "No digest at this tier" });
|
|
@@ -4131,7 +4339,7 @@ function createSkillTools(deps) {
|
|
|
4131
4339
|
);
|
|
4132
4340
|
}
|
|
4133
4341
|
try {
|
|
4134
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
4342
|
+
const { syncSkillSymlinks } = await import("./installer-N4UTEACX.js");
|
|
4135
4343
|
syncSkillSymlinks(root, params.name, { remove: true });
|
|
4136
4344
|
} catch (rollbackErr) {
|
|
4137
4345
|
console.warn(
|
|
@@ -4149,7 +4357,7 @@ function createSkillTools(deps) {
|
|
|
4149
4357
|
};
|
|
4150
4358
|
}
|
|
4151
4359
|
try {
|
|
4152
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
4360
|
+
const { syncSkillSymlinks } = await import("./installer-N4UTEACX.js");
|
|
4153
4361
|
syncSkillSymlinks(root, params.name);
|
|
4154
4362
|
} catch (err) {
|
|
4155
4363
|
console.warn(
|
|
@@ -4351,14 +4559,15 @@ function createSkillTools(deps) {
|
|
|
4351
4559
|
);
|
|
4352
4560
|
const vaultSkillRecords = tool4(
|
|
4353
4561
|
"vault_skill_records",
|
|
4354
|
-
"Read, update, and delete skill records (materialized skills on disk). Supports list, get, update, and delete actions. The get action includes the full SKILL.md file content.",
|
|
4562
|
+
"Read, update, and delete skill records (materialized skills on disk). Supports list, get, update, and delete actions. The get action includes the full SKILL.md file content. For update, at least one mutating field (status, generation, source_ids, description, or properties) is required \u2014 calls with only {action, id} are rejected to prevent silent no-op updates.",
|
|
4355
4563
|
{
|
|
4356
4564
|
action: external_exports.enum(["list", "get", "update", "delete"]).describe("Action to perform"),
|
|
4357
4565
|
id: external_exports.string().optional().describe("Skill record ID or name (required for get/update/delete)"),
|
|
4358
|
-
status: external_exports.enum(["active", "stale", "retired"]).optional().describe("Filter by status"),
|
|
4566
|
+
status: external_exports.enum(["active", "stale", "retired"]).optional().describe("Filter by status or new status (for update)"),
|
|
4359
4567
|
generation: external_exports.number().optional().describe("New generation number (for update)"),
|
|
4360
4568
|
source_ids: external_exports.string().optional().describe("JSON array of source IDs (for update)"),
|
|
4361
4569
|
description: external_exports.string().optional().describe("Updated description (for update)"),
|
|
4570
|
+
properties: external_exports.string().optional().describe(`JSON-encoded object of properties to MERGE into the existing properties (for update). Example: '{"last_verified_at": 1776580022}'. Existing keys not included in the payload are preserved; included keys overwrite. Used by skill-evolve to persist watermarks like last_assessed_at, knowledge_watermark, last_verified_at, last_classification.`),
|
|
4362
4571
|
limit: external_exports.number().optional().describe("Maximum records to return (for list)")
|
|
4363
4572
|
},
|
|
4364
4573
|
async (args) => {
|
|
@@ -4386,14 +4595,44 @@ function createSkillTools(deps) {
|
|
|
4386
4595
|
}
|
|
4387
4596
|
case "update": {
|
|
4388
4597
|
if (!args.id) return textResult({ error: "id is required for update action" });
|
|
4598
|
+
const hasMutatingField = args.status !== void 0 || args.generation !== void 0 || args.source_ids !== void 0 || args.description !== void 0 || args.properties !== void 0;
|
|
4599
|
+
if (!hasMutatingField) {
|
|
4600
|
+
return textResult({
|
|
4601
|
+
error: "update action requires at least one mutating field (status, generation, source_ids, description, or properties). Calls with only {action, id} are rejected to prevent silent no-op updates."
|
|
4602
|
+
});
|
|
4603
|
+
}
|
|
4389
4604
|
const existing = getSkillRecord(args.id) ?? getSkillRecordByName(args.id);
|
|
4390
4605
|
if (!existing) return textResult({ error: `Skill record not found: ${args.id}` });
|
|
4606
|
+
let mergedProperties;
|
|
4607
|
+
if (args.properties !== void 0) {
|
|
4608
|
+
let incoming;
|
|
4609
|
+
try {
|
|
4610
|
+
const parsed = JSON.parse(args.properties);
|
|
4611
|
+
if (parsed === null || typeof parsed !== "object" || Array.isArray(parsed)) {
|
|
4612
|
+
return textResult({ error: "properties must be a JSON-encoded object (not null, array, or primitive)." });
|
|
4613
|
+
}
|
|
4614
|
+
incoming = parsed;
|
|
4615
|
+
} catch (err) {
|
|
4616
|
+
return textResult({ error: `properties is not valid JSON: ${errorMessage(err)}` });
|
|
4617
|
+
}
|
|
4618
|
+
let existingProps = {};
|
|
4619
|
+
try {
|
|
4620
|
+
const parsedExisting = JSON.parse(existing.properties || "{}");
|
|
4621
|
+
if (parsedExisting && typeof parsedExisting === "object" && !Array.isArray(parsedExisting)) {
|
|
4622
|
+
existingProps = parsedExisting;
|
|
4623
|
+
}
|
|
4624
|
+
} catch (err) {
|
|
4625
|
+
console.warn(`[vault_skill_records] Skill ${existing.id} has unparseable properties; treating as empty for merge. Error: ${errorMessage(err)}`);
|
|
4626
|
+
}
|
|
4627
|
+
mergedProperties = JSON.stringify({ ...existingProps, ...incoming });
|
|
4628
|
+
}
|
|
4391
4629
|
const now = epochSeconds();
|
|
4392
4630
|
const updated = updateSkillRecord(existing.id, {
|
|
4393
4631
|
...args.status !== void 0 ? { status: args.status } : {},
|
|
4394
4632
|
...args.generation !== void 0 ? { generation: args.generation } : {},
|
|
4395
4633
|
...args.source_ids !== void 0 ? { source_ids: args.source_ids } : {},
|
|
4396
4634
|
...args.description !== void 0 ? { description: args.description } : {},
|
|
4635
|
+
...mergedProperties !== void 0 ? { properties: mergedProperties } : {},
|
|
4397
4636
|
updated_at: now
|
|
4398
4637
|
});
|
|
4399
4638
|
if (!updated) return textResult({ error: `Failed to update skill record: ${existing.id}` });
|
|
@@ -4416,7 +4655,7 @@ function createSkillTools(deps) {
|
|
|
4416
4655
|
console.warn("[vault_skill_records] Failed to remove skill directory:", err instanceof Error ? err.message : err);
|
|
4417
4656
|
}
|
|
4418
4657
|
try {
|
|
4419
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
4658
|
+
const { syncSkillSymlinks } = await import("./installer-N4UTEACX.js");
|
|
4420
4659
|
syncSkillSymlinks(root, result.name, { remove: true });
|
|
4421
4660
|
} catch (err) {
|
|
4422
4661
|
console.warn("[vault_skill_records] Failed to remove symlinks:", err instanceof Error ? err.message : err);
|
|
@@ -4534,7 +4773,7 @@ function createSkillTools(deps) {
|
|
|
4534
4773
|
return textResult({ error: `Failed to write skill file: ${err instanceof Error ? err.message : String(err)}` });
|
|
4535
4774
|
}
|
|
4536
4775
|
try {
|
|
4537
|
-
const { syncSkillSymlinks } = await import("./installer-
|
|
4776
|
+
const { syncSkillSymlinks } = await import("./installer-N4UTEACX.js");
|
|
4538
4777
|
syncSkillSymlinks(root, args.name);
|
|
4539
4778
|
} catch (err) {
|
|
4540
4779
|
console.warn("[vault_write_skill] syncSkillSymlinks failed:", err instanceof Error ? err.message : err);
|
|
@@ -5116,19 +5355,34 @@ function truncateSummary(text) {
|
|
|
5116
5355
|
if (!text) return null;
|
|
5117
5356
|
return text.length > TOOL_OUTPUT_SUMMARY_LIMIT ? `${text.slice(0, TOOL_OUTPUT_SUMMARY_LIMIT - 1)}\u2026` : text;
|
|
5118
5357
|
}
|
|
5358
|
+
var TOOL_ERROR_PREFIX = "[ERROR] ";
|
|
5359
|
+
function isErrorResult(result) {
|
|
5360
|
+
if (!result || typeof result !== "object") return false;
|
|
5361
|
+
const content = result.content;
|
|
5362
|
+
if (!Array.isArray(content) || content.length === 0) return false;
|
|
5363
|
+
const first = content[0];
|
|
5364
|
+
if (!first || first.type !== "text" || typeof first.text !== "string") return false;
|
|
5365
|
+
const trimmed = first.text.trimStart();
|
|
5366
|
+
if (!trimmed.startsWith("{")) return false;
|
|
5367
|
+
try {
|
|
5368
|
+
const parsed = JSON.parse(trimmed);
|
|
5369
|
+
return !!parsed && typeof parsed === "object" && "error" in parsed && parsed.error !== void 0;
|
|
5370
|
+
} catch {
|
|
5371
|
+
return false;
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5119
5374
|
function summarizeToolResult(result) {
|
|
5120
5375
|
if (!result || typeof result !== "object") return null;
|
|
5121
5376
|
const content = result.content;
|
|
5122
5377
|
if (!Array.isArray(content) || content.length === 0) return null;
|
|
5123
5378
|
const first = content[0];
|
|
5124
5379
|
if (!first || first.type !== "text" || typeof first.text !== "string") return null;
|
|
5125
|
-
|
|
5380
|
+
const body = first.text.replace(/\s+/g, " ").trim();
|
|
5381
|
+
const prefix = isErrorResult(result) ? TOOL_ERROR_PREFIX : "";
|
|
5382
|
+
return truncateSummary(prefix + body);
|
|
5126
5383
|
}
|
|
5127
5384
|
function summarizeToolError(error) {
|
|
5128
|
-
|
|
5129
|
-
return truncateSummary(error.message) ?? "Tool failed";
|
|
5130
|
-
}
|
|
5131
|
-
return truncateSummary(String(error)) ?? "Tool failed";
|
|
5385
|
+
return truncateSummary(TOOL_ERROR_PREFIX + errorMessage(error)) ?? TOOL_ERROR_PREFIX + "Tool failed";
|
|
5132
5386
|
}
|
|
5133
5387
|
function buildRepeatedReadSuppressionResult(toolName, repeatedCalls) {
|
|
5134
5388
|
return {
|
|
@@ -5265,6 +5519,7 @@ function createVaultTools(agentId, runId, options) {
|
|
|
5265
5519
|
}
|
|
5266
5520
|
function wrapToolWithAudit(toolDef) {
|
|
5267
5521
|
const originalHandler = toolDef.handler;
|
|
5522
|
+
const declaredKeys = toolDef.inputSchema && typeof toolDef.inputSchema === "object" ? new Set(Object.keys(toolDef.inputSchema)) : /* @__PURE__ */ new Set();
|
|
5268
5523
|
return {
|
|
5269
5524
|
...toolDef,
|
|
5270
5525
|
handler: async (args, extra) => {
|
|
@@ -5272,6 +5527,28 @@ function createVaultTools(agentId, runId, options) {
|
|
|
5272
5527
|
const priorIdenticalCalls = repeatedReadKey ? repeatedReadCounts.get(repeatedReadKey) ?? 0 : 0;
|
|
5273
5528
|
const turnId = recordTurn(toolDef.name, args);
|
|
5274
5529
|
try {
|
|
5530
|
+
if (declaredKeys.size > 0 && args && typeof args === "object") {
|
|
5531
|
+
const unknown = [];
|
|
5532
|
+
for (const key of Object.keys(args)) {
|
|
5533
|
+
if (!declaredKeys.has(key)) unknown.push(key);
|
|
5534
|
+
}
|
|
5535
|
+
if (unknown.length > 0) {
|
|
5536
|
+
const accepted = Array.from(declaredKeys).sort().join(", ");
|
|
5537
|
+
const result2 = textResult({
|
|
5538
|
+
error: `Unknown parameter(s) for ${toolDef.name}: ${unknown.join(", ")}. Accepted parameters: ${accepted}.`
|
|
5539
|
+
});
|
|
5540
|
+
if (turnId !== null) {
|
|
5541
|
+
try {
|
|
5542
|
+
updateTurn(turnId, {
|
|
5543
|
+
tool_output_summary: summarizeToolResult(result2),
|
|
5544
|
+
completed_at: epochSeconds()
|
|
5545
|
+
});
|
|
5546
|
+
} catch {
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5549
|
+
return result2;
|
|
5550
|
+
}
|
|
5551
|
+
}
|
|
5275
5552
|
if (priorIdenticalCalls >= REPEATED_READ_FAILURE_THRESHOLD) {
|
|
5276
5553
|
throw new Error(
|
|
5277
5554
|
`Repeated identical ${toolDef.name} reads detected (${priorIdenticalCalls + 1} calls). Reuse the prior result already in context and proceed to a write, report, or different query.`
|
|
@@ -5405,6 +5682,13 @@ function getIsolatedPluginCacheDir() {
|
|
|
5405
5682
|
if (isolatedPluginCacheDir) return isolatedPluginCacheDir;
|
|
5406
5683
|
const dir = path3.join(os.tmpdir(), `myco-agent-plugin-cache-${process.pid}`);
|
|
5407
5684
|
fs3.mkdirSync(dir, { recursive: true });
|
|
5685
|
+
const manifestPath = path3.join(dir, "installed_plugins.json");
|
|
5686
|
+
if (!fs3.existsSync(manifestPath)) {
|
|
5687
|
+
fs3.writeFileSync(
|
|
5688
|
+
manifestPath,
|
|
5689
|
+
JSON.stringify({ version: 2, plugins: {} })
|
|
5690
|
+
);
|
|
5691
|
+
}
|
|
5408
5692
|
isolatedPluginCacheDir = dir;
|
|
5409
5693
|
return dir;
|
|
5410
5694
|
}
|
|
@@ -5450,6 +5734,18 @@ var ClaudeSdkRuntime = class {
|
|
|
5450
5734
|
// user hasn't explicitly overridden the cache dir themselves.
|
|
5451
5735
|
CLAUDE_CODE_PLUGIN_CACHE_DIR: process.env.CLAUDE_CODE_PLUGIN_CACHE_DIR ?? getIsolatedPluginCacheDir()
|
|
5452
5736
|
};
|
|
5737
|
+
if (input.logger) {
|
|
5738
|
+
const mcpToolNames = input.toolSurface.toolNames ?? (toolServer ? ["<full-vault-surface>"] : []);
|
|
5739
|
+
input.logger.debug("agent.runtime.request", "Agent runtime request", {
|
|
5740
|
+
runId: input.toolSurface.runId,
|
|
5741
|
+
agentId: input.toolSurface.agentId,
|
|
5742
|
+
model: input.model,
|
|
5743
|
+
mcpToolCount: mcpToolNames.length,
|
|
5744
|
+
mcpTools: mcpToolNames,
|
|
5745
|
+
pluginCacheDir: env.CLAUDE_CODE_PLUGIN_CACHE_DIR,
|
|
5746
|
+
sessionRef: input.sessionRef ?? null
|
|
5747
|
+
});
|
|
5748
|
+
}
|
|
5453
5749
|
let finalText = "";
|
|
5454
5750
|
let turnsUsed = 0;
|
|
5455
5751
|
let inputTokens = 0;
|
|
@@ -5464,6 +5760,7 @@ var ClaudeSdkRuntime = class {
|
|
|
5464
5760
|
tools: [],
|
|
5465
5761
|
mcpServers: toolServer ? { [MCP_SERVER_NAME]: toolServer } : {},
|
|
5466
5762
|
strictMcpConfig: true,
|
|
5763
|
+
settingSources: [],
|
|
5467
5764
|
maxTurns: input.maxTurns,
|
|
5468
5765
|
permissionMode: "bypassPermissions",
|
|
5469
5766
|
allowDangerouslySkipPermissions: true,
|
|
@@ -5504,7 +5801,7 @@ var ClaudeSdkRuntime = class {
|
|
|
5504
5801
|
} catch (err) {
|
|
5505
5802
|
if (turnsUsed > 0 || inputTokens > 0 || outputTokens > 0) {
|
|
5506
5803
|
throw new RuntimeExecutionError(
|
|
5507
|
-
|
|
5804
|
+
errorMessage(err),
|
|
5508
5805
|
{ usage: buildUsage(), sessionRef: input.sessionRef },
|
|
5509
5806
|
{ cause: err }
|
|
5510
5807
|
);
|
|
@@ -13069,7 +13366,17 @@ function getAgentRuntime(runtimeId) {
|
|
|
13069
13366
|
// src/agent/phase-loop.ts
|
|
13070
13367
|
async function executePhase(input) {
|
|
13071
13368
|
const { ctx, phasePrompt, phaseModel, phase, toolSurface, provider, sessionId, sessionData } = input;
|
|
13369
|
+
const logger = ctx.options?.logger;
|
|
13072
13370
|
const runtime = getAgentRuntime(ctx.config.runtime);
|
|
13371
|
+
logger?.debug("agent.phase.start", `Phase ${phase.name} starting`, {
|
|
13372
|
+
runId: ctx.runId,
|
|
13373
|
+
phase: phase.name,
|
|
13374
|
+
model: phaseModel,
|
|
13375
|
+
maxTurns: phase.maxTurns,
|
|
13376
|
+
required: phase.required ?? false,
|
|
13377
|
+
toolNames: toolSurface.toolNames ?? null,
|
|
13378
|
+
sessionRef: sessionId ?? null
|
|
13379
|
+
});
|
|
13073
13380
|
try {
|
|
13074
13381
|
let result;
|
|
13075
13382
|
try {
|
|
@@ -13082,13 +13389,19 @@ async function executePhase(input) {
|
|
|
13082
13389
|
sessionRef: sessionId,
|
|
13083
13390
|
sessionData,
|
|
13084
13391
|
abortController: ctx.abortController,
|
|
13085
|
-
toolSurface
|
|
13392
|
+
toolSurface,
|
|
13393
|
+
logger
|
|
13086
13394
|
});
|
|
13087
13395
|
} catch (error) {
|
|
13088
|
-
if (!sessionId || !runtime.supports("supportsSessionResume") || !isSessionResumeFailure(error)) {
|
|
13396
|
+
if (!sessionId || !runtime.supports("supportsSessionResume") || !isSessionResumeFailure(error) && !isExpiredSessionError(error)) {
|
|
13089
13397
|
throw error;
|
|
13090
13398
|
}
|
|
13091
|
-
|
|
13399
|
+
logger?.info("agent.phase.session-retry", `Phase ${phase.name} session failed, retrying without prior session`, {
|
|
13400
|
+
runId: ctx.runId,
|
|
13401
|
+
phase: phase.name,
|
|
13402
|
+
priorSession: sessionId,
|
|
13403
|
+
error: errorMessage(error)
|
|
13404
|
+
});
|
|
13092
13405
|
result = await runtime.execute({
|
|
13093
13406
|
prompt: phasePrompt,
|
|
13094
13407
|
model: phaseModel,
|
|
@@ -13096,14 +13409,24 @@ async function executePhase(input) {
|
|
|
13096
13409
|
systemPrompt: ctx.systemPrompt,
|
|
13097
13410
|
provider,
|
|
13098
13411
|
abortController: ctx.abortController,
|
|
13099
|
-
toolSurface
|
|
13412
|
+
toolSurface,
|
|
13413
|
+
logger
|
|
13100
13414
|
});
|
|
13101
13415
|
}
|
|
13102
|
-
|
|
13103
|
-
|
|
13104
|
-
|
|
13416
|
+
logger?.debug("agent.phase.end", `Phase ${phase.name} finished`, {
|
|
13417
|
+
runId: ctx.runId,
|
|
13418
|
+
phase: phase.name,
|
|
13419
|
+
status: "completed",
|
|
13420
|
+
turnsUsed: result.turnsUsed,
|
|
13421
|
+
maxTurns: phase.maxTurns ?? null,
|
|
13422
|
+
tokensUsed: result.usage.totalTokens ?? 0,
|
|
13423
|
+
costUsd: result.usage.costUsd ?? null
|
|
13424
|
+
});
|
|
13105
13425
|
if (phase.required && result.turnsUsed === 0) {
|
|
13106
|
-
|
|
13426
|
+
logger?.warn("agent.phase.zero-turns", `Required phase ${phase.name} produced 0 turns`, {
|
|
13427
|
+
runId: ctx.runId,
|
|
13428
|
+
phase: phase.name
|
|
13429
|
+
});
|
|
13107
13430
|
}
|
|
13108
13431
|
const costData = await resolveCost({
|
|
13109
13432
|
runtime: ctx.config.runtime,
|
|
@@ -13129,6 +13452,15 @@ async function executePhase(input) {
|
|
|
13129
13452
|
model: phaseModel,
|
|
13130
13453
|
usage: telemetry.usage
|
|
13131
13454
|
}) : void 0;
|
|
13455
|
+
logger?.debug("agent.phase.end", `Phase ${phase.name} failed`, {
|
|
13456
|
+
runId: ctx.runId,
|
|
13457
|
+
phase: phase.name,
|
|
13458
|
+
status: "failed",
|
|
13459
|
+
turnsUsed: telemetry?.usage.requests ?? 0,
|
|
13460
|
+
tokensUsed: telemetry?.usage.totalTokens ?? 0,
|
|
13461
|
+
costUsd: telemetry?.usage.costUsd ?? null,
|
|
13462
|
+
error: abortReason ?? errorMessage(err)
|
|
13463
|
+
});
|
|
13132
13464
|
return buildPhaseResult({
|
|
13133
13465
|
name: phase.name,
|
|
13134
13466
|
status: "failed",
|
|
@@ -13146,23 +13478,41 @@ async function executeSingleQuery(ctx, taskPrompt, provider, sessionRef, session
|
|
|
13146
13478
|
provider,
|
|
13147
13479
|
ctx.config.model
|
|
13148
13480
|
);
|
|
13149
|
-
const
|
|
13481
|
+
const toolSurface = {
|
|
13482
|
+
agentId: ctx.agentId,
|
|
13483
|
+
runId: ctx.runId,
|
|
13484
|
+
vaultDir: ctx.vaultDir,
|
|
13485
|
+
embeddingManager: ctx.embeddingManager,
|
|
13486
|
+
dryRun: ctx.config.dryRun ?? false
|
|
13487
|
+
};
|
|
13488
|
+
const baseInput = {
|
|
13150
13489
|
prompt: taskPrompt,
|
|
13151
13490
|
model: effectiveModel,
|
|
13152
13491
|
maxTurns: ctx.config.maxTurns,
|
|
13153
13492
|
systemPrompt: ctx.systemPrompt,
|
|
13154
13493
|
provider,
|
|
13155
13494
|
abortController: ctx.abortController,
|
|
13156
|
-
|
|
13157
|
-
|
|
13158
|
-
|
|
13159
|
-
|
|
13160
|
-
|
|
13161
|
-
|
|
13162
|
-
|
|
13163
|
-
|
|
13495
|
+
toolSurface,
|
|
13496
|
+
logger: ctx.options?.logger
|
|
13497
|
+
};
|
|
13498
|
+
let result;
|
|
13499
|
+
try {
|
|
13500
|
+
result = await runtime.execute({ ...baseInput, sessionRef, sessionData });
|
|
13501
|
+
} catch (err) {
|
|
13502
|
+
if (!sessionRef || !runtime.supports("supportsSessionResume") || !isSessionResumeFailure(err) && !isExpiredSessionError(err)) {
|
|
13503
|
+
throw err;
|
|
13164
13504
|
}
|
|
13165
|
-
|
|
13505
|
+
ctx.options?.logger?.info(
|
|
13506
|
+
"agent.single-query.session-retry",
|
|
13507
|
+
"Single-query session failed, retrying without prior session",
|
|
13508
|
+
{
|
|
13509
|
+
runId: ctx.runId,
|
|
13510
|
+
priorSession: sessionRef,
|
|
13511
|
+
error: errorMessage(err)
|
|
13512
|
+
}
|
|
13513
|
+
);
|
|
13514
|
+
result = await runtime.execute(baseInput);
|
|
13515
|
+
}
|
|
13166
13516
|
const costData = await resolveCost({
|
|
13167
13517
|
runtime: ctx.config.runtime,
|
|
13168
13518
|
provider,
|
|
@@ -13210,10 +13560,17 @@ async function executePhasedQuery(ctx) {
|
|
|
13210
13560
|
vaultDir: ctx.vaultDir,
|
|
13211
13561
|
dryRun: config.dryRun ?? false
|
|
13212
13562
|
},
|
|
13213
|
-
abortController: ctx.abortController
|
|
13563
|
+
abortController: ctx.abortController,
|
|
13564
|
+
logger: ctx.options?.logger
|
|
13214
13565
|
});
|
|
13215
|
-
const plan = parseOrchestratorPlan(planResponse.finalText, phases);
|
|
13566
|
+
const plan = parseOrchestratorPlan(planResponse.finalText, phases, ctx.options?.logger);
|
|
13216
13567
|
effectivePhases = applyDirectives(phases, plan.phases);
|
|
13568
|
+
ctx.options?.logger?.debug("agent.orchestrator.plan", "Orchestrator plan applied", {
|
|
13569
|
+
runId,
|
|
13570
|
+
reasoning: plan.reasoning,
|
|
13571
|
+
effectivePhases: effectivePhases.map((p) => p.name),
|
|
13572
|
+
skippedPhases: plan.phases.filter((d) => d.skip).map((d) => d.name)
|
|
13573
|
+
});
|
|
13217
13574
|
}
|
|
13218
13575
|
const declarationOrder = new Map(phases.map((p, i) => [p.name, i]));
|
|
13219
13576
|
const waves = computeWaves(effectivePhases);
|
|
@@ -13373,12 +13730,16 @@ var SKIP_REASON_ALREADY_RUNNING = "already_running";
|
|
|
13373
13730
|
var CORTEX_INSTRUCTIONS_REPORT_ACTION = "cortex_instructions";
|
|
13374
13731
|
var CORTEX_INSTRUCTIONS_CONTENT_KEY = "content";
|
|
13375
13732
|
var TOKEN_BUDGET_PRESSURE_STATUSES = /* @__PURE__ */ new Set(["warning", "post_run_pressure"]);
|
|
13376
|
-
function logTokenBudgetPressure(taskName, usage, provider) {
|
|
13733
|
+
function logTokenBudgetPressure(taskName, usage, provider, logger) {
|
|
13377
13734
|
const budget = analyzeRuntimeTokenBudget(usage, provider);
|
|
13378
13735
|
if (!TOKEN_BUDGET_PRESSURE_STATUSES.has(budget.status)) return;
|
|
13379
|
-
|
|
13380
|
-
|
|
13381
|
-
|
|
13736
|
+
logger?.warn("agent.token-budget-pressure", `${taskName} token budget ${budget.status}`, {
|
|
13737
|
+
task: taskName,
|
|
13738
|
+
status: budget.status,
|
|
13739
|
+
utilizationPercent: budget.utilizationPercent,
|
|
13740
|
+
contextWindowTokens: budget.contextWindowTokens,
|
|
13741
|
+
peakRequestTotalTokens: budget.peakRequestTotalTokens
|
|
13742
|
+
});
|
|
13382
13743
|
}
|
|
13383
13744
|
async function runAgent(vaultDir, options) {
|
|
13384
13745
|
const db = initDatabase(vaultDbPath(vaultDir));
|
|
@@ -13523,15 +13884,25 @@ async function runAgent(vaultDir, options) {
|
|
|
13523
13884
|
taskProviderOverride = resolved.taskProvider;
|
|
13524
13885
|
phaseProviderOverrides = resolved.phaseOverrides;
|
|
13525
13886
|
for (const conflict of resolved.conflicts) {
|
|
13526
|
-
|
|
13527
|
-
|
|
13887
|
+
options?.logger?.warn(
|
|
13888
|
+
"agent.ollama.context-variant-conflict",
|
|
13889
|
+
`Ollama model "${conflict.model}" referenced with conflicting context_length values \u2014 reconciled to ${conflict.resolved}`,
|
|
13890
|
+
{
|
|
13891
|
+
model: conflict.model,
|
|
13892
|
+
values: conflict.values,
|
|
13893
|
+
resolved: conflict.resolved
|
|
13894
|
+
}
|
|
13528
13895
|
);
|
|
13529
13896
|
}
|
|
13530
13897
|
}
|
|
13531
13898
|
const taskAbortController = new AbortController();
|
|
13532
13899
|
const timeoutMs = config.timeoutSeconds * MS_PER_SECOND;
|
|
13533
13900
|
const timeoutId = setTimeout(() => {
|
|
13534
|
-
|
|
13901
|
+
options?.logger?.warn("agent.run.timeout", `Run ${runId} exceeded timeout, aborting`, {
|
|
13902
|
+
runId,
|
|
13903
|
+
taskName: config.taskName,
|
|
13904
|
+
timeoutSeconds: config.timeoutSeconds
|
|
13905
|
+
});
|
|
13535
13906
|
taskAbortController.abort(new Error(`Agent run timed out after ${config.timeoutSeconds} seconds`));
|
|
13536
13907
|
}, timeoutMs);
|
|
13537
13908
|
timeoutId.unref?.();
|
|
@@ -13623,13 +13994,14 @@ async function runAgent(vaultDir, options) {
|
|
|
13623
13994
|
}
|
|
13624
13995
|
}
|
|
13625
13996
|
clearTimeout(timeoutId);
|
|
13626
|
-
logTokenBudgetPressure(config.taskName, usage, effectiveProvider);
|
|
13997
|
+
logTokenBudgetPressure(config.taskName, usage, effectiveProvider, options?.logger);
|
|
13627
13998
|
await finalizeOnTaskSuccess({
|
|
13628
13999
|
taskName: config.taskName,
|
|
13629
14000
|
agentId,
|
|
13630
14001
|
runId,
|
|
13631
14002
|
runContext: options?.runContext,
|
|
13632
|
-
instruction: options?.instruction
|
|
14003
|
+
instruction: options?.instruction,
|
|
14004
|
+
dryRun: options?.dryRun
|
|
13633
14005
|
});
|
|
13634
14006
|
const completedAt = epochSeconds();
|
|
13635
14007
|
updateRunStatus(runId, STATUS_COMPLETED, {
|
|
@@ -13677,34 +14049,48 @@ ${err.stack.split("\n").slice(0, 3).join("\n")}`;
|
|
|
13677
14049
|
}
|
|
13678
14050
|
}
|
|
13679
14051
|
const failedAt = epochSeconds();
|
|
13680
|
-
|
|
14052
|
+
options?.logger?.error("agent.run.failed", `Run ${runId} failed`, {
|
|
14053
|
+
runId,
|
|
14054
|
+
taskName: config.taskName,
|
|
14055
|
+
error: errorMessage2
|
|
14056
|
+
});
|
|
13681
14057
|
try {
|
|
13682
14058
|
const usage = aggregateUsage(phaseResults?.map((phase) => phase.usage) ?? []);
|
|
13683
|
-
logTokenBudgetPressure(config.taskName, usage, effectiveProvider);
|
|
14059
|
+
logTokenBudgetPressure(config.taskName, usage, effectiveProvider, options?.logger);
|
|
13684
14060
|
const costData = phaseResults ? summarizePhaseCosts(phaseResults) : await resolveCost({
|
|
13685
14061
|
runtime: runtimeId,
|
|
13686
14062
|
provider: effectiveProvider,
|
|
13687
14063
|
model: effectiveModel,
|
|
13688
14064
|
usage
|
|
13689
14065
|
});
|
|
14066
|
+
const hadPriorSession = Boolean(checkpointState.sessionRef) || Object.values(checkpointState.phases).some((phase) => Boolean(phase.sessionRef));
|
|
14067
|
+
const recordedAnyTurns = (usage.requests ?? 0) > 0 || (phaseResults?.some((phase) => phase.turnsUsed > 0) ?? false);
|
|
14068
|
+
const sessionExpired = Boolean(options?.resumeRunId) && hadPriorSession && !recordedAnyTurns && isExpiredSessionError(err);
|
|
14069
|
+
const accountingUpdate = buildRunAccountingUpdate({
|
|
14070
|
+
runtime: runtimeId,
|
|
14071
|
+
provider: effectiveProvider,
|
|
14072
|
+
model: effectiveModel,
|
|
14073
|
+
checkpointState,
|
|
14074
|
+
usage,
|
|
14075
|
+
costData,
|
|
14076
|
+
phaseResults
|
|
14077
|
+
});
|
|
14078
|
+
if (sessionExpired) {
|
|
14079
|
+
accountingUpdate.checkpoints = null;
|
|
14080
|
+
}
|
|
13690
14081
|
updateRunStatus(runId, STATUS_FAILED, {
|
|
13691
|
-
resumable: 1,
|
|
13692
|
-
resume_status: RESUME_STATUS_READY,
|
|
14082
|
+
resumable: sessionExpired ? 0 : 1,
|
|
14083
|
+
resume_status: sessionExpired ? RESUME_STATUS_SESSION_EXPIRED : RESUME_STATUS_READY,
|
|
13693
14084
|
completed_at: failedAt,
|
|
13694
14085
|
tokens_used: usage.totalTokens ?? phaseResults?.reduce((sum, phase) => sum + phase.tokensUsed, 0) ?? void 0,
|
|
13695
14086
|
error: errorMessage2,
|
|
13696
|
-
...
|
|
13697
|
-
runtime: runtimeId,
|
|
13698
|
-
provider: effectiveProvider,
|
|
13699
|
-
model: effectiveModel,
|
|
13700
|
-
checkpointState,
|
|
13701
|
-
usage,
|
|
13702
|
-
costData,
|
|
13703
|
-
phaseResults
|
|
13704
|
-
})
|
|
14087
|
+
...accountingUpdate
|
|
13705
14088
|
});
|
|
13706
14089
|
} catch (dbErr) {
|
|
13707
|
-
|
|
14090
|
+
options?.logger?.error("agent.run.db-save-failed", `Failed to save error to DB for run ${runId}`, {
|
|
14091
|
+
runId,
|
|
14092
|
+
error: errorMessage(dbErr)
|
|
14093
|
+
});
|
|
13708
14094
|
}
|
|
13709
14095
|
await cleanupOnTaskFailure({
|
|
13710
14096
|
taskName: config.taskName,
|
|
@@ -13742,6 +14128,7 @@ async function cleanupOnTaskFailure(args) {
|
|
|
13742
14128
|
}
|
|
13743
14129
|
async function finalizeOnTaskSuccess(args) {
|
|
13744
14130
|
if (args.taskName !== CORTEX_INSTRUCTIONS_TASK) return;
|
|
14131
|
+
if (args.dryRun) return;
|
|
13745
14132
|
const reports = listReports(args.runId);
|
|
13746
14133
|
let report;
|
|
13747
14134
|
for (let i = reports.length - 1; i >= 0; i -= 1) {
|
|
@@ -13832,6 +14219,8 @@ export {
|
|
|
13832
14219
|
countWriteIntents,
|
|
13833
14220
|
countWriteIntentsByTool,
|
|
13834
14221
|
countWriteIntentsByToolForEvaluation,
|
|
14222
|
+
hasSemanticSearchFilters,
|
|
14223
|
+
matchesSemanticSearchFilters,
|
|
13835
14224
|
getGraphForNode,
|
|
13836
14225
|
createBatchLineage,
|
|
13837
14226
|
insertResolutionEvent,
|
|
@@ -13841,4 +14230,4 @@ export {
|
|
|
13841
14230
|
cleanupOnTaskFailure,
|
|
13842
14231
|
finalizeOnTaskSuccess
|
|
13843
14232
|
};
|
|
13844
|
-
//# sourceMappingURL=chunk-
|
|
14233
|
+
//# sourceMappingURL=chunk-HCT7RMM2.js.map
|