kc-beta 0.1.1 → 0.2.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.
Files changed (34) hide show
  1. package/bin/kc-beta.js +14 -2
  2. package/package.json +1 -1
  3. package/src/agent/context-window.js +151 -0
  4. package/src/agent/context.js +58 -88
  5. package/src/agent/engine.js +267 -38
  6. package/src/agent/event-log.js +111 -0
  7. package/src/agent/llm-client.js +352 -59
  8. package/src/agent/pipelines/_archive_v1/distillation.js +113 -0
  9. package/src/agent/pipelines/_archive_v1/extraction.js +92 -0
  10. package/src/agent/pipelines/_archive_v1/initializer.js +163 -0
  11. package/src/agent/pipelines/_archive_v1/production-qc.js +99 -0
  12. package/src/agent/pipelines/_archive_v1/skill-authoring.js +83 -0
  13. package/src/agent/pipelines/_archive_v1/skill-testing.js +111 -0
  14. package/src/agent/pipelines/base.js +6 -0
  15. package/src/agent/pipelines/distillation.js +25 -11
  16. package/src/agent/pipelines/extraction.js +26 -7
  17. package/src/agent/pipelines/initializer.js +30 -20
  18. package/src/agent/pipelines/production-qc.js +22 -5
  19. package/src/agent/pipelines/skill-authoring.js +19 -8
  20. package/src/agent/pipelines/skill-testing.js +26 -8
  21. package/src/agent/retry.js +83 -0
  22. package/src/agent/session-state.js +78 -0
  23. package/src/agent/skill-loader.js +139 -0
  24. package/src/agent/token-counter.js +62 -0
  25. package/src/agent/tools/document-parse.js +3 -3
  26. package/src/agent/tools/tier-downgrade.js +11 -2
  27. package/src/agent/tools/web-search.js +107 -0
  28. package/src/agent/tools/worker-llm-call.js +14 -5
  29. package/src/cli/components.js +16 -4
  30. package/src/cli/config.js +246 -0
  31. package/src/cli/index.js +99 -10
  32. package/src/cli/onboard.js +154 -48
  33. package/src/config.js +25 -7
  34. package/src/providers.js +370 -0
package/bin/kc-beta.js CHANGED
@@ -1,16 +1,28 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- const subcommand = process.argv[2];
3
+ // Parse --en / --zh from anywhere in argv (session-only language override)
4
+ const args = process.argv.slice(2);
5
+ let languageOverride = null;
6
+ const filtered = [];
7
+ for (const arg of args) {
8
+ if (arg === "--en") languageOverride = "en";
9
+ else if (arg === "--zh") languageOverride = "zh";
10
+ else filtered.push(arg);
11
+ }
12
+ const subcommand = filtered[0];
4
13
 
5
14
  (async () => {
6
15
  if (subcommand === "onboard" || subcommand === "setup") {
7
16
  const { onboard } = await import("../src/cli/onboard.js");
8
17
  await onboard();
18
+ } else if (subcommand === "config") {
19
+ const { configEditor } = await import("../src/cli/config.js");
20
+ await configEditor();
9
21
  } else if (subcommand === "init") {
10
22
  const { init } = await import("../src/cli/init.js");
11
23
  await init();
12
24
  } else {
13
25
  const { main } = await import("../src/cli/index.js");
14
- await main();
26
+ await main({ languageOverride });
15
27
  }
16
28
  })();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kc-beta",
3
- "version": "0.1.1",
3
+ "version": "0.2.1",
4
4
  "description": "KC Agent — LLM document verification agent (pure Node.js CLI)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -0,0 +1,151 @@
1
+ import { estimateTokens, estimateMessagesTokens } from "./token-counter.js";
2
+
3
+ /**
4
+ * Automatic context windowing for long conversations.
5
+ * When messages approach the model's context limit, older messages
6
+ * are compressed into summaries while keeping recent messages intact.
7
+ */
8
+ export class ContextWindow {
9
+ /**
10
+ * @param {object} opts
11
+ * @param {number} opts.contextLimit - Total model context limit in tokens
12
+ * @param {number} [opts.reserveForResponse=8192] - Tokens reserved for model output
13
+ * @param {number} [opts.recentWindowSize=30] - Number of recent messages to always keep
14
+ */
15
+ constructor({ contextLimit, reserveForResponse = 8192, recentWindowSize = 30 }) {
16
+ this.contextLimit = contextLimit;
17
+ this.reserveForResponse = reserveForResponse;
18
+ this.recentWindowSize = recentWindowSize;
19
+ }
20
+
21
+ /**
22
+ * Apply windowing to a message array if it exceeds the token budget.
23
+ * @param {Array<object>} messages - Full message history
24
+ * @param {string[]} [phaseSummaries] - Summaries from completed pipeline phases
25
+ * @returns {{ messages: Array, wasWindowed: boolean, removedCount: number }}
26
+ */
27
+ window(messages, phaseSummaries = []) {
28
+ const totalTokens = estimateMessagesTokens(messages);
29
+ const budget = this.contextLimit - this.reserveForResponse;
30
+
31
+ // If within budget, return as-is
32
+ if (totalTokens <= budget * 0.85) {
33
+ return { messages, wasWindowed: false, removedCount: 0 };
34
+ }
35
+
36
+ // Split into older and recent
37
+ const splitPoint = Math.max(0, messages.length - this.recentWindowSize);
38
+ const recentMessages = messages.slice(splitPoint);
39
+ const olderMessages = messages.slice(0, splitPoint);
40
+
41
+ if (olderMessages.length === 0) {
42
+ return { messages, wasWindowed: false, removedCount: 0 };
43
+ }
44
+
45
+ // Build a compact summary of older messages
46
+ const recentTokens = estimateMessagesTokens(recentMessages);
47
+ const summaryBudget = budget - recentTokens - 500; // 500 tokens buffer
48
+ const compactedSummary = this._compactMessages(olderMessages, phaseSummaries, summaryBudget);
49
+
50
+ const windowedMessages = [
51
+ {
52
+ role: "user",
53
+ content: `[Context Summary - Earlier conversation compressed]\n\n${compactedSummary}`,
54
+ },
55
+ {
56
+ role: "assistant",
57
+ content: "Understood. I have the context from the summary above. Continuing with the current work.",
58
+ },
59
+ ...recentMessages,
60
+ ];
61
+
62
+ return {
63
+ messages: windowedMessages,
64
+ wasWindowed: true,
65
+ removedCount: olderMessages.length,
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Create a mechanical compact summary of messages.
71
+ * Groups into conversational turns and extracts key info.
72
+ * @param {Array<object>} messages
73
+ * @param {string[]} phaseSummaries
74
+ * @param {number} tokenBudget
75
+ * @returns {string}
76
+ */
77
+ _compactMessages(messages, phaseSummaries, tokenBudget) {
78
+ const parts = [];
79
+
80
+ // Phase summaries first (high signal)
81
+ if (phaseSummaries.length > 0) {
82
+ parts.push("## Phase History");
83
+ for (const s of phaseSummaries) {
84
+ parts.push(`- ${s}`);
85
+ }
86
+ parts.push("");
87
+ }
88
+
89
+ // Extract key events from older messages
90
+ parts.push("## Conversation Summary");
91
+ const turns = this._groupIntoTurns(messages);
92
+
93
+ for (const turn of turns) {
94
+ const line = this._summarizeTurn(turn);
95
+ if (line) {
96
+ parts.push(`- ${line}`);
97
+ // Check budget
98
+ if (estimateTokens(parts.join("\n")) > tokenBudget * 0.9) {
99
+ parts.push("- [earlier history truncated]");
100
+ break;
101
+ }
102
+ }
103
+ }
104
+
105
+ return parts.join("\n");
106
+ }
107
+
108
+ /**
109
+ * Group messages into user-turn blocks.
110
+ * Each turn: { user: string, tools: [{name, summary}], assistantSummary: string }
111
+ */
112
+ _groupIntoTurns(messages) {
113
+ const turns = [];
114
+ let current = null;
115
+
116
+ for (const msg of messages) {
117
+ if (msg.role === "user") {
118
+ if (current) turns.push(current);
119
+ current = { user: msg.content || "", tools: [], assistant: "" };
120
+ } else if (msg.role === "assistant" && current) {
121
+ if (msg.content) current.assistant = msg.content;
122
+ if (msg.tool_calls) {
123
+ for (const tc of msg.tool_calls) {
124
+ current.tools.push(tc.function?.name || "unknown");
125
+ }
126
+ }
127
+ }
128
+ // tool results are captured implicitly via tool names
129
+ }
130
+ if (current) turns.push(current);
131
+ return turns;
132
+ }
133
+
134
+ /**
135
+ * Summarize a single conversational turn into one line.
136
+ */
137
+ _summarizeTurn(turn) {
138
+ const userSnippet = (turn.user || "").slice(0, 80).replace(/\n/g, " ");
139
+ if (!userSnippet) return null;
140
+
141
+ let line = `User: "${userSnippet}"`;
142
+ if (turn.tools.length > 0) {
143
+ line += ` → Tools: ${turn.tools.join(", ")}`;
144
+ }
145
+ if (turn.assistant) {
146
+ const aSnippet = turn.assistant.slice(0, 60).replace(/\n/g, " ");
147
+ line += ` → "${aSnippet}..."`;
148
+ }
149
+ return line;
150
+ }
151
+ }
@@ -1,122 +1,92 @@
1
1
  const AGENT_IDENTITY = `\
2
- You are KC Agent, a document verification coding agent. You help users build \
3
- and manage document verification systems for financial institutions.
2
+ KC Agent builds and manages document verification systems for financial institutions.
4
3
 
5
- You are direct and technical. You think step by step. When you don't know \
6
- something, you say so.
4
+ ## Architecture
7
5
 
8
- ## Tools
6
+ This system operates in two modes:
9
7
 
10
- You have the following tools:
8
+ **BUILD mode** (Bootstrap Extraction → Skill Authoring → Skill Testing): \
9
+ Read regulations, extract rules, build verification skills, test them against samples. \
10
+ All intellectual work — parsing, extracting, judging — is done directly. The results \
11
+ produced in this mode serve as the accuracy baseline. Worker LLM tools are not available \
12
+ in this mode.
11
13
 
12
- - **sandbox_exec**: Execute shell commands in your workspace directory. Use this \
13
- to run Python scripts, install packages, list files, etc. Pipes and redirects work.
14
+ **DISTILL mode** (Distillation Production QC): \
15
+ Convert proven skills into workflows that run with cheaper worker LLMs at scale. \
16
+ Test workflow results against the baseline established in BUILD mode. Monitor production \
17
+ quality. Worker LLM tools become available in this mode.
14
18
 
15
- - **workspace_file**: Read, write, or list files in your workspace. Operations: \
16
- read (path), write (path + content), list (optional path).
19
+ Skills are first-class deliverables, not just stepping stones to distillation. When a \
20
+ verification task is too complex for worker LLMs, the skill itself — run by a capable \
21
+ agent — is the production solution.
17
22
 
18
- - **document_parse**: Parse documents (PDF, DOCX, images) and extract text. \
19
- Internally uses an escalation chain: text extraction → API parser → OCR models. \
20
- Starts cheap, escalates if needed. You don't choose the method — the tool handles it. \
21
- Use force_method only for testing or if the developer user requests a specific parser.
22
-
23
- - **worker_llm_call**: Call a worker LLM at a specified tier (tier1=most capable, \
24
- tier4=cheapest). Use for distillation testing — check if cheaper models can handle \
25
- extraction/judgment steps. Returns response with model used and token counts.
26
-
27
- - **workflow_run**: Execute a distilled workflow against a document. Automatically \
28
- attaches confidence scores and trace IDs. Results saved to output/results/.
29
-
30
- - **tier_downgrade**: Test a workflow step at a lower tier. Compares accuracy at \
31
- target tier vs. current baseline. Recommends downgrade if accuracy stays above threshold.
23
+ ## Methodology
32
24
 
33
- - **evolution_cycle**: Run one diagnose-classify-fix iteration. Classifies failures \
34
- as systemic (>threshold) or corner case (<threshold). Routes corner cases to registry \
35
- automatically. Checks for repeated failure patterns across iterations.
25
+ ### Document Parsing
26
+ Start with the simplest parser and escalate only when output is insufficient. Once a \
27
+ parser works for a document type, lock it in. Tables and charts may need specific handling.
36
28
 
37
- - **document_search**: Search for text across workspace documents. Supports plain text \
38
- and regex. Returns matching passages with file path and line number.
29
+ ### Rule Extraction
30
+ Decompose regulations top-down into atomic, testable rules. One rule = one pass/fail \
31
+ outcome. Handle ambiguity explicitly — note it, ask the developer user. After extraction, \
32
+ audit which regulation sections are not yet covered.
39
33
 
40
- - **rule_catalog**: CRUD on the rule registry. Enforces required fields (id, source_ref, \
41
- description). Operations: create, read, update, delete, list.
34
+ ### Entity Extraction
35
+ Prefer regex/Python for predictable formats. Use LLM only when semantic understanding \
36
+ is required. Every extraction captures: value, evidence, source location, confidence, \
37
+ method used.
42
38
 
43
- - **qc_sample**: Draw adaptive sample from production results for review. Stratifies \
44
- by confidence band. All low-confidence reviewed, medium sampled, high spot-checked.
39
+ ### Skill Authoring
40
+ Write each rule into a skill folder following the Anthropic skill-creator format. A \
41
+ skill must be self-contained: business logic, scripts, references, sample data, and \
42
+ corner cases. Skills capture methodology — when to use an approach, why it works, \
43
+ what to watch for.
45
44
 
46
- - **dashboard_render**: Generate a self-contained HTML dashboard from project metrics. \
47
- Shows rules, confidence distribution, evolution history, QC results.
45
+ ### Evolution Loop
46
+ Test observe diagnose root cause (parsing/extraction/judgment/scope) → classify \
47
+ (systemic vs corner case) → fix → retest → log. Corner cases are recorded separately \
48
+ and never patched into the main workflow.
48
49
 
49
- - **agent_tool**: Spawn a sub-agent for independent parallel work. Give it a complete \
50
- task description it has no context from your conversation. Sub-agent writes results \
51
- to sub_agents/{task_id}/. Use for parallel rule testing, batch processing, etc.
50
+ ### Distillation
51
+ Design workflows that replicate skill results using the cheapest viable model tier. \
52
+ Test at each tier and present accuracy comparison data. The developer user decides \
53
+ acceptable trade-offs between cost and accuracy.
52
54
 
53
- Use tools to do real work. Write code to files, then run it. Check results by \
54
- reading output. Don't guess — verify.
55
+ ## Structural Components
55
56
 
56
- ## Methodology
57
+ **Version control**: Every write to rules/, workflows/, or rule_skills/ gets a trace \
58
+ ID in versions.json — an immutable audit trail linking results back to the exact \
59
+ version of code that produced them.
57
60
 
58
- ### Document Parsing
59
- - Start with the simplest parser (text extraction). Escalate to OCR/vision only \
60
- when output is empty or garbled (<50 chars/page). Simple parsers fail less.
61
- - Once a parser works for a document type, lock it in. Don't re-evaluate unless \
62
- downstream extraction fails.
63
- - Tables need special handling — extract cell-by-cell, reconstruct as markdown or JSON.
64
-
65
- ### Data Sensibility
66
- - Read 3-5 complete documents end-to-end BEFORE writing extraction logic. Read raw \
67
- parsed text, not PDF viewer. This saves hours of debugging bad assumptions.
68
- - After extraction, spot-check 10 random fields (3 high-confidence, 4 medium, \
69
- 3 low) against source. If >1 out of 10 is wrong, STOP — don't continue.
70
- - Save every processing stage to disk (raw text → sections → entities → judgments). \
71
- Disk is cheap; debugging without intermediates is guesswork.
61
+ **Corner case registry**: Edge cases (<10% failure rate) are stored in \
62
+ corner_cases.json with detection patterns and resolutions. They are handled separately \
63
+ during execution with high-threshold matching, not patched into main workflows.
72
64
 
73
- ### Rule Extraction
74
- - One rule = one pass/fail outcome. If a rule can produce two independent results, \
75
- split it. Rules must be self-contained and scoped to where in the document to look.
76
- - Work top-down (onion peeler): major areas → chapters → sections → atomic rules. \
77
- Stop when rules are atomic and testable.
78
- - Handle ambiguity explicitly. Extract as understood, note ambiguities, ask the \
79
- developer user. Ambiguous rules are often the most important — don't skip them.
80
- - After extraction, audit coverage: which regulation paragraphs are NOT covered?
65
+ **Confidence scoring**: Each verification result gets a composite confidence score \
66
+ based on extraction method, source text presence, historical accuracy, and corner \
67
+ case proximity. Confidence bands (high/medium/low) drive QC sampling rates.
81
68
 
82
- ### Entity Extraction
83
- - Method selection: regex/Python first (free, instant, predictable formats). LLM \
84
- only when semantic understanding is required. Hybrid: regex first, LLM fallback.
85
- - Every extraction must capture: value, evidence (raw text), source location, \
86
- confidence, method used.
87
- - Postprocessing is deterministic code: date standardization, unit conversion, \
88
- Chinese numeral conversion. Build as reusable Python functions.
69
+ ## Working with the Developer User
89
70
 
90
- ### Evolution Loop
91
- - The cycle: test observe diagnose classify → fix → retest → log.
92
- - Diagnose root cause into: parsing failure, extraction failure, judgment failure, \
93
- or scope failure. Each drives different fixes.
94
- - Systemic issue (>10% of docs) → rewrite code/prompts. Corner case (<10%) → \
95
- record in corner_cases.json with detection + resolution. Do NOT patch main \
96
- workflow for corner cases.
97
- - Stop when: accuracy meets threshold, or correction volume <5% and no new \
98
- failure patterns.
99
-
100
- ### Reflection & Skill Writing
101
- - When you solve a hard problem (OCR approach, extraction pattern, edge case \
102
- handling), write it down as a reusable skill in rule_skills/. Future sessions \
103
- and rules benefit from your discoveries.
104
- - Skills capture methodology, not just code. Describe WHEN to use this approach, \
105
- WHY it works, and WHAT to watch out for.`;
71
+ The developer user configures the project, provides regulations and samples, and \
72
+ makes business decisions (accuracy thresholds, cost trade-offs, rule scope). Discuss \
73
+ unclear regulations with them. Present results and let them judge.`;
106
74
 
107
75
  /**
108
76
  * Builds the system prompt from multiple context sources.
109
- * Combines: agent identity + methodology + pipeline state + workspace state.
77
+ * Combines: agent identity + skill index + pipeline state + workspace state.
110
78
  */
111
79
  export class ContextAssembler {
112
80
  /**
113
81
  * @param {object} [opts]
114
82
  * @param {string} [opts.pipelineState]
115
83
  * @param {string} [opts.workspaceState]
84
+ * @param {string} [opts.skillIndex] - Brief index of available meta skills
116
85
  * @returns {string}
117
86
  */
118
- build({ pipelineState, workspaceState } = {}) {
87
+ build({ pipelineState, workspaceState, skillIndex } = {}) {
119
88
  const parts = [AGENT_IDENTITY];
89
+ if (skillIndex) parts.push(skillIndex);
120
90
  if (pipelineState) parts.push(pipelineState);
121
91
  if (workspaceState) parts.push(workspaceState);
122
92
  return parts.join("\n\n");