compact-agent 1.22.0 → 1.24.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/dist/api.d.ts +11 -0
- package/dist/api.js +65 -15
- package/dist/api.js.map +1 -1
- package/dist/config.js +1 -1
- package/dist/config.js.map +1 -1
- package/dist/index.js +133 -0
- package/dist/index.js.map +1 -1
- package/dist/key-rotation.d.ts +54 -0
- package/dist/key-rotation.js +117 -0
- package/dist/key-rotation.js.map +1 -0
- package/dist/swarm.d.ts +70 -0
- package/dist/swarm.js +119 -0
- package/dist/swarm.js.map +1 -0
- package/dist/types.d.ts +1 -0
- package/dist/types.js +11 -0
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* API key rotation pool — for users with multiple OpenRouter (or any
|
|
3
|
+
* compatible) accounts who want to round-robin / failover across them
|
|
4
|
+
* when one hits a rate limit or runs out of free credits.
|
|
5
|
+
*
|
|
6
|
+
* Pool composition: config.apiKey + config.apiKeys (deduplicated, order
|
|
7
|
+
* preserved). The single `apiKey` field always becomes pool[0] so users
|
|
8
|
+
* with only the legacy config see no change in behavior.
|
|
9
|
+
*
|
|
10
|
+
* Rotation strategy: on 401 / 429 / quota errors, the failing key is
|
|
11
|
+
* marked "cool" for `COOL_DOWN_MS`, the next healthy key takes over.
|
|
12
|
+
* If all keys are cool, the request fails normally — the user will see
|
|
13
|
+
* the last error message. Health state lives in module memory; restart
|
|
14
|
+
* = fresh start.
|
|
15
|
+
*
|
|
16
|
+
* Why module-level vs persisted: rate-limit windows are usually 60s-5m
|
|
17
|
+
* and reset naturally. Persisting cool-down across processes would
|
|
18
|
+
* make the agent worse at recovering from transient blips.
|
|
19
|
+
*/
|
|
20
|
+
const COOL_DOWN_MS = 60_000; // 1 min — typical free-tier RPM window
|
|
21
|
+
const QUOTA_COOL_DOWN_MS = 60 * 60_000; // 1 hour — daily/monthly quota errors
|
|
22
|
+
let pool = [];
|
|
23
|
+
let cursor = 0; // round-robin pointer for which key to try first
|
|
24
|
+
/**
|
|
25
|
+
* Build the pool from a config snapshot. Idempotent; if the same keys
|
|
26
|
+
* are passed in the same order, the existing state is preserved
|
|
27
|
+
* (so cool-downs persist across rebuilds in the same process).
|
|
28
|
+
*/
|
|
29
|
+
export function setPool(primary, extras = []) {
|
|
30
|
+
// Dedupe in order: primary first, then extras
|
|
31
|
+
const seen = new Set();
|
|
32
|
+
const all = [];
|
|
33
|
+
for (const k of [primary, ...extras]) {
|
|
34
|
+
if (k && !seen.has(k)) {
|
|
35
|
+
seen.add(k);
|
|
36
|
+
all.push(k);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// Preserve state for keys that are still in the pool
|
|
40
|
+
const existing = new Map(pool.map((s) => [s.key, s]));
|
|
41
|
+
pool = all.map((k) => existing.get(k) || {
|
|
42
|
+
key: k, coolUntil: 0, successes: 0, failures: 0,
|
|
43
|
+
});
|
|
44
|
+
if (cursor >= pool.length)
|
|
45
|
+
cursor = 0;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Pick the next healthy key to use. Round-robin from the current cursor.
|
|
49
|
+
* Returns null if the pool is empty or all keys are cool.
|
|
50
|
+
*/
|
|
51
|
+
export function pickKey() {
|
|
52
|
+
if (pool.length === 0)
|
|
53
|
+
return null;
|
|
54
|
+
const now = Date.now();
|
|
55
|
+
// Try each key once, starting from cursor
|
|
56
|
+
for (let i = 0; i < pool.length; i++) {
|
|
57
|
+
const idx = (cursor + i) % pool.length;
|
|
58
|
+
if (pool[idx].coolUntil <= now) {
|
|
59
|
+
cursor = (idx + 1) % pool.length; // next call rotates one further
|
|
60
|
+
return pool[idx].key;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Mark a key as failed. The classifier maps the error to either a
|
|
67
|
+
* short cooldown (rate-limit) or a long one (quota / auth). Used by
|
|
68
|
+
* api.ts's retry logic to skip dead keys without re-trying them.
|
|
69
|
+
*/
|
|
70
|
+
export function reportFailure(key, err) {
|
|
71
|
+
const state = pool.find((s) => s.key === key);
|
|
72
|
+
if (!state)
|
|
73
|
+
return;
|
|
74
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
75
|
+
const lower = msg.toLowerCase();
|
|
76
|
+
let cooldown = COOL_DOWN_MS;
|
|
77
|
+
let reason = msg.slice(0, 80);
|
|
78
|
+
if (/quota|insufficient|credit|payment|billing/.test(lower)) {
|
|
79
|
+
cooldown = QUOTA_COOL_DOWN_MS;
|
|
80
|
+
reason = 'quota/credit exhausted';
|
|
81
|
+
}
|
|
82
|
+
else if (/auth|invalid.*key|forbidden|401|403/.test(lower)) {
|
|
83
|
+
cooldown = QUOTA_COOL_DOWN_MS;
|
|
84
|
+
reason = 'auth rejected (bad/revoked key)';
|
|
85
|
+
}
|
|
86
|
+
else if (/rate.?limit|429|too.many/.test(lower)) {
|
|
87
|
+
cooldown = COOL_DOWN_MS;
|
|
88
|
+
reason = 'rate limited';
|
|
89
|
+
}
|
|
90
|
+
state.coolUntil = Date.now() + cooldown;
|
|
91
|
+
state.lastReason = reason;
|
|
92
|
+
state.failures++;
|
|
93
|
+
}
|
|
94
|
+
/** Mark a key as having succeeded — clears any cool-down + records stat. */
|
|
95
|
+
export function reportSuccess(key) {
|
|
96
|
+
const state = pool.find((s) => s.key === key);
|
|
97
|
+
if (!state)
|
|
98
|
+
return;
|
|
99
|
+
state.coolUntil = 0;
|
|
100
|
+
state.lastReason = undefined;
|
|
101
|
+
state.successes++;
|
|
102
|
+
}
|
|
103
|
+
export function listStatus() {
|
|
104
|
+
const now = Date.now();
|
|
105
|
+
return pool.map((s, i) => ({
|
|
106
|
+
index: i,
|
|
107
|
+
tail: `…${s.key.slice(-4)}`,
|
|
108
|
+
healthy: s.coolUntil <= now,
|
|
109
|
+
coolDownRemainingSec: s.coolUntil > now ? Math.ceil((s.coolUntil - now) / 1000) : undefined,
|
|
110
|
+
successes: s.successes,
|
|
111
|
+
failures: s.failures,
|
|
112
|
+
lastReason: s.lastReason,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
/** Currently-active pool size (post-dedup). */
|
|
116
|
+
export function poolSize() { return pool.length; }
|
|
117
|
+
//# sourceMappingURL=key-rotation.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"key-rotation.js","sourceRoot":"","sources":["../src/key-rotation.ts"],"names":[],"mappings":"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"}
|
package/dist/swarm.d.ts
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic swarming — fan out N specialized agents on the same task
|
|
3
|
+
* concurrently and merge their outputs.
|
|
4
|
+
*
|
|
5
|
+
* Inspired by LangGraph's `Send` map-reduce primitive and OpenAI Agents
|
|
6
|
+
* SDK's handoff pattern. The audit ranked these as the two most-portable
|
|
7
|
+
* concepts from the swarming-framework ecosystem; this is the map-reduce
|
|
8
|
+
* half (Send-style fan-out). Sequential handoff stays on the roadmap
|
|
9
|
+
* for /multi-execute.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* /swarm code-architect,silent-failure-hunter,type-design-analyzer audit the auth flow
|
|
13
|
+
*
|
|
14
|
+
* Each agent receives:
|
|
15
|
+
* - System prompt: its own ECC agent prompt (the role-specific persona)
|
|
16
|
+
* - User message: the task verbatim
|
|
17
|
+
* - Empty tool list: swarm runs are analysis-only; no file edits or
|
|
18
|
+
* bash commands. If you want a swarm to make changes, /architect (or
|
|
19
|
+
* other agent slash) first, then act on the synthesis manually.
|
|
20
|
+
*
|
|
21
|
+
* Concurrency: Promise.allSettled — one agent failing doesn't kill the
|
|
22
|
+
* others. Errors surface in the result block.
|
|
23
|
+
*
|
|
24
|
+
* Key pool: every concurrent agent uses streamChat which goes through
|
|
25
|
+
* the key rotation pool from v1.23.0. Users with multiple OpenRouter
|
|
26
|
+
* accounts get true parallel throughput across keys.
|
|
27
|
+
*
|
|
28
|
+
* Cost note: N agents = N model calls. The orchestrator's /help text
|
|
29
|
+
* surfaces this so it isn't surprising.
|
|
30
|
+
*/
|
|
31
|
+
import type { CrowcoderConfig } from './types.js';
|
|
32
|
+
export interface SwarmAgent {
|
|
33
|
+
/** Display name (matches the ECC slug like 'code-architect') */
|
|
34
|
+
name: string;
|
|
35
|
+
/** The system prompt the agent runs with — usually the ECC skill body */
|
|
36
|
+
prompt: string;
|
|
37
|
+
}
|
|
38
|
+
export interface SwarmResult {
|
|
39
|
+
agent: string;
|
|
40
|
+
text: string;
|
|
41
|
+
durationMs: number;
|
|
42
|
+
/** Set when this agent's call threw — others may still have succeeded */
|
|
43
|
+
error?: string;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Look up agents by slug and return their full prompts. Throws on the
|
|
47
|
+
* first unknown slug so the caller can correct + retry rather than
|
|
48
|
+
* partially running.
|
|
49
|
+
*
|
|
50
|
+
* Accepts both bare slugs ("code-architect") and the "agent: <slug>"
|
|
51
|
+
* form that listSkills() returns.
|
|
52
|
+
*/
|
|
53
|
+
export declare function resolveAgents(slugs: string[]): SwarmAgent[];
|
|
54
|
+
/**
|
|
55
|
+
* Run all agents concurrently against the same task. Each agent gets a
|
|
56
|
+
* private message history (its prompt + the task); they don't see each
|
|
57
|
+
* other's output. Merging is the caller's job — usually print-with-
|
|
58
|
+
* attribution + an optional synthesis prompt.
|
|
59
|
+
*
|
|
60
|
+
* No tools available to swarm agents — analysis only. If we exposed
|
|
61
|
+
* tools we'd need lock coordination on the filesystem + permission
|
|
62
|
+
* prompts for every parallel write, which defeats the purpose.
|
|
63
|
+
*/
|
|
64
|
+
export declare function runSwarm(agents: SwarmAgent[], task: string, config: CrowcoderConfig): Promise<SwarmResult[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Format swarm results for stdout — attribution headers + clear visual
|
|
67
|
+
* separation between agents. The caller can pipe this into a follow-up
|
|
68
|
+
* synthesis prompt if they want consensus or comparison.
|
|
69
|
+
*/
|
|
70
|
+
export declare function formatSwarmResults(results: SwarmResult[]): string;
|
package/dist/swarm.js
ADDED
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agentic swarming — fan out N specialized agents on the same task
|
|
3
|
+
* concurrently and merge their outputs.
|
|
4
|
+
*
|
|
5
|
+
* Inspired by LangGraph's `Send` map-reduce primitive and OpenAI Agents
|
|
6
|
+
* SDK's handoff pattern. The audit ranked these as the two most-portable
|
|
7
|
+
* concepts from the swarming-framework ecosystem; this is the map-reduce
|
|
8
|
+
* half (Send-style fan-out). Sequential handoff stays on the roadmap
|
|
9
|
+
* for /multi-execute.
|
|
10
|
+
*
|
|
11
|
+
* Usage:
|
|
12
|
+
* /swarm code-architect,silent-failure-hunter,type-design-analyzer audit the auth flow
|
|
13
|
+
*
|
|
14
|
+
* Each agent receives:
|
|
15
|
+
* - System prompt: its own ECC agent prompt (the role-specific persona)
|
|
16
|
+
* - User message: the task verbatim
|
|
17
|
+
* - Empty tool list: swarm runs are analysis-only; no file edits or
|
|
18
|
+
* bash commands. If you want a swarm to make changes, /architect (or
|
|
19
|
+
* other agent slash) first, then act on the synthesis manually.
|
|
20
|
+
*
|
|
21
|
+
* Concurrency: Promise.allSettled — one agent failing doesn't kill the
|
|
22
|
+
* others. Errors surface in the result block.
|
|
23
|
+
*
|
|
24
|
+
* Key pool: every concurrent agent uses streamChat which goes through
|
|
25
|
+
* the key rotation pool from v1.23.0. Users with multiple OpenRouter
|
|
26
|
+
* accounts get true parallel throughput across keys.
|
|
27
|
+
*
|
|
28
|
+
* Cost note: N agents = N model calls. The orchestrator's /help text
|
|
29
|
+
* surfaces this so it isn't surprising.
|
|
30
|
+
*/
|
|
31
|
+
import { streamChat } from './api.js';
|
|
32
|
+
import { findEccSkillByName } from './ecc.js';
|
|
33
|
+
/**
|
|
34
|
+
* Look up agents by slug and return their full prompts. Throws on the
|
|
35
|
+
* first unknown slug so the caller can correct + retry rather than
|
|
36
|
+
* partially running.
|
|
37
|
+
*
|
|
38
|
+
* Accepts both bare slugs ("code-architect") and the "agent: <slug>"
|
|
39
|
+
* form that listSkills() returns.
|
|
40
|
+
*/
|
|
41
|
+
export function resolveAgents(slugs) {
|
|
42
|
+
const out = [];
|
|
43
|
+
for (const raw of slugs) {
|
|
44
|
+
const slug = raw.trim();
|
|
45
|
+
if (!slug)
|
|
46
|
+
continue;
|
|
47
|
+
// Try direct name match first ("agent: <slug>"), then bare slug
|
|
48
|
+
const skill = findEccSkillByName(`agent: ${slug}`) ?? findEccSkillByName(slug);
|
|
49
|
+
if (!skill) {
|
|
50
|
+
throw new Error(`Unknown agent: "${slug}". Run /ecc-guide agents to see what's available.`);
|
|
51
|
+
}
|
|
52
|
+
out.push({ name: slug, prompt: skill.prompt });
|
|
53
|
+
}
|
|
54
|
+
return out;
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Run all agents concurrently against the same task. Each agent gets a
|
|
58
|
+
* private message history (its prompt + the task); they don't see each
|
|
59
|
+
* other's output. Merging is the caller's job — usually print-with-
|
|
60
|
+
* attribution + an optional synthesis prompt.
|
|
61
|
+
*
|
|
62
|
+
* No tools available to swarm agents — analysis only. If we exposed
|
|
63
|
+
* tools we'd need lock coordination on the filesystem + permission
|
|
64
|
+
* prompts for every parallel write, which defeats the purpose.
|
|
65
|
+
*/
|
|
66
|
+
export async function runSwarm(agents, task, config) {
|
|
67
|
+
const results = await Promise.allSettled(agents.map(async (agent) => {
|
|
68
|
+
const start = Date.now();
|
|
69
|
+
try {
|
|
70
|
+
const messages = [
|
|
71
|
+
{ role: 'system', content: agent.prompt },
|
|
72
|
+
{ role: 'user', content: task },
|
|
73
|
+
];
|
|
74
|
+
let text = '';
|
|
75
|
+
for await (const event of streamChat(config, messages, [])) {
|
|
76
|
+
if (event.type === 'text' && event.content)
|
|
77
|
+
text += event.content;
|
|
78
|
+
}
|
|
79
|
+
return { agent: agent.name, text, durationMs: Date.now() - start };
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
return {
|
|
83
|
+
agent: agent.name,
|
|
84
|
+
text: '',
|
|
85
|
+
durationMs: Date.now() - start,
|
|
86
|
+
error: err instanceof Error ? err.message : String(err),
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
}));
|
|
90
|
+
// Promise.allSettled always resolves; un-pack the values.
|
|
91
|
+
return results.map((r) => (r.status === 'fulfilled' ? r.value : {
|
|
92
|
+
agent: 'unknown',
|
|
93
|
+
text: '',
|
|
94
|
+
durationMs: 0,
|
|
95
|
+
error: `swarm task crashed: ${r.reason}`,
|
|
96
|
+
}));
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Format swarm results for stdout — attribution headers + clear visual
|
|
100
|
+
* separation between agents. The caller can pipe this into a follow-up
|
|
101
|
+
* synthesis prompt if they want consensus or comparison.
|
|
102
|
+
*/
|
|
103
|
+
export function formatSwarmResults(results) {
|
|
104
|
+
const lines = [];
|
|
105
|
+
for (const r of results) {
|
|
106
|
+
lines.push('');
|
|
107
|
+
lines.push(`══════════════════════════════════════════════`);
|
|
108
|
+
lines.push(` ${r.agent} (${(r.durationMs / 1000).toFixed(1)}s${r.error ? ', ERROR' : ''})`);
|
|
109
|
+
lines.push(`──────────────────────────────────────────────`);
|
|
110
|
+
if (r.error) {
|
|
111
|
+
lines.push(` error: ${r.error}`);
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
lines.push(r.text.trim() || '(no output)');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return lines.join('\n');
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=swarm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"swarm.js","sourceRoot":"","sources":["../src/swarm.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
CHANGED
package/dist/types.js
CHANGED
|
@@ -47,6 +47,17 @@ export const PROVIDERS = {
|
|
|
47
47
|
defaultModel: 'glm-4-plus',
|
|
48
48
|
requiresKey: true,
|
|
49
49
|
},
|
|
50
|
+
nvidia: {
|
|
51
|
+
name: 'NVIDIA NIM',
|
|
52
|
+
baseURL: 'https://integrate.api.nvidia.com/v1',
|
|
53
|
+
// meta/llama-3.1-70b-instruct is the most-reliable widely-available
|
|
54
|
+
// default on build.nvidia.com's free tier as of 2026. Users can switch
|
|
55
|
+
// to nvidia/nemotron-4-340b-instruct, qwen/qwen-2.5-coder-32b-instruct,
|
|
56
|
+
// deepseek-ai/deepseek-coder-6.7b-instruct, or any of the ~100 models
|
|
57
|
+
// exposed at /v1/chat/completions via /model.
|
|
58
|
+
defaultModel: 'meta/llama-3.1-70b-instruct',
|
|
59
|
+
requiresKey: true,
|
|
60
|
+
},
|
|
50
61
|
custom: {
|
|
51
62
|
name: 'Custom',
|
|
52
63
|
baseURL: '',
|
package/dist/types.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAiHA,MAAM,CAAC,MAAM,SAAS,GAAmC;IACvD,SAAS,EAAE;QACT,IAAI,EAAE,oBAAoB;QAC1B,OAAO,EAAE,+BAA+B;QACxC,YAAY,EAAE,0BAA0B;QACxC,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,cAAc;QACpB,OAAO,EAAE,2BAA2B;QACpC,YAAY,EAAE,QAAQ;QACtB,WAAW,EAAE,IAAI;KAClB;IACD,UAAU,EAAE;QACV,IAAI,EAAE,wBAAwB;QAC9B,OAAO,EAAE,8BAA8B;QACvC,YAAY,EAAE,2BAA2B;QACzC,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,iBAAiB;QACvB,OAAO,EAAE,0DAA0D;QACnE,YAAY,EAAE,kBAAkB;QAChC,WAAW,EAAE,IAAI;KAClB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,6BAA6B;QACtC,YAAY,EAAE,eAAe;QAC7B,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,gBAAgB;QACtB,OAAO,EAAE,2BAA2B;QACpC,YAAY,EAAE,sBAAsB;QACpC,WAAW,EAAE,KAAK;KACnB;IACD,QAAQ,EAAE;QACR,IAAI,EAAE,WAAW;QACjB,OAAO,EAAE,0BAA0B;QACnC,YAAY,EAAE,cAAc;QAC5B,WAAW,EAAE,KAAK;KACnB;IACD,GAAG,EAAE;QACH,IAAI,EAAE,eAAe;QACrB,OAAO,EAAE,sCAAsC;QAC/C,YAAY,EAAE,YAAY;QAC1B,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,qCAAqC;QAC9C,oEAAoE;QACpE,uEAAuE;QACvE,wEAAwE;QACxE,sEAAsE;QACtE,8CAA8C;QAC9C,YAAY,EAAE,6BAA6B;QAC3C,WAAW,EAAE,IAAI;KAClB;IACD,MAAM,EAAE;QACN,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,EAAE;QACX,YAAY,EAAE,EAAE;QAChB,WAAW,EAAE,IAAI;KAClB;CACF,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "compact-agent",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.24.0",
|
|
4
4
|
"description": "A dense, feature-rich AI coding agent for the terminal. Built-in voice dictation (Whisper) + TTS readout (ElevenLabs) + screen-reader mode for blind / low-vision users. 80+ slash commands, 9 modes including Hermes self-improving loop, multi-agent orchestration, bundled everything-claude-code skills library, learning system, and observable LLM transport. Works with OpenRouter, OpenAI, Anthropic-compatible, Ollama, LM Studio, DeepSeek, or any OpenAI-compatible API.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|