@lazyingart/agintiflow 0.20.288 → 0.20.290
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/docs/skills-and-tools.md +8 -0
- package/docs/state-of-the-art-agent-runtime.md +7 -0
- package/package.json +1 -1
- package/scripts/smoke-progressive-tool-selection.js +107 -0
- package/scripts/smoke-skills.js +18 -0
- package/src/agent-runner.js +42 -0
- package/src/model-client.js +3 -1
- package/src/progressive-tool-selection.js +4 -1
- package/src/research-routing.js +1 -1
- package/src/skill-library.js +57 -8
package/docs/skills-and-tools.md
CHANGED
|
@@ -79,6 +79,14 @@ tools:
|
|
|
79
79
|
|
|
80
80
|
Selected skills are injected into the plan and execution prompts. The LLM still decides what to do; skills only provide domain playbooks and guardrails.
|
|
81
81
|
|
|
82
|
+
Automatic selection requires substantive relevance. Exact IDs, focused short
|
|
83
|
+
requests, specific triggers, and several matching description terms score
|
|
84
|
+
strongly. Generic words such as `data`, `search`, `project`, or `commit` are
|
|
85
|
+
discounted when they occur incidentally inside a longer request, and automatic
|
|
86
|
+
mode omits weak matches instead of filling the skill budget. Explicit profiles
|
|
87
|
+
and direct topic wording remain authoritative. This keeps unrelated guidance
|
|
88
|
+
out of the context without hard-coding task-specific exclusions.
|
|
89
|
+
|
|
82
90
|
## Adding A Skill
|
|
83
91
|
|
|
84
92
|
For a reusable project workflow, create `.aginti/skills/<id>/SKILL.md` with valid YAML frontmatter and a short Markdown body. These skills are loaded from the current project, shown as `source=project-local`, and are preferred for task-specific knowledge that should not become core runtime policy.
|
|
@@ -130,6 +130,13 @@ only after a categorized provider failure and must not replay verified side
|
|
|
130
130
|
effects. Codex and Claude remain explicit opt-in backends rather than hidden
|
|
131
131
|
fallbacks.
|
|
132
132
|
|
|
133
|
+
Timeout compaction also preserves goal-scoped deep-research completion. A
|
|
134
|
+
same-task repair of the immediately preceding report keeps ordinary file,
|
|
135
|
+
shell, and validation tools after a model switch instead of forcing another
|
|
136
|
+
research pass. A genuinely new research request does not inherit that marker
|
|
137
|
+
and still begins with the bounded `deep_research` workflow. Native function
|
|
138
|
+
calling and the text-tool fallback apply the same rule.
|
|
139
|
+
|
|
133
140
|
## Machine Host Protocol
|
|
134
141
|
|
|
135
142
|
The supported subprocess boundary is:
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@lazyingart/agintiflow",
|
|
3
|
-
"version": "0.20.
|
|
3
|
+
"version": "0.20.290",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -5151,6 +5151,113 @@ assert(
|
|
|
5151
5151
|
"post-research compaction forgot the completed bounded research call"
|
|
5152
5152
|
);
|
|
5153
5153
|
|
|
5154
|
+
const timeoutCompactedResearchRepairGoal =
|
|
5155
|
+
"External verification failed for the existing research report. Preserve the report and evidence, add the missing sources.json and PDF, run the validator, and commit the repair.";
|
|
5156
|
+
const timeoutCompactedResearchRepairState = {
|
|
5157
|
+
goal: timeoutCompactedResearchRepairGoal,
|
|
5158
|
+
meta: {
|
|
5159
|
+
goalContract: {
|
|
5160
|
+
revision: 2,
|
|
5161
|
+
currentHash: "research-repair-goal",
|
|
5162
|
+
currentRequest: timeoutCompactedResearchRepairGoal,
|
|
5163
|
+
history: [
|
|
5164
|
+
{ revision: 1, hash: "original-research-goal" },
|
|
5165
|
+
{
|
|
5166
|
+
revision: 2,
|
|
5167
|
+
hash: "research-repair-goal",
|
|
5168
|
+
previousHash: "original-research-goal",
|
|
5169
|
+
},
|
|
5170
|
+
],
|
|
5171
|
+
},
|
|
5172
|
+
completedDeepResearch: [
|
|
5173
|
+
{
|
|
5174
|
+
goalKey: "original-research-goal",
|
|
5175
|
+
result: {
|
|
5176
|
+
ok: true,
|
|
5177
|
+
version: 14,
|
|
5178
|
+
reportPath: path.join(repoRoot, "package.json"),
|
|
5179
|
+
},
|
|
5180
|
+
},
|
|
5181
|
+
],
|
|
5182
|
+
},
|
|
5183
|
+
};
|
|
5184
|
+
const timeoutCompactedResearchRepairRuntime = nextStepRuntimeConfig(
|
|
5185
|
+
{
|
|
5186
|
+
provider: "deepseek",
|
|
5187
|
+
goal: timeoutCompactedResearchRepairGoal,
|
|
5188
|
+
commandCwd: repoRoot,
|
|
5189
|
+
},
|
|
5190
|
+
timeoutCompactedResearchRepairState
|
|
5191
|
+
);
|
|
5192
|
+
assertStrict.equal(
|
|
5193
|
+
timeoutCompactedResearchRepairRuntime.deepResearchCompletedForCurrentWork,
|
|
5194
|
+
true,
|
|
5195
|
+
"a successor artifact repair lost the completed research record from its immediately preceding goal"
|
|
5196
|
+
);
|
|
5197
|
+
const timeoutCompactedResearchRepair = selectProgressiveTools(allTools, {
|
|
5198
|
+
config: timeoutCompactedResearchRepairRuntime,
|
|
5199
|
+
goal: timeoutCompactedResearchRepairGoal,
|
|
5200
|
+
profile: "research",
|
|
5201
|
+
messages: [
|
|
5202
|
+
{
|
|
5203
|
+
role: "user",
|
|
5204
|
+
content:
|
|
5205
|
+
"A previous agent-step request was interrupted by a model timeout. Continue from this compacted, valid transcript.",
|
|
5206
|
+
},
|
|
5207
|
+
{
|
|
5208
|
+
role: "user",
|
|
5209
|
+
content:
|
|
5210
|
+
"Retained runtime tool evidence. This operation already completed; use its result and do not repeat it solely because context was compacted.\nTool: read_file\nVerified result: existing evidence report",
|
|
5211
|
+
},
|
|
5212
|
+
],
|
|
5213
|
+
});
|
|
5214
|
+
assert(names(timeoutCompactedResearchRepair).includes("run_command"), "timeout-compacted research repair omitted shell validation");
|
|
5215
|
+
assert(names(timeoutCompactedResearchRepair).includes("write_file"), "timeout-compacted research repair omitted artifact writing");
|
|
5216
|
+
assert(
|
|
5217
|
+
!(names(timeoutCompactedResearchRepair).length === 2 && names(timeoutCompactedResearchRepair)[0] === "deep_research"),
|
|
5218
|
+
"timeout recovery forced a completed research task back into deep_research"
|
|
5219
|
+
);
|
|
5220
|
+
|
|
5221
|
+
const unrelatedNewResearchGoal =
|
|
5222
|
+
"Write a new deep research report comparing current optical sensor calibration methods.";
|
|
5223
|
+
const unrelatedNewResearchRuntime = nextStepRuntimeConfig(
|
|
5224
|
+
{ provider: "deepseek", goal: unrelatedNewResearchGoal, commandCwd: repoRoot },
|
|
5225
|
+
{
|
|
5226
|
+
...timeoutCompactedResearchRepairState,
|
|
5227
|
+
goal: unrelatedNewResearchGoal,
|
|
5228
|
+
meta: {
|
|
5229
|
+
...timeoutCompactedResearchRepairState.meta,
|
|
5230
|
+
goalContract: {
|
|
5231
|
+
revision: 3,
|
|
5232
|
+
currentHash: "new-research-goal",
|
|
5233
|
+
currentRequest: unrelatedNewResearchGoal,
|
|
5234
|
+
history: [
|
|
5235
|
+
...timeoutCompactedResearchRepairState.meta.goalContract.history,
|
|
5236
|
+
{
|
|
5237
|
+
revision: 3,
|
|
5238
|
+
hash: "new-research-goal",
|
|
5239
|
+
previousHash: "research-repair-goal",
|
|
5240
|
+
},
|
|
5241
|
+
],
|
|
5242
|
+
},
|
|
5243
|
+
},
|
|
5244
|
+
}
|
|
5245
|
+
);
|
|
5246
|
+
assertStrict.equal(
|
|
5247
|
+
unrelatedNewResearchRuntime.deepResearchCompletedForCurrentWork,
|
|
5248
|
+
undefined,
|
|
5249
|
+
"an old completed report suppressed a genuinely new research request"
|
|
5250
|
+
);
|
|
5251
|
+
sameNames(
|
|
5252
|
+
selectProgressiveTools(allTools, {
|
|
5253
|
+
config: unrelatedNewResearchRuntime,
|
|
5254
|
+
goal: unrelatedNewResearchGoal,
|
|
5255
|
+
profile: "research",
|
|
5256
|
+
}),
|
|
5257
|
+
["deep_research", "finish"],
|
|
5258
|
+
"a genuinely new research request did not retain the bounded deep-research starter"
|
|
5259
|
+
);
|
|
5260
|
+
|
|
5154
5261
|
const documentRuntimeSnapshot =
|
|
5155
5262
|
'Step 1/30. Latest runtime snapshot:\n{"pageText":"Workspace file tools are ready. Web search and resumable deep research are available when current evidence is required."}';
|
|
5156
5263
|
const localDocumentStarter = selectProgressiveTools(allTools, {
|
package/scripts/smoke-skills.js
CHANGED
|
@@ -112,6 +112,24 @@ const pythonSkill = skills.find((skill) => skill.id === "python");
|
|
|
112
112
|
assert(pythonSkill?.body.includes("PEP 701 relaxed f-strings"), "Python skill must mention 3.12 f-string compatibility traps");
|
|
113
113
|
assert(pythonSkill?.body.includes("only proves the active interpreter"), "Python skill must guard syntax-check overclaims");
|
|
114
114
|
assert(selectedIds("write SQL migrations for sqlite schema").includes("database"), "database prompt did not select database");
|
|
115
|
+
const imperfectDatabaseRepairSkills = selectedIds(
|
|
116
|
+
"The reading archive broke after its recent schema upgrade: an old library came back empty, and search gives surprising results for some punctuation. Please inspect the project, fix the underlying problems without discarding existing data, add useful regression coverage, run the checks, and commit the intentional repair. Keep the implementation small and standard-library only."
|
|
117
|
+
);
|
|
118
|
+
assert(imperfectDatabaseRepairSkills.includes("database"), "normal database repair prompt omitted database guidance");
|
|
119
|
+
assert(imperfectDatabaseRepairSkills.includes("qa-testing"), "normal database repair prompt omitted regression-test guidance");
|
|
120
|
+
for (const unrelated of [
|
|
121
|
+
"autonomous-artifact-pipeline",
|
|
122
|
+
"bgpt-paper-search",
|
|
123
|
+
"data-analysis",
|
|
124
|
+
"exa-search",
|
|
125
|
+
"exploratory-data-analysis",
|
|
126
|
+
"optimize-for-gpu",
|
|
127
|
+
]) {
|
|
128
|
+
assert(
|
|
129
|
+
!imperfectDatabaseRepairSkills.includes(unrelated),
|
|
130
|
+
`normal database repair prompt selected unrelated ${unrelated} guidance`
|
|
131
|
+
);
|
|
132
|
+
}
|
|
115
133
|
assert(selectedIds("debug Docker deployment logs and port config").includes("devops-deployment"), "devops prompt did not select devops-deployment");
|
|
116
134
|
assert(selectedIds("review auth security and secrets handling").includes("security-review"), "security prompt did not select security-review");
|
|
117
135
|
assert(selectedIds("make a PowerPoint pitch deck").includes("presentation-slides"), "slides prompt did not select presentation-slides");
|
package/src/agent-runner.js
CHANGED
|
@@ -13687,6 +13687,45 @@ export function convergenceSuppressedToolNames(state = {}) {
|
|
|
13687
13687
|
return [toolName];
|
|
13688
13688
|
}
|
|
13689
13689
|
|
|
13690
|
+
function currentWorkHasCompletedDeepResearch(state = {}, config = {}) {
|
|
13691
|
+
const records = Array.isArray(state.meta?.completedDeepResearch)
|
|
13692
|
+
? state.meta.completedDeepResearch
|
|
13693
|
+
: [];
|
|
13694
|
+
if (!records.length) return false;
|
|
13695
|
+
|
|
13696
|
+
const goalContract = state.meta?.goalContract || {};
|
|
13697
|
+
const currentKey = String(
|
|
13698
|
+
goalContract.currentHash || goalContract.activeHash || currentGoalKey(state)
|
|
13699
|
+
).trim();
|
|
13700
|
+
const latestHistory = Array.isArray(goalContract.history)
|
|
13701
|
+
? goalContract.history.at(-1) || {}
|
|
13702
|
+
: {};
|
|
13703
|
+
const previousKey = String(latestHistory.previousHash || "").trim();
|
|
13704
|
+
const currentRequest = String(
|
|
13705
|
+
goalContract.currentRequest || config.goal || state.goal || ""
|
|
13706
|
+
).replace(/\s+/g, " ").trim();
|
|
13707
|
+
const continuesExistingResearchArtifact = Boolean(
|
|
13708
|
+
previousKey &&
|
|
13709
|
+
/\b(?:preserve|reuse|continue|recover|repair|fix|correct|revise|validate|verify|rebuild|missing|existing|completed|retained|saved)\b/i.test(currentRequest) &&
|
|
13710
|
+
/\b(?:research|report|evidence|sources?|citations?|manifest|pdf|artifact|validation|validator)\b/i.test(currentRequest)
|
|
13711
|
+
);
|
|
13712
|
+
|
|
13713
|
+
return records.some((record) => {
|
|
13714
|
+
const result = record?.result || {};
|
|
13715
|
+
if (
|
|
13716
|
+
result.ok !== true ||
|
|
13717
|
+
Number(result.version || 0) !== RESEARCH_VERSION ||
|
|
13718
|
+
!String(result.reportPath || "").trim() ||
|
|
13719
|
+
!fsSync.existsSync(String(result.reportPath))
|
|
13720
|
+
) {
|
|
13721
|
+
return false;
|
|
13722
|
+
}
|
|
13723
|
+
const recordKey = String(record.goalKey || "").trim();
|
|
13724
|
+
if (recordKey && recordKey === currentKey) return true;
|
|
13725
|
+
return continuesExistingResearchArtifact && recordKey === previousKey;
|
|
13726
|
+
});
|
|
13727
|
+
}
|
|
13728
|
+
|
|
13690
13729
|
export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
13691
13730
|
const staticOrder = Array.isArray(state.meta?.toolLoop?.staticOrder)
|
|
13692
13731
|
? state.meta.toolLoop.staticOrder
|
|
@@ -13699,6 +13738,9 @@ export function nextStepRuntimeConfig(config = {}, state = {}) {
|
|
|
13699
13738
|
const runtimeConfig = {
|
|
13700
13739
|
...applyLocalFailureRecovery(config, state),
|
|
13701
13740
|
...(retainedDataDiscoveryReady ? { dataProjectDiscoveryReady: true } : {}),
|
|
13741
|
+
...(currentWorkHasCompletedDeepResearch(state, config)
|
|
13742
|
+
? { deepResearchCompletedForCurrentWork: true }
|
|
13743
|
+
: {}),
|
|
13702
13744
|
};
|
|
13703
13745
|
const suppressedToolNames = convergenceSuppressedToolNames(state);
|
|
13704
13746
|
if (suppressedToolNames.length) {
|
package/src/model-client.js
CHANGED
|
@@ -517,7 +517,9 @@ function messagesWithTextToolProtocol(config, messages, tools) {
|
|
|
517
517
|
}
|
|
518
518
|
return message;
|
|
519
519
|
});
|
|
520
|
-
const requireDeepResearch =
|
|
520
|
+
const requireDeepResearch =
|
|
521
|
+
config.deepResearchCompletedForCurrentWork !== true &&
|
|
522
|
+
tools.some((tool) => tool?.function?.name === "deep_research") &&
|
|
521
523
|
shouldStartWithDeepResearch(config.goal, messages);
|
|
522
524
|
const protocol = {
|
|
523
525
|
role: "system",
|
|
@@ -2741,7 +2741,10 @@ export function selectProgressiveTools(
|
|
|
2741
2741
|
)
|
|
2742
2742
|
: enabled;
|
|
2743
2743
|
|
|
2744
|
-
if (
|
|
2744
|
+
if (
|
|
2745
|
+
config.deepResearchCompletedForCurrentWork !== true &&
|
|
2746
|
+
shouldStartWithDeepResearch(goal || config.goal, messages)
|
|
2747
|
+
) {
|
|
2745
2748
|
const deepResearch = phaseEnabled.find(({ name }) => name === "deep_research")?.tool;
|
|
2746
2749
|
if (deepResearch) return [deepResearch, finish];
|
|
2747
2750
|
}
|
package/src/research-routing.js
CHANGED
|
@@ -10,7 +10,7 @@ const RUNTIME_USER_MESSAGE_PATTERNS = Object.freeze([
|
|
|
10
10
|
/^Step \d+\/\d+\b.*Latest runtime snapshot:/i,
|
|
11
11
|
/^Retained runtime tool evidence\./i,
|
|
12
12
|
/^The runtime proactively compacted a long agent history/i,
|
|
13
|
-
/^A previous agent-step model request timed out/i,
|
|
13
|
+
/^A previous agent-step (?:model request timed out|request was interrupted by a (?:model timeout|transient provider transport interruption))/i,
|
|
14
14
|
/^Continue from this compacted, valid transcript/i,
|
|
15
15
|
/^Previous assistant response retained as compacted history/i,
|
|
16
16
|
/^Highest-priority retained state:/i,
|
package/src/skill-library.js
CHANGED
|
@@ -419,21 +419,31 @@ const DESCRIPTION_STOP_WORDS = new Set([
|
|
|
419
419
|
"after",
|
|
420
420
|
"also",
|
|
421
421
|
"before",
|
|
422
|
+
"checks",
|
|
422
423
|
"content",
|
|
423
424
|
"create",
|
|
425
|
+
"data",
|
|
424
426
|
"exact",
|
|
427
|
+
"existing",
|
|
425
428
|
"file",
|
|
426
429
|
"files",
|
|
427
430
|
"from",
|
|
428
431
|
"general",
|
|
429
432
|
"into",
|
|
433
|
+
"keep",
|
|
434
|
+
"only",
|
|
430
435
|
"output",
|
|
431
436
|
"path",
|
|
432
437
|
"paths",
|
|
433
438
|
"project",
|
|
434
439
|
"read",
|
|
440
|
+
"reading",
|
|
441
|
+
"recent",
|
|
435
442
|
"report",
|
|
436
443
|
"request",
|
|
444
|
+
"results",
|
|
445
|
+
"search",
|
|
446
|
+
"standard",
|
|
437
447
|
"task",
|
|
438
448
|
"that",
|
|
439
449
|
"their",
|
|
@@ -443,14 +453,19 @@ const DESCRIPTION_STOP_WORDS = new Set([
|
|
|
443
453
|
"user",
|
|
444
454
|
"when",
|
|
445
455
|
"with",
|
|
456
|
+
"without",
|
|
446
457
|
"work",
|
|
447
458
|
"write",
|
|
448
459
|
]);
|
|
449
460
|
|
|
450
461
|
const SKILL_ID_STOP_WORDS = new Set([
|
|
462
|
+
"and",
|
|
451
463
|
"agent",
|
|
452
464
|
"aginti",
|
|
465
|
+
"for",
|
|
453
466
|
"development",
|
|
467
|
+
"of",
|
|
468
|
+
"the",
|
|
454
469
|
"production",
|
|
455
470
|
"skill",
|
|
456
471
|
"system",
|
|
@@ -459,6 +474,30 @@ const SKILL_ID_STOP_WORDS = new Set([
|
|
|
459
474
|
"workflow",
|
|
460
475
|
]);
|
|
461
476
|
|
|
477
|
+
// These words are useful in a focused request, but occur incidentally across
|
|
478
|
+
// many unrelated tasks. Weakening them in longer goals keeps one generic word
|
|
479
|
+
// from consuming a full skill slot while preserving short requests such as
|
|
480
|
+
// "analyze data" or "commit changes".
|
|
481
|
+
const GENERIC_ROUTING_TERMS = new Set([
|
|
482
|
+
"analysis",
|
|
483
|
+
"app",
|
|
484
|
+
"application",
|
|
485
|
+
"code",
|
|
486
|
+
"commit",
|
|
487
|
+
"data",
|
|
488
|
+
"file",
|
|
489
|
+
"files",
|
|
490
|
+
"project",
|
|
491
|
+
"report",
|
|
492
|
+
"result",
|
|
493
|
+
"results",
|
|
494
|
+
"search",
|
|
495
|
+
"test",
|
|
496
|
+
"tests",
|
|
497
|
+
"testing",
|
|
498
|
+
"work",
|
|
499
|
+
]);
|
|
500
|
+
|
|
462
501
|
function descriptionTerms(value = "") {
|
|
463
502
|
return [
|
|
464
503
|
...new Set(
|
|
@@ -470,7 +509,16 @@ function descriptionTerms(value = "") {
|
|
|
470
509
|
];
|
|
471
510
|
}
|
|
472
511
|
|
|
473
|
-
function
|
|
512
|
+
function focusedGenericSignal(goalText, needle) {
|
|
513
|
+
if (!GENERIC_ROUTING_TERMS.has(needle)) return true;
|
|
514
|
+
const terms = String(goalText || "")
|
|
515
|
+
.toLowerCase()
|
|
516
|
+
.split(/[^a-z0-9+#.]+/)
|
|
517
|
+
.filter(Boolean);
|
|
518
|
+
return terms.length <= 4 && textHasTrigger(goalText, needle);
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
function scoreSkill(skill, text, taskProfile, goalText = text) {
|
|
474
522
|
let score = 0;
|
|
475
523
|
if (skill.id === taskProfile) score += 10;
|
|
476
524
|
if (skill.triggers.includes(taskProfile)) score += 6;
|
|
@@ -479,13 +527,14 @@ function scoreSkill(skill, text, taskProfile) {
|
|
|
479
527
|
.split(/[^a-z0-9+#.]+/)
|
|
480
528
|
.filter((term) => term.length >= 3 && !SKILL_ID_STOP_WORDS.has(term));
|
|
481
529
|
for (const term of idTerms) {
|
|
482
|
-
if (textHasTrigger(text, term)) score += 2;
|
|
530
|
+
if (textHasTrigger(text, term)) score += focusedGenericSignal(goalText, term) ? 2 : 0.5;
|
|
483
531
|
}
|
|
484
532
|
for (const trigger of skill.triggers) {
|
|
485
533
|
const needle = trigger.toLowerCase();
|
|
486
534
|
if (!needle) continue;
|
|
487
535
|
if (textHasTrigger(text, needle)) {
|
|
488
|
-
|
|
536
|
+
const triggerScore = Math.max(2, Math.min(6, Math.ceil(needle.length / 6)));
|
|
537
|
+
score += focusedGenericSignal(goalText, needle) ? triggerScore : 0.5;
|
|
489
538
|
continue;
|
|
490
539
|
}
|
|
491
540
|
const triggerTerms = descriptionTerms(needle);
|
|
@@ -495,7 +544,7 @@ function scoreSkill(skill, text, taskProfile) {
|
|
|
495
544
|
}
|
|
496
545
|
const descriptionMatches = descriptionTerms(skill.description).filter((token) => textHasTrigger(text, token));
|
|
497
546
|
if (descriptionMatches.length >= 3) {
|
|
498
|
-
score += Math.min(3, descriptionMatches.length * 0.
|
|
547
|
+
score += Math.min(3, descriptionMatches.length * 0.5);
|
|
499
548
|
}
|
|
500
549
|
return score;
|
|
501
550
|
}
|
|
@@ -516,19 +565,19 @@ function textHasTrigger(text, needle) {
|
|
|
516
565
|
|
|
517
566
|
export function selectSkillsForGoal(goal = "", { taskProfile = "auto", limit = 6, includeBody = true, projectRoot = process.cwd() } = {}) {
|
|
518
567
|
const goalText = String(goal || "").toLowerCase();
|
|
519
|
-
const text =
|
|
568
|
+
const text = goalText;
|
|
520
569
|
const skills = listSkills({ includeBody, projectRoot });
|
|
521
570
|
const ranked = skills
|
|
522
571
|
.map((skill) => ({
|
|
523
572
|
skill,
|
|
524
|
-
score: scoreSkill(skill, text, taskProfile),
|
|
525
|
-
directGoalScore: scoreSkill(skill, goalText, "auto"),
|
|
573
|
+
score: scoreSkill(skill, text, taskProfile, goalText),
|
|
574
|
+
directGoalScore: scoreSkill(skill, goalText, "auto", goalText),
|
|
526
575
|
}))
|
|
527
576
|
.filter((item) => item.score > 0)
|
|
528
577
|
.sort((a, b) => b.score - a.score || a.skill.id.localeCompare(b.skill.id));
|
|
529
578
|
const explicitProfile = Boolean(taskProfile && taskProfile !== "auto");
|
|
530
579
|
const bestScore = ranked[0]?.score || 0;
|
|
531
|
-
const relevanceFloor = explicitProfile && bestScore >= 6 ? Math.max(2, bestScore * 0.5) :
|
|
580
|
+
const relevanceFloor = explicitProfile && bestScore >= 6 ? Math.max(2, bestScore * 0.5) : 2;
|
|
532
581
|
const scored = ranked
|
|
533
582
|
.filter((item) => item.score >= relevanceFloor || item.directGoalScore >= 4)
|
|
534
583
|
.map((item) => item.skill);
|