@sunilp-org/jam-cli 0.1.1 → 0.1.2
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 +130 -14
- package/dist/commands/config.d.ts.map +1 -1
- package/dist/commands/config.js +2 -1
- package/dist/commands/config.js.map +1 -1
- package/dist/config/loader.d.ts.map +1 -1
- package/dist/config/loader.js +36 -3
- package/dist/config/loader.js.map +1 -1
- package/dist/providers/embedded.d.ts +20 -0
- package/dist/providers/embedded.d.ts.map +1 -0
- package/dist/providers/embedded.js +302 -0
- package/dist/providers/embedded.js.map +1 -0
- package/dist/providers/factory.d.ts.map +1 -1
- package/dist/providers/factory.js +9 -1
- package/dist/providers/factory.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -58,7 +58,8 @@ Most AI coding tools are built around a single vendor's model, require a browser
|
|
|
58
58
|
| 📂 | **Repo-aware** | Explain files, search code, review diffs with full workspace context |
|
|
59
59
|
| 🩹 | **Patch workflow** | Generate unified diffs, validate, preview, and apply with confirmation |
|
|
60
60
|
| 🤖 | **Tool-calling agent** | `jam run` gives the model access to local tools (read, search, diff, apply) |
|
|
61
|
-
| 🔌 | **Pluggable providers** | Ollama, OpenAI, Groq built-in; adapter pattern for adding any LLM |
|
|
61
|
+
| 🔌 | **Pluggable providers** | Ollama, OpenAI, Groq, **Embedded** built-in; adapter pattern for adding any LLM |
|
|
62
|
+
| 📦 | **Embedded inference** | **[Experimental]** Run without Ollama — tiny GGUF model runs directly in-process via `node-llama-cpp` |
|
|
62
63
|
| ⚙️ | **Layered config** | Global → repo → CLI flags; multiple named profiles |
|
|
63
64
|
| 🔐 | **Secure secrets** | OS keychain via keytar, env var fallback |
|
|
64
65
|
| 🐚 | **Shell completions** | Bash and Zsh |
|
|
@@ -100,14 +101,23 @@ Most AI coding tools are built around a single vendor's model, require a browser
|
|
|
100
101
|
### Prerequisites
|
|
101
102
|
|
|
102
103
|
- **Node.js 20+**
|
|
103
|
-
- **
|
|
104
|
-
-
|
|
104
|
+
- **One of the following model backends:**
|
|
105
|
+
- **[Ollama](https://ollama.ai)** running locally (`ollama serve`) + a pulled model (`ollama pull llama3.2`)
|
|
106
|
+
- **Embedded mode** — no server needed! Uses `node-llama-cpp` to run a tiny GGUF model in-process.
|
|
107
|
+
Install with: `npm install node-llama-cpp` (auto-downloads a ~250 MB model on first run)
|
|
105
108
|
|
|
106
109
|
### Install
|
|
107
110
|
|
|
108
111
|
```bash
|
|
109
|
-
#
|
|
110
|
-
|
|
112
|
+
# Try instantly — no install required
|
|
113
|
+
npx @sunilp-org/jam-cli doctor
|
|
114
|
+
|
|
115
|
+
# Global install from npm
|
|
116
|
+
npm install -g @sunilp-org/jam-cli
|
|
117
|
+
|
|
118
|
+
# Homebrew (macOS / Linux)
|
|
119
|
+
brew tap sunilp/tap
|
|
120
|
+
brew install jam-cli
|
|
111
121
|
|
|
112
122
|
# Or run from source
|
|
113
123
|
git clone https://github.com/sunilp/jam-cli.git
|
|
@@ -415,12 +425,16 @@ Checks:
|
|
|
415
425
|
Jam merges config in priority order (highest wins):
|
|
416
426
|
|
|
417
427
|
```
|
|
418
|
-
1. CLI flags
|
|
419
|
-
2. .jam/config.json or .jamrc
|
|
420
|
-
3. ~/.
|
|
421
|
-
4.
|
|
428
|
+
1. CLI flags (--provider, --model, etc.)
|
|
429
|
+
2. .jam/config.json or .jamrc (repo-level)
|
|
430
|
+
3. ~/.jam/config.json (user home-dir dotfile — preferred)
|
|
431
|
+
4. ~/.config/jam/config.json (XDG user config — fallback)
|
|
432
|
+
5. Built-in defaults
|
|
422
433
|
```
|
|
423
434
|
|
|
435
|
+
> **Recommended:** Use `~/.jam/config.json` for your personal settings (provider, API keys, default model).
|
|
436
|
+
> Use `.jam/config.json` at the repo root for project-specific overrides (tool policy, redact patterns).
|
|
437
|
+
|
|
424
438
|
### Config Schema
|
|
425
439
|
|
|
426
440
|
```json
|
|
@@ -439,6 +453,10 @@ Jam merges config in priority order (highest wins):
|
|
|
439
453
|
"provider": "ollama",
|
|
440
454
|
"model": "qwen2.5-coder:1.5b",
|
|
441
455
|
"baseUrl": "http://localhost:11434"
|
|
456
|
+
},
|
|
457
|
+
"embedded": {
|
|
458
|
+
"provider": "embedded",
|
|
459
|
+
"model": "smollm2-360m"
|
|
442
460
|
}
|
|
443
461
|
},
|
|
444
462
|
"toolPolicy": "ask_every_time",
|
|
@@ -465,7 +483,7 @@ Jam merges config in priority order (highest wins):
|
|
|
465
483
|
|
|
466
484
|
| Field | Type | Description |
|
|
467
485
|
|-------|------|-------------|
|
|
468
|
-
| `provider` | string | Provider name (`ollama`, `openai`, `groq`) |
|
|
486
|
+
| `provider` | string | Provider name (`ollama`, `openai`, `groq`, `embedded`) |
|
|
469
487
|
| `model` | string | Model ID (e.g. `llama3.2`, `codellama`) |
|
|
470
488
|
| `baseUrl` | string | Provider API base URL |
|
|
471
489
|
| `apiKey` | string | API key (prefer keychain or env vars) |
|
|
@@ -476,11 +494,43 @@ Jam merges config in priority order (highest wins):
|
|
|
476
494
|
### Initialize Config
|
|
477
495
|
|
|
478
496
|
```bash
|
|
479
|
-
#
|
|
497
|
+
# User-level — creates ~/.jam/config.json (recommended)
|
|
498
|
+
jam config init --global
|
|
499
|
+
|
|
500
|
+
# Repo-level — creates .jam/config.json (committed to version control)
|
|
480
501
|
jam config init
|
|
502
|
+
```
|
|
481
503
|
|
|
482
|
-
|
|
483
|
-
|
|
504
|
+
The global config at `~/.jam/config.json` is the best place to set your default provider, model, API keys, and personal preferences. Edit it directly:
|
|
505
|
+
|
|
506
|
+
```bash
|
|
507
|
+
# Example: switch default provider to embedded
|
|
508
|
+
vim ~/.jam/config.json
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
```json
|
|
512
|
+
{
|
|
513
|
+
"defaultProfile": "default",
|
|
514
|
+
"profiles": {
|
|
515
|
+
"default": {
|
|
516
|
+
"provider": "ollama",
|
|
517
|
+
"model": "llama3.2",
|
|
518
|
+
"baseUrl": "http://localhost:11434"
|
|
519
|
+
},
|
|
520
|
+
"openai": {
|
|
521
|
+
"provider": "openai",
|
|
522
|
+
"model": "gpt-4o-mini",
|
|
523
|
+
"apiKey": "sk-..."
|
|
524
|
+
},
|
|
525
|
+
"offline": {
|
|
526
|
+
"provider": "embedded",
|
|
527
|
+
"model": "smollm2-360m"
|
|
528
|
+
}
|
|
529
|
+
},
|
|
530
|
+
"toolPolicy": "ask_every_time",
|
|
531
|
+
"historyEnabled": true,
|
|
532
|
+
"logLevel": "warn"
|
|
533
|
+
}
|
|
484
534
|
```
|
|
485
535
|
|
|
486
536
|
### Using Profiles
|
|
@@ -506,6 +556,72 @@ echo '{"defaultProfile": "fast"}' > .jamrc
|
|
|
506
556
|
|
|
507
557
|
---
|
|
508
558
|
|
|
559
|
+
## Embedded Provider — Experimental ⚗️
|
|
560
|
+
|
|
561
|
+
> **⚠️ EXPERIMENTAL** — The embedded provider is functional but quality is limited by small model sizes. For production workloads, use Ollama or OpenAI.
|
|
562
|
+
|
|
563
|
+
The `embedded` provider runs a tiny GGUF model **directly in-process** via [`node-llama-cpp`](https://github.com/withcatai/node-llama-cpp). No Ollama installation, no server process, no network calls. **Models are only downloaded when you explicitly set `provider: "embedded"`** — it never downloads anything unless you opt in.
|
|
564
|
+
|
|
565
|
+
### Setup
|
|
566
|
+
|
|
567
|
+
```bash
|
|
568
|
+
# Install the native dependency (optional — only needed for embedded mode)
|
|
569
|
+
npm install node-llama-cpp
|
|
570
|
+
|
|
571
|
+
# Switch to embedded provider
|
|
572
|
+
jam ask "Hello" --provider embedded
|
|
573
|
+
|
|
574
|
+
# Or set it permanently in your config
|
|
575
|
+
jam config init --global # then edit ~/.jam/config.json
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
### How It Works
|
|
579
|
+
|
|
580
|
+
1. On first use, Jam auto-downloads a small model (~250 MB) to `~/.jam/models/`
|
|
581
|
+
2. The model loads in-process using llama.cpp bindings — no external server
|
|
582
|
+
3. Streaming, tool-calling, and all standard commands work as usual
|
|
583
|
+
|
|
584
|
+
### Available Models
|
|
585
|
+
|
|
586
|
+
| Alias | Size (Q4_K_M) | Notes |
|
|
587
|
+
|-------|---------------|-------|
|
|
588
|
+
| `smollm2-135m` | ~100 MB | Ultra-light, very fast, basic quality |
|
|
589
|
+
| `smollm2-360m` | ~250 MB | **Default** — good quality-to-size ratio |
|
|
590
|
+
| `smollm2-1.7b` | ~1 GB | Best quality for embedded, needs more RAM |
|
|
591
|
+
|
|
592
|
+
```bash
|
|
593
|
+
# Use a specific embedded model alias
|
|
594
|
+
jam ask "Explain git rebase" --provider embedded --model smollm2-1.7b
|
|
595
|
+
|
|
596
|
+
# Or point to any local GGUF file
|
|
597
|
+
jam ask "Hello" --provider embedded --model /path/to/custom-model.gguf
|
|
598
|
+
|
|
599
|
+
# Profile-based setup
|
|
600
|
+
# In ~/.jam/config.json:
|
|
601
|
+
# {
|
|
602
|
+
# "profiles": {
|
|
603
|
+
# "offline": {
|
|
604
|
+
# "provider": "embedded",
|
|
605
|
+
# "model": "smollm2-1.7b"
|
|
606
|
+
# }
|
|
607
|
+
# }
|
|
608
|
+
# }
|
|
609
|
+
jam ask "Hello" --profile offline
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
### When to Use Embedded vs Ollama
|
|
613
|
+
|
|
614
|
+
| Scenario | Recommendation |
|
|
615
|
+
|----------|---------------|
|
|
616
|
+
| No Ollama / can't install system software | **Embedded** |
|
|
617
|
+
| CI/CD pipeline, Docker container, SSH box | **Embedded** |
|
|
618
|
+
| Air-gapped / offline machine | **Embedded** (after initial model download) |
|
|
619
|
+
| Want best quality & larger models (7B+) | **Ollama** |
|
|
620
|
+
| GPU acceleration needed | **Ollama** |
|
|
621
|
+
| Already have Ollama running | **Ollama** |
|
|
622
|
+
|
|
623
|
+
---
|
|
624
|
+
|
|
509
625
|
## Development
|
|
510
626
|
|
|
511
627
|
```bash
|
|
@@ -524,7 +640,7 @@ npm run test:coverage # coverage report
|
|
|
524
640
|
src/
|
|
525
641
|
├── index.ts # CLI entry point — command registration (Commander)
|
|
526
642
|
├── commands/ # One file per command (ask, chat, run, review, commit, …)
|
|
527
|
-
├── providers/ # LLM adapter layer — ProviderAdapter interface + Ollama impl
|
|
643
|
+
├── providers/ # LLM adapter layer — ProviderAdapter interface + Ollama, Embedded impl
|
|
528
644
|
├── tools/ # Model-callable tools + registry + permission enforcement
|
|
529
645
|
├── config/ # Zod schema, cosmiconfig loader, built-in defaults
|
|
530
646
|
├── storage/ # Chat session persistence (JSON files)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMxD,wBAAsB,aAAa,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB7E;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAMxD,wBAAsB,aAAa,CAAC,OAAO,GAAE,YAAiB,GAAG,OAAO,CAAC,IAAI,CAAC,CAmB7E;AAED,wBAAsB,aAAa,CAAC,OAAO,GAAE;IAAE,MAAM,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAkCrF"}
|
package/dist/commands/config.js
CHANGED
|
@@ -29,7 +29,8 @@ export async function runConfigInit(options = {}) {
|
|
|
29
29
|
let configDir;
|
|
30
30
|
let configPath;
|
|
31
31
|
if (options.global) {
|
|
32
|
-
|
|
32
|
+
// Use ~/.jam/config.json as the preferred user-level location
|
|
33
|
+
configDir = join(homedir(), '.jam');
|
|
33
34
|
configPath = join(configDir, 'config.json');
|
|
34
35
|
}
|
|
35
36
|
else {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAC7D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAExD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAwB,EAAE;IAC5D,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,OAAO,CAAC,CAAC;QACxD,MAAM,OAAO,GAAG,gBAAgB,CAAC,MAAM,CAAC,CAAC;QAEzC,MAAM,MAAM,GAAG;YACb,MAAM;YACN,aAAa,EAAE;gBACb,IAAI,EAAE,MAAM,CAAC,cAAc;gBAC3B,GAAG,OAAO;aACX;SACF,CAAC;QAEF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAC/D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,MAAM,MAAM,GAAG,QAAQ,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;QACzC,MAAM,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QACjC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAgC,EAAE;IACpE,IAAI,CAAC;QACH,IAAI,SAAiB,CAAC;QACtB,IAAI,UAAkB,CAAC;QAEvB,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;YACnB,SAAS,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/commands/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"loader.d.ts","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAgHpE,wBAAsB,UAAU,CAC9B,GAAG,GAAE,MAAsB,EAC3B,YAAY,GAAE,YAAiB,GAC9B,OAAO,CAAC,SAAS,CAAC,CAsCpB;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAS3D"}
|
package/dist/config/loader.js
CHANGED
|
@@ -50,7 +50,32 @@ async function loadFile(searchFrom) {
|
|
|
50
50
|
}
|
|
51
51
|
return parsed.data;
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
/**
|
|
54
|
+
* Load config from ~/.jam/config.json (user home-directory dotfile).
|
|
55
|
+
* This is the preferred user-level config location.
|
|
56
|
+
*/
|
|
57
|
+
async function loadDotJamConfig() {
|
|
58
|
+
const dotJamDir = join(homedir(), '.jam');
|
|
59
|
+
if (!existsSync(dotJamDir))
|
|
60
|
+
return {};
|
|
61
|
+
const explorer = cosmiconfig(MODULE_NAME, {
|
|
62
|
+
searchPlaces: ['config.json', 'config.yaml', 'config.yml'],
|
|
63
|
+
stopDir: dotJamDir,
|
|
64
|
+
});
|
|
65
|
+
const result = await explorer.search(dotJamDir);
|
|
66
|
+
if (!result)
|
|
67
|
+
return {};
|
|
68
|
+
const parsed = JamConfigSchema.partial().safeParse(result.config);
|
|
69
|
+
if (!parsed.success) {
|
|
70
|
+
throw new JamError(`Invalid config at ${result.filepath}: ${parsed.error.message}`, 'CONFIG_INVALID');
|
|
71
|
+
}
|
|
72
|
+
return parsed.data;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Load config from ~/.config/jam/config.json (XDG-style user config).
|
|
76
|
+
* Lower priority than ~/.jam/config.json.
|
|
77
|
+
*/
|
|
78
|
+
async function loadXdgUserConfig() {
|
|
54
79
|
const userConfigDir = join(homedir(), '.config', MODULE_NAME);
|
|
55
80
|
if (!existsSync(userConfigDir))
|
|
56
81
|
return {};
|
|
@@ -68,9 +93,17 @@ async function loadUserConfig() {
|
|
|
68
93
|
return parsed.data;
|
|
69
94
|
}
|
|
70
95
|
export async function loadConfig(cwd = process.cwd(), cliOverrides = {}) {
|
|
71
|
-
|
|
96
|
+
// Merge order (lowest → highest priority):
|
|
97
|
+
// 1. Built-in defaults
|
|
98
|
+
// 2. ~/.config/jam/config.json (XDG user config)
|
|
99
|
+
// 3. ~/.jam/config.json (home-dir dotfile — preferred)
|
|
100
|
+
// 4. .jam/config.json / .jamrc (repo-level)
|
|
101
|
+
// 5. CLI flags
|
|
102
|
+
const xdgConfig = await loadXdgUserConfig();
|
|
103
|
+
const dotJamConfig = await loadDotJamConfig();
|
|
72
104
|
const repoConfig = await loadFile(cwd);
|
|
73
|
-
let config = mergeConfigs(CONFIG_DEFAULTS,
|
|
105
|
+
let config = mergeConfigs(CONFIG_DEFAULTS, xdgConfig);
|
|
106
|
+
config = mergeConfigs(config, dotJamConfig);
|
|
74
107
|
config = mergeConfigs(config, repoConfig);
|
|
75
108
|
// Apply CLI overrides to the active profile
|
|
76
109
|
const profileName = cliOverrides.profile ?? config.defaultProfile;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC1C,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAClC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,WAAW,GAAG,KAAK,CAAC;AAE1B,SAAS,iBAAiB,CACxB,IAA6B,EAC7B,QAAiC;IAEjC,MAAM,MAAM,GAA4B,EAAE,GAAG,IAAI,EAAE,CAAC;IACpD,KAAK,MAAM,CAAC,GAAG,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;QAClD,MAAM,QAAQ,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,CAAC,GAAG,EAAE,GAAG,QAAQ,EAAE,GAAG,GAAG,EAAE,CAAC;QACxC,CAAC;aAAM,CAAC;YACN,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC;QACpB,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,SAAS,YAAY,CAAC,IAAe,EAAE,QAA4B;IACjE,OAAO;QACL,GAAG,IAAI;QACP,GAAG,QAAQ;QACX,QAAQ,EAAE,iBAAiB,CAAC,IAAI,CAAC,QAAQ,EAAE,QAAQ,CAAC,QAAQ,IAAI,EAAE,CAAC;QACnE,aAAa,EAAE,QAAQ,CAAC,aAAa,IAAI,IAAI,CAAC,aAAa;QAC3D,cAAc,EAAE,QAAQ,CAAC,cAAc,IAAI,IAAI,CAAC,cAAc;KAC/D,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,UAAkB;IACxC,MAAM,QAAQ,GAAG,WAAW,CAAC,WAAW,EAAE;QACxC,YAAY,EAAE;YACZ,IAAI,WAAW,IAAI;YACnB,IAAI,WAAW,SAAS;YACxB,IAAI,WAAW,SAAS;YACxB,IAAI,WAAW,QAAQ;YACvB,IAAI,WAAW,cAAc;YAC7B,GAAG,WAAW,YAAY;YAC1B,GAAG,WAAW,aAAa;SAC5B;QACD,OAAO,EAAE,UAAU;KACpB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACjD,IAAI,CAAC,MAAM;QAAE,OAAO,EAAE,CAAC;IAEvB,MAAM,MAAM,GAAG,eAAe,CAAC,OAAO,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;IAClE,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,QAAQ,CAChB,qBAAqB,MAAM,CAAC,QAAQ,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,EAC/D,gBAAgB,CACjB,CAAC;IACJ,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED,KAAK,UAAU,
|
|
1
|
+
{"version":3,"file":"loader.js","sourceRoot":"","sources":["../../src/config/loader.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { ProviderAdapter, ProviderInfo, CompletionRequest, StreamChunk, Message, ToolDefinition, ChatWithToolsResponse } from './base.js';
|
|
2
|
+
export declare class EmbeddedAdapter implements ProviderAdapter {
|
|
3
|
+
readonly info: ProviderInfo;
|
|
4
|
+
private readonly modelSpec;
|
|
5
|
+
private _llama;
|
|
6
|
+
private _model;
|
|
7
|
+
constructor(options?: {
|
|
8
|
+
model?: string;
|
|
9
|
+
});
|
|
10
|
+
/**
|
|
11
|
+
* Lazily load node-llama-cpp, download the model if needed, and warm up.
|
|
12
|
+
* All heavy work happens here so the constructor stays synchronous.
|
|
13
|
+
*/
|
|
14
|
+
private boot;
|
|
15
|
+
validateCredentials(): Promise<void>;
|
|
16
|
+
listModels(): Promise<string[]>;
|
|
17
|
+
streamCompletion(request: CompletionRequest): AsyncIterable<StreamChunk>;
|
|
18
|
+
chatWithTools(messages: Message[], tools: ToolDefinition[], options?: Pick<CompletionRequest, 'model' | 'temperature' | 'maxTokens' | 'systemPrompt'>): Promise<ChatWithToolsResponse>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=embedded.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded.d.ts","sourceRoot":"","sources":["../../src/providers/embedded.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,iBAAiB,EACjB,WAAW,EACX,OAAO,EACP,cAAc,EAEd,qBAAqB,EACtB,MAAM,WAAW,CAAC;AAsFnB,qBAAa,eAAgB,YAAW,eAAe;IACrD,QAAQ,CAAC,IAAI,EAAE,YAAY,CAGzB;IAEF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAE/C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,MAAM,CAAiB;gBAEnB,OAAO,GAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAO;IAM5C;;;OAGG;YACW,IAAI;IA0FZ,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC;IAIpC,UAAU,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;IAuB9B,gBAAgB,CAAC,OAAO,EAAE,iBAAiB,GAAG,aAAa,CAAC,WAAW,CAAC;IA6DzE,aAAa,CACjB,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,cAAc,EAAE,EACvB,OAAO,GAAE,IAAI,CAAC,iBAAiB,EAAE,OAAO,GAAG,aAAa,GAAG,WAAW,GAAG,cAAc,CAAM,GAC5F,OAAO,CAAC,qBAAqB,CAAC;CAuElC"}
|
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
import { JamError } from '../utils/errors.js';
|
|
2
|
+
import { homedir } from 'node:os';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { existsSync, mkdirSync } from 'node:fs';
|
|
5
|
+
// ── Defaults ─────────────────────────────────────────────────────────────────
|
|
6
|
+
/**
|
|
7
|
+
* Directory where embedded GGUF models are cached.
|
|
8
|
+
* ~/.jam/models/
|
|
9
|
+
*/
|
|
10
|
+
const MODELS_DIR = join(homedir(), '.jam', 'models');
|
|
11
|
+
/**
|
|
12
|
+
* Default model to download when no model is specified.
|
|
13
|
+
* SmolLM2-360M is extremely lightweight (~250 MB quantized) and runs
|
|
14
|
+
* comfortably on machines without a GPU.
|
|
15
|
+
*/
|
|
16
|
+
const DEFAULT_HF_REPO = 'HuggingFaceTB/SmolLM2-360M-Instruct-GGUF';
|
|
17
|
+
const DEFAULT_MODEL_FILENAME = 'smollm2-360m-instruct-q4_k_m.gguf';
|
|
18
|
+
const DEFAULT_MODEL_LABEL = 'SmolLM2-360M-Instruct-Q4_K_M';
|
|
19
|
+
/**
|
|
20
|
+
* A curated list of known models users can request by short alias.
|
|
21
|
+
* Maps alias → { repo, file }.
|
|
22
|
+
*/
|
|
23
|
+
const MODEL_ALIASES = {
|
|
24
|
+
'smollm2-135m': {
|
|
25
|
+
repo: 'HuggingFaceTB/SmolLM2-135M-Instruct-GGUF',
|
|
26
|
+
file: 'smollm2-135m-instruct-q4_k_m.gguf',
|
|
27
|
+
},
|
|
28
|
+
'smollm2-360m': {
|
|
29
|
+
repo: 'HuggingFaceTB/SmolLM2-360M-Instruct-GGUF',
|
|
30
|
+
file: 'smollm2-360m-instruct-q4_k_m.gguf',
|
|
31
|
+
},
|
|
32
|
+
'smollm2-1.7b': {
|
|
33
|
+
repo: 'HuggingFaceTB/SmolLM2-1.7B-Instruct-GGUF',
|
|
34
|
+
file: 'smollm2-1.7b-instruct-q4_k_m.gguf',
|
|
35
|
+
},
|
|
36
|
+
};
|
|
37
|
+
// ── Helpers ──────────────────────────────────────────────────────────────────
|
|
38
|
+
function ensureModelsDir() {
|
|
39
|
+
if (!existsSync(MODELS_DIR)) {
|
|
40
|
+
mkdirSync(MODELS_DIR, { recursive: true });
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Resolve a model specifier to { repo, file }.
|
|
45
|
+
* Supports:
|
|
46
|
+
* - Known aliases → "smollm2-360m"
|
|
47
|
+
* - HF repo paths → "HuggingFaceTB/SmolLM2-360M-Instruct-GGUF/smollm2-360m-instruct-q4_k_m.gguf"
|
|
48
|
+
* - Plain filenames → treated as already-downloaded under ~/.jam/models/
|
|
49
|
+
*/
|
|
50
|
+
function resolveModel(model) {
|
|
51
|
+
if (!model) {
|
|
52
|
+
return { repo: DEFAULT_HF_REPO, file: DEFAULT_MODEL_FILENAME };
|
|
53
|
+
}
|
|
54
|
+
const lower = model.toLowerCase();
|
|
55
|
+
if (MODEL_ALIASES[lower]) {
|
|
56
|
+
return MODEL_ALIASES[lower];
|
|
57
|
+
}
|
|
58
|
+
// HF-style "org/repo/filename.gguf"
|
|
59
|
+
const parts = model.split('/');
|
|
60
|
+
if (parts.length >= 3 && model.endsWith('.gguf')) {
|
|
61
|
+
const file = parts.pop();
|
|
62
|
+
const repo = parts.join('/');
|
|
63
|
+
return { repo, file };
|
|
64
|
+
}
|
|
65
|
+
// Already a local path or just a filename
|
|
66
|
+
if (model.endsWith('.gguf')) {
|
|
67
|
+
return { localPath: model.startsWith('/') ? model : join(MODELS_DIR, model) };
|
|
68
|
+
}
|
|
69
|
+
// Default: treat as alias key, fall back to default model
|
|
70
|
+
return { repo: DEFAULT_HF_REPO, file: DEFAULT_MODEL_FILENAME };
|
|
71
|
+
}
|
|
72
|
+
// ── Adapter ──────────────────────────────────────────────────────────────────
|
|
73
|
+
export class EmbeddedAdapter {
|
|
74
|
+
info = {
|
|
75
|
+
name: 'embedded (experimental)',
|
|
76
|
+
supportsStreaming: true,
|
|
77
|
+
};
|
|
78
|
+
modelSpec;
|
|
79
|
+
// Lazy-loaded resources
|
|
80
|
+
_llama = null;
|
|
81
|
+
_model = null;
|
|
82
|
+
constructor(options = {}) {
|
|
83
|
+
this.modelSpec = options.model;
|
|
84
|
+
}
|
|
85
|
+
// ── Bootstrap ────────────────────────────────────────────────────────────
|
|
86
|
+
/**
|
|
87
|
+
* Lazily load node-llama-cpp, download the model if needed, and warm up.
|
|
88
|
+
* All heavy work happens here so the constructor stays synchronous.
|
|
89
|
+
*/
|
|
90
|
+
async boot() {
|
|
91
|
+
if (this._llama && this._model) {
|
|
92
|
+
return { llama: this._llama, model: this._model };
|
|
93
|
+
}
|
|
94
|
+
let nlc;
|
|
95
|
+
try {
|
|
96
|
+
nlc = await import('node-llama-cpp');
|
|
97
|
+
}
|
|
98
|
+
catch {
|
|
99
|
+
throw new JamError('The "embedded" provider requires the `node-llama-cpp` package.\n' +
|
|
100
|
+
'Install it with: npm install node-llama-cpp\n' +
|
|
101
|
+
'Then run `jam doctor` to verify.', 'PROVIDER_UNAVAILABLE', { retryable: false });
|
|
102
|
+
}
|
|
103
|
+
ensureModelsDir();
|
|
104
|
+
process.stderr.write('\n ⚠️ Embedded provider is EXPERIMENTAL. Quality is limited by small model size.\n' +
|
|
105
|
+
' For production workloads, consider using Ollama or OpenAI.\n\n');
|
|
106
|
+
const resolved = resolveModel(this.modelSpec);
|
|
107
|
+
let modelPath;
|
|
108
|
+
if ('localPath' in resolved) {
|
|
109
|
+
modelPath = resolved.localPath;
|
|
110
|
+
if (!existsSync(modelPath)) {
|
|
111
|
+
throw new JamError(`Model file not found: ${modelPath}`, 'PROVIDER_MODEL_NOT_FOUND', { retryable: false });
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
// Check if already downloaded
|
|
116
|
+
const cached = join(MODELS_DIR, resolved.file);
|
|
117
|
+
if (existsSync(cached)) {
|
|
118
|
+
modelPath = cached;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
process.stderr.write(`\n Downloading embedded model: ${resolved.file}\n` +
|
|
122
|
+
` From: huggingface.co/${resolved.repo}\n` +
|
|
123
|
+
` Destination: ${cached}\n` +
|
|
124
|
+
` This is a one-time download...\n\n`);
|
|
125
|
+
try {
|
|
126
|
+
await nlc.downloadModel({
|
|
127
|
+
url: `https://huggingface.co/${resolved.repo}/resolve/main/${resolved.file}`,
|
|
128
|
+
dirPath: MODELS_DIR,
|
|
129
|
+
fileName: resolved.file,
|
|
130
|
+
onProgress: (progress) => {
|
|
131
|
+
const pct = Math.round((progress.downloaded / progress.total) * 100);
|
|
132
|
+
process.stderr.write(`\r Progress: ${pct}%`);
|
|
133
|
+
},
|
|
134
|
+
});
|
|
135
|
+
process.stderr.write('\n Download complete!\n\n');
|
|
136
|
+
}
|
|
137
|
+
catch (err) {
|
|
138
|
+
throw new JamError(`Failed to download model "${resolved.file}" from huggingface.co/${resolved.repo}.\n` +
|
|
139
|
+
`Check your internet connection and try again.`, 'PROVIDER_UNAVAILABLE', { retryable: true, cause: err });
|
|
140
|
+
}
|
|
141
|
+
modelPath = cached;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
try {
|
|
145
|
+
const llama = await nlc.getLlama();
|
|
146
|
+
const model = await llama.loadModel({ modelPath });
|
|
147
|
+
this._llama = llama;
|
|
148
|
+
this._model = model;
|
|
149
|
+
return { llama, model };
|
|
150
|
+
}
|
|
151
|
+
catch (err) {
|
|
152
|
+
throw new JamError(`Failed to load model from ${modelPath}. The file may be corrupted.\n` +
|
|
153
|
+
`Try deleting it and re-running so it re-downloads.`, 'PROVIDER_UNAVAILABLE', { retryable: true, cause: err });
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
// ── ProviderAdapter interface ────────────────────────────────────────────
|
|
157
|
+
async validateCredentials() {
|
|
158
|
+
await this.boot();
|
|
159
|
+
}
|
|
160
|
+
async listModels() {
|
|
161
|
+
// List known aliases + any .gguf files already cached
|
|
162
|
+
const aliases = Object.keys(MODEL_ALIASES);
|
|
163
|
+
const cached = [];
|
|
164
|
+
try {
|
|
165
|
+
const { readdirSync } = await import('node:fs');
|
|
166
|
+
const files = readdirSync(MODELS_DIR);
|
|
167
|
+
for (const f of files) {
|
|
168
|
+
if (f.endsWith('.gguf')) {
|
|
169
|
+
cached.push(f);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
catch {
|
|
174
|
+
// Models dir may not exist yet — that's fine
|
|
175
|
+
}
|
|
176
|
+
return [
|
|
177
|
+
...aliases.map((a) => `${a} (alias)`),
|
|
178
|
+
...cached.map((f) => `${f} (cached)`),
|
|
179
|
+
];
|
|
180
|
+
}
|
|
181
|
+
async *streamCompletion(request) {
|
|
182
|
+
const { model } = await this.boot();
|
|
183
|
+
// node-llama-cpp v3 API
|
|
184
|
+
const nlc = await import('node-llama-cpp');
|
|
185
|
+
const context = await model.createContext();
|
|
186
|
+
const session = new nlc.LlamaChatSession({ contextSequence: context.getSequence() });
|
|
187
|
+
// Build prompt from messages
|
|
188
|
+
const promptParts = [];
|
|
189
|
+
if (request.systemPrompt) {
|
|
190
|
+
promptParts.push(request.systemPrompt);
|
|
191
|
+
}
|
|
192
|
+
for (const msg of request.messages) {
|
|
193
|
+
if (msg.role === 'system') {
|
|
194
|
+
promptParts.push(msg.content);
|
|
195
|
+
}
|
|
196
|
+
else if (msg.role === 'user') {
|
|
197
|
+
promptParts.push(msg.content);
|
|
198
|
+
}
|
|
199
|
+
else if (msg.role === 'assistant') {
|
|
200
|
+
promptParts.push(msg.content);
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
// Get the last user message as the prompt (chat session manages history)
|
|
204
|
+
const lastUserMsg = [...request.messages].reverse().find((m) => m.role === 'user');
|
|
205
|
+
const prompt = lastUserMsg?.content ?? promptParts.join('\n');
|
|
206
|
+
let totalTokens = 0;
|
|
207
|
+
let completionText = '';
|
|
208
|
+
try {
|
|
209
|
+
const response = await session.prompt(prompt, {
|
|
210
|
+
maxTokens: request.maxTokens ?? 2048,
|
|
211
|
+
temperature: request.temperature ?? 0.7,
|
|
212
|
+
onTextChunk: undefined, // we'll use the non-streaming path and chunk it
|
|
213
|
+
});
|
|
214
|
+
completionText = response;
|
|
215
|
+
totalTokens = completionText.split(/\s+/).length; // rough estimate
|
|
216
|
+
// Emit the complete response as chunks for streaming compatibility
|
|
217
|
+
const chunkSize = 4; // characters per chunk for simulated streaming
|
|
218
|
+
for (let i = 0; i < completionText.length; i += chunkSize) {
|
|
219
|
+
const delta = completionText.slice(i, i + chunkSize);
|
|
220
|
+
yield { delta, done: false };
|
|
221
|
+
}
|
|
222
|
+
yield {
|
|
223
|
+
delta: '',
|
|
224
|
+
done: true,
|
|
225
|
+
usage: {
|
|
226
|
+
promptTokens: 0, // node-llama-cpp doesn't expose this easily
|
|
227
|
+
completionTokens: totalTokens,
|
|
228
|
+
totalTokens,
|
|
229
|
+
},
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
finally {
|
|
233
|
+
context.dispose();
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
async chatWithTools(messages, tools, options = {}) {
|
|
237
|
+
const { model } = await this.boot();
|
|
238
|
+
const nlc = await import('node-llama-cpp');
|
|
239
|
+
const context = await model.createContext();
|
|
240
|
+
const session = new nlc.LlamaChatSession({ contextSequence: context.getSequence() });
|
|
241
|
+
// Build prompt that describes available tools (small models won't do
|
|
242
|
+
// native function calling, so we describe them in the system prompt).
|
|
243
|
+
const toolDescriptions = tools.map((t) => {
|
|
244
|
+
const params = Object.entries(t.parameters.properties)
|
|
245
|
+
.map(([name, schema]) => ` - ${name} (${schema.type}): ${schema.description ?? ''}`)
|
|
246
|
+
.join('\n');
|
|
247
|
+
return `Tool: ${t.name}\nDescription: ${t.description}\nParameters:\n${params}`;
|
|
248
|
+
}).join('\n\n');
|
|
249
|
+
const systemInstructions = [
|
|
250
|
+
options.systemPrompt ?? '',
|
|
251
|
+
tools.length > 0
|
|
252
|
+
? `You have access to the following tools. To call a tool, respond with EXACTLY this JSON format on its own line:\n` +
|
|
253
|
+
`{"tool_call": {"name": "<tool_name>", "arguments": {<args>}}}\n\n` +
|
|
254
|
+
`Available tools:\n${toolDescriptions}`
|
|
255
|
+
: '',
|
|
256
|
+
].filter(Boolean).join('\n\n');
|
|
257
|
+
const lastUserMsg = [...messages].reverse().find((m) => m.role === 'user');
|
|
258
|
+
const prompt = (systemInstructions ? systemInstructions + '\n\n' : '') +
|
|
259
|
+
(lastUserMsg?.content ?? '');
|
|
260
|
+
let response;
|
|
261
|
+
try {
|
|
262
|
+
response = await session.prompt(prompt, {
|
|
263
|
+
maxTokens: options.maxTokens ?? 2048,
|
|
264
|
+
temperature: options.temperature ?? 0.3,
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
finally {
|
|
268
|
+
context.dispose();
|
|
269
|
+
}
|
|
270
|
+
// Parse tool calls from the response
|
|
271
|
+
const toolCalls = [];
|
|
272
|
+
const lines = response.split('\n');
|
|
273
|
+
const textParts = [];
|
|
274
|
+
for (const line of lines) {
|
|
275
|
+
const trimmed = line.trim();
|
|
276
|
+
if (trimmed.startsWith('{"tool_call"')) {
|
|
277
|
+
try {
|
|
278
|
+
const parsed = JSON.parse(trimmed);
|
|
279
|
+
toolCalls.push({
|
|
280
|
+
name: parsed.tool_call.name,
|
|
281
|
+
arguments: parsed.tool_call.arguments,
|
|
282
|
+
});
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Not valid JSON — treat as text
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
textParts.push(line);
|
|
290
|
+
}
|
|
291
|
+
return {
|
|
292
|
+
content: textParts.join('\n').trim() || null,
|
|
293
|
+
toolCalls: toolCalls.length > 0 ? toolCalls : undefined,
|
|
294
|
+
usage: {
|
|
295
|
+
promptTokens: 0,
|
|
296
|
+
completionTokens: 0,
|
|
297
|
+
totalTokens: 0,
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
//# sourceMappingURL=embedded.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"embedded.js","sourceRoot":"","sources":["../../src/providers/embedded.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AACjD,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAGnD,wBAAsB,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,OAAO,CAAC,eAAe,CAAC,CA4C/E"}
|
|
@@ -24,6 +24,14 @@ export async function createProvider(profile) {
|
|
|
24
24
|
apiKey: profile.apiKey,
|
|
25
25
|
});
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
if (provider === 'embedded') {
|
|
28
|
+
process.stderr.write('\n \x1b[33m[EXPERIMENTAL]\x1b[0m Using embedded provider — model runs in-process via node-llama-cpp.\n' +
|
|
29
|
+
' Model will be downloaded on first use only when provider is set to "embedded".\n\n');
|
|
30
|
+
const { EmbeddedAdapter } = await import('./embedded.js');
|
|
31
|
+
return new EmbeddedAdapter({
|
|
32
|
+
model: profile.model,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
throw new JamError(`Unknown provider: "${provider}". Supported providers: ollama, openai, groq, embedded`, 'CONFIG_INVALID');
|
|
28
36
|
}
|
|
29
37
|
//# sourceMappingURL=factory.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAgB;IACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACtD,OAAO,IAAI,aAAa,CAAC;YACvB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACtD,OAAO,IAAI,aAAa,CAAC;YACvB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAClD,OAAO,IAAI,WAAW,CAAC;YACrB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,QAAQ,CAChB,sBAAsB,QAAQ,
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../../src/providers/factory.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAC;AAE9C,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,OAAgB;IACnD,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACtD,OAAO,IAAI,aAAa,CAAC;YACvB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAC1B,MAAM,EAAE,aAAa,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;QACtD,OAAO,IAAI,aAAa,CAAC;YACvB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,KAAK,MAAM,EAAE,CAAC;QACxB,MAAM,EAAE,WAAW,EAAE,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;QAClD,OAAO,IAAI,WAAW,CAAC;YACrB,OAAO,EAAE,OAAO,CAAC,OAAO;YACxB,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,QAAQ,KAAK,UAAU,EAAE,CAAC;QAC5B,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,yGAAyG;YACzG,sFAAsF,CACvF,CAAC;QACF,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,eAAe,CAAC,CAAC;QAC1D,OAAO,IAAI,eAAe,CAAC;YACzB,KAAK,EAAE,OAAO,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAED,MAAM,IAAI,QAAQ,CAChB,sBAAsB,QAAQ,wDAAwD,EACtF,gBAAgB,CACjB,CAAC;AACJ,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sunilp-org/jam-cli",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.2",
|
|
4
4
|
"description": "Jam — developer-first AI assistant CLI for the terminal. Ask questions, explain code, review diffs, generate patches, and run agentic tasks powered by Ollama.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
"assistant",
|
|
24
24
|
"terminal",
|
|
25
25
|
"ollama",
|
|
26
|
+
"embedded",
|
|
26
27
|
"llm",
|
|
27
28
|
"developer-tools",
|
|
28
29
|
"code-review",
|
|
@@ -54,7 +55,8 @@
|
|
|
54
55
|
"clean": "rm -rf dist"
|
|
55
56
|
},
|
|
56
57
|
"optionalDependencies": {
|
|
57
|
-
"keytar": "^7.9.0"
|
|
58
|
+
"keytar": "^7.9.0",
|
|
59
|
+
"node-llama-cpp": "^3.0.0"
|
|
58
60
|
},
|
|
59
61
|
"dependencies": {
|
|
60
62
|
"chalk": "^5.3.0",
|