kc-beta 0.7.3 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +57 -4
- package/bin/kc-beta.js +20 -6
- package/package.json +3 -2
- package/src/agent/engine.js +493 -132
- package/src/agent/pipelines/_advance-hints.js +92 -0
- package/src/agent/pipelines/_milestone-derive.js +387 -17
- package/src/agent/pipelines/initializer.js +4 -1
- package/src/agent/pipelines/skill-authoring.js +30 -1
- package/src/agent/skill-loader.js +433 -111
- package/src/agent/tools/agent-tool.js +2 -2
- package/src/agent/tools/consult-skill.js +127 -0
- package/src/agent/tools/copy-to-workspace.js +4 -3
- package/src/agent/tools/dashboard-render.js +48 -1
- package/src/agent/tools/document-parse.js +31 -2
- package/src/agent/tools/phase-advance.js +17 -13
- package/src/agent/tools/release.js +378 -8
- package/src/agent/tools/sandbox-exec.js +65 -8
- package/src/agent/tools/worker-llm-call.js +95 -15
- package/src/agent/tools/workspace-file.js +7 -7
- package/src/agent/workspace.js +25 -4
- package/src/cli/components.js +4 -1
- package/src/cli/index.js +97 -1
- package/src/config.js +20 -3
- package/src/marathon/driver.js +217 -0
- package/src/marathon/prompts.js +93 -0
- package/template/.env.template +16 -0
- package/template/AGENT.md +182 -7
- package/template/skills/en/{meta-meta/auto-model-selection → auto-model-selection}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/bootstrap-workspace → bootstrap-workspace}/SKILL.md +15 -0
- package/template/skills/{zh/meta → en}/compliance-judgment/SKILL.md +1 -0
- package/template/skills/en/{meta/confidence-system → confidence-system}/SKILL.md +1 -0
- package/template/skills/en/{meta/corner-case-management → corner-case-management}/SKILL.md +1 -0
- package/template/skills/en/{meta/cross-document-verification → cross-document-verification}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/dashboard-reporting → dashboard-reporting}/SKILL.md +1 -0
- package/template/skills/en/{meta/data-sensibility → data-sensibility}/SKILL.md +1 -0
- package/template/skills/{zh/meta → en}/document-chunking/SKILL.md +1 -0
- package/template/skills/en/{meta/document-parsing → document-parsing}/SKILL.md +1 -0
- package/template/skills/{zh/meta → en}/entity-extraction/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/evolution-loop → evolution-loop}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/pdf-review-dashboard → pdf-review-dashboard}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/quality-control → quality-control}/SKILL.md +10 -0
- package/template/skills/en/{meta-meta/rule-extraction → rule-extraction}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/rule-graph → rule-graph}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/skill-authoring → skill-authoring}/SKILL.md +40 -0
- package/template/skills/en/skill-creator/SKILL.md +2 -1
- package/template/skills/en/{meta-meta/skill-to-workflow → skill-to-workflow}/SKILL.md +58 -4
- package/template/skills/en/{meta-meta/task-decomposition → task-decomposition}/SKILL.md +1 -0
- package/template/skills/en/{meta/tree-processing → tree-processing}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/version-control → version-control}/SKILL.md +1 -0
- package/template/skills/en/{meta-meta/work-decomposition → work-decomposition}/SKILL.md +51 -6
- package/template/skills/phase_skills.yaml +112 -0
- package/template/skills/zh/{meta-meta/auto-model-selection → auto-model-selection}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/bootstrap-workspace → bootstrap-workspace}/SKILL.md +15 -0
- package/template/skills/zh/compliance-judgment/SKILL.md +83 -0
- package/template/skills/zh/{meta/confidence-system → confidence-system}/SKILL.md +1 -0
- package/template/skills/zh/{meta/corner-case-management → corner-case-management}/SKILL.md +1 -0
- package/template/skills/zh/{meta/cross-document-verification → cross-document-verification}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/dashboard-reporting → dashboard-reporting}/SKILL.md +1 -0
- package/template/skills/zh/{meta/data-sensibility → data-sensibility}/SKILL.md +1 -0
- package/template/skills/zh/document-chunking/SKILL.md +40 -0
- package/template/skills/zh/document-parsing/SKILL.md +102 -0
- package/template/skills/zh/entity-extraction/SKILL.md +121 -0
- package/template/skills/zh/{meta-meta/evolution-loop → evolution-loop}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/pdf-review-dashboard → pdf-review-dashboard}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/quality-control → quality-control}/SKILL.md +10 -0
- package/template/skills/zh/{meta-meta/rule-extraction → rule-extraction}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/rule-graph → rule-graph}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/skill-authoring → skill-authoring}/SKILL.md +40 -0
- package/template/skills/zh/skill-creator/SKILL.md +205 -200
- package/template/skills/zh/skill-to-workflow/SKILL.md +243 -0
- package/template/skills/zh/{meta-meta/task-decomposition → task-decomposition}/SKILL.md +1 -0
- package/template/skills/zh/tree-processing/SKILL.md +126 -0
- package/template/skills/zh/{meta-meta/version-control → version-control}/SKILL.md +1 -0
- package/template/skills/zh/{meta-meta/work-decomposition → work-decomposition}/SKILL.md +49 -4
- package/template/workflows/common/llm_client.py +168 -0
- package/template/workflows/common/utils.py +132 -0
- package/template/CLAUDE.md +0 -150
- package/template/skills/en/meta/compliance-judgment/SKILL.md +0 -82
- package/template/skills/en/meta/document-chunking/SKILL.md +0 -32
- package/template/skills/en/meta/entity-extraction/SKILL.md +0 -120
- package/template/skills/zh/meta/document-parsing/SKILL.md +0 -101
- package/template/skills/zh/meta/tree-processing/SKILL.md +0 -121
- package/template/skills/zh/meta-meta/skill-to-workflow/SKILL.md +0 -188
- /package/template/skills/en/{meta/compliance-judgment → compliance-judgment}/references/output-format.md +0 -0
- /package/template/skills/en/{meta/cross-document-verification → cross-document-verification}/references/contradiction-taxonomy.md +0 -0
- /package/template/skills/en/{meta-meta/dashboard-reporting → dashboard-reporting}/scripts/generate_dashboard.py +0 -0
- /package/template/skills/en/{meta/document-parsing → document-parsing}/references/parser-catalog.md +0 -0
- /package/template/skills/en/{meta-meta/evolution-loop → evolution-loop}/references/convergence-guide.md +0 -0
- /package/template/skills/en/{meta-meta/pdf-review-dashboard → pdf-review-dashboard}/scripts/generate_review.js +0 -0
- /package/template/skills/en/{meta-meta/quality-control → quality-control}/references/qa-layers.md +0 -0
- /package/template/skills/en/{meta-meta/quality-control → quality-control}/references/sampling-strategies.md +0 -0
- /package/template/skills/en/{meta-meta/rule-extraction → rule-extraction}/references/chunking-strategies.md +0 -0
- /package/template/skills/en/{meta-meta/skill-authoring → skill-authoring}/references/skill-format-spec.md +0 -0
- /package/template/skills/en/{meta-meta/skill-to-workflow → skill-to-workflow}/references/worker-llm-catalog.md +0 -0
- /package/template/skills/en/{meta-meta/task-decomposition → task-decomposition}/references/decision-matrix.md +0 -0
- /package/template/skills/en/{meta-meta/version-control → version-control}/references/trace-id-spec.md +0 -0
- /package/template/skills/zh/{meta/compliance-judgment → compliance-judgment}/references/output-format.md +0 -0
- /package/template/skills/zh/{meta/cross-document-verification → cross-document-verification}/references/contradiction-taxonomy.md +0 -0
- /package/template/skills/zh/{meta-meta/dashboard-reporting → dashboard-reporting}/scripts/generate_dashboard.py +0 -0
- /package/template/skills/zh/{meta/document-parsing → document-parsing}/references/parser-catalog.md +0 -0
- /package/template/skills/zh/{meta-meta/evolution-loop → evolution-loop}/references/convergence-guide.md +0 -0
- /package/template/skills/zh/{meta-meta/pdf-review-dashboard → pdf-review-dashboard}/scripts/generate_review.js +0 -0
- /package/template/skills/zh/{meta-meta/quality-control → quality-control}/references/qa-layers.md +0 -0
- /package/template/skills/zh/{meta-meta/quality-control → quality-control}/references/sampling-strategies.md +0 -0
- /package/template/skills/zh/{meta-meta/rule-extraction → rule-extraction}/references/chunking-strategies.md +0 -0
- /package/template/skills/zh/{meta-meta/skill-authoring → skill-authoring}/references/skill-format-spec.md +0 -0
- /package/template/skills/zh/{meta-meta/skill-to-workflow → skill-to-workflow}/references/worker-llm-catalog.md +0 -0
- /package/template/skills/zh/{meta-meta/task-decomposition → task-decomposition}/references/decision-matrix.md +0 -0
- /package/template/skills/zh/{meta-meta/version-control → version-control}/references/trace-id-spec.md +0 -0
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { BaseTool, ToolResult } from "./base.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* v0.7.5: load a methodology skill's body into the agent's conversation
|
|
5
|
+
* history as a tool result. Pairs with the always-loaded body injection
|
|
6
|
+
* in SkillLoader.formatForContext — that handles the 1-2 architecturally-
|
|
7
|
+
* required skills per phase; consult_skill handles the rest on demand.
|
|
8
|
+
*
|
|
9
|
+
* Validation:
|
|
10
|
+
* - Skill name must be in the current phase's available set (per
|
|
11
|
+
* template/skills/phase_skills.yaml).
|
|
12
|
+
* - Already-always-loaded skills return a hint pointing the agent at the
|
|
13
|
+
* system prompt (don't double-load).
|
|
14
|
+
* - Missing bodies return an error result.
|
|
15
|
+
*
|
|
16
|
+
* Emits `skill_invoked` event with proper skill name on success — replaces
|
|
17
|
+
* the older path-matching regex at engine.js:1297-1313 that produced
|
|
18
|
+
* "(unknown)" spam from rule_skills/<id>/SKILL.md writes.
|
|
19
|
+
*/
|
|
20
|
+
export class ConsultSkillTool extends BaseTool {
|
|
21
|
+
/**
|
|
22
|
+
* @param {import('../workspace.js').Workspace} workspace
|
|
23
|
+
* @param {import('../skill-loader.js').SkillLoader} skillLoader
|
|
24
|
+
* @param {() => string} getCurrentPhase — returns the engine's current phase
|
|
25
|
+
* @param {import('../event-log.js').EventLog} [eventLog] — for skill_invoked emission
|
|
26
|
+
*/
|
|
27
|
+
constructor(workspace, skillLoader, getCurrentPhase, eventLog) {
|
|
28
|
+
super();
|
|
29
|
+
this._workspace = workspace;
|
|
30
|
+
this._skillLoader = skillLoader;
|
|
31
|
+
this._getCurrentPhase = getCurrentPhase;
|
|
32
|
+
this._eventLog = eventLog;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
get name() { return "consult_skill"; }
|
|
36
|
+
|
|
37
|
+
get description() {
|
|
38
|
+
return (
|
|
39
|
+
"Load the full body of a methodology skill into your context for the " +
|
|
40
|
+
"current turn. Use when the description tease in the system prompt's " +
|
|
41
|
+
"'Available Methodology Skills' section isn't enough detail to proceed. " +
|
|
42
|
+
"The body lands in your conversation history; subsequent turns can " +
|
|
43
|
+
"reference it via context, or you can re-consult if it ages out. " +
|
|
44
|
+
"Skills already in the 'Loaded Into Your Context' section don't need " +
|
|
45
|
+
"consulting — they're already in your prompt."
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
get inputSchema() {
|
|
50
|
+
return {
|
|
51
|
+
type: "object",
|
|
52
|
+
properties: {
|
|
53
|
+
name: {
|
|
54
|
+
type: "string",
|
|
55
|
+
description: "Skill name as listed in the system prompt (e.g., 'work-decomposition', 'evolution-loop').",
|
|
56
|
+
},
|
|
57
|
+
},
|
|
58
|
+
required: ["name"],
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async execute(input) {
|
|
63
|
+
const name = (input?.name || "").trim();
|
|
64
|
+
if (!name) return new ToolResult("name required (e.g. consult_skill({name: 'work-decomposition'}))", true);
|
|
65
|
+
|
|
66
|
+
// v0.8 P0-A: defensive null-check. v0.7.5 shipped with an init-order bug
|
|
67
|
+
// where ConsultSkillTool received undefined skillLoader and threw
|
|
68
|
+
// "Cannot read properties of undefined (reading 'getPhaseSkillSet')"
|
|
69
|
+
// on every invocation (资管 audit § 9.1, 5/5 failure rate). The init-order
|
|
70
|
+
// fix is in engine.js:238; this guard prevents an uncaught exception if
|
|
71
|
+
// the bug recurs from any future constructor reorder.
|
|
72
|
+
if (!this._skillLoader || typeof this._skillLoader.getPhaseSkillSet !== "function") {
|
|
73
|
+
return new ToolResult(
|
|
74
|
+
"consult_skill is misconfigured: skillLoader unavailable. This is an engine-side bug — " +
|
|
75
|
+
"surface to the developer user. The agent should fall back to reading skill bodies " +
|
|
76
|
+
"directly from <workspace>/skills/<name>/SKILL.md or the system prompt's always-loaded section.",
|
|
77
|
+
true,
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const phase = this._getCurrentPhase ? this._getCurrentPhase() : null;
|
|
82
|
+
const { alwaysLoaded, available } = this._skillLoader.getPhaseSkillSet(phase);
|
|
83
|
+
|
|
84
|
+
const alwaysSet = new Set(alwaysLoaded);
|
|
85
|
+
const availableSet = new Set(available);
|
|
86
|
+
|
|
87
|
+
if (alwaysSet.has(name)) {
|
|
88
|
+
return new ToolResult(
|
|
89
|
+
`Skill '${name}' is already always-loaded in your system prompt for phase '${phase}'. ` +
|
|
90
|
+
`Re-read the system prompt's 'Methodology Skills — Loaded Into Your Context' section ` +
|
|
91
|
+
`— the body is there. No separate consult needed.`,
|
|
92
|
+
);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (!availableSet.has(name)) {
|
|
96
|
+
const sorted = [...availableSet].sort();
|
|
97
|
+
return new ToolResult(
|
|
98
|
+
`Skill '${name}' is not available in phase '${phase}'. ` +
|
|
99
|
+
`Available for this phase: ${sorted.join(", ")}. ` +
|
|
100
|
+
`If you genuinely need this skill, either advance/retreat to a phase ` +
|
|
101
|
+
`where it's available, or check the spelling.`,
|
|
102
|
+
true,
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
const body = this._skillLoader.loadSkillBody(name);
|
|
107
|
+
if (!body) {
|
|
108
|
+
return new ToolResult(
|
|
109
|
+
`Skill '${name}' is declared available for phase '${phase}' but its body could not be loaded. ` +
|
|
110
|
+
`This is an engine/template inconsistency — surface to the developer user.`,
|
|
111
|
+
true,
|
|
112
|
+
);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Emit skill_invoked event with the real skill name (replaces the
|
|
116
|
+
// old path-matching regex that produced "(unknown)" spam).
|
|
117
|
+
try {
|
|
118
|
+
this._eventLog?.append?.("skill_invoked", {
|
|
119
|
+
skill: name,
|
|
120
|
+
via_tool: "consult_skill",
|
|
121
|
+
phase,
|
|
122
|
+
});
|
|
123
|
+
} catch { /* event logging is best-effort */ }
|
|
124
|
+
|
|
125
|
+
return new ToolResult(body);
|
|
126
|
+
}
|
|
127
|
+
}
|
|
@@ -114,9 +114,10 @@ export class CopyToWorkspaceTool extends BaseTool {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
async _appendManifest(entry) {
|
|
117
|
-
// v0.7.3: refs/manifest.json is a
|
|
118
|
-
// whole read-modify-write
|
|
119
|
-
//
|
|
117
|
+
// v0.7.4 (re-applied from v0.7.3 G1a): refs/manifest.json is a
|
|
118
|
+
// shared coordination path — wrap the whole read-modify-write
|
|
119
|
+
// under the workspace lock so two parallel copy_to_workspace
|
|
120
|
+
// calls (main agent + subagent) don't lose entries.
|
|
120
121
|
return await this._workspace.withSharedLockIfApplicable(MANIFEST_REL, () => {
|
|
121
122
|
const manifestAbs = this._workspace.resolvePath(MANIFEST_REL);
|
|
122
123
|
fs.mkdirSync(path.dirname(manifestAbs), { recursive: true });
|
|
@@ -81,11 +81,57 @@ export class DashboardRenderTool extends BaseTool {
|
|
|
81
81
|
metrics.evolution_iterations = fs.readdirSync(evoDir).filter((f) => f.endsWith(".json")).length;
|
|
82
82
|
}
|
|
83
83
|
|
|
84
|
+
// v0.8 P1-G: QC counter now reads from multiple known agent-write
|
|
85
|
+
// locations + counts per-doc reviews. Pre-v0.8 read only output/qc/*.json
|
|
86
|
+
// top-level; 资管 v0.7.5 wrote output/results/production_qc_results.json
|
|
87
|
+
// so the dashboard showed `QC Batches: 0` despite 126 pairs of data.
|
|
88
|
+
let qcBatches = 0;
|
|
89
|
+
let qcDocsReviewed = 0;
|
|
90
|
+
|
|
91
|
+
// (a) Top-level batch files in output/qc/ (贷款 v0.7.5 shape)
|
|
84
92
|
const qcDir = path.join(ws, "output", "qc");
|
|
85
93
|
if (fs.existsSync(qcDir)) {
|
|
86
|
-
|
|
94
|
+
for (const f of fs.readdirSync(qcDir).filter((f) => f.endsWith(".json"))) {
|
|
95
|
+
qcBatches++;
|
|
96
|
+
try {
|
|
97
|
+
const data = JSON.parse(fs.readFileSync(path.join(qcDir, f), "utf-8"));
|
|
98
|
+
const n = Number(data?.documents_reviewed);
|
|
99
|
+
if (Number.isFinite(n) && n > qcDocsReviewed) qcDocsReviewed = n;
|
|
100
|
+
} catch { /* skip malformed */ }
|
|
101
|
+
}
|
|
87
102
|
}
|
|
88
103
|
|
|
104
|
+
// (b) Per-doc reviews at output/qc/reviews/ (贷款 detail shape)
|
|
105
|
+
const reviewsDir = path.join(ws, "output", "qc", "reviews");
|
|
106
|
+
if (fs.existsSync(reviewsDir)) {
|
|
107
|
+
const reviewFiles = fs.readdirSync(reviewsDir).filter((f) => f.endsWith(".json"));
|
|
108
|
+
qcDocsReviewed = Math.max(qcDocsReviewed, reviewFiles.length);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
// (c) production_qc_results.json shape (资管 v0.7.5)
|
|
112
|
+
const productionQc = path.join(ws, "output", "results", "production_qc_results.json");
|
|
113
|
+
if (fs.existsSync(productionQc)) {
|
|
114
|
+
qcBatches++;
|
|
115
|
+
try {
|
|
116
|
+
const data = JSON.parse(fs.readFileSync(productionQc, "utf-8"));
|
|
117
|
+
const totalDocs = Number(data?.total_docs);
|
|
118
|
+
if (Number.isFinite(totalDocs)) qcDocsReviewed = Math.max(qcDocsReviewed, totalDocs);
|
|
119
|
+
// Otherwise, dedup doc keys from nested results
|
|
120
|
+
if (!Number.isFinite(totalDocs) && data?.results && typeof data.results === "object") {
|
|
121
|
+
const docSet = new Set();
|
|
122
|
+
for (const docs of Object.values(data.results)) {
|
|
123
|
+
if (docs && typeof docs === "object") {
|
|
124
|
+
for (const k of Object.keys(docs)) docSet.add(k);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
if (docSet.size > 0) qcDocsReviewed = Math.max(qcDocsReviewed, docSet.size);
|
|
128
|
+
}
|
|
129
|
+
} catch { /* skip */ }
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
metrics.qc_batches = qcBatches;
|
|
133
|
+
metrics.qc_docs_reviewed = qcDocsReviewed;
|
|
134
|
+
|
|
89
135
|
return metrics;
|
|
90
136
|
}
|
|
91
137
|
|
|
@@ -126,6 +172,7 @@ th { color: #737373; font-size: 0.85em; }
|
|
|
126
172
|
<div class="metric"><span class="value">${total}</span><br><span class="label">Results</span></div>
|
|
127
173
|
<div class="metric"><span class="value">${metrics.evolution_iterations}</span><br><span class="label">Evolution Cycles</span></div>
|
|
128
174
|
<div class="metric"><span class="value">${metrics.qc_batches}</span><br><span class="label">QC Batches</span></div>
|
|
175
|
+
<div class="metric"><span class="value">${metrics.qc_docs_reviewed || 0}</span><br><span class="label">Docs Reviewed</span></div>
|
|
129
176
|
</div>
|
|
130
177
|
<h2>Confidence Distribution</h2>
|
|
131
178
|
<div class="card">
|
|
@@ -12,14 +12,43 @@ const MIN_CHARS_PER_PAGE = 50;
|
|
|
12
12
|
* Level 3: OCR models via SiliconFlow — fallback via vision models
|
|
13
13
|
*/
|
|
14
14
|
export class DocumentParseTool extends BaseTool {
|
|
15
|
-
|
|
15
|
+
/**
|
|
16
|
+
* @param {object} workspace
|
|
17
|
+
* @param {object} opts
|
|
18
|
+
* @param {string} [opts.mineruApiUrl]
|
|
19
|
+
* @param {string} [opts.mineruApiKey]
|
|
20
|
+
* @param {string} [opts.llmApiKey]
|
|
21
|
+
* @param {string} [opts.llmBaseUrl]
|
|
22
|
+
* @param {string} [opts.ocrModel] — static fallback (legacy)
|
|
23
|
+
* @param {() => string} [opts.getOcrModel] — v0.8.1 P9-B: live-read
|
|
24
|
+
* callback. If provided, takes precedence over `ocrModel`. The
|
|
25
|
+
* constructor used to capture vlmTier1 once at engine startup, but
|
|
26
|
+
* workspace_env_overlay (P1-B) fires AFTER tool construction in
|
|
27
|
+
* some flows (e.g. agent edits .env mid-run, OR overlay applies on
|
|
28
|
+
* a subagent's engine but parent already cached the gc default).
|
|
29
|
+
* E2E #11 资管 v0.8 audit found document_parse errors quoting
|
|
30
|
+
* Qwen3-VL-235B-A22B-Instruct (gc default) even though .env set
|
|
31
|
+
* OCR_MODEL_TIER1=zai-org/GLM-4.6V — the overlay applied 5 min
|
|
32
|
+
* after first failed call. Live-read fixes the race.
|
|
33
|
+
*/
|
|
34
|
+
constructor(workspace, { mineruApiUrl, mineruApiKey, llmApiKey, llmBaseUrl, ocrModel, getOcrModel } = {}) {
|
|
16
35
|
super();
|
|
17
36
|
this._workspace = workspace;
|
|
18
37
|
this._mineruApiUrl = mineruApiUrl || "";
|
|
19
38
|
this._mineruApiKey = mineruApiKey || "";
|
|
20
39
|
this._vlmApiKey = llmApiKey || "";
|
|
21
40
|
this._vlmBaseUrl = (llmBaseUrl || "").replace(/\/+$/, "");
|
|
22
|
-
this.
|
|
41
|
+
this._ocrModelStatic = ocrModel || "";
|
|
42
|
+
this._getOcrModel = typeof getOcrModel === "function" ? getOcrModel : null;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/** Read ocrModel live (P9-B) or fall back to the static value captured at construction. */
|
|
46
|
+
get _ocrModel() {
|
|
47
|
+
if (this._getOcrModel) {
|
|
48
|
+
try { return this._getOcrModel() || this._ocrModelStatic; }
|
|
49
|
+
catch { return this._ocrModelStatic; }
|
|
50
|
+
}
|
|
51
|
+
return this._ocrModelStatic;
|
|
23
52
|
}
|
|
24
53
|
|
|
25
54
|
get name() { return "document_parse"; }
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { BaseTool, ToolResult } from "./base.js";
|
|
2
2
|
import { Phase } from "../pipelines/index.js";
|
|
3
|
+
import { getPrescriptiveHint } from "../pipelines/_advance-hints.js";
|
|
3
4
|
|
|
4
5
|
const VALID_PHASES = new Set(Object.values(Phase));
|
|
5
6
|
|
|
@@ -72,12 +73,12 @@ export class PhaseAdvanceTool extends BaseTool {
|
|
|
72
73
|
|
|
73
74
|
const beforePhase = this._getCurrentPhase();
|
|
74
75
|
// H1: short-circuit the "already in target" case with an informational
|
|
75
|
-
// message —
|
|
76
|
-
//
|
|
77
|
-
//
|
|
76
|
+
// message — agent was trying to advance correctly, engine was already
|
|
77
|
+
// there (from a prior pipeline_event-driven advance or an earlier
|
|
78
|
+
// explicit call). Treat as success, not refusal.
|
|
78
79
|
if (beforePhase && beforePhase === to) {
|
|
79
80
|
return new ToolResult(
|
|
80
|
-
`Already in phase ${to} (engine
|
|
81
|
+
`Already in phase ${to} (engine was already there from a prior advance). Proceed with phase-appropriate work.`,
|
|
81
82
|
);
|
|
82
83
|
}
|
|
83
84
|
|
|
@@ -126,18 +127,21 @@ export class PhaseAdvanceTool extends BaseTool {
|
|
|
126
127
|
// exactly which milestones the gate is reading and can satisfy them.
|
|
127
128
|
// E2E #6 v070 showed the generic "check /status" hint wasn't concrete
|
|
128
129
|
// enough — agents forced through. Naming the gap inline reduces that.
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
130
|
+
// v0.8 P0-E: prescriptive refusal hint — name the artifacts the agent
|
|
131
|
+
// needs to produce, derived from the same paths _milestone-derive.js
|
|
132
|
+
// walks. Replaces the v0.7.x descriptive "check /status" message that
|
|
133
|
+
// 资管 + 贷款 v0.7.5 audits showed agents force-bypassing.
|
|
134
|
+
const prescriptive = getPrescriptiveHint(
|
|
135
|
+
beforePhase,
|
|
136
|
+
advanceResult?.engineCounts,
|
|
137
|
+
advanceResult?.engineCounts || "",
|
|
138
|
+
);
|
|
132
139
|
|
|
133
140
|
return new ToolResult(
|
|
134
141
|
`Did not advance to ${to} (currently in ${beforePhase || "?"}). ` +
|
|
135
|
-
`Likely cause: source-phase exit criteria not met
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
`the engine derives milestones from filesystem facts (rule_skills/<id>/SKILL.md, check.py, ` +
|
|
139
|
-
`workflows/<id>/*.py, output/results/*.json, etc.). ` +
|
|
140
|
-
`If the transition is non-adjacent or this phase truly is done despite the gate, ` +
|
|
142
|
+
`Likely cause: source-phase exit criteria not met.\n\n` +
|
|
143
|
+
prescriptive +
|
|
144
|
+
`\n\nIf the transition is non-adjacent or this phase truly is done despite the gate, ` +
|
|
141
145
|
`re-call with the documented schema flag. The engine logged the precise reason in ` +
|
|
142
146
|
`events.jsonl as 'phase_advance_refused'.`,
|
|
143
147
|
false,
|