@compilr-dev/sdk 0.29.6 → 0.29.8
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.
|
@@ -46,9 +46,9 @@ export const MODEL_REGISTRY = [
|
|
|
46
46
|
contextWindow: 1000000,
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
|
-
id: 'claude-opus-
|
|
50
|
-
displayName: 'Opus
|
|
51
|
-
description: 'Most capable',
|
|
49
|
+
id: 'claude-opus-5-5',
|
|
50
|
+
displayName: 'Opus 5.5',
|
|
51
|
+
description: 'Most capable Opus',
|
|
52
52
|
provider: 'claude',
|
|
53
53
|
supportsImages: true,
|
|
54
54
|
supportsTools: true,
|
|
@@ -56,10 +56,11 @@ export const MODEL_REGISTRY = [
|
|
|
56
56
|
thinkingFormat: 'claude',
|
|
57
57
|
status: 'supported',
|
|
58
58
|
contextWindow: 1000000,
|
|
59
|
+
notes: 'Thinking always on (effort is the only control; default effort medium); $4/$20 per MTok',
|
|
59
60
|
},
|
|
60
61
|
{
|
|
61
|
-
id: 'claude-fable-5',
|
|
62
|
-
displayName: 'Fable 5',
|
|
62
|
+
id: 'claude-fable-5-1',
|
|
63
|
+
displayName: 'Fable 5.1',
|
|
63
64
|
description: 'Highest capability, long-running agents',
|
|
64
65
|
provider: 'claude',
|
|
65
66
|
supportsImages: true,
|
|
@@ -70,6 +71,42 @@ export const MODEL_REGISTRY = [
|
|
|
70
71
|
notes: 'Flagship: adaptive thinking always on; premium pricing ($10/$50 per MTok)',
|
|
71
72
|
},
|
|
72
73
|
// Legacy Claude models (still supported)
|
|
74
|
+
{
|
|
75
|
+
id: 'claude-opus-5',
|
|
76
|
+
displayName: 'Opus 5',
|
|
77
|
+
description: 'Previous generation',
|
|
78
|
+
provider: 'claude',
|
|
79
|
+
supportsImages: true,
|
|
80
|
+
supportsTools: true,
|
|
81
|
+
thinkingFormat: 'claude',
|
|
82
|
+
status: 'supported',
|
|
83
|
+
contextWindow: 1000000,
|
|
84
|
+
notes: 'Legacy — consider upgrading to Opus 5.5',
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
id: 'claude-fable-5',
|
|
88
|
+
displayName: 'Fable 5',
|
|
89
|
+
description: 'Previous generation',
|
|
90
|
+
provider: 'claude',
|
|
91
|
+
supportsImages: true,
|
|
92
|
+
supportsTools: true,
|
|
93
|
+
thinkingFormat: 'claude',
|
|
94
|
+
status: 'supported',
|
|
95
|
+
contextWindow: 1000000,
|
|
96
|
+
notes: 'Legacy — consider upgrading to Fable 5.1 (same price)',
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
id: 'claude-opus-4-8',
|
|
100
|
+
displayName: 'Opus 4.8',
|
|
101
|
+
description: 'Previous generation',
|
|
102
|
+
provider: 'claude',
|
|
103
|
+
supportsImages: true,
|
|
104
|
+
supportsTools: true,
|
|
105
|
+
thinkingFormat: 'claude',
|
|
106
|
+
status: 'supported',
|
|
107
|
+
contextWindow: 1000000,
|
|
108
|
+
notes: 'Legacy — consider upgrading to Opus 5.5',
|
|
109
|
+
},
|
|
73
110
|
{
|
|
74
111
|
id: 'claude-opus-4-7',
|
|
75
112
|
displayName: 'Opus 4.7',
|
|
@@ -80,7 +117,7 @@ export const MODEL_REGISTRY = [
|
|
|
80
117
|
thinkingFormat: 'claude',
|
|
81
118
|
status: 'supported',
|
|
82
119
|
contextWindow: 1000000,
|
|
83
|
-
notes: 'Legacy — consider upgrading to Opus
|
|
120
|
+
notes: 'Legacy — consider upgrading to Opus 5.5',
|
|
84
121
|
},
|
|
85
122
|
{
|
|
86
123
|
id: 'claude-opus-4-6',
|
|
@@ -92,7 +129,7 @@ export const MODEL_REGISTRY = [
|
|
|
92
129
|
thinkingFormat: 'claude',
|
|
93
130
|
status: 'supported',
|
|
94
131
|
contextWindow: 1000000,
|
|
95
|
-
notes: 'Legacy — consider upgrading to Opus
|
|
132
|
+
notes: 'Legacy — consider upgrading to Opus 5.5',
|
|
96
133
|
},
|
|
97
134
|
{
|
|
98
135
|
id: 'claude-sonnet-4-6',
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
* └── project-{id}.json # Per-project anchors
|
|
11
11
|
*/
|
|
12
12
|
import { AnchorManager } from '@compilr-dev/agents';
|
|
13
|
-
import type { Anchor, AnchorInput, AnchorQueryOptions } from '@compilr-dev/agents';
|
|
13
|
+
import type { Anchor, AnchorInput, AnchorPriority, AnchorQueryOptions } from '@compilr-dev/agents';
|
|
14
14
|
import type { IAnchorService } from './services.js';
|
|
15
15
|
export interface ProjectAnchorStoreConfig {
|
|
16
16
|
/** Directory for anchor JSON files (e.g. ~/.compilr-dev/anchors/) */
|
|
@@ -36,6 +36,55 @@ export declare class ProjectAnchorStore {
|
|
|
36
36
|
addAnchor(input: AnchorInput & {
|
|
37
37
|
projectId?: string;
|
|
38
38
|
}): Anchor;
|
|
39
|
+
/**
|
|
40
|
+
* Find an anchor by id, and say which file holds it.
|
|
41
|
+
*
|
|
42
|
+
* Searches the active project's manager then the global one — the same two the UI lists, and
|
|
43
|
+
* the same order `toService().remove` already uses. It deliberately does not sweep
|
|
44
|
+
* `this.managers`: those are lazily cached, so which ones exist depends on what happened
|
|
45
|
+
* earlier in the session, and the answer would drift with it.
|
|
46
|
+
*
|
|
47
|
+
* The null check on `currentProjectId` is defensive rather than behavioural — `String(null)`
|
|
48
|
+
* would key an empty manager and the lookup would fall through to global with the same
|
|
49
|
+
* result, and `loadPersistent` writes nothing for a file that does not exist. It is here so
|
|
50
|
+
* the intent is legible, not because a test can tell the difference. Mutating it away leaves
|
|
51
|
+
* every test green, and that is correct.
|
|
52
|
+
*/
|
|
53
|
+
findAnchor(id: string, currentProjectId?: string | null): {
|
|
54
|
+
anchor: Anchor;
|
|
55
|
+
projectKey: string | null;
|
|
56
|
+
} | undefined;
|
|
57
|
+
/** Remove an anchor by id from whichever file holds it. */
|
|
58
|
+
removeAnchorById(id: string, currentProjectId?: string | null): {
|
|
59
|
+
removed: boolean;
|
|
60
|
+
scope?: 'global' | 'project';
|
|
61
|
+
};
|
|
62
|
+
/**
|
|
63
|
+
* Edit an anchor in place, keeping its id.
|
|
64
|
+
*
|
|
65
|
+
* ⚠️ WHY THE ID MATTERS. Without this the caller has to remove and re-add, which mints a new
|
|
66
|
+
* id — an open tab would then point at an anchor that no longer exists, and the row would
|
|
67
|
+
* jump in the list. `AnchorInput` accepts an id, so the re-add reuses the old one and both
|
|
68
|
+
* stay put.
|
|
69
|
+
*
|
|
70
|
+
* ⚠️ CHANGING SCOPE IS A MOVE BETWEEN FILES, not a field edit. Global anchors live in
|
|
71
|
+
* `global.json` and project ones in `project-<id>.json`, so switching "applies to" removes
|
|
72
|
+
* from one manager and adds to the other. The id survives that too.
|
|
73
|
+
*
|
|
74
|
+
* ⚠️ `createdAt` IS RESET, deliberately. `AnchorManager.add` always stamps `new Date()` and
|
|
75
|
+
* its `savePersistent` is private, so the only ways to keep the original are to mutate a
|
|
76
|
+
* stored object behind the manager's back or to widen `AnchorInput` in @compilr-dev/agents.
|
|
77
|
+
* Nothing displays `createdAt`; it is read only by the two eviction tie-breakers
|
|
78
|
+
* (`makeRoom`, `removeOldestLowPriority`), so on an edited anchor it now means "last edited"
|
|
79
|
+
* and that anchor is evicted last under budget pressure. Built-ins keep `new Date(0)` because
|
|
80
|
+
* they cannot be edited at all. See F-4.
|
|
81
|
+
*/
|
|
82
|
+
updateAnchor(id: string, patch: {
|
|
83
|
+
content?: string;
|
|
84
|
+
priority?: AnchorPriority;
|
|
85
|
+
tags?: string[];
|
|
86
|
+
scope?: 'global' | 'project';
|
|
87
|
+
}, currentProjectId?: string | null): Anchor | undefined;
|
|
39
88
|
/** Get all anchors across all cached managers. */
|
|
40
89
|
getAllAnchors(options?: AnchorQueryOptions): Anchor[];
|
|
41
90
|
/** Clear all anchors for a project and delete the persistence file. */
|
|
@@ -53,6 +102,29 @@ export declare class ProjectAnchorStore {
|
|
|
53
102
|
projectCounts: Map<string, number>;
|
|
54
103
|
totalTokens: number;
|
|
55
104
|
};
|
|
105
|
+
/**
|
|
106
|
+
* Usage against the caps, per file.
|
|
107
|
+
*
|
|
108
|
+
* ⚠️ THE CAPS ARE PER FILE, NOT COMBINED. Each `AnchorManager` enforces `maxAnchors` and
|
|
109
|
+
* `maxTokens` on its own store, so global.json and project-<id>.json each get the full
|
|
110
|
+
* budget. A single meter summing the two and measuring it against one cap would read half
|
|
111
|
+
* full at the moment an `anchor_add` starts evicting — which is the opposite of the point,
|
|
112
|
+
* since the meter exists to show the limit before it bites.
|
|
113
|
+
*
|
|
114
|
+
* Both are returned and the caller shows the fuller one.
|
|
115
|
+
*/
|
|
116
|
+
getUsage(projectId?: string | null): {
|
|
117
|
+
global: {
|
|
118
|
+
anchors: number;
|
|
119
|
+
tokens: number;
|
|
120
|
+
};
|
|
121
|
+
project: {
|
|
122
|
+
anchors: number;
|
|
123
|
+
tokens: number;
|
|
124
|
+
} | null;
|
|
125
|
+
maxAnchors: number;
|
|
126
|
+
maxTokens: number;
|
|
127
|
+
};
|
|
56
128
|
/** Clear all cached managers (useful for testing or refresh). */
|
|
57
129
|
clearCache(): void;
|
|
58
130
|
/** Create an IAnchorService implementation for use with createPlatformTools(). */
|
|
@@ -52,6 +52,89 @@ export class ProjectAnchorStore {
|
|
|
52
52
|
const manager = this.getManager(input.projectId ?? null);
|
|
53
53
|
return manager.add(input);
|
|
54
54
|
}
|
|
55
|
+
/**
|
|
56
|
+
* Find an anchor by id, and say which file holds it.
|
|
57
|
+
*
|
|
58
|
+
* Searches the active project's manager then the global one — the same two the UI lists, and
|
|
59
|
+
* the same order `toService().remove` already uses. It deliberately does not sweep
|
|
60
|
+
* `this.managers`: those are lazily cached, so which ones exist depends on what happened
|
|
61
|
+
* earlier in the session, and the answer would drift with it.
|
|
62
|
+
*
|
|
63
|
+
* The null check on `currentProjectId` is defensive rather than behavioural — `String(null)`
|
|
64
|
+
* would key an empty manager and the lookup would fall through to global with the same
|
|
65
|
+
* result, and `loadPersistent` writes nothing for a file that does not exist. It is here so
|
|
66
|
+
* the intent is legible, not because a test can tell the difference. Mutating it away leaves
|
|
67
|
+
* every test green, and that is correct.
|
|
68
|
+
*/
|
|
69
|
+
findAnchor(id, currentProjectId) {
|
|
70
|
+
if (currentProjectId != null && currentProjectId !== '') {
|
|
71
|
+
const projectManager = this.getManager(currentProjectId);
|
|
72
|
+
const anchor = projectManager.get(id);
|
|
73
|
+
if (anchor)
|
|
74
|
+
return { anchor, projectKey: currentProjectId };
|
|
75
|
+
}
|
|
76
|
+
const anchor = this.getGlobalManager().get(id);
|
|
77
|
+
return anchor ? { anchor, projectKey: null } : undefined;
|
|
78
|
+
}
|
|
79
|
+
/** Remove an anchor by id from whichever file holds it. */
|
|
80
|
+
removeAnchorById(id, currentProjectId) {
|
|
81
|
+
const found = this.findAnchor(id, currentProjectId);
|
|
82
|
+
if (!found)
|
|
83
|
+
return { removed: false };
|
|
84
|
+
const removed = this.getManager(found.projectKey).remove(id);
|
|
85
|
+
return { removed, scope: found.projectKey === null ? 'global' : 'project' };
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Edit an anchor in place, keeping its id.
|
|
89
|
+
*
|
|
90
|
+
* ⚠️ WHY THE ID MATTERS. Without this the caller has to remove and re-add, which mints a new
|
|
91
|
+
* id — an open tab would then point at an anchor that no longer exists, and the row would
|
|
92
|
+
* jump in the list. `AnchorInput` accepts an id, so the re-add reuses the old one and both
|
|
93
|
+
* stay put.
|
|
94
|
+
*
|
|
95
|
+
* ⚠️ CHANGING SCOPE IS A MOVE BETWEEN FILES, not a field edit. Global anchors live in
|
|
96
|
+
* `global.json` and project ones in `project-<id>.json`, so switching "applies to" removes
|
|
97
|
+
* from one manager and adds to the other. The id survives that too.
|
|
98
|
+
*
|
|
99
|
+
* ⚠️ `createdAt` IS RESET, deliberately. `AnchorManager.add` always stamps `new Date()` and
|
|
100
|
+
* its `savePersistent` is private, so the only ways to keep the original are to mutate a
|
|
101
|
+
* stored object behind the manager's back or to widen `AnchorInput` in @compilr-dev/agents.
|
|
102
|
+
* Nothing displays `createdAt`; it is read only by the two eviction tie-breakers
|
|
103
|
+
* (`makeRoom`, `removeOldestLowPriority`), so on an edited anchor it now means "last edited"
|
|
104
|
+
* and that anchor is evicted last under budget pressure. Built-ins keep `new Date(0)` because
|
|
105
|
+
* they cannot be edited at all. See F-4.
|
|
106
|
+
*/
|
|
107
|
+
updateAnchor(id, patch, currentProjectId) {
|
|
108
|
+
const found = this.findAnchor(id, currentProjectId);
|
|
109
|
+
if (!found)
|
|
110
|
+
return undefined;
|
|
111
|
+
const { anchor, projectKey } = found;
|
|
112
|
+
let targetKey = projectKey;
|
|
113
|
+
if (patch.scope !== undefined) {
|
|
114
|
+
if (patch.scope === 'project') {
|
|
115
|
+
if (currentProjectId == null || currentProjectId === '') {
|
|
116
|
+
throw new Error('Cannot scope an anchor to a project: no active project. Use scope: "global" instead.');
|
|
117
|
+
}
|
|
118
|
+
targetKey = currentProjectId;
|
|
119
|
+
}
|
|
120
|
+
else {
|
|
121
|
+
targetKey = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Remove first: re-adding the same id into the same manager would otherwise be an
|
|
125
|
+
// overwrite whose budget accounting counts the content twice.
|
|
126
|
+
this.getManager(projectKey).remove(id);
|
|
127
|
+
return this.getManager(targetKey).add({
|
|
128
|
+
id,
|
|
129
|
+
content: patch.content ?? anchor.content,
|
|
130
|
+
priority: patch.priority ?? anchor.priority,
|
|
131
|
+
scope: anchor.scope,
|
|
132
|
+
tags: patch.tags ?? anchor.tags,
|
|
133
|
+
metadata: anchor.metadata,
|
|
134
|
+
expiresAt: anchor.expiresAt,
|
|
135
|
+
projectId: targetKey ?? undefined,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
55
138
|
/** Get all anchors across all cached managers. */
|
|
56
139
|
getAllAnchors(options) {
|
|
57
140
|
const all = [];
|
|
@@ -127,6 +210,30 @@ export class ProjectAnchorStore {
|
|
|
127
210
|
totalTokens,
|
|
128
211
|
};
|
|
129
212
|
}
|
|
213
|
+
/**
|
|
214
|
+
* Usage against the caps, per file.
|
|
215
|
+
*
|
|
216
|
+
* ⚠️ THE CAPS ARE PER FILE, NOT COMBINED. Each `AnchorManager` enforces `maxAnchors` and
|
|
217
|
+
* `maxTokens` on its own store, so global.json and project-<id>.json each get the full
|
|
218
|
+
* budget. A single meter summing the two and measuring it against one cap would read half
|
|
219
|
+
* full at the moment an `anchor_add` starts evicting — which is the opposite of the point,
|
|
220
|
+
* since the meter exists to show the limit before it bites.
|
|
221
|
+
*
|
|
222
|
+
* Both are returned and the caller shows the fuller one.
|
|
223
|
+
*/
|
|
224
|
+
getUsage(projectId) {
|
|
225
|
+
const globalManager = this.getGlobalManager();
|
|
226
|
+
const hasProject = projectId != null && projectId !== '';
|
|
227
|
+
const projectManager = hasProject ? this.getManager(projectId) : null;
|
|
228
|
+
return {
|
|
229
|
+
global: { anchors: globalManager.size, tokens: globalManager.getTotalTokens() },
|
|
230
|
+
project: projectManager === null
|
|
231
|
+
? null
|
|
232
|
+
: { anchors: projectManager.size, tokens: projectManager.getTotalTokens() },
|
|
233
|
+
maxAnchors: this.config.maxAnchors ?? 50,
|
|
234
|
+
maxTokens: this.config.maxTokens ?? 4000,
|
|
235
|
+
};
|
|
236
|
+
}
|
|
130
237
|
/** Clear all cached managers (useful for testing or refresh). */
|
|
131
238
|
clearCache() {
|
|
132
239
|
this.managers.clear();
|
|
@@ -164,6 +271,32 @@ export class ProjectAnchorStore {
|
|
|
164
271
|
tags: anchor.tags,
|
|
165
272
|
});
|
|
166
273
|
},
|
|
274
|
+
update: (id, patch) => {
|
|
275
|
+
const projId = this.config.getCurrentProjectId();
|
|
276
|
+
const updated = this.updateAnchor(id, patch, projId == null ? null : String(projId));
|
|
277
|
+
if (!updated)
|
|
278
|
+
return Promise.resolve(null);
|
|
279
|
+
return Promise.resolve({
|
|
280
|
+
id: updated.id,
|
|
281
|
+
content: updated.content,
|
|
282
|
+
priority: updated.priority,
|
|
283
|
+
scope: updated.projectId === undefined ? 'global' : 'project',
|
|
284
|
+
tags: updated.tags,
|
|
285
|
+
});
|
|
286
|
+
},
|
|
287
|
+
get: (id) => {
|
|
288
|
+
const projId = this.config.getCurrentProjectId();
|
|
289
|
+
const found = this.findAnchor(id, projId == null ? null : String(projId));
|
|
290
|
+
if (!found)
|
|
291
|
+
return Promise.resolve(null);
|
|
292
|
+
return Promise.resolve({
|
|
293
|
+
id: found.anchor.id,
|
|
294
|
+
content: found.anchor.content,
|
|
295
|
+
priority: found.anchor.priority,
|
|
296
|
+
scope: found.projectKey === null ? 'global' : 'project',
|
|
297
|
+
tags: found.anchor.tags,
|
|
298
|
+
});
|
|
299
|
+
},
|
|
167
300
|
remove: (id) => {
|
|
168
301
|
let removed = false;
|
|
169
302
|
let scope;
|
|
@@ -23,6 +23,21 @@ export interface IAnchorService {
|
|
|
23
23
|
removed: boolean;
|
|
24
24
|
scope?: string;
|
|
25
25
|
}>;
|
|
26
|
+
/**
|
|
27
|
+
* Edit an anchor in place, keeping its id.
|
|
28
|
+
*
|
|
29
|
+
* Optional so existing hosts are unaffected. Without it a caller has to remove and re-add,
|
|
30
|
+
* which mints a new id — anything holding the old one (an open tab, a row in a list) is then
|
|
31
|
+
* pointing at an anchor that no longer exists.
|
|
32
|
+
*/
|
|
33
|
+
update?(id: string, patch: {
|
|
34
|
+
content?: string;
|
|
35
|
+
priority?: AnchorPriority;
|
|
36
|
+
tags?: string[];
|
|
37
|
+
scope?: 'global' | 'project';
|
|
38
|
+
}): Promise<AnchorData | null>;
|
|
39
|
+
/** One anchor by id, or null. */
|
|
40
|
+
get?(id: string): Promise<AnchorData | null>;
|
|
26
41
|
list(options?: {
|
|
27
42
|
scope?: 'global' | 'project' | 'all';
|
|
28
43
|
priority?: AnchorPriority;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@compilr-dev/sdk",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.8",
|
|
4
4
|
"description": "Universal agent runtime for building AI-powered applications",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"node": ">=20.0.0"
|
|
82
82
|
},
|
|
83
83
|
"dependencies": {
|
|
84
|
-
"@compilr-dev/agents": "^0.6.
|
|
84
|
+
"@compilr-dev/agents": "^0.6.10",
|
|
85
85
|
"@compilr-dev/logger": "^0.1.0",
|
|
86
86
|
"ajv": "^6.14.0",
|
|
87
87
|
"yaml": "^2.8.4"
|