uneven-ai 1.2.2 → 1.3.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/CHANGELOG.md +19 -0
- package/README.md +1 -1
- package/dist/application/orchestration/engine/ask/brain.d.ts +2 -8
- package/dist/application/orchestration/engine/ask/brain.d.ts.map +1 -1
- package/dist/application/orchestration/engine/ask/brain.js +16 -14
- package/dist/application/orchestration/engine/ask/chat-template.d.ts +9 -0
- package/dist/application/orchestration/engine/ask/chat-template.d.ts.map +1 -0
- package/dist/application/orchestration/engine/ask/chat-template.js +82 -0
- package/dist/application/orchestration/engine/ask/context-assembler.js +3 -3
- package/dist/application/orchestration/engine/ask/prompts.d.ts +2 -0
- package/dist/application/orchestration/engine/ask/prompts.d.ts.map +1 -1
- package/dist/application/orchestration/engine/ask/prompts.js +7 -12
- package/dist/application/orchestration/engine/ask.js +3 -13
- package/dist/cli/commands/ask.d.ts.map +1 -1
- package/dist/cli/commands/ask.js +1 -0
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +1 -0
- package/dist/cli/commands/docs.d.ts.map +1 -1
- package/dist/cli/commands/docs.js +1 -0
- package/dist/cli/commands/explain.d.ts.map +1 -1
- package/dist/cli/commands/explain.js +1 -0
- package/dist/cli/commands/init/config-builder.js +1 -1
- package/dist/cli/commands/init/constants.js +8 -8
- package/dist/domain/entities/session/constants.d.ts +1 -1
- package/dist/domain/entities/session/constants.js +1 -1
- package/dist/infrastructure/adapters/bridge.d.ts +2 -0
- package/dist/infrastructure/adapters/bridge.d.ts.map +1 -1
- package/dist/infrastructure/adapters/bridge.js +4 -2
- package/dist/infrastructure/utils/config-loader.js +2 -2
- package/dist/infrastructure/utils/llm-error.d.ts +2 -0
- package/dist/infrastructure/utils/llm-error.d.ts.map +1 -0
- package/dist/infrastructure/utils/llm-error.js +20 -0
- package/package.json +1 -1
- package/prebuilds/darwin-arm64/uneven_core.node +0 -0
- package/prebuilds/linux-arm64/uneven_core.node +0 -0
- package/prebuilds/linux-x64/uneven_core.node +0 -0
- package/prebuilds/win32-x64/uneven_core.node +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,25 @@ All notable changes to Uneven AI will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [1.3.0] - 2026-05-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- **Multi-architecture GGUF dispatcher** — The Rust inference loader now reads `general.architecture` from GGUF metadata and routes to the correct candle-transformers backend (`quantized_llama`, `quantized_qwen2`, `quantized_gemma3`, `quantized_phi3`). All seven catalog models are now supported out of the box.
|
|
13
|
+
- **Chat templates** — Each model family now receives prompts in its correct format: Llama 3 (`<|begin_of_text|>` header tokens), ChatML (`<|im_start|>`, used by Qwen and SmolLM2), DeepSeek-R1 (Unicode BOS/EOS tokens), Gemma 3 (`<start_of_turn>`), and Phi 3/4 (`<|system|>` role tokens). The `detectTemplate` helper selects the right template from the model ID automatically.
|
|
14
|
+
- **DeepSeek-R1 thinking-token stripping** — `<think>…</think>` blocks emitted by DeepSeek-R1 models are removed before the response reaches the user.
|
|
15
|
+
- **Adaptive inference timeout** — Local inference timeout is now `max(300 s, maxTokens × 1.2 s)` instead of a fixed 120 s, preventing spurious timeouts on slower hardware.
|
|
16
|
+
- **`llm-error` utility module** — `sanitizeLlmError` extracted to `src/infrastructure/utils/llm-error.ts` for isolated unit testing without the native binding mock.
|
|
17
|
+
- **Unit tests — chat templates (60 tests)** — Per-architecture token structure, content integrity, multi-turn history ordering, and per-model send/receive simulation for all seven catalog models.
|
|
18
|
+
- **Unit tests — error sanitisation (12 tests)** — Covers every error category mapped by `sanitizeLlmError`.
|
|
19
|
+
|
|
20
|
+
### Fixed
|
|
21
|
+
|
|
22
|
+
- **Double BOS token** — `encode(prompt, true)` was adding a BOS token on top of the one already embedded in the chat template, corrupting Llama 3 prompts. Changed to `encode(prompt, false)`.
|
|
23
|
+
- **Default model ID** — Fallback model in the NAPI layer updated from `llama-3.2-1b-q8` to `llama-3.2-1b-q4` to match the catalog.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
8
27
|
## [1.2.2] - 2026-05-02
|
|
9
28
|
|
|
10
29
|
### Fixed
|
package/README.md
CHANGED
|
@@ -157,7 +157,7 @@ uneven-ai ci
|
|
|
157
157
|
Run `uneven-ai` with no arguments to open the interactive shell:
|
|
158
158
|
|
|
159
159
|
```
|
|
160
|
-
◈ Uneven AI v1.
|
|
160
|
+
◈ Uneven AI v1.3.0
|
|
161
161
|
────────────────────────────────────────────────────────────
|
|
162
162
|
Olá! O que posso fazer por você hoje?
|
|
163
163
|
(Escreva sua mensagem ou "sair" para encerrar)
|
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
import type { EngineCtx } from '../context.js';
|
|
2
|
-
|
|
3
|
-
* EngineBrain — Encapsulates the inference logic for the engine.
|
|
4
|
-
* Handles switching between local and external providers, timeouts, and streaming.
|
|
5
|
-
*/
|
|
2
|
+
import type { ChatTurn } from './chat-template.js';
|
|
6
3
|
export declare class EngineBrain {
|
|
7
4
|
private ctx;
|
|
8
5
|
constructor(ctx: EngineCtx);
|
|
9
|
-
|
|
10
|
-
* Performs an inference (completion) with the configured provider.
|
|
11
|
-
*/
|
|
12
|
-
infer(prompt: string, onToken?: (token: string) => void): Promise<string>;
|
|
6
|
+
infer(user: string, onToken?: (token: string) => void, maxTokensOverride?: number, system?: string, history?: ChatTurn[]): Promise<string>;
|
|
13
7
|
}
|
|
14
8
|
//# sourceMappingURL=brain.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"brain.d.ts","sourceRoot":"","sources":["../../../../../src/application/orchestration/engine/ask/brain.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"brain.d.ts","sourceRoot":"","sources":["../../../../../src/application/orchestration/engine/ask/brain.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAElD,qBAAa,WAAW;IACV,OAAO,CAAC,GAAG;gBAAH,GAAG,EAAE,SAAS;IAE5B,KAAK,CACT,IAAI,EAAE,MAAM,EACZ,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,EACjC,iBAAiB,CAAC,EAAE,MAAM,EAC1B,MAAM,CAAC,EAAE,MAAM,EACf,OAAO,GAAE,QAAQ,EAAO,GACvB,OAAO,CAAC,MAAM,CAAC;CA2CnB"}
|
|
@@ -1,43 +1,45 @@
|
|
|
1
1
|
import { llmInfer, llmInferStream, } from '../../../../infrastructure/adapters/bridge.js';
|
|
2
2
|
import { ExternalProviders } from '../../../../infrastructure/adapters/providers/index.js';
|
|
3
|
-
|
|
4
|
-
* EngineBrain — Encapsulates the inference logic for the engine.
|
|
5
|
-
* Handles switching between local and external providers, timeouts, and streaming.
|
|
6
|
-
*/
|
|
3
|
+
import { detectTemplate, applyTemplate, stripThinkingTokens } from './chat-template.js';
|
|
7
4
|
export class EngineBrain {
|
|
8
5
|
ctx;
|
|
9
6
|
constructor(ctx) {
|
|
10
7
|
this.ctx = ctx;
|
|
11
8
|
}
|
|
12
|
-
|
|
13
|
-
* Performs an inference (completion) with the configured provider.
|
|
14
|
-
*/
|
|
15
|
-
async infer(prompt, onToken) {
|
|
9
|
+
async infer(user, onToken, maxTokensOverride, system, history = []) {
|
|
16
10
|
const brainConfig = this.ctx.config.brain;
|
|
17
11
|
const provider = brainConfig?.provider || 'local';
|
|
18
|
-
const model = brainConfig?.model || '
|
|
19
|
-
const maxTokens = brainConfig?.maxTokens
|
|
12
|
+
const model = brainConfig?.model || 'llama-3.2-1b-q4';
|
|
13
|
+
const maxTokens = maxTokensOverride ?? brainConfig?.maxTokens ?? 1024;
|
|
20
14
|
const temperature = brainConfig?.temperature ?? 0.0;
|
|
21
|
-
const timeoutMs = brainConfig?.local?.inferTimeoutMs
|
|
15
|
+
const timeoutMs = brainConfig?.local?.inferTimeoutMs
|
|
16
|
+
?? Math.max(300_000, maxTokens * 1_200);
|
|
22
17
|
const withTimeout = (p) => Promise.race([
|
|
23
18
|
p,
|
|
24
19
|
new Promise((_, reject) => setTimeout(() => reject(new Error(`LLM inference timed out after ${timeoutMs}ms`)), timeoutMs)),
|
|
25
20
|
]);
|
|
26
21
|
if (provider === 'local') {
|
|
27
22
|
const threads = brainConfig?.local?.threads ?? 4;
|
|
23
|
+
const template = detectTemplate(model);
|
|
24
|
+
const prompt = system
|
|
25
|
+
? applyTemplate(template, system, history, user)
|
|
26
|
+
: user;
|
|
27
|
+
const isDeepSeek = model.toLowerCase().startsWith('deepseek');
|
|
28
|
+
let content;
|
|
28
29
|
if (onToken) {
|
|
29
30
|
const result = await withTimeout(llmInferStream(prompt, onToken, maxTokens, threads, temperature));
|
|
30
|
-
|
|
31
|
+
content = result.content;
|
|
31
32
|
}
|
|
32
33
|
else {
|
|
33
34
|
const result = await withTimeout(llmInfer(prompt, maxTokens, threads, temperature));
|
|
34
|
-
|
|
35
|
+
content = result.content;
|
|
35
36
|
}
|
|
37
|
+
return isDeepSeek ? stripThinkingTokens(content) : content;
|
|
36
38
|
}
|
|
37
39
|
else {
|
|
38
40
|
const extProviders = new ExternalProviders(this.ctx.logger);
|
|
39
41
|
const apiKey = brainConfig?.apiKey;
|
|
40
|
-
const result = await withTimeout(extProviders.infer(
|
|
42
|
+
const result = await withTimeout(extProviders.infer(user, provider, model, maxTokens, onToken, apiKey));
|
|
41
43
|
return result.content;
|
|
42
44
|
}
|
|
43
45
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ChatTemplate = 'llama3' | 'chatml' | 'deepseek-r1' | 'gemma3' | 'phi3';
|
|
2
|
+
export declare function detectTemplate(modelId: string): ChatTemplate;
|
|
3
|
+
export interface ChatTurn {
|
|
4
|
+
role: 'user' | 'assistant';
|
|
5
|
+
content: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function applyTemplate(template: ChatTemplate, system: string, history: ChatTurn[], user: string): string;
|
|
8
|
+
export declare function stripThinkingTokens(text: string): string;
|
|
9
|
+
//# sourceMappingURL=chat-template.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chat-template.d.ts","sourceRoot":"","sources":["../../../../../src/application/orchestration/engine/ask/chat-template.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG,QAAQ,GAAG,QAAQ,GAAG,aAAa,GAAG,QAAQ,GAAG,MAAM,CAAA;AAElF,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAQ5D;AAED,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,YAAY,EACtB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,QAAQ,EAAE,EACnB,IAAI,EAAE,MAAM,GACX,MAAM,CAiER;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAExD"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export function detectTemplate(modelId) {
|
|
2
|
+
const id = modelId.toLowerCase();
|
|
3
|
+
if (id.startsWith('deepseek'))
|
|
4
|
+
return 'deepseek-r1';
|
|
5
|
+
if (id.startsWith('llama') || id.startsWith('smollm'))
|
|
6
|
+
return 'llama3';
|
|
7
|
+
if (id.startsWith('qwen'))
|
|
8
|
+
return 'chatml';
|
|
9
|
+
if (id.startsWith('gemma'))
|
|
10
|
+
return 'gemma3';
|
|
11
|
+
if (id.startsWith('phi'))
|
|
12
|
+
return 'phi3';
|
|
13
|
+
return 'llama3';
|
|
14
|
+
}
|
|
15
|
+
export function applyTemplate(template, system, history, user) {
|
|
16
|
+
switch (template) {
|
|
17
|
+
case 'llama3': {
|
|
18
|
+
let prompt = `<|begin_of_text|><|start_header_id|>system<|end_header_id|>\n\n${system}<|eot_id|>`;
|
|
19
|
+
for (const turn of history) {
|
|
20
|
+
prompt += `<|start_header_id|>${turn.role}<|end_header_id|>\n\n${turn.content}<|eot_id|>`;
|
|
21
|
+
}
|
|
22
|
+
prompt += `<|start_header_id|>user<|end_header_id|>\n\n${user}<|eot_id|><|start_header_id|>assistant<|end_header_id|>\n\n`;
|
|
23
|
+
return prompt;
|
|
24
|
+
}
|
|
25
|
+
case 'chatml': {
|
|
26
|
+
let prompt = `<|im_start|>system\n${system}<|im_end|>\n`;
|
|
27
|
+
for (const turn of history) {
|
|
28
|
+
prompt += `<|im_start|>${turn.role}\n${turn.content}<|im_end|>\n`;
|
|
29
|
+
}
|
|
30
|
+
prompt += `<|im_start|>user\n${user}<|im_end|>\n<|im_start|>assistant\n`;
|
|
31
|
+
return prompt;
|
|
32
|
+
}
|
|
33
|
+
case 'deepseek-r1': {
|
|
34
|
+
// DeepSeek-R1 uses its own special tokens (Unicode full-width vertical bars)
|
|
35
|
+
// System message goes before the first User marker (no dedicated system role)
|
|
36
|
+
let prompt = `<|begin▁of▁sentence|>${system}\n`;
|
|
37
|
+
for (const turn of history) {
|
|
38
|
+
if (turn.role === 'user') {
|
|
39
|
+
prompt += `<|User|>${turn.content}\n`;
|
|
40
|
+
}
|
|
41
|
+
else {
|
|
42
|
+
prompt += `<|Assistant|>${turn.content}<|end▁of▁sentence|>\n`;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
prompt += `<|User|>${user}\n<|Assistant|>`;
|
|
46
|
+
return prompt;
|
|
47
|
+
}
|
|
48
|
+
case 'gemma3': {
|
|
49
|
+
// Gemma 3 has no system role — system message goes inside the first user turn
|
|
50
|
+
let prompt = `<start_of_turn>user\n${system}\n\n`;
|
|
51
|
+
// First user turn already opened; if there's history, close it and add alternating turns
|
|
52
|
+
if (history.length > 0) {
|
|
53
|
+
prompt += `<end_of_turn>\n`;
|
|
54
|
+
for (const turn of history) {
|
|
55
|
+
const role = turn.role === 'user' ? 'user' : 'model';
|
|
56
|
+
prompt += `<start_of_turn>${role}\n${turn.content}<end_of_turn>\n`;
|
|
57
|
+
}
|
|
58
|
+
prompt += `<start_of_turn>user\n${user}<end_of_turn>\n<start_of_turn>model\n`;
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
prompt += `${user}<end_of_turn>\n<start_of_turn>model\n`;
|
|
62
|
+
}
|
|
63
|
+
return prompt;
|
|
64
|
+
}
|
|
65
|
+
case 'phi3': {
|
|
66
|
+
let prompt = `<|system|>\n${system}<|end|>\n`;
|
|
67
|
+
for (const turn of history) {
|
|
68
|
+
if (turn.role === 'user') {
|
|
69
|
+
prompt += `<|user|>\n${turn.content}<|end|>\n`;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
prompt += `<|assistant|>\n${turn.content}<|end|>\n`;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
prompt += `<|user|>\n${user}<|end|>\n<|assistant|>\n`;
|
|
76
|
+
return prompt;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
export function stripThinkingTokens(text) {
|
|
81
|
+
return text.replace(/<think>[\s\S]*?<\/think>\s*/g, '').trim();
|
|
82
|
+
}
|
|
@@ -4,7 +4,7 @@ import * as path from 'path';
|
|
|
4
4
|
import { llmEmbed, retrievalSearch } from '../../../../infrastructure/adapters/bridge.js';
|
|
5
5
|
import { KnowledgeRetriever } from '../../knowledge-retriever.js';
|
|
6
6
|
import { FixEngine } from '../../../development/fix/index.js';
|
|
7
|
-
import {
|
|
7
|
+
import { ROUTER_SYSTEM, ROUTER_USER } from './prompts.js';
|
|
8
8
|
/**
|
|
9
9
|
* ContextAssembler — Responsible for gathering relevant project context.
|
|
10
10
|
* Uses Knowledge Map routing, Vector Search, and Proactive Auditing.
|
|
@@ -57,9 +57,9 @@ export class ContextAssembler {
|
|
|
57
57
|
}
|
|
58
58
|
}
|
|
59
59
|
async detectRelevantPaths(filesMap, question, brain) {
|
|
60
|
-
const
|
|
60
|
+
const routerUser = ROUTER_USER(filesMap, question);
|
|
61
61
|
try {
|
|
62
|
-
const result = await brain.infer(
|
|
62
|
+
const result = await brain.infer(routerUser, undefined, 128, ROUTER_SYSTEM);
|
|
63
63
|
// Use [\s\S] so the match works on both compact and pretty-printed arrays.
|
|
64
64
|
const jsonMatch = result.match(/\[[\s\S]*?\]/);
|
|
65
65
|
if (jsonMatch) {
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prompts for the Ask Engine
|
|
3
3
|
*/
|
|
4
|
+
export declare const ROUTER_SYSTEM = "You are a context router for a coding assistant. Your only job is to identify which files (MAX 5) are relevant to the user's question and return them as a JSON array. Output ONLY the JSON array \u2014 no explanation, no markdown, no extra text.";
|
|
5
|
+
export declare const ROUTER_USER: (filesMap: string, question: string) => string;
|
|
4
6
|
export declare const ROUTER_PROMPT: (filesMap: string, question: string) => string;
|
|
5
7
|
export declare const SYSTEM_INSTRUCTIONS_HEADER: string;
|
|
6
8
|
//# sourceMappingURL=prompts.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../../src/application/orchestration/engine/ask/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,EAAE,UAAU,MAAM,
|
|
1
|
+
{"version":3,"file":"prompts.d.ts","sourceRoot":"","sources":["../../../../../src/application/orchestration/engine/ask/prompts.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,eAAO,MAAM,aAAa,yPACyN,CAAA;AAEnP,eAAO,MAAM,WAAW,GAAI,UAAU,MAAM,EAAE,UAAU,MAAM,WAQtD,CAAA;AAER,eAAO,MAAM,aAAa,GAAI,UAAU,MAAM,EAAE,UAAU,MAAM,WACN,CAAA;AAE1D,eAAO,MAAM,0BAA0B,QAI/B,CAAA"}
|
|
@@ -1,22 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Prompts for the Ask Engine
|
|
3
3
|
*/
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
### PROJECT FILES:
|
|
4
|
+
export const ROUTER_SYSTEM = `You are a context router for a coding assistant. Your only job is to identify which files (MAX 5) are relevant to the user's question and return them as a JSON array. Output ONLY the JSON array — no explanation, no markdown, no extra text.`;
|
|
5
|
+
export const ROUTER_USER = (filesMap, question) => `
|
|
6
|
+
PROJECT FILES:
|
|
9
7
|
${filesMap}
|
|
10
8
|
|
|
11
|
-
|
|
12
|
-
${question}
|
|
9
|
+
QUESTION: ${question}
|
|
13
10
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
- Answer ONLY with a JSON array of relative paths.
|
|
17
|
-
- If no files are relevant, return [].
|
|
18
|
-
- Example: ["src/controllers/user.js", "src/models/user.ts"]
|
|
11
|
+
Answer with ONLY a JSON array of relative paths. If no files are relevant, return [].
|
|
12
|
+
Example: ["src/controllers/user.js", "src/models/user.ts"]
|
|
19
13
|
`.trim();
|
|
14
|
+
export const ROUTER_PROMPT = (filesMap, question) => `${ROUTER_SYSTEM}\n\n${ROUTER_USER(filesMap, question)}`;
|
|
20
15
|
export const SYSTEM_INSTRUCTIONS_HEADER = `
|
|
21
16
|
You are Uneven AI (Snatchy), a senior software engineer assistant.
|
|
22
17
|
Base your answers on the provided project context and conversation history.
|
|
@@ -30,12 +30,12 @@ export async function doAsk(ctx, question, onToken, history = [], fixEngineOverr
|
|
|
30
30
|
// 3. Context Assembly (Data Diet)
|
|
31
31
|
const context = await assembler.assemble(question, brain);
|
|
32
32
|
// 4. Prompt Synthesis
|
|
33
|
-
const historySection = formatHistory(history);
|
|
34
33
|
const SafetyGuard = ctx.safetyGuard.constructor;
|
|
35
34
|
const sysInstructions = SafetyGuard.SYSTEM_INSTRUCTIONS ?? SYSTEM_INSTRUCTIONS_HEADER;
|
|
36
|
-
const
|
|
35
|
+
const userContent = `${context}\nQuestion: ${question}`;
|
|
36
|
+
const chatHistory = history.map(t => ({ role: t.role, content: t.content }));
|
|
37
37
|
// 5. Brain Inference (Thought Process)
|
|
38
|
-
let response = await brain.infer(
|
|
38
|
+
let response = await brain.infer(userContent, onToken, undefined, sysInstructions, chatHistory);
|
|
39
39
|
// 6. Sanitization & Finalization
|
|
40
40
|
response = ctx.safetyGuard.sanitizeResponse(response);
|
|
41
41
|
ctx.logger.info(`Ask: Generated answer (${response.length} chars)`);
|
|
@@ -52,13 +52,3 @@ export async function doAsk(ctx, question, onToken, history = [], fixEngineOverr
|
|
|
52
52
|
throw error;
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
|
-
/**
|
|
56
|
-
* Formats conversation history for the prompt.
|
|
57
|
-
*/
|
|
58
|
-
function formatHistory(history) {
|
|
59
|
-
if (history.length === 0)
|
|
60
|
-
return '';
|
|
61
|
-
return '\n## CONVERSATION HISTORY\n\n' +
|
|
62
|
-
history.map(t => t.role === 'user' ? `User: ${t.content}` : `Assistant: ${t.content}`).join('\n') +
|
|
63
|
-
'\n';
|
|
64
|
-
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ask.ts"],"names":[],"mappings":"AAQA,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"ask.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/ask.ts"],"names":[],"mappings":"AAQA,wBAAsB,UAAU,CAC9B,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,IAAI,CAAC,CAsEf"}
|
package/dist/cli/commands/ask.js
CHANGED
|
@@ -33,6 +33,7 @@ export async function askCommand(question, options = {}) {
|
|
|
33
33
|
console.log(t.dim(' Action stopped to keep your machine responsive.'));
|
|
34
34
|
}
|
|
35
35
|
blank();
|
|
36
|
+
process.exit(0);
|
|
36
37
|
});
|
|
37
38
|
let streamingStarted = false;
|
|
38
39
|
const answer = await uneven.ask(question, (token) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAEnC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAQ5E;AAED,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,GAAG,WAAW,CAAA;IAC1B,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,eAAO,MAAM,iBAAiB,KAAK,CAAA;AAEnC,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,MAAM,CAQ5E;AAED,wBAAsB,WAAW,CAC/B,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAO,GAClD,OAAO,CAAC,IAAI,CAAC,CAiHf"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/docs.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,OAAO,CAAA;AAEvC,eAAO,MAAM,mBAAmB,QAAS,CAAA;AAEzC,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAA4B,GACrC,MAAM,CAMR;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,GACjB,MAAM,CAuCR;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAW,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"docs.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/docs.ts"],"names":[],"mappings":"AASA,MAAM,MAAM,UAAU,GAAG,IAAI,GAAG,OAAO,CAAA;AAEvC,eAAO,MAAM,mBAAmB,QAAS,CAAA;AAEzC,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAA4B,GACrC,MAAM,CAMR;AAED,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,UAAU,GACjB,MAAM,CAuCR;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAA;IACnB,GAAG,CAAC,EAAE,MAAM,CAAA;IACZ,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,WAAW,CAC/B,QAAQ,EAAE,MAAM,EAChB,MAAM,GAAE,MAAW,EACnB,OAAO,GAAE,WAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA6Ef"}
|
|
@@ -86,6 +86,7 @@ export async function docsCommand(filePath, symbol = '', options = {}) {
|
|
|
86
86
|
guardian = new ResourceGuardian(new Logger('./.uneven/logs/guardian.md'));
|
|
87
87
|
guardian.start((reason) => {
|
|
88
88
|
console.error(t.rust(`\n Safety interrupt: ${reason}`));
|
|
89
|
+
process.exit(0);
|
|
89
90
|
});
|
|
90
91
|
blank();
|
|
91
92
|
const modeLabel = format === 'jsdoc' ? 'TSDoc' : 'Markdown';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc,QAAS,CAAA;AAEpC,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAuB,GAChC,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,CAqBR;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAW,EAClB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"explain.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/explain.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,cAAc,QAAS,CAAA;AAEpC,wBAAgB,mBAAmB,CACjC,OAAO,EAAE,MAAM,EACf,QAAQ,GAAE,MAAuB,GAChC,MAAM,CAMR;AAED,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,GACZ,MAAM,CAqBR;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,wBAAsB,cAAc,CAClC,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,MAAW,EAClB,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,IAAI,CAAC,CAkEf"}
|
|
@@ -66,6 +66,7 @@ export async function explainCommand(filePath, focus = '', options = {}) {
|
|
|
66
66
|
guardian = new ResourceGuardian(new Logger(logPath));
|
|
67
67
|
guardian.start((reason) => {
|
|
68
68
|
console.error(t.rust(`\n Safety interrupt: ${reason}`));
|
|
69
|
+
process.exit(0);
|
|
69
70
|
});
|
|
70
71
|
blank();
|
|
71
72
|
console.log(t.dim(' ┌─ Explanation'));
|
|
@@ -2,7 +2,7 @@ export function defaultModelFor(provider, localModelId) {
|
|
|
2
2
|
if (provider === 'local' && localModelId)
|
|
3
3
|
return localModelId;
|
|
4
4
|
const MAP = {
|
|
5
|
-
local: 'llama-3.2-1b-
|
|
5
|
+
local: 'llama-3.2-1b-q4',
|
|
6
6
|
ollama: 'llama3.2',
|
|
7
7
|
claude: 'claude-sonnet-4-6',
|
|
8
8
|
openai: 'gpt-4o-mini',
|
|
@@ -18,19 +18,19 @@ export const EMBEDDING_FILES = [
|
|
|
18
18
|
];
|
|
19
19
|
export const LOCAL_MODEL_CATALOG = [
|
|
20
20
|
{
|
|
21
|
-
id: 'llama-3.2-1b-
|
|
22
|
-
label: 'Llama 3.2 1B
|
|
23
|
-
ram: '~
|
|
24
|
-
storage: '~
|
|
21
|
+
id: 'llama-3.2-1b-q4',
|
|
22
|
+
label: 'Llama 3.2 1B Q4',
|
|
23
|
+
ram: '~1.5 GB',
|
|
24
|
+
storage: '~700 MB',
|
|
25
25
|
files: [
|
|
26
26
|
{
|
|
27
|
-
url: 'https://huggingface.co/bartowski/Llama-3.2-1B-Instruct-GGUF/resolve/main/Llama-3.2-1B-Instruct-
|
|
28
|
-
dest: '.uneven/models/llama-3.2-1b-
|
|
29
|
-
size: '~
|
|
27
|
+
url: 'https://huggingface.co/bartowski/Llama-3.2-1B-Instruct-GGUF/resolve/main/Llama-3.2-1B-Instruct-Q4_K_M.gguf',
|
|
28
|
+
dest: '.uneven/models/llama-3.2-1b-q4.gguf',
|
|
29
|
+
size: '~700 MB',
|
|
30
30
|
},
|
|
31
31
|
{
|
|
32
32
|
url: 'https://huggingface.co/unsloth/Llama-3.2-1B-Instruct/resolve/main/tokenizer.json',
|
|
33
|
-
dest: '.uneven/models/llama-3.2-1b-
|
|
33
|
+
dest: '.uneven/models/llama-3.2-1b-q4-tokenizer.json',
|
|
34
34
|
size: '~1.7 MB',
|
|
35
35
|
},
|
|
36
36
|
],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export declare const SESSION_FILE = ".uneven/session.json";
|
|
2
|
-
export declare const UNEVEN_VERSION = "1.
|
|
2
|
+
export declare const UNEVEN_VERSION = "1.3.0";
|
|
3
3
|
export declare const STALE_THRESHOLD_MS: number;
|
|
4
4
|
export declare const LOCK_TIMEOUT_MS = 30000;
|
|
5
5
|
export declare const LOCK_DEBOUNCE_MS = 1500;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export const SESSION_FILE = '.uneven/session.json';
|
|
2
|
-
export const UNEVEN_VERSION = '1.
|
|
2
|
+
export const UNEVEN_VERSION = '1.3.0';
|
|
3
3
|
export const STALE_THRESHOLD_MS = 60 * 60 * 1000; // 1 hour
|
|
4
4
|
export const LOCK_TIMEOUT_MS = 30_000; // 30 seconds
|
|
5
5
|
export const LOCK_DEBOUNCE_MS = 1_500; // 1.5 seconds
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/adapters/bridge.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/adapters/bridge.ts"],"names":[],"mappings":"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"}
|
|
@@ -3,6 +3,8 @@ import { createRequire } from 'module';
|
|
|
3
3
|
import { resolve, dirname, join } from 'path';
|
|
4
4
|
import { fileURLToPath } from 'url';
|
|
5
5
|
import { withTimeout, TimeoutError } from '../utils/timeout.js';
|
|
6
|
+
import { sanitizeLlmError } from '../utils/llm-error.js';
|
|
7
|
+
export { sanitizeLlmError };
|
|
6
8
|
// Embedding: fast pass through the model — 2 min covers cold-start on CPU
|
|
7
9
|
const LLM_EMBED_TIMEOUT_MS = 120_000;
|
|
8
10
|
// Inference: generating 300-500 tokens on CPU — 3 min
|
|
@@ -210,7 +212,7 @@ repeatPenalty = 1.1) {
|
|
|
210
212
|
catch (error) {
|
|
211
213
|
if (error instanceof TimeoutError)
|
|
212
214
|
nativeBinding.interruptLocalInference();
|
|
213
|
-
throw new Error(
|
|
215
|
+
throw new Error(sanitizeLlmError(error));
|
|
214
216
|
}
|
|
215
217
|
}
|
|
216
218
|
export async function llmInferStream(prompt, onToken, maxTokens, threads = 4, temperature = 0.0, repeatPenalty = 1.1) {
|
|
@@ -224,7 +226,7 @@ export async function llmInferStream(prompt, onToken, maxTokens, threads = 4, te
|
|
|
224
226
|
catch (error) {
|
|
225
227
|
if (error instanceof TimeoutError)
|
|
226
228
|
nativeBinding.interruptLocalInference();
|
|
227
|
-
throw new Error(
|
|
229
|
+
throw new Error(sanitizeLlmError(error));
|
|
228
230
|
}
|
|
229
231
|
}
|
|
230
232
|
export async function flushVectorStore() {
|
|
@@ -43,7 +43,7 @@ export async function findProjectRoot(startDir = process.cwd()) {
|
|
|
43
43
|
const DEFAULTS = {
|
|
44
44
|
brain: {
|
|
45
45
|
provider: 'local',
|
|
46
|
-
model: 'llama-3.2-1b-
|
|
46
|
+
model: 'llama-3.2-1b-q4',
|
|
47
47
|
temperature: 0.3,
|
|
48
48
|
maxTokens: 2048,
|
|
49
49
|
local: {
|
|
@@ -475,7 +475,7 @@ export async function saveConfig(config, projectRoot) {
|
|
|
475
475
|
}
|
|
476
476
|
// Display names for local model ids — keep in sync with init/constants LOCAL_MODEL_CATALOG
|
|
477
477
|
const LOCAL_MODEL_LABELS = {
|
|
478
|
-
'llama-3.2-1b-
|
|
478
|
+
'llama-3.2-1b-q4': 'Llama 3.2 1B Q4',
|
|
479
479
|
'qwen-2.5-1.5b-q8': 'Qwen 2.5 1.5B Q8',
|
|
480
480
|
'deepseek-r1-1.5b-q8': 'DeepSeek-R1 1.5B Q8',
|
|
481
481
|
'gemma-3-1b-q8': 'Gemma 3 1B Q8',
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"llm-error.d.ts","sourceRoot":"","sources":["../../../src/infrastructure/utils/llm-error.ts"],"names":[],"mappings":"AAAA,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CA2BvD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function sanitizeLlmError(error) {
|
|
2
|
+
const raw = error instanceof Error ? error.message : String(error);
|
|
3
|
+
if (/model.*not found|cannot open.*models|no such file/i.test(raw))
|
|
4
|
+
return 'Local model not found. Run `uneven init` to download it.';
|
|
5
|
+
if (/tokenizer not found/i.test(raw))
|
|
6
|
+
return 'Model tokenizer missing. Run `uneven init` to reinstall.';
|
|
7
|
+
if (/model not loaded/i.test(raw))
|
|
8
|
+
return 'Local model is not loaded. Run `uneven init` to set up.';
|
|
9
|
+
if (/out of memory|insufficient memory|oom/i.test(raw))
|
|
10
|
+
return 'Not enough memory for local inference. Try a smaller model.';
|
|
11
|
+
if (/timed out|timeout/i.test(raw))
|
|
12
|
+
return 'Inference timed out. The model may be too slow for your hardware.';
|
|
13
|
+
if (/interrupted/i.test(raw))
|
|
14
|
+
return 'Inference was interrupted.';
|
|
15
|
+
if (/context window.*too small|unavailable/i.test(raw))
|
|
16
|
+
return raw;
|
|
17
|
+
if (process.env.UNEVEN_DEBUG)
|
|
18
|
+
return raw;
|
|
19
|
+
return 'Local inference failed. Set UNEVEN_DEBUG=1 for technical details.';
|
|
20
|
+
}
|
package/package.json
CHANGED
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|