capman 0.4.5 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +89 -0
- package/CODEBASE.md +94 -156
- package/README.md +23 -0
- package/bin/lib/cmd-generate.js +20 -3
- package/dist/cjs/cache.d.ts +6 -4
- package/dist/cjs/cache.d.ts.map +1 -1
- package/dist/cjs/cache.js +38 -11
- package/dist/cjs/cache.js.map +1 -1
- package/dist/cjs/engine.d.ts +46 -4
- package/dist/cjs/engine.d.ts.map +1 -1
- package/dist/cjs/engine.js +157 -211
- package/dist/cjs/engine.js.map +1 -1
- package/dist/cjs/index.d.ts +1 -1
- package/dist/cjs/index.d.ts.map +1 -1
- package/dist/cjs/index.js +2 -1
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/learning.d.ts +16 -1
- package/dist/cjs/learning.d.ts.map +1 -1
- package/dist/cjs/learning.js +161 -10
- package/dist/cjs/learning.js.map +1 -1
- package/dist/cjs/matcher.d.ts +23 -0
- package/dist/cjs/matcher.d.ts.map +1 -1
- package/dist/cjs/matcher.js +53 -18
- package/dist/cjs/matcher.js.map +1 -1
- package/dist/cjs/parser.js +15 -1
- package/dist/cjs/parser.js.map +1 -1
- package/dist/cjs/resolver.d.ts.map +1 -1
- package/dist/cjs/resolver.js +22 -5
- package/dist/cjs/resolver.js.map +1 -1
- package/dist/cjs/version.d.ts +1 -1
- package/dist/cjs/version.js +1 -1
- package/dist/esm/cache.d.ts +6 -4
- package/dist/esm/cache.js +38 -11
- package/dist/esm/engine.d.ts +46 -4
- package/dist/esm/engine.js +158 -212
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/learning.d.ts +16 -1
- package/dist/esm/learning.js +161 -10
- package/dist/esm/matcher.d.ts +23 -0
- package/dist/esm/matcher.js +49 -16
- package/dist/esm/parser.js +15 -1
- package/dist/esm/resolver.js +22 -5
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAA2C,MAAM,SAAS,CAAA;AAIlG,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,eAAe,EAAE,OAAO,CAAA;IACxB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;
|
|
1
|
+
{"version":3,"file":"resolver.d.ts","sourceRoot":"","sources":["../../src/resolver.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAA2C,MAAM,SAAS,CAAA;AAIlG,MAAM,WAAW,WAAW;IAC1B,mDAAmD;IACnD,eAAe,EAAE,OAAO,CAAA;IACxB,0BAA0B;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IACvB,uDAAuD;IACvD,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,cAAc;IAC7B,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,CAAA;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAqCD,wBAAsB,OAAO,CAC3B,WAAW,EAAE,WAAW,EACxB,MAAM,GAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAM,EACpC,OAAO,GAAE,cAAmB,GAC3B,OAAO,CAAC,aAAa,CAAC,CA+ExB"}
|
package/dist/cjs/resolver.js
CHANGED
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.resolve = resolve;
|
|
4
4
|
const logger_1 = require("./logger");
|
|
5
|
+
function redactParams(params) {
|
|
6
|
+
return Object.fromEntries(Object.entries(params).map(([k, v]) => [k, v != null ? '[REDACTED]' : 'null']));
|
|
7
|
+
}
|
|
5
8
|
function checkPrivacy(capability, auth) {
|
|
6
9
|
const level = capability.privacy.level;
|
|
7
10
|
if (level === 'public')
|
|
@@ -44,19 +47,25 @@ async function resolve(matchResult, params = {}, options = {}) {
|
|
|
44
47
|
};
|
|
45
48
|
}
|
|
46
49
|
// ── Session param injection ───────────────────────────────────────────────
|
|
47
|
-
// Inject auth.userId into
|
|
50
|
+
// Inject auth.userId into params marked as source: 'session'
|
|
51
|
+
// Session params are only injected if they appear as {template} in the path —
|
|
52
|
+
// they must never leak into the query string as ?user_id=xyz
|
|
48
53
|
const enrichedParams = { ...params };
|
|
49
54
|
if (options.auth?.userId !== undefined && options.auth.userId !== '') {
|
|
55
|
+
const resolver = capability.resolver;
|
|
56
|
+
const pathTemplate = resolver.type === 'api' ? resolver.endpoints.map(e => e.path).join('') :
|
|
57
|
+
resolver.type === 'hybrid' ? resolver.api.endpoints.map(e => e.path).join('') :
|
|
58
|
+
resolver.type === 'nav' ? resolver.destination : '';
|
|
50
59
|
for (const param of capability.params) {
|
|
51
|
-
if (param.source === 'session') {
|
|
60
|
+
if (param.source === 'session' && pathTemplate.includes(`{${param.name}}`)) {
|
|
52
61
|
enrichedParams[param.name] = options.auth.userId;
|
|
53
|
-
logger_1.logger.debug(`Injected session param "${param.name}"
|
|
62
|
+
logger_1.logger.debug(`Injected session param "${param.name}" (value redacted)`);
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
}
|
|
57
66
|
const resolver = capability.resolver;
|
|
58
67
|
logger_1.logger.info(`Resolving capability "${capability.id}" via ${resolver.type} resolver`);
|
|
59
|
-
logger_1.logger.debug(`Params: ${JSON.stringify(params)}`);
|
|
68
|
+
logger_1.logger.debug(`Params: ${JSON.stringify(redactParams(params))}`);
|
|
60
69
|
logger_1.logger.debug(`Options: baseUrl=${options.baseUrl} dryRun=${options.dryRun}`);
|
|
61
70
|
try {
|
|
62
71
|
switch (resolver.type) {
|
|
@@ -172,12 +181,20 @@ async function resolveApi(resolver, params, options) {
|
|
|
172
181
|
};
|
|
173
182
|
}
|
|
174
183
|
}
|
|
184
|
+
function validateNavParam(key, value) {
|
|
185
|
+
if (!/^[a-zA-Z0-9_\-]+$/.test(value)) {
|
|
186
|
+
throw new Error(`Nav param "${key}" contains invalid characters: "${value}". ` +
|
|
187
|
+
`Only alphanumeric, hyphens, and underscores are allowed.`);
|
|
188
|
+
}
|
|
189
|
+
}
|
|
175
190
|
function resolveNav(resolver, params) {
|
|
176
191
|
let destination = resolver.destination;
|
|
177
192
|
for (const [key, value] of Object.entries(params)) {
|
|
178
193
|
if (value === null || value === undefined)
|
|
179
194
|
continue;
|
|
180
|
-
|
|
195
|
+
const str = String(value);
|
|
196
|
+
validateNavParam(key, str);
|
|
197
|
+
destination = destination.replace(`{${key}}`, encodeURIComponent(str));
|
|
181
198
|
}
|
|
182
199
|
return { success: true, resolverType: 'nav', navTarget: destination };
|
|
183
200
|
}
|
package/dist/cjs/resolver.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/resolver.ts"],"names":[],"mappings":";;
|
|
1
|
+
{"version":3,"file":"resolver.js","sourceRoot":"","sources":["../../src/resolver.ts"],"names":[],"mappings":"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"}
|
package/dist/cjs/version.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const VERSION = "0.
|
|
1
|
+
export declare const VERSION = "0.5.1";
|
|
2
2
|
//# sourceMappingURL=version.d.ts.map
|
package/dist/cjs/version.js
CHANGED
package/dist/esm/cache.d.ts
CHANGED
|
@@ -6,7 +6,7 @@ export interface CacheEntry {
|
|
|
6
6
|
hits: number;
|
|
7
7
|
}
|
|
8
8
|
export interface CacheStore {
|
|
9
|
-
get(key: string): Promise<CacheEntry | null>;
|
|
9
|
+
get(key: string, ttlMs?: number): Promise<CacheEntry | null>;
|
|
10
10
|
set(key: string, result: MatchResult): Promise<void>;
|
|
11
11
|
clear(): Promise<void>;
|
|
12
12
|
size(): Promise<number>;
|
|
@@ -21,7 +21,7 @@ export declare function normalizeQuery(query: string): string;
|
|
|
21
21
|
export declare function buildCacheKey(query: string, capabilityId: string | null, extractedParams: Record<string, string | null>): string;
|
|
22
22
|
export declare class MemoryCache implements CacheStore {
|
|
23
23
|
private store;
|
|
24
|
-
get(key: string): Promise<CacheEntry | null>;
|
|
24
|
+
get(key: string, ttlMs?: number): Promise<CacheEntry | null>;
|
|
25
25
|
set(key: string, result: MatchResult): Promise<void>;
|
|
26
26
|
clear(): Promise<void>;
|
|
27
27
|
size(): Promise<number>;
|
|
@@ -30,10 +30,12 @@ export declare class FileCache implements CacheStore {
|
|
|
30
30
|
private filePath;
|
|
31
31
|
private store;
|
|
32
32
|
private loaded;
|
|
33
|
+
private saveQueue;
|
|
33
34
|
constructor(filePath?: string);
|
|
34
35
|
private load;
|
|
35
36
|
private save;
|
|
36
|
-
|
|
37
|
+
private _doSave;
|
|
38
|
+
get(key: string, ttlMs?: number): Promise<CacheEntry | null>;
|
|
37
39
|
set(key: string, result: MatchResult): Promise<void>;
|
|
38
40
|
clear(): Promise<void>;
|
|
39
41
|
size(): Promise<number>;
|
|
@@ -42,7 +44,7 @@ export declare class ComboCache implements CacheStore {
|
|
|
42
44
|
private memory;
|
|
43
45
|
private file;
|
|
44
46
|
constructor(filePath?: string);
|
|
45
|
-
get(key: string): Promise<CacheEntry | null>;
|
|
47
|
+
get(key: string, ttlMs?: number): Promise<CacheEntry | null>;
|
|
46
48
|
set(key: string, result: MatchResult): Promise<void>;
|
|
47
49
|
clear(): Promise<void>;
|
|
48
50
|
size(): Promise<number>;
|
package/dist/esm/cache.js
CHANGED
|
@@ -27,10 +27,17 @@ export class MemoryCache {
|
|
|
27
27
|
constructor() {
|
|
28
28
|
this.store = new Map();
|
|
29
29
|
}
|
|
30
|
-
async get(key) {
|
|
30
|
+
async get(key, ttlMs) {
|
|
31
31
|
const entry = this.store.get(key);
|
|
32
32
|
if (entry) {
|
|
33
|
+
if (ttlMs && Date.now() - new Date(entry.cachedAt).getTime() > ttlMs) {
|
|
34
|
+
this.store.delete(key);
|
|
35
|
+
logger.debug(`Cache entry expired (memory): "${key}"`);
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
33
38
|
entry.hits++;
|
|
39
|
+
this.store.delete(key);
|
|
40
|
+
this.store.set(key, entry);
|
|
34
41
|
logger.debug(`Cache hit (memory): "${key}"`);
|
|
35
42
|
return entry;
|
|
36
43
|
}
|
|
@@ -55,10 +62,12 @@ export class MemoryCache {
|
|
|
55
62
|
async size() { return this.store.size; }
|
|
56
63
|
}
|
|
57
64
|
// ─── File Cache ───────────────────────────────────────────────────────────────
|
|
65
|
+
const FILE_CACHE_MAX = 2048;
|
|
58
66
|
export class FileCache {
|
|
59
67
|
constructor(filePath = '.capman/cache.json') {
|
|
60
68
|
this.store = new Map();
|
|
61
69
|
this.loaded = false;
|
|
70
|
+
this.saveQueue = Promise.resolve();
|
|
62
71
|
this.filePath = path.resolve(process.cwd(), filePath);
|
|
63
72
|
logger.info(`FileCache initialized — writing to: ${this.filePath}`);
|
|
64
73
|
}
|
|
@@ -81,28 +90,47 @@ export class FileCache {
|
|
|
81
90
|
}
|
|
82
91
|
this.loaded = true;
|
|
83
92
|
}
|
|
84
|
-
|
|
93
|
+
save() {
|
|
94
|
+
this.saveQueue = this.saveQueue.then(() => this._doSave());
|
|
95
|
+
return this.saveQueue;
|
|
96
|
+
}
|
|
97
|
+
async _doSave() {
|
|
85
98
|
try {
|
|
86
99
|
const dir = path.dirname(this.filePath);
|
|
87
100
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
88
101
|
await fs.promises.writeFile(this.filePath, JSON.stringify(Object.fromEntries(this.store), null, 2));
|
|
89
102
|
}
|
|
90
|
-
catch {
|
|
91
|
-
logger.warn(`Failed to save file cache to ${this.filePath}`);
|
|
103
|
+
catch (err) {
|
|
104
|
+
logger.warn(`Failed to save file cache to ${this.filePath}: ${err instanceof Error ? err.message : String(err)}`);
|
|
92
105
|
}
|
|
93
106
|
}
|
|
94
|
-
async get(key) {
|
|
107
|
+
async get(key, ttlMs) {
|
|
95
108
|
await this.load();
|
|
96
109
|
const entry = this.store.get(key);
|
|
97
110
|
if (entry) {
|
|
111
|
+
if (ttlMs && Date.now() - new Date(entry.cachedAt).getTime() > ttlMs) {
|
|
112
|
+
this.store.delete(key);
|
|
113
|
+
await this.save();
|
|
114
|
+
logger.debug(`Cache entry expired (file): "${key}"`);
|
|
115
|
+
return null;
|
|
116
|
+
}
|
|
98
117
|
entry.hits++;
|
|
118
|
+
this.store.delete(key);
|
|
119
|
+
this.store.set(key, entry);
|
|
99
120
|
logger.debug(`Cache hit (file): "${key}"`);
|
|
100
|
-
|
|
121
|
+
await this.save();
|
|
101
122
|
}
|
|
102
|
-
return null;
|
|
123
|
+
return entry ?? null;
|
|
103
124
|
}
|
|
104
125
|
async set(key, result) {
|
|
105
126
|
await this.load();
|
|
127
|
+
if (this.store.size >= FILE_CACHE_MAX) {
|
|
128
|
+
const oldest = this.store.keys().next().value;
|
|
129
|
+
if (oldest !== undefined) {
|
|
130
|
+
this.store.delete(oldest);
|
|
131
|
+
logger.debug(`File cache evicted oldest entry (max size ${FILE_CACHE_MAX} reached)`);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
106
134
|
this.store.set(key, {
|
|
107
135
|
query: key,
|
|
108
136
|
result,
|
|
@@ -127,14 +155,13 @@ export class ComboCache {
|
|
|
127
155
|
this.memory = new MemoryCache();
|
|
128
156
|
this.file = new FileCache(filePath);
|
|
129
157
|
}
|
|
130
|
-
async get(key) {
|
|
131
|
-
const memHit = await this.memory.get(key);
|
|
158
|
+
async get(key, ttlMs) {
|
|
159
|
+
const memHit = await this.memory.get(key, ttlMs);
|
|
132
160
|
if (memHit)
|
|
133
161
|
return memHit;
|
|
134
|
-
const fileHit = await this.file.get(key);
|
|
162
|
+
const fileHit = await this.file.get(key, ttlMs);
|
|
135
163
|
if (fileHit) {
|
|
136
164
|
await this.memory.set(key, fileHit.result);
|
|
137
|
-
logger.debug(`Cache promoted to memory: "${key}"`);
|
|
138
165
|
return fileHit;
|
|
139
166
|
}
|
|
140
167
|
return null;
|
package/dist/esm/engine.d.ts
CHANGED
|
@@ -2,8 +2,27 @@ import type { Manifest, MatchResult, ResolveResult, ExecutionTrace, ExplainResul
|
|
|
2
2
|
import type { LLMMatcherOptions } from './matcher';
|
|
3
3
|
import type { ResolveOptions, AuthContext } from './resolver';
|
|
4
4
|
import type { CacheStore } from './cache';
|
|
5
|
-
import type { LearningStore
|
|
5
|
+
import type { LearningStore } from './learning';
|
|
6
6
|
import type { MatchMode } from './index';
|
|
7
|
+
/**
|
|
8
|
+
* Options for constructing a CapmanEngine instance.
|
|
9
|
+
*
|
|
10
|
+
* ⚠️ CONCURRENCY: CapmanEngine is not safe for sharing across concurrent
|
|
11
|
+
* async request handlers. The LLM rate limiter, circuit breaker, and
|
|
12
|
+
* learning index cache are all instance-level mutable state. In an
|
|
13
|
+
* Express/Fastify/etc. server, either:
|
|
14
|
+
* (a) Create one engine per request — safest, no shared state
|
|
15
|
+
* (b) Use a single instance only with cheap mode (no LLM calls)
|
|
16
|
+
* (c) Add an external mutex around LLM calls if sharing is required
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* // Safe — per-request engine
|
|
20
|
+
* app.post('/ask', async (req, res) => {
|
|
21
|
+
* const engine = new CapmanEngine({ manifest, llm, mode: 'balanced' })
|
|
22
|
+
* const result = await engine.ask(req.body.query)
|
|
23
|
+
* res.json(result)
|
|
24
|
+
* })
|
|
25
|
+
*/
|
|
7
26
|
export interface EngineOptions {
|
|
8
27
|
/** The capability manifest to use */
|
|
9
28
|
manifest: Manifest;
|
|
@@ -28,6 +47,19 @@ export interface EngineOptions {
|
|
|
28
47
|
headers?: Record<string, string>;
|
|
29
48
|
/** Confidence threshold for keyword matcher (default: 50) */
|
|
30
49
|
threshold?: number;
|
|
50
|
+
/**
|
|
51
|
+
* Optional TTL for cache entries in milliseconds.
|
|
52
|
+
* Entries older than this are treated as misses and evicted on read.
|
|
53
|
+
* Default: no expiry.
|
|
54
|
+
*
|
|
55
|
+
* Useful when capabilities are frequently updated or removed — ensures
|
|
56
|
+
* stale entries don't persist indefinitely after a manifest change.
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* // Expire cache entries after 1 hour
|
|
60
|
+
* new CapmanEngine({ manifest, cacheTtlMs: 60 * 60 * 1000 })
|
|
61
|
+
*/
|
|
62
|
+
cacheTtlMs?: number;
|
|
31
63
|
/**
|
|
32
64
|
* Maximum LLM calls per minute in balanced/accurate mode.
|
|
33
65
|
* After limit is hit, falls back to keyword result.
|
|
@@ -70,12 +102,11 @@ export declare class CapmanEngine {
|
|
|
70
102
|
private auth?;
|
|
71
103
|
private headers?;
|
|
72
104
|
private threshold;
|
|
105
|
+
private cacheTtlMs;
|
|
73
106
|
private maxLLMCallsPerMinute;
|
|
74
107
|
private llmCooldownMs;
|
|
75
108
|
private llmCircuitBreakerThreshold;
|
|
76
109
|
private llmCircuitBreakerResetMs;
|
|
77
|
-
private cachedStats;
|
|
78
|
-
private statsInvalidated;
|
|
79
110
|
private llmCallsThisMinute;
|
|
80
111
|
private llmWindowStart;
|
|
81
112
|
private llmLastCallAt;
|
|
@@ -98,7 +129,7 @@ export declare class CapmanEngine {
|
|
|
98
129
|
* Get stats from the learning store.
|
|
99
130
|
* Shows which capabilities are most used, LLM vs keyword ratio, cache hit rate.
|
|
100
131
|
*/
|
|
101
|
-
getStats(): Promise<KeywordStats | null>;
|
|
132
|
+
getStats(): Promise<import("./learning").KeywordStats | null>;
|
|
102
133
|
/**
|
|
103
134
|
* Get the most frequently matched capabilities.
|
|
104
135
|
*/
|
|
@@ -141,6 +172,17 @@ export declare class CapmanEngine {
|
|
|
141
172
|
* Records a failed LLM call — may open the circuit breaker.
|
|
142
173
|
*/
|
|
143
174
|
private recordLLMFailure;
|
|
175
|
+
/**
|
|
176
|
+
* Runs the matching pipeline for a query — shared by ask() and explain().
|
|
177
|
+
* Handles cheap / balanced / accurate mode dispatch and LLM rate limiting.
|
|
178
|
+
* Returns the match result and which resolver was used.
|
|
179
|
+
*/
|
|
180
|
+
private _runMatch;
|
|
181
|
+
/**
|
|
182
|
+
* Applies learning boost to a MatchResult and returns the updated result.
|
|
183
|
+
* Shared by ask() and explain() to avoid logic divergence.
|
|
184
|
+
*/
|
|
185
|
+
private applyBoostToMatchResult;
|
|
144
186
|
/**
|
|
145
187
|
* Applies learning boost to match candidates based on historical usage.
|
|
146
188
|
* Capabilities that have previously matched similar keywords get a small
|