skyloom 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.github/workflows/ci.yml +36 -0
- package/CONVERSION_PLAN.md +191 -0
- package/README.md +67 -0
- package/dist/agents/dew.d.ts +15 -0
- package/dist/agents/dew.d.ts.map +1 -0
- package/dist/agents/dew.js +74 -0
- package/dist/agents/dew.js.map +1 -0
- package/dist/agents/fair.d.ts +15 -0
- package/dist/agents/fair.d.ts.map +1 -0
- package/dist/agents/fair.js +106 -0
- package/dist/agents/fair.js.map +1 -0
- package/dist/agents/fog.d.ts +15 -0
- package/dist/agents/fog.d.ts.map +1 -0
- package/dist/agents/fog.js +52 -0
- package/dist/agents/fog.js.map +1 -0
- package/dist/agents/frost.d.ts +15 -0
- package/dist/agents/frost.d.ts.map +1 -0
- package/dist/agents/frost.js +54 -0
- package/dist/agents/frost.js.map +1 -0
- package/dist/agents/rain.d.ts +15 -0
- package/dist/agents/rain.d.ts.map +1 -0
- package/dist/agents/rain.js +54 -0
- package/dist/agents/rain.js.map +1 -0
- package/dist/agents/snow.d.ts +27 -0
- package/dist/agents/snow.d.ts.map +1 -0
- package/dist/agents/snow.js +226 -0
- package/dist/agents/snow.js.map +1 -0
- package/dist/cli/main.d.ts +7 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +402 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/mode.d.ts +17 -0
- package/dist/cli/mode.d.ts.map +1 -0
- package/dist/cli/mode.js +56 -0
- package/dist/cli/mode.js.map +1 -0
- package/dist/core/agent.d.ts +174 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +1332 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/agent_helpers.d.ts +51 -0
- package/dist/core/agent_helpers.d.ts.map +1 -0
- package/dist/core/agent_helpers.js +477 -0
- package/dist/core/agent_helpers.js.map +1 -0
- package/dist/core/bus.d.ts +99 -0
- package/dist/core/bus.d.ts.map +1 -0
- package/dist/core/bus.js +191 -0
- package/dist/core/bus.js.map +1 -0
- package/dist/core/cache.d.ts +63 -0
- package/dist/core/cache.d.ts.map +1 -0
- package/dist/core/cache.js +121 -0
- package/dist/core/cache.js.map +1 -0
- package/dist/core/checkpoint.d.ts +19 -0
- package/dist/core/checkpoint.d.ts.map +1 -0
- package/dist/core/checkpoint.js +120 -0
- package/dist/core/checkpoint.js.map +1 -0
- package/dist/core/circuit_breaker.d.ts +46 -0
- package/dist/core/circuit_breaker.d.ts.map +1 -0
- package/dist/core/circuit_breaker.js +99 -0
- package/dist/core/circuit_breaker.js.map +1 -0
- package/dist/core/config.d.ts +97 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +281 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/constants.d.ts +78 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +84 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/factory.d.ts +63 -0
- package/dist/core/factory.d.ts.map +1 -0
- package/dist/core/factory.js +537 -0
- package/dist/core/factory.js.map +1 -0
- package/dist/core/icons.d.ts +28 -0
- package/dist/core/icons.d.ts.map +1 -0
- package/dist/core/icons.js +86 -0
- package/dist/core/icons.js.map +1 -0
- package/dist/core/index.d.ts +29 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +54 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/llm.d.ts +121 -0
- package/dist/core/llm.d.ts.map +1 -0
- package/dist/core/llm.js +532 -0
- package/dist/core/llm.js.map +1 -0
- package/dist/core/logger.d.ts +57 -0
- package/dist/core/logger.d.ts.map +1 -0
- package/dist/core/logger.js +122 -0
- package/dist/core/logger.js.map +1 -0
- package/dist/core/mcp.d.ts +190 -0
- package/dist/core/mcp.d.ts.map +1 -0
- package/dist/core/mcp.js +822 -0
- package/dist/core/mcp.js.map +1 -0
- package/dist/core/mcp_server.d.ts +26 -0
- package/dist/core/mcp_server.d.ts.map +1 -0
- package/dist/core/mcp_server.js +211 -0
- package/dist/core/mcp_server.js.map +1 -0
- package/dist/core/memory.d.ts +190 -0
- package/dist/core/memory.d.ts.map +1 -0
- package/dist/core/memory.js +988 -0
- package/dist/core/memory.js.map +1 -0
- package/dist/core/middleware.d.ts +114 -0
- package/dist/core/middleware.d.ts.map +1 -0
- package/dist/core/middleware.js +248 -0
- package/dist/core/middleware.js.map +1 -0
- package/dist/core/pipelines.d.ts +87 -0
- package/dist/core/pipelines.d.ts.map +1 -0
- package/dist/core/pipelines.js +301 -0
- package/dist/core/pipelines.js.map +1 -0
- package/dist/core/profile.d.ts +23 -0
- package/dist/core/profile.d.ts.map +1 -0
- package/dist/core/profile.js +289 -0
- package/dist/core/profile.js.map +1 -0
- package/dist/core/router.d.ts +24 -0
- package/dist/core/router.d.ts.map +1 -0
- package/dist/core/router.js +111 -0
- package/dist/core/router.js.map +1 -0
- package/dist/core/schemas.d.ts +82 -0
- package/dist/core/schemas.d.ts.map +1 -0
- package/dist/core/schemas.js +200 -0
- package/dist/core/schemas.js.map +1 -0
- package/dist/core/semantic.d.ts +92 -0
- package/dist/core/semantic.d.ts.map +1 -0
- package/dist/core/semantic.js +175 -0
- package/dist/core/semantic.js.map +1 -0
- package/dist/core/skill.d.ts +68 -0
- package/dist/core/skill.d.ts.map +1 -0
- package/dist/core/skill.js +350 -0
- package/dist/core/skill.js.map +1 -0
- package/dist/core/tool.d.ts +99 -0
- package/dist/core/tool.d.ts.map +1 -0
- package/dist/core/tool.js +341 -0
- package/dist/core/tool.js.map +1 -0
- package/dist/core/tool_router.d.ts +29 -0
- package/dist/core/tool_router.d.ts.map +1 -0
- package/dist/core/tool_router.js +172 -0
- package/dist/core/tool_router.js.map +1 -0
- package/dist/core/workspace.d.ts +48 -0
- package/dist/core/workspace.d.ts.map +1 -0
- package/dist/core/workspace.js +179 -0
- package/dist/core/workspace.js.map +1 -0
- package/dist/plugins/loader.d.ts +17 -0
- package/dist/plugins/loader.d.ts.map +1 -0
- package/dist/plugins/loader.js +96 -0
- package/dist/plugins/loader.js.map +1 -0
- package/dist/skills/loader.d.ts +9 -0
- package/dist/skills/loader.d.ts.map +1 -0
- package/dist/skills/loader.js +78 -0
- package/dist/skills/loader.js.map +1 -0
- package/dist/tools/builtin.d.ts +10 -0
- package/dist/tools/builtin.d.ts.map +1 -0
- package/dist/tools/builtin.js +414 -0
- package/dist/tools/builtin.js.map +1 -0
- package/dist/tools/computer.d.ts +12 -0
- package/dist/tools/computer.d.ts.map +1 -0
- package/dist/tools/computer.js +326 -0
- package/dist/tools/computer.js.map +1 -0
- package/dist/tools/delegate.d.ts +10 -0
- package/dist/tools/delegate.d.ts.map +1 -0
- package/dist/tools/delegate.js +45 -0
- package/dist/tools/delegate.js.map +1 -0
- package/dist/web/server.d.ts +5 -0
- package/dist/web/server.d.ts.map +1 -0
- package/dist/web/server.js +647 -0
- package/dist/web/server.js.map +1 -0
- package/dist/web/tts.d.ts +33 -0
- package/dist/web/tts.d.ts.map +1 -0
- package/dist/web/tts.js +69 -0
- package/dist/web/tts.js.map +1 -0
- package/package.json +60 -0
- package/scripts/install.js +48 -0
- package/scripts/link.js +10 -0
- package/setup.bat +79 -0
- package/skill-test-ty2fOA/test.md +10 -0
- package/src/agents/dew.ts +70 -0
- package/src/agents/fair.ts +102 -0
- package/src/agents/fog.ts +48 -0
- package/src/agents/frost.ts +50 -0
- package/src/agents/rain.ts +50 -0
- package/src/agents/snow.ts +239 -0
- package/src/cli/main.ts +405 -0
- package/src/cli/mode.ts +58 -0
- package/src/core/agent.ts +1506 -0
- package/src/core/agent_helpers.ts +461 -0
- package/src/core/bus.ts +221 -0
- package/src/core/cache.ts +153 -0
- package/src/core/checkpoint.ts +94 -0
- package/src/core/circuit_breaker.ts +119 -0
- package/src/core/config.ts +341 -0
- package/src/core/constants.ts +95 -0
- package/src/core/factory.ts +627 -0
- package/src/core/icons.ts +53 -0
- package/src/core/index.ts +31 -0
- package/src/core/llm.ts +724 -0
- package/src/core/logger.ts +144 -0
- package/src/core/mcp.ts +953 -0
- package/src/core/mcp_server.ts +176 -0
- package/src/core/memory.ts +1169 -0
- package/src/core/middleware.ts +350 -0
- package/src/core/pipelines.ts +424 -0
- package/src/core/profile.ts +255 -0
- package/src/core/router.ts +124 -0
- package/src/core/schemas.ts +282 -0
- package/src/core/semantic.ts +211 -0
- package/src/core/skill.ts +342 -0
- package/src/core/tool.ts +427 -0
- package/src/core/tool_router.ts +193 -0
- package/src/core/workspace.ts +150 -0
- package/src/plugins/loader.ts +66 -0
- package/src/skills/loader.ts +46 -0
- package/src/sql.js.d.ts +29 -0
- package/src/tools/builtin.ts +382 -0
- package/src/tools/computer.ts +269 -0
- package/src/tools/delegate.ts +49 -0
- package/src/web/server.ts +634 -0
- package/src/web/tts.ts +93 -0
- package/tests/bus.test.ts +121 -0
- package/tests/icons.test.ts +45 -0
- package/tests/router.test.ts +86 -0
- package/tests/schemas.test.ts +51 -0
- package/tests/semantic.test.ts +83 -0
- package/tests/setup.ts +10 -0
- package/tests/skill.test.ts +172 -0
- package/tests/tool.test.ts +108 -0
- package/tests/tool_router.test.ts +71 -0
- package/tsconfig.json +37 -0
- package/vitest.config.ts +17 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.d.ts","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,IAAI,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,CAAC;AAgCvD;;;;;;GAMG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAiD3C;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,MAAM,CAmB7E"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Complexity router: classify a user goal into direct / single / orchestrate.
|
|
4
|
+
*
|
|
5
|
+
* Rules-first (no LLM), so classification stays under 1ms. The router exists
|
|
6
|
+
* solely to keep simple goals from triggering Snow's full task-decomposition
|
|
7
|
+
* LLM call when a single agent could answer in one shot.
|
|
8
|
+
*/
|
|
9
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
|
+
exports.classify = classify;
|
|
11
|
+
exports.pickAgentForGoal = pickAgentForGoal;
|
|
12
|
+
const MULTI_STEP_TOKENS = [
|
|
13
|
+
'先', '再', '然后', '接着', '之后', '其次', '最后',
|
|
14
|
+
'第一步', '第二步', '第三步', '步骤', '顺序', '依次', '首先',
|
|
15
|
+
'step 1', 'step 2', 'first,', 'then,', 'after that', 'finally',
|
|
16
|
+
];
|
|
17
|
+
const GREETING_TOKENS = [
|
|
18
|
+
'你好', '您好', 'hi', 'hello', 'hey', '在吗', '嗨',
|
|
19
|
+
'早上好', '晚安', '谢谢', 'thanks', 'thank you', '再见', 'bye',
|
|
20
|
+
];
|
|
21
|
+
const SINGLE_ACTION_HINTS = [
|
|
22
|
+
'解释', '什么是', '为什么', '如何', '怎么', '查询', '搜索',
|
|
23
|
+
'搜一下', '翻译', '总结', 'summarize', 'explain', 'what is', 'why', 'how do',
|
|
24
|
+
];
|
|
25
|
+
const ACTION_VERBS = [
|
|
26
|
+
'写', '帮我写', '生成', '创建', '实现', '做', '搜', '查',
|
|
27
|
+
'找', '审查', '审计', '翻译', '重构', '修改', '改', '部署',
|
|
28
|
+
'运行', '执行',
|
|
29
|
+
'write', 'create', 'generate', 'implement', 'search', 'find',
|
|
30
|
+
'review', 'translate', 'deploy', 'run',
|
|
31
|
+
];
|
|
32
|
+
const CODE_BLOCK = /```[\s\S]+?```/;
|
|
33
|
+
const URL_PATTERN = /https?:\/\/\S+/;
|
|
34
|
+
const PATH_PATTERN = /(?:[A-Za-z]:[\\/]|[\\/])[\w\-./\\]+/;
|
|
35
|
+
const NUMBERED_LIST = /(?:^|\n)\s*(?:\d+[.)、]|[-*])\s+/gm;
|
|
36
|
+
const INLINE_ENUMERATED = /\b\d+[.)、]\s*\S/g;
|
|
37
|
+
/**
|
|
38
|
+
* Decide the execution mode for a user goal.
|
|
39
|
+
*
|
|
40
|
+
* direct: short greeting / single factual question, no tools needed.
|
|
41
|
+
* single: clear single-purpose task, one agent + tools.
|
|
42
|
+
* orchestrate: multi-step plan worth decomposing into sub-tasks.
|
|
43
|
+
*/
|
|
44
|
+
function classify(goal) {
|
|
45
|
+
if (!goal || !goal.trim())
|
|
46
|
+
return 'direct';
|
|
47
|
+
const text = goal.trim();
|
|
48
|
+
const lower = text.toLowerCase();
|
|
49
|
+
const length = text.length;
|
|
50
|
+
const hasCode = CODE_BLOCK.test(text);
|
|
51
|
+
const hasUrl = URL_PATTERN.test(text);
|
|
52
|
+
const hasPath = PATH_PATTERN.test(text);
|
|
53
|
+
const listMatches = (text.match(NUMBERED_LIST) || []).length;
|
|
54
|
+
const inlineEnumHits = (text.match(INLINE_ENUMERATED) || []).length;
|
|
55
|
+
const multiStepHits = MULTI_STEP_TOKENS.filter(t => lower.includes(t)).length;
|
|
56
|
+
const greetingHits = GREETING_TOKENS.filter(t => lower.includes(t)).length;
|
|
57
|
+
const singleHits = SINGLE_ACTION_HINTS.filter(t => lower.includes(t)).length;
|
|
58
|
+
const actionHits = ACTION_VERBS.filter(t => lower.includes(t)).length;
|
|
59
|
+
if (greetingHits >= 1 && length < 30 && multiStepHits === 0 && actionHits === 0) {
|
|
60
|
+
return 'direct';
|
|
61
|
+
}
|
|
62
|
+
if (multiStepHits >= 2 || listMatches >= 2 || inlineEnumHits >= 3) {
|
|
63
|
+
return 'orchestrate';
|
|
64
|
+
}
|
|
65
|
+
if (length > 200 && multiStepHits >= 1) {
|
|
66
|
+
return 'orchestrate';
|
|
67
|
+
}
|
|
68
|
+
if (hasCode && length > 150) {
|
|
69
|
+
return 'orchestrate';
|
|
70
|
+
}
|
|
71
|
+
// Tool-use signals push toward single, not direct
|
|
72
|
+
if (hasPath || hasUrl || actionHits >= 1) {
|
|
73
|
+
return 'single';
|
|
74
|
+
}
|
|
75
|
+
if (length < 50 && !hasCode) {
|
|
76
|
+
if (singleHits >= 1 || text.endsWith('?') || text.endsWith('?')) {
|
|
77
|
+
return 'direct';
|
|
78
|
+
}
|
|
79
|
+
if (multiStepHits === 0) {
|
|
80
|
+
return 'direct';
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return 'single';
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Pick a single agent for a non-orchestrate goal, by keyword routing.
|
|
87
|
+
*
|
|
88
|
+
* Returns an agent name guaranteed to be in available, falling back to
|
|
89
|
+
* rain (generation generalist) then to any available agent.
|
|
90
|
+
*/
|
|
91
|
+
function pickAgentForGoal(goal, available) {
|
|
92
|
+
const lower = goal.toLowerCase();
|
|
93
|
+
// More specific buckets first
|
|
94
|
+
const buckets = [
|
|
95
|
+
['frost', ['审查', 'review', '漏洞', '安全', '审计', 'lint', '重构建议', 'code smell']],
|
|
96
|
+
['dew', ['部署', '运行', '执行命令', 'shell', 'deploy', 'ci', 'cd', '环境变量', '运维']],
|
|
97
|
+
['fog', ['研究', '调研', '搜一下', '搜索', '查一下', '查资料', 'research', 'search', '调查', '找一下', '找资料']],
|
|
98
|
+
['rain', ['写', '生成', '实现', 'create', 'generate', '写一段', '写个', '代码', '函数', '实现一个']],
|
|
99
|
+
['fair', ['陪我', '聊天', '心情', '难过', '开心', '孤独', '倾诉', '你好', 'hi', 'hello', '嗨']],
|
|
100
|
+
];
|
|
101
|
+
for (const [agent, hints] of buckets) {
|
|
102
|
+
if (!available.has(agent))
|
|
103
|
+
continue;
|
|
104
|
+
if (hints.some(h => lower.includes(h)))
|
|
105
|
+
return agent;
|
|
106
|
+
}
|
|
107
|
+
if (available.has('rain'))
|
|
108
|
+
return 'rain';
|
|
109
|
+
return Array.from(available)[0];
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=router.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"router.js","sourceRoot":"","sources":["../../src/core/router.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight structured output schemas for LLM response validation.
|
|
3
|
+
*
|
|
4
|
+
* Why: LLM JSON output is inherently fragile — models emit markdown fences,
|
|
5
|
+
* trailing commas, unquoted keys, or hallucinated fields. Rather than layering
|
|
6
|
+
* heuristic repair (which silently passes corrupted data), we define typed
|
|
7
|
+
* schemas and validate on ingress. Parsing failures surface immediately so the
|
|
8
|
+
* caller can retry with a corrected prompt instead of propagating garbage.
|
|
9
|
+
*
|
|
10
|
+
* Zero external dependencies: uses only JSON and TypeScript types.
|
|
11
|
+
*/
|
|
12
|
+
/**
|
|
13
|
+
* Error raised when an LLM response fails schema validation.
|
|
14
|
+
* Carries both a human-readable message and the raw text so callers
|
|
15
|
+
* can log / retry with full context.
|
|
16
|
+
*/
|
|
17
|
+
export declare class SchemaValidationError extends Error {
|
|
18
|
+
raw: string;
|
|
19
|
+
constructor(message: string, raw?: string);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* One step in a task plan (mirrors PipelineStep / Task)
|
|
23
|
+
*/
|
|
24
|
+
export interface TaskStepSchema {
|
|
25
|
+
id: string | number;
|
|
26
|
+
description: string;
|
|
27
|
+
agent?: string;
|
|
28
|
+
depends_on?: string[];
|
|
29
|
+
priority?: "low" | "medium" | "high";
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Full task plan output from Snow's orchestrator
|
|
33
|
+
*/
|
|
34
|
+
export interface TaskPlanSchema {
|
|
35
|
+
goal: string;
|
|
36
|
+
steps: TaskStepSchema[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* A single extracted fact for long-term memory
|
|
40
|
+
*/
|
|
41
|
+
export interface FactSchema {
|
|
42
|
+
key: string;
|
|
43
|
+
value: string;
|
|
44
|
+
category?: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Structured fact-extraction output from the LLM
|
|
48
|
+
*/
|
|
49
|
+
export interface ExtractionResultSchema {
|
|
50
|
+
facts: FactSchema[];
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Tool call schema for LLM responses
|
|
54
|
+
*/
|
|
55
|
+
export interface ToolCallSchema {
|
|
56
|
+
name: string;
|
|
57
|
+
arguments: Record<string, unknown>;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Message schema for agent communication
|
|
61
|
+
*/
|
|
62
|
+
export interface MessageSchema {
|
|
63
|
+
role: "user" | "assistant" | "tool";
|
|
64
|
+
content: string;
|
|
65
|
+
tool_calls?: ToolCallSchema[];
|
|
66
|
+
tool_call_id?: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse a raw LLM response string into a typed JSON object.
|
|
70
|
+
* Handles markdown fences, leading/trailing text, and minor JSON quirks.
|
|
71
|
+
* Raises SchemaValidationError on failure.
|
|
72
|
+
*/
|
|
73
|
+
export declare function parseSchema<T extends Record<string, unknown>>(raw: string, schemaType?: new () => T): T;
|
|
74
|
+
/**
|
|
75
|
+
* Validate task plan schema
|
|
76
|
+
*/
|
|
77
|
+
export declare function validateTaskPlan(data: unknown): TaskPlanSchema;
|
|
78
|
+
/**
|
|
79
|
+
* Validate extraction result schema
|
|
80
|
+
*/
|
|
81
|
+
export declare function validateExtractionResult(data: unknown): ExtractionResultSchema;
|
|
82
|
+
//# sourceMappingURL=schemas.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.d.ts","sourceRoot":"","sources":["../../src/core/schemas.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,GAAG,EAAE,MAAM,CAAC;gBAEA,OAAO,EAAE,MAAM,EAAE,GAAG,GAAE,MAAW;CAK9C;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;CACtC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,UAAU,EAAE,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACpC;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,WAAW,GAAG,MAAM,CAAC;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAuFD;;;;GAIG;AACH,wBAAgB,WAAW,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC3D,GAAG,EAAE,MAAM,EACX,UAAU,CAAC,EAAE,UAAU,CAAC,GACvB,CAAC,CAuBH;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,OAAO,GAAG,cAAc,CA4C9D;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CAAC,IAAI,EAAE,OAAO,GAAG,sBAAsB,CA+B9E"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Lightweight structured output schemas for LLM response validation.
|
|
4
|
+
*
|
|
5
|
+
* Why: LLM JSON output is inherently fragile — models emit markdown fences,
|
|
6
|
+
* trailing commas, unquoted keys, or hallucinated fields. Rather than layering
|
|
7
|
+
* heuristic repair (which silently passes corrupted data), we define typed
|
|
8
|
+
* schemas and validate on ingress. Parsing failures surface immediately so the
|
|
9
|
+
* caller can retry with a corrected prompt instead of propagating garbage.
|
|
10
|
+
*
|
|
11
|
+
* Zero external dependencies: uses only JSON and TypeScript types.
|
|
12
|
+
*/
|
|
13
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
14
|
+
exports.SchemaValidationError = void 0;
|
|
15
|
+
exports.parseSchema = parseSchema;
|
|
16
|
+
exports.validateTaskPlan = validateTaskPlan;
|
|
17
|
+
exports.validateExtractionResult = validateExtractionResult;
|
|
18
|
+
/**
|
|
19
|
+
* Error raised when an LLM response fails schema validation.
|
|
20
|
+
* Carries both a human-readable message and the raw text so callers
|
|
21
|
+
* can log / retry with full context.
|
|
22
|
+
*/
|
|
23
|
+
class SchemaValidationError extends Error {
|
|
24
|
+
constructor(message, raw = "") {
|
|
25
|
+
super(message);
|
|
26
|
+
this.name = "SchemaValidationError";
|
|
27
|
+
this.raw = raw;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
exports.SchemaValidationError = SchemaValidationError;
|
|
31
|
+
/**
|
|
32
|
+
* Coerce a value to a target type with best-effort conversion
|
|
33
|
+
*/
|
|
34
|
+
function coerceType(value, targetType) {
|
|
35
|
+
if (value === null || value === undefined) {
|
|
36
|
+
return value;
|
|
37
|
+
}
|
|
38
|
+
switch (targetType) {
|
|
39
|
+
case "string":
|
|
40
|
+
return String(value);
|
|
41
|
+
case "number":
|
|
42
|
+
return Number(value);
|
|
43
|
+
case "boolean":
|
|
44
|
+
return Boolean(value);
|
|
45
|
+
case "array":
|
|
46
|
+
return Array.isArray(value) ? value : [];
|
|
47
|
+
case "object":
|
|
48
|
+
return typeof value === "object" ? value : {};
|
|
49
|
+
default:
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Extract JSON object/array from a potentially malformed string
|
|
55
|
+
*/
|
|
56
|
+
function extractJSON(text) {
|
|
57
|
+
let cleaned = text.trim();
|
|
58
|
+
// Strip markdown code fences
|
|
59
|
+
if (cleaned.includes("```")) {
|
|
60
|
+
for (const fence of ["```json", "```"]) {
|
|
61
|
+
if (cleaned.includes(fence)) {
|
|
62
|
+
const after = cleaned.split(fence, 1)[1];
|
|
63
|
+
if (after && after.includes("```")) {
|
|
64
|
+
cleaned = after.split("```")[0].trim();
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
// Find first JSON object or array
|
|
71
|
+
let objStart = -1;
|
|
72
|
+
let depth = 0;
|
|
73
|
+
for (let i = 0; i < cleaned.length; i++) {
|
|
74
|
+
const ch = cleaned[i];
|
|
75
|
+
if (ch === "{") {
|
|
76
|
+
if (objStart < 0)
|
|
77
|
+
objStart = i;
|
|
78
|
+
depth++;
|
|
79
|
+
}
|
|
80
|
+
else if (ch === "}") {
|
|
81
|
+
depth--;
|
|
82
|
+
if (depth === 0 && objStart >= 0) {
|
|
83
|
+
return cleaned.substring(objStart, i + 1);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
// If still not closed, close with extra braces
|
|
88
|
+
if (objStart >= 0) {
|
|
89
|
+
return cleaned.substring(objStart) + "}".repeat(depth);
|
|
90
|
+
}
|
|
91
|
+
throw new SchemaValidationError("No valid JSON found in response", text);
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Repair common JSON issues (trailing commas, unquoted keys, etc.)
|
|
95
|
+
*/
|
|
96
|
+
function repairJSON(text) {
|
|
97
|
+
let repaired = text;
|
|
98
|
+
// Remove trailing commas
|
|
99
|
+
repaired = repaired.replace(/,\s*([}\]])/g, "$1");
|
|
100
|
+
// Quote unquoted keys
|
|
101
|
+
repaired = repaired.replace(/(?<!["\'\w])(\w[\w\d_]*)(\s*:)/g, '"$1"$2');
|
|
102
|
+
// Normalize quotes
|
|
103
|
+
repaired = repaired.replace(/'/g, '"').replace(/`/g, '"');
|
|
104
|
+
return repaired;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Parse a raw LLM response string into a typed JSON object.
|
|
108
|
+
* Handles markdown fences, leading/trailing text, and minor JSON quirks.
|
|
109
|
+
* Raises SchemaValidationError on failure.
|
|
110
|
+
*/
|
|
111
|
+
function parseSchema(raw, schemaType) {
|
|
112
|
+
if (!raw || !raw.trim()) {
|
|
113
|
+
throw new SchemaValidationError("empty response", raw);
|
|
114
|
+
}
|
|
115
|
+
try {
|
|
116
|
+
const extracted = extractJSON(raw);
|
|
117
|
+
let data = JSON.parse(extracted);
|
|
118
|
+
return data;
|
|
119
|
+
}
|
|
120
|
+
catch (error) {
|
|
121
|
+
if (error instanceof SchemaValidationError)
|
|
122
|
+
throw error;
|
|
123
|
+
try {
|
|
124
|
+
const repaired = repairJSON(raw);
|
|
125
|
+
const data = JSON.parse(repaired);
|
|
126
|
+
return data;
|
|
127
|
+
}
|
|
128
|
+
catch (repairError) {
|
|
129
|
+
throw new SchemaValidationError(`JSON parse failed: ${error.message}`, raw);
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Validate task plan schema
|
|
135
|
+
*/
|
|
136
|
+
function validateTaskPlan(data) {
|
|
137
|
+
if (!data || typeof data !== "object") {
|
|
138
|
+
throw new SchemaValidationError("Invalid task plan: must be an object");
|
|
139
|
+
}
|
|
140
|
+
const plan = data;
|
|
141
|
+
if (typeof plan.goal !== "string") {
|
|
142
|
+
throw new SchemaValidationError("Invalid task plan: goal must be a string");
|
|
143
|
+
}
|
|
144
|
+
if (!Array.isArray(plan.steps)) {
|
|
145
|
+
throw new SchemaValidationError("Invalid task plan: steps must be an array");
|
|
146
|
+
}
|
|
147
|
+
const steps = plan.steps.map((step) => {
|
|
148
|
+
if (!step || typeof step !== "object") {
|
|
149
|
+
throw new SchemaValidationError("Invalid task plan: step must be an object");
|
|
150
|
+
}
|
|
151
|
+
const s = step;
|
|
152
|
+
if (typeof s.id !== "string" && typeof s.id !== "number") {
|
|
153
|
+
throw new SchemaValidationError("Invalid task plan: step.id must be string or number");
|
|
154
|
+
}
|
|
155
|
+
if (typeof s.description !== "string") {
|
|
156
|
+
throw new SchemaValidationError("Invalid task plan: step.description must be a string");
|
|
157
|
+
}
|
|
158
|
+
return {
|
|
159
|
+
id: s.id,
|
|
160
|
+
description: s.description,
|
|
161
|
+
agent: typeof s.agent === "string" ? s.agent : "rain",
|
|
162
|
+
depends_on: Array.isArray(s.depends_on) ? s.depends_on : [],
|
|
163
|
+
priority: (["low", "medium", "high"].includes(s.priority)
|
|
164
|
+
? s.priority
|
|
165
|
+
: "medium"),
|
|
166
|
+
};
|
|
167
|
+
});
|
|
168
|
+
return {
|
|
169
|
+
goal: plan.goal,
|
|
170
|
+
steps,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
/**
|
|
174
|
+
* Validate extraction result schema
|
|
175
|
+
*/
|
|
176
|
+
function validateExtractionResult(data) {
|
|
177
|
+
if (!data || typeof data !== "object") {
|
|
178
|
+
throw new SchemaValidationError("Invalid extraction result: must be an object");
|
|
179
|
+
}
|
|
180
|
+
const result = data;
|
|
181
|
+
if (!Array.isArray(result.facts)) {
|
|
182
|
+
throw new SchemaValidationError("Invalid extraction result: facts must be an array");
|
|
183
|
+
}
|
|
184
|
+
const facts = result.facts.map((fact) => {
|
|
185
|
+
if (!fact || typeof fact !== "object") {
|
|
186
|
+
throw new SchemaValidationError("Invalid extraction result: fact must be an object");
|
|
187
|
+
}
|
|
188
|
+
const f = fact;
|
|
189
|
+
if (typeof f.key !== "string" || typeof f.value !== "string") {
|
|
190
|
+
throw new SchemaValidationError("Invalid extraction result: fact must have key and value strings");
|
|
191
|
+
}
|
|
192
|
+
return {
|
|
193
|
+
key: f.key,
|
|
194
|
+
value: f.value,
|
|
195
|
+
category: typeof f.category === "string" ? f.category : "auto_extracted",
|
|
196
|
+
};
|
|
197
|
+
});
|
|
198
|
+
return { facts };
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=schemas.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schemas.js","sourceRoot":"","sources":["../../src/core/schemas.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;GAUG;;;AAgKH,kCA0BC;AAKD,4CA4CC;AAKD,4DA+BC;AA7QD;;;;GAIG;AACH,MAAa,qBAAsB,SAAQ,KAAK;IAG9C,YAAY,OAAe,EAAE,MAAc,EAAE;QAC3C,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,uBAAuB,CAAC;QACpC,IAAI,CAAC,GAAG,GAAG,GAAG,CAAC;IACjB,CAAC;CACF;AARD,sDAQC;AAuDD;;GAEG;AACH,SAAS,UAAU,CAAC,KAAc,EAAE,UAAkB;IACpD,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,KAAK,CAAC;IACf,CAAC;IAED,QAAQ,UAAU,EAAE,CAAC;QACnB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QACvB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;QACvB,KAAK,SAAS;YACZ,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;QACxB,KAAK,OAAO;YACV,OAAO,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3C,KAAK,QAAQ;YACX,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;QAChD;YACE,OAAO,KAAK,CAAC;IACjB,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAS,WAAW,CAAC,IAAY;IAC/B,IAAI,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE1B,6BAA6B;IAC7B,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC5B,KAAK,MAAM,KAAK,IAAI,CAAC,SAAS,EAAE,KAAK,CAAC,EAAE,CAAC;YACvC,IAAI,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;gBAC5B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;gBACzC,IAAI,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;oBACnC,OAAO,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;oBACvC,MAAM;gBACR,CAAC;YACH,CAAC;QACH,CAAC;IACH,CAAC;IAED,kCAAkC;IAClC,IAAI,QAAQ,GAAG,CAAC,CAAC,CAAC;IAClB,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACxC,MAAM,EAAE,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;QACtB,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACf,IAAI,QAAQ,GAAG,CAAC;gBAAE,QAAQ,GAAG,CAAC,CAAC;YAC/B,KAAK,EAAE,CAAC;QACV,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACtB,KAAK,EAAE,CAAC;YACR,IAAI,KAAK,KAAK,CAAC,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;gBACjC,OAAO,OAAO,CAAC,SAAS,CAAC,QAAQ,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAED,+CAA+C;IAC/C,IAAI,QAAQ,IAAI,CAAC,EAAE,CAAC;QAClB,OAAO,OAAO,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IACzD,CAAC;IAED,MAAM,IAAI,qBAAqB,CAAC,iCAAiC,EAAE,IAAI,CAAC,CAAC;AAC3E,CAAC;AAED;;GAEG;AACH,SAAS,UAAU,CAAC,IAAY;IAC9B,IAAI,QAAQ,GAAG,IAAI,CAAC;IAEpB,yBAAyB;IACzB,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,cAAc,EAAE,IAAI,CAAC,CAAC;IAElD,sBAAsB;IACtB,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,iCAAiC,EAAE,QAAQ,CAAC,CAAC;IAEzE,mBAAmB;IACnB,QAAQ,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAE1D,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED;;;;GAIG;AACH,SAAgB,WAAW,CACzB,GAAW,EACX,UAAwB;IAExB,IAAI,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC;QACxB,MAAM,IAAI,qBAAqB,CAAC,gBAAgB,EAAE,GAAG,CAAC,CAAC;IACzD,CAAC;IAED,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;QACnC,IAAI,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC;QACjC,OAAO,IAAS,CAAC;IACnB,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,qBAAqB;YAAE,MAAM,KAAK,CAAC;QAExD,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC;YACjC,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;YAClC,OAAO,IAAS,CAAC;QACnB,CAAC;QAAC,OAAO,WAAW,EAAE,CAAC;YACrB,MAAM,IAAI,qBAAqB,CAC7B,sBAAuB,KAAe,CAAC,OAAO,EAAE,EAChD,GAAG,CACJ,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,IAAa;IAC5C,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,qBAAqB,CAAC,sCAAsC,CAAC,CAAC;IAC1E,CAAC;IAED,MAAM,IAAI,GAAG,IAA+B,CAAC;IAE7C,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;QAClC,MAAM,IAAI,qBAAqB,CAAC,0CAA0C,CAAC,CAAC;IAC9E,CAAC;IAED,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAC/B,MAAM,IAAI,qBAAqB,CAAC,2CAA2C,CAAC,CAAC;IAC/E,CAAC;IAED,MAAM,KAAK,GAAI,IAAI,CAAC,KAAmB,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE;QAC5D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,qBAAqB,CAAC,2CAA2C,CAAC,CAAC;QAC/E,CAAC;QAED,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,EAAE,KAAK,QAAQ,EAAE,CAAC;YACzD,MAAM,IAAI,qBAAqB,CAAC,qDAAqD,CAAC,CAAC;QACzF,CAAC;QAED,IAAI,OAAO,CAAC,CAAC,WAAW,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,qBAAqB,CAAC,sDAAsD,CAAC,CAAC;QAC1F,CAAC;QAED,OAAO;YACL,EAAE,EAAE,CAAC,CAAC,EAAE;YACR,WAAW,EAAE,CAAC,CAAC,WAAW;YAC1B,KAAK,EAAE,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;YACrD,UAAU,EAAE,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAE,CAAC,CAAC,UAAuB,CAAC,CAAC,CAAC,EAAE;YACzE,QAAQ,EAAE,CAAC,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,QAAkB,CAAC;gBACjE,CAAC,CAAC,CAAC,CAAC,QAAQ;gBACZ,CAAC,CAAC,QAAQ,CAA8B;SAC3C,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO;QACL,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,KAAK;KACN,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,SAAgB,wBAAwB,CAAC,IAAa;IACpD,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QACtC,MAAM,IAAI,qBAAqB,CAAC,8CAA8C,CAAC,CAAC;IAClF,CAAC;IAED,MAAM,MAAM,GAAG,IAA+B,CAAC;IAE/C,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;QACjC,MAAM,IAAI,qBAAqB,CAAC,mDAAmD,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,KAAK,GAAI,MAAM,CAAC,KAAmB,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,EAAE;QAC9D,IAAI,CAAC,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACtC,MAAM,IAAI,qBAAqB,CAAC,mDAAmD,CAAC,CAAC;QACvF,CAAC;QAED,MAAM,CAAC,GAAG,IAA+B,CAAC;QAC1C,IAAI,OAAO,CAAC,CAAC,GAAG,KAAK,QAAQ,IAAI,OAAO,CAAC,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC7D,MAAM,IAAI,qBAAqB,CAC7B,iEAAiE,CAClE,CAAC;QACJ,CAAC;QAED,OAAO;YACL,GAAG,EAAE,CAAC,CAAC,GAAG;YACV,KAAK,EAAE,CAAC,CAAC,KAAK;YACd,QAAQ,EAAE,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,gBAAgB;SACzE,CAAC;IACJ,CAAC,CAAC,CAAC;IAEH,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC"}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Lightweight semantic retrieval — zero external dependencies.
|
|
3
|
+
*
|
|
4
|
+
* Why: The existing `recall_for_injection` uses SQL LIKE on tokens, which
|
|
5
|
+
* misses semantically related facts that share few literal characters (e.g.
|
|
6
|
+
* query "deploy" vs. stored fact "release_command"). This module provides
|
|
7
|
+
* a character n-gram Jaccard similarity scorer that catches those cross-
|
|
8
|
+
* lingual and synonym relationships without adding PyTorch / sentence-transformers.
|
|
9
|
+
*
|
|
10
|
+
* Design:
|
|
11
|
+
* - Character n-grams (size 2-4) naturally handle CJK, mixed-language, and
|
|
12
|
+
* code identifiers better than word-level tokenization.
|
|
13
|
+
* - Jaccard similarity on n-gram sets is fast (< 10 µs per pair) and
|
|
14
|
+
* well-correlated with human relevance judgments for short text.
|
|
15
|
+
* - Zero dependencies beyond stdlib.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Represents a candidate item for ranking
|
|
19
|
+
*/
|
|
20
|
+
export interface Candidate {
|
|
21
|
+
key?: string;
|
|
22
|
+
value?: string | Record<string, unknown>;
|
|
23
|
+
[key: string]: unknown;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Character n-gram semantic similarity scorer.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* ```
|
|
30
|
+
* const scorer = new SemanticScorer();
|
|
31
|
+
* const score = scorer.similarity("deploy to prod", "release_command");
|
|
32
|
+
* // score ≈ 0.15 (low but non-zero — catches partial overlap)
|
|
33
|
+
*
|
|
34
|
+
* const ranked = scorer.rank(
|
|
35
|
+
* "search query",
|
|
36
|
+
* [{value: "candidate A"}, {value: "candidate B"}]
|
|
37
|
+
* );
|
|
38
|
+
* // ranked → [[0.85, {value: "candidate A"}], [0.30, {value: "candidate B"}]]
|
|
39
|
+
* ```
|
|
40
|
+
*/
|
|
41
|
+
export declare class SemanticScorer {
|
|
42
|
+
private nRange;
|
|
43
|
+
private cache;
|
|
44
|
+
private maxCacheSize;
|
|
45
|
+
/**
|
|
46
|
+
* Initialize scorer with n-gram range.
|
|
47
|
+
* @param nRange - Tuple of [minSize, maxSize] for n-grams (default [2, 4])
|
|
48
|
+
*/
|
|
49
|
+
constructor(nRange?: [number, number]);
|
|
50
|
+
/**
|
|
51
|
+
* Generate character n-gram fingerprint (cached).
|
|
52
|
+
* @param text - Input text to fingerprint
|
|
53
|
+
* @returns Set of n-grams for the text
|
|
54
|
+
*/
|
|
55
|
+
private fingerprint;
|
|
56
|
+
/**
|
|
57
|
+
* Calculate Jaccard similarity between two texts using character n-grams.
|
|
58
|
+
* @param a - First text
|
|
59
|
+
* @param b - Second text
|
|
60
|
+
* @returns Similarity score between 0 and 1
|
|
61
|
+
*/
|
|
62
|
+
similarity(a: string, b: string): number;
|
|
63
|
+
/**
|
|
64
|
+
* Rank candidates by semantic similarity to the query.
|
|
65
|
+
*
|
|
66
|
+
* Each candidate is a dict. The scorer reads `candidate[keyField]`
|
|
67
|
+
* for text to compare. Also scores the "key" field if present.
|
|
68
|
+
* Returns `[score, candidate]` tuples sorted descending, filtered by `minScore`.
|
|
69
|
+
*
|
|
70
|
+
* @param query - Query string to match against
|
|
71
|
+
* @param candidates - Array of candidate objects
|
|
72
|
+
* @param keyField - Field name to extract text from (default "value")
|
|
73
|
+
* @param topK - Maximum number of results to return (default 3)
|
|
74
|
+
* @param minScore - Minimum similarity threshold (default 0.02)
|
|
75
|
+
* @returns Array of [score, candidate] tuples, sorted by score descending
|
|
76
|
+
*/
|
|
77
|
+
rank(query: string, candidates: Candidate[], keyField?: string, topK?: number, minScore?: number): Array<[number, Candidate]>;
|
|
78
|
+
/**
|
|
79
|
+
* Clear the fingerprint cache.
|
|
80
|
+
*/
|
|
81
|
+
clearCache(): void;
|
|
82
|
+
/**
|
|
83
|
+
* Get current cache size.
|
|
84
|
+
*/
|
|
85
|
+
getCacheSize(): number;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Get or create the module-level semantic scorer singleton.
|
|
89
|
+
* @returns SemanticScorer instance
|
|
90
|
+
*/
|
|
91
|
+
export declare function getScorer(): SemanticScorer;
|
|
92
|
+
//# sourceMappingURL=semantic.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"semantic.d.ts","sourceRoot":"","sources":["../../src/core/semantic.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACzC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAmB;IACjC,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,YAAY,CAAO;IAE3B;;;OAGG;gBACS,MAAM,GAAE,CAAC,MAAM,EAAE,MAAM,CAAU;IAK7C;;;;OAIG;IACH,OAAO,CAAC,WAAW;IA2BnB;;;;;OAKG;IACH,UAAU,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM;IA0BxC;;;;;;;;;;;;;OAaG;IACH,IAAI,CACF,KAAK,EAAE,MAAM,EACb,UAAU,EAAE,SAAS,EAAE,EACvB,QAAQ,GAAE,MAAgB,EAC1B,IAAI,GAAE,MAAU,EAChB,QAAQ,GAAE,MAAa,GACtB,KAAK,CAAC,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAyC7B;;OAEG;IACH,UAAU,IAAI,IAAI;IAIlB;;OAEG;IACH,YAAY,IAAI,MAAM;CAGvB;AAOD;;;GAGG;AACH,wBAAgB,SAAS,IAAI,cAAc,CAK1C"}
|