@revealui/ai 0.6.3 → 0.7.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.
Files changed (52) hide show
  1. package/README.md +5 -4
  2. package/dist/a2a/card.d.ts +9 -0
  3. package/dist/a2a/card.d.ts.map +1 -1
  4. package/dist/a2a/card.js +11 -2
  5. package/dist/embeddings/index.d.ts +8 -0
  6. package/dist/embeddings/index.d.ts.map +1 -1
  7. package/dist/embeddings/index.js +3 -2
  8. package/dist/index.d.ts +1 -0
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +1 -0
  11. package/dist/llm/cache-utils.d.ts +11 -25
  12. package/dist/llm/cache-utils.d.ts.map +1 -1
  13. package/dist/llm/cache-utils.js +27 -27
  14. package/dist/llm/client.d.ts +28 -8
  15. package/dist/llm/client.d.ts.map +1 -1
  16. package/dist/llm/client.js +92 -13
  17. package/dist/llm/providers/anthropic.d.ts +30 -0
  18. package/dist/llm/providers/anthropic.d.ts.map +1 -0
  19. package/dist/llm/providers/anthropic.js +45 -0
  20. package/dist/llm/providers/base.d.ts +80 -27
  21. package/dist/llm/providers/base.d.ts.map +1 -1
  22. package/dist/llm/providers/base.js +5 -1
  23. package/dist/llm/providers/groq.d.ts +2 -1
  24. package/dist/llm/providers/groq.d.ts.map +1 -1
  25. package/dist/llm/providers/groq.js +14 -0
  26. package/dist/llm/providers/inference-snaps.d.ts +2 -1
  27. package/dist/llm/providers/inference-snaps.d.ts.map +1 -1
  28. package/dist/llm/providers/inference-snaps.js +15 -0
  29. package/dist/llm/providers/ollama.d.ts +2 -1
  30. package/dist/llm/providers/ollama.d.ts.map +1 -1
  31. package/dist/llm/providers/ollama.js +14 -0
  32. package/dist/llm/providers/openai-compat.d.ts +18 -1
  33. package/dist/llm/providers/openai-compat.d.ts.map +1 -1
  34. package/dist/llm/providers/openai-compat.js +50 -3
  35. package/dist/llm/providers/openai.d.ts +27 -0
  36. package/dist/llm/providers/openai.d.ts.map +1 -0
  37. package/dist/llm/providers/openai.js +41 -0
  38. package/dist/llm/resolve.d.ts +97 -0
  39. package/dist/llm/resolve.d.ts.map +1 -0
  40. package/dist/llm/resolve.js +218 -0
  41. package/dist/llm/server.d.ts +1 -0
  42. package/dist/llm/server.d.ts.map +1 -1
  43. package/dist/llm/server.js +2 -0
  44. package/dist/llm/token-counter.d.ts +18 -0
  45. package/dist/llm/token-counter.d.ts.map +1 -1
  46. package/dist/llm/token-counter.js +16 -13
  47. package/dist/orchestration/runtime.d.ts +6 -12
  48. package/dist/orchestration/runtime.d.ts.map +1 -1
  49. package/dist/orchestration/runtime.js +4 -16
  50. package/dist/orchestration/streaming-runtime.js +1 -1
  51. package/dist/skills/types.d.ts +6 -6
  52. package/package.json +7 -7
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Per-request LLM client resolver (GAP-360 PR-2).
3
+ *
4
+ * The single home for key resolution at every dispatch site (spec §5.2 / §5.4).
5
+ * One resolver, consumed by all sites — no site-local copies.
6
+ *
7
+ * Resolution order (spec §5.2):
8
+ * 1. Per-user BYOK — createLLMClientForUser (preferred)
9
+ * 2. Site inference config — workspace_inference_configs (hostedViable on hosted)
10
+ * 3. Deployment env — createLLMClientFromEnv (SELF-HOSTED ONLY)
11
+ * 4. Hosted + nothing above → throw LLMNotConfiguredError (typed → HTTP 409)
12
+ *
13
+ * Security invariants (spec §6, guardrail-2):
14
+ * - §6.1 userId is authenticated-identity-scoped; the caller derives it from
15
+ * session/entitlement context — or, for the durable worker, the
16
+ * authenticated dispatcher captured server-side at enqueue time — never
17
+ * from request params/body, and never from a client-writable DB column
18
+ * (e.g. a ticket's `reporterId`, which has no ownership check on the
19
+ * general tickets API). The resolver takes userId as an argument and
20
+ * never reads it from a request. The same rule binds the step-2 site
21
+ * inference key: the workspaceId is client-writable, so its stored key is
22
+ * decrypted only after userCanAccessSite confirms the caller owns or
23
+ * collaborates on that site. Otherwise a request could name another
24
+ * tenant's site id and run on that site's key.
25
+ * - §6.2 plaintext lifetime = request scope. The client is constructed per
26
+ * request; no key cache. Nothing here logs, serializes, or returns a key.
27
+ * - §6.3 decryption is server-side only via the existing decryptApiKey.
28
+ * - §6.4 the byok:key:accessed audit event fires inside createLLMClientForUser
29
+ * when an audit store is wired (ctx.auditStore).
30
+ * - §6.5 fail-closed: unknown provider / failed decrypt / a non-hostedViable
31
+ * provider on hosted resolves to LLMNotConfiguredError, never an env
32
+ * fallthrough on hosted (the exact silent-localhost defect class).
33
+ * - §6.6 no new secret surface.
34
+ *
35
+ * Feature flag (spec §7): HOSTED_BYOK_DISPATCH. Default ON for hosted, absent
36
+ * (off) for self-hosted so self-hosted env-first behavior is byte-unchanged.
37
+ * The flag is the one-release rollback lever.
38
+ */
39
+ import type { Database } from '@revealui/db/client';
40
+ import type { AuditStore } from '../audit/store.js';
41
+ import { LLMClient } from './client.js';
42
+ /**
43
+ * Thrown when a hosted deployment has no usable LLM configuration for the
44
+ * request. Maps to HTTP 409 (configuration is the remedy, not payment).
45
+ * Callers name {@link settingsPath} in the machine-readable response body.
46
+ */
47
+ export declare class LLMNotConfiguredError extends Error {
48
+ /** Stable machine-readable code for API response bodies. */
49
+ readonly code: "LLM_NOT_CONFIGURED";
50
+ /** Where the account owner configures a key. */
51
+ readonly settingsPath: "/settings/api-keys";
52
+ constructor(message?: string);
53
+ }
54
+ /** The 409 response body every dispatch site returns for an unconfigured account. */
55
+ export interface LLMNotConfiguredBody {
56
+ success: false;
57
+ error: string;
58
+ code: 'LLM_NOT_CONFIGURED';
59
+ settingsPath: '/settings/api-keys';
60
+ }
61
+ /** Build the machine-readable 409 body for {@link LLMNotConfiguredError}. */
62
+ export declare function llmNotConfiguredBody(err: LLMNotConfiguredError): LLMNotConfiguredBody;
63
+ export interface ResolveLLMContext {
64
+ /**
65
+ * True on the hosted revealui.com SaaS deployment. Derived by the caller from
66
+ * the existing deployment-mode signal (server: detectDeploymentMode; admin:
67
+ * REVEALUI_LICENSE_PRIVATE_KEY presence) — never sniffed here.
68
+ */
69
+ isHosted: boolean;
70
+ /** Site id for step-2 site-level config lookup. Omit when the site has none. */
71
+ workspaceId?: string;
72
+ /**
73
+ * Durable audit sink for the byok:key:accessed event (§6.4). Only `append` is
74
+ * used, so a persistent store (DrizzleAuditStore) fits. Omit where none is
75
+ * wired (e.g. the admin process, in-memory until GAP-338 closes).
76
+ */
77
+ auditStore?: Pick<AuditStore, 'append'>;
78
+ }
79
+ /**
80
+ * Whether the BYOK dispatch order (spec §5.2) is active. Default follows the
81
+ * deployment: ON when hosted, OFF when self-hosted. HOSTED_BYOK_DISPATCH
82
+ * overrides explicitly; an unrecognized value falls back to the default.
83
+ */
84
+ export declare function hostedByokDispatchEnabled(isHosted: boolean): boolean;
85
+ /**
86
+ * Resolve the LLM client for a single request.
87
+ *
88
+ * @param userId - Authenticated user id, from session/entitlement context for
89
+ * request-scoped callers, or the authenticated dispatcher captured
90
+ * server-side at enqueue time for the durable worker. Never a request
91
+ * param/body value, and never a client-writable DB column. Null when there
92
+ * is no authenticated user.
93
+ * @param db - Drizzle client.
94
+ * @param ctx - Deployment mode, optional site id, optional audit sink.
95
+ */
96
+ export declare function resolveLLMClientForRequest(userId: string | null, db: Database, ctx: ResolveLLMContext): Promise<LLMClient>;
97
+ //# sourceMappingURL=resolve.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolve.d.ts","sourceRoot":"","sources":["../../src/llm/resolve.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,qBAAqB,CAAC;AAIpD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAIL,SAAS,EAEV,MAAM,aAAa,CAAC;AAMrB;;;;GAIG;AACH,qBAAa,qBAAsB,SAAQ,KAAK;IAC9C,4DAA4D;IAC5D,QAAQ,CAAC,IAAI,EAAG,oBAAoB,CAAU;IAC9C,gDAAgD;IAChD,QAAQ,CAAC,YAAY,EAAG,oBAAoB,CAAU;gBAE1C,OAAO,SAAoD;CAIxE;AAED,qFAAqF;AACrF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,oBAAoB,CAAC;IAC3B,YAAY,EAAE,oBAAoB,CAAC;CACpC;AAED,6EAA6E;AAC7E,wBAAgB,oBAAoB,CAAC,GAAG,EAAE,qBAAqB,GAAG,oBAAoB,CAOrF;AAED,MAAM,WAAW,iBAAiB;IAChC;;;;OAIG;IACH,QAAQ,EAAE,OAAO,CAAC;IAClB,gFAAgF;IAChF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;OAIG;IACH,UAAU,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;CACzC;AAKD;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,QAAQ,EAAE,OAAO,GAAG,OAAO,CAOpE;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,0BAA0B,CAC9C,MAAM,EAAE,MAAM,GAAG,IAAI,EACrB,EAAE,EAAE,QAAQ,EACZ,GAAG,EAAE,iBAAiB,GACrB,OAAO,CAAC,SAAS,CAAC,CAsDpB"}
@@ -0,0 +1,218 @@
1
+ /**
2
+ * Per-request LLM client resolver (GAP-360 PR-2).
3
+ *
4
+ * The single home for key resolution at every dispatch site (spec §5.2 / §5.4).
5
+ * One resolver, consumed by all sites — no site-local copies.
6
+ *
7
+ * Resolution order (spec §5.2):
8
+ * 1. Per-user BYOK — createLLMClientForUser (preferred)
9
+ * 2. Site inference config — workspace_inference_configs (hostedViable on hosted)
10
+ * 3. Deployment env — createLLMClientFromEnv (SELF-HOSTED ONLY)
11
+ * 4. Hosted + nothing above → throw LLMNotConfiguredError (typed → HTTP 409)
12
+ *
13
+ * Security invariants (spec §6, guardrail-2):
14
+ * - §6.1 userId is authenticated-identity-scoped; the caller derives it from
15
+ * session/entitlement context — or, for the durable worker, the
16
+ * authenticated dispatcher captured server-side at enqueue time — never
17
+ * from request params/body, and never from a client-writable DB column
18
+ * (e.g. a ticket's `reporterId`, which has no ownership check on the
19
+ * general tickets API). The resolver takes userId as an argument and
20
+ * never reads it from a request. The same rule binds the step-2 site
21
+ * inference key: the workspaceId is client-writable, so its stored key is
22
+ * decrypted only after userCanAccessSite confirms the caller owns or
23
+ * collaborates on that site. Otherwise a request could name another
24
+ * tenant's site id and run on that site's key.
25
+ * - §6.2 plaintext lifetime = request scope. The client is constructed per
26
+ * request; no key cache. Nothing here logs, serializes, or returns a key.
27
+ * - §6.3 decryption is server-side only via the existing decryptApiKey.
28
+ * - §6.4 the byok:key:accessed audit event fires inside createLLMClientForUser
29
+ * when an audit store is wired (ctx.auditStore).
30
+ * - §6.5 fail-closed: unknown provider / failed decrypt / a non-hostedViable
31
+ * provider on hosted resolves to LLMNotConfiguredError, never an env
32
+ * fallthrough on hosted (the exact silent-localhost defect class).
33
+ * - §6.6 no new secret surface.
34
+ *
35
+ * Feature flag (spec §7): HOSTED_BYOK_DISPATCH. Default ON for hosted, absent
36
+ * (off) for self-hosted so self-hosted env-first behavior is byte-unchanged.
37
+ * The flag is the one-release rollback lever.
38
+ */
39
+ import { createLogger } from '@revealui/core/observability/logger';
40
+ import { decryptApiKey } from '@revealui/db/crypto';
41
+ import { siteCollaborators, sites, workspaceInferenceConfigs } from '@revealui/db/schema';
42
+ import { and, eq } from 'drizzle-orm';
43
+ import { createLLMClientForUser, createLLMClientFromEnv, isHostedViable, LLMClient, } from './client.js';
44
+ const resolverLogger = createLogger({ component: 'resolveLLMClientForRequest' });
45
+ /** Emitted once per process when the hosted BYOK rollback lever is pulled. */
46
+ let warnedBreakGlass = false;
47
+ /**
48
+ * Thrown when a hosted deployment has no usable LLM configuration for the
49
+ * request. Maps to HTTP 409 (configuration is the remedy, not payment).
50
+ * Callers name {@link settingsPath} in the machine-readable response body.
51
+ */
52
+ export class LLMNotConfiguredError extends Error {
53
+ /** Stable machine-readable code for API response bodies. */
54
+ code = 'LLM_NOT_CONFIGURED';
55
+ /** Where the account owner configures a key. */
56
+ settingsPath = '/settings/api-keys';
57
+ constructor(message = 'No LLM provider is configured for this account.') {
58
+ super(message);
59
+ this.name = 'LLMNotConfiguredError';
60
+ }
61
+ }
62
+ /** Build the machine-readable 409 body for {@link LLMNotConfiguredError}. */
63
+ export function llmNotConfiguredBody(err) {
64
+ return {
65
+ success: false,
66
+ error: err.message,
67
+ code: err.code,
68
+ settingsPath: err.settingsPath,
69
+ };
70
+ }
71
+ const FLAG_ON = new Set(['true', '1', 'on', 'yes']);
72
+ const FLAG_OFF = new Set(['false', '0', 'off', 'no']);
73
+ /**
74
+ * Whether the BYOK dispatch order (spec §5.2) is active. Default follows the
75
+ * deployment: ON when hosted, OFF when self-hosted. HOSTED_BYOK_DISPATCH
76
+ * overrides explicitly; an unrecognized value falls back to the default.
77
+ */
78
+ export function hostedByokDispatchEnabled(isHosted) {
79
+ const raw = process.env.HOSTED_BYOK_DISPATCH;
80
+ if (raw === undefined || raw.trim() === '')
81
+ return isHosted;
82
+ const value = raw.trim().toLowerCase();
83
+ if (FLAG_OFF.has(value))
84
+ return false;
85
+ if (FLAG_ON.has(value))
86
+ return true;
87
+ return isHosted;
88
+ }
89
+ /**
90
+ * Resolve the LLM client for a single request.
91
+ *
92
+ * @param userId - Authenticated user id, from session/entitlement context for
93
+ * request-scoped callers, or the authenticated dispatcher captured
94
+ * server-side at enqueue time for the durable worker. Never a request
95
+ * param/body value, and never a client-writable DB column. Null when there
96
+ * is no authenticated user.
97
+ * @param db - Drizzle client.
98
+ * @param ctx - Deployment mode, optional site id, optional audit sink.
99
+ */
100
+ export async function resolveLLMClientForRequest(userId, db, ctx) {
101
+ const hosted = ctx.isHosted;
102
+ // Feature-flag gate. When disabled (self-hosted default), behavior is
103
+ // byte-unchanged: env-first, exactly as before this PR.
104
+ if (!hostedByokDispatchEnabled(hosted)) {
105
+ if (hosted && !warnedBreakGlass) {
106
+ warnedBreakGlass = true;
107
+ // Break-glass: HOSTED_BYOK_DISPATCH is explicitly off on a hosted
108
+ // deployment. Every account now shares the deployment env client while
109
+ // this lever is pulled — a deliberate one-release rollback, but an
110
+ // operator must know it is active.
111
+ resolverLogger.warn('HOSTED_BYOK_DISPATCH is disabled on a hosted deployment — all accounts are ' +
112
+ 'sharing the deployment env LLM client instead of per-account BYOK keys.');
113
+ }
114
+ return createLLMClientFromEnv();
115
+ }
116
+ // 1. Per-user BYOK (preferred). On hosted, filter to hostedViable providers
117
+ // so a localhost-only BYOK key (e.g. ollama) can never yield a localhost
118
+ // client — that is the silent-localhost defect (§6.5, fail-closed).
119
+ if (userId) {
120
+ try {
121
+ const byok = await createLLMClientForUser(userId, db, ctx.auditStore, {
122
+ hostedViableOnly: hosted,
123
+ });
124
+ if (byok)
125
+ return byok;
126
+ }
127
+ catch {
128
+ // Failed decrypt / unknown-provider row / CHECK-violating row. Fail-closed
129
+ // on hosted — never fall through to env. Self-hosted may continue.
130
+ if (hosted) {
131
+ throw new LLMNotConfiguredError('Your stored API key could not be used. Re-add it under /settings/api-keys.');
132
+ }
133
+ }
134
+ }
135
+ // 2. Site-level inference config. userId is passed so the site's stored key
136
+ // is decrypted only for a caller authorized on that site (§6.1) — the
137
+ // workspaceId reaching here is a client-writable value (e.g. a request
138
+ // body field), so it carries no ownership guarantee on its own.
139
+ const siteClient = await resolveSiteInferenceClient(db, userId, ctx.workspaceId, hosted);
140
+ if (siteClient)
141
+ return siteClient;
142
+ // 3. Deployment env — SELF-HOSTED ONLY. Forbidden on hosted (§5.2 step 3).
143
+ if (!hosted) {
144
+ return createLLMClientFromEnv();
145
+ }
146
+ // 4. Hosted + nothing above → fail loud, actionable.
147
+ throw new LLMNotConfiguredError();
148
+ }
149
+ /**
150
+ * Whether `userId` is authorized to act on `siteId` — the site's owner, or a
151
+ * row in `site_collaborators`. Gate for the site inference key (§6.1): the
152
+ * site's stored provider key must never be decrypted for a caller who does not
153
+ * belong to the site, even though the workspaceId is client-supplied.
154
+ */
155
+ async function userCanAccessSite(db, userId, siteId) {
156
+ const [owned] = await db
157
+ .select({ id: sites.id })
158
+ .from(sites)
159
+ .where(and(eq(sites.id, siteId), eq(sites.ownerId, userId)))
160
+ .limit(1);
161
+ if (owned)
162
+ return true;
163
+ const [collaborator] = await db
164
+ .select({ id: siteCollaborators.id })
165
+ .from(siteCollaborators)
166
+ .where(and(eq(siteCollaborators.siteId, siteId), eq(siteCollaborators.userId, userId)))
167
+ .limit(1);
168
+ return Boolean(collaborator);
169
+ }
170
+ /**
171
+ * Build a client from the site's workspace_inference_configs row (spec §5.2
172
+ * step 2). Returns null when the site has no config, when the caller is not
173
+ * authorized on the site, or (on hosted) when its provider is not hostedViable.
174
+ * Fail-closed: a malformed row throws on hosted and is skipped on self-hosted.
175
+ */
176
+ async function resolveSiteInferenceClient(db, userId, workspaceId, hosted) {
177
+ if (!workspaceId)
178
+ return null;
179
+ // §6.1 authorization: only decrypt a site's key for a caller who belongs to
180
+ // that site. An unauthorized (or anonymous) request skips the site config
181
+ // entirely; on hosted it then falls through to the step-4 409, never a
182
+ // decrypt of another tenant's key.
183
+ if (!(userId && (await userCanAccessSite(db, userId, workspaceId))))
184
+ return null;
185
+ const [config] = await db
186
+ .select()
187
+ .from(workspaceInferenceConfigs)
188
+ .where(eq(workspaceInferenceConfigs.workspaceId, workspaceId))
189
+ .limit(1);
190
+ if (!config)
191
+ return null;
192
+ const provider = config.provider;
193
+ // On hosted, only hostedViable providers are reachable. A non-viable site
194
+ // config is skipped so resolution fails closed rather than hitting localhost.
195
+ if (hosted && !isHostedViable(provider))
196
+ return null;
197
+ try {
198
+ // Keyless providers (ollama / inference-snaps) carry a NULL encrypted key
199
+ // and use the provider name as the placeholder key — matches the env
200
+ // factory. Keyed providers decrypt server-side at dispatch time (§6.3).
201
+ const apiKey = config.encryptedApiKey ? decryptApiKey(config.encryptedApiKey) : provider;
202
+ return new LLMClient({
203
+ provider,
204
+ apiKey,
205
+ model: config.model ?? undefined,
206
+ baseURL: config.baseURL ?? undefined,
207
+ temperature: config.temperature ?? undefined,
208
+ maxTokens: config.maxTokens ?? undefined,
209
+ });
210
+ }
211
+ catch {
212
+ // Unknown provider / failed decrypt. Fail-closed on hosted; skip on self-hosted.
213
+ if (hosted) {
214
+ throw new LLMNotConfiguredError('This site’s inference configuration could not be used. Update it under /settings/api-keys.');
215
+ }
216
+ return null;
217
+ }
218
+ }
@@ -10,5 +10,6 @@ export * from './providers/groq.js';
10
10
  export * from './providers/inference-snaps.js';
11
11
  export * from './providers/ollama.js';
12
12
  export * from './providers/openai-compat.js';
13
+ export * from './resolve.js';
13
14
  export * from './workspace-provider-config.js';
14
15
  //# sourceMappingURL=server.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAC;AAG5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAI7C,cAAc,gCAAgC,CAAC"}
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/llm/server.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,cAAc,aAAa,CAAC;AAE5B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,gCAAgC,CAAC;AAC/C,cAAc,uBAAuB,CAAC;AACtC,cAAc,8BAA8B,CAAC;AAE7C,cAAc,cAAc,CAAC;AAI7B,cAAc,gCAAgC,CAAC"}
@@ -12,6 +12,8 @@ export * from './providers/groq.js';
12
12
  export * from './providers/inference-snaps.js';
13
13
  export * from './providers/ollama.js';
14
14
  export * from './providers/openai-compat.js';
15
+ // Export the per-request client resolver (GAP-360 PR-2)
16
+ export * from './resolve.js';
15
17
  // Export per-workspace provider registry (used by admin inference-config route
16
18
  // to hydrate per-site config at boot + apply changes immediately on PUT)
17
19
  export * from './workspace-provider-config.js';
@@ -19,6 +19,24 @@ export interface CostEstimate {
19
19
  model: string;
20
20
  direction: 'input' | 'output';
21
21
  }
22
+ /**
23
+ * Per-1M-token pricing (USD). Single source of truth for every cost path in the package:
24
+ * `estimateCost` (input/output) and `calculateCacheCost` (cache-utils, cacheWrite/cacheRead).
25
+ * Cache rates follow Anthropic's model (write ~125% of input, read ~10%); non-caching
26
+ * providers carry 0 (local models are free; cache cost is not modelled for hosted
27
+ * non-Anthropic providers here).
28
+ */
29
+ export interface ModelPricing {
30
+ /** USD per 1M input tokens. */
31
+ input: number;
32
+ /** USD per 1M output tokens. */
33
+ output: number;
34
+ /** USD per 1M tokens written to the prompt cache (0 where unsupported/unmodelled). */
35
+ cacheWrite: number;
36
+ /** USD per 1M tokens read from the prompt cache (0 where unsupported/unmodelled). */
37
+ cacheRead: number;
38
+ }
39
+ export declare const MODEL_PRICING: Record<string, ModelPricing>;
22
40
  /**
23
41
  * Estimate token count for a string.
24
42
  */
@@ -1 +1 @@
1
- {"version":3,"file":"token-counter.d.ts","sourceRoot":"","sources":["../../src/llm/token-counter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAiCD;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAGxF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAQjG;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,GAAG,QAAQ,GAC5B,YAAY,CASd;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,MAAM,GACZ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAI9C"}
1
+ {"version":3,"file":"token-counter.d.ts","sourceRoot":"","sources":["../../src/llm/token-counter.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,WAAW,CAAC;CACrB;AAED,MAAM,WAAW,YAAY;IAC3B,gBAAgB,EAAE,MAAM,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;CAC/B;AAED;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,+BAA+B;IAC/B,KAAK,EAAE,MAAM,CAAC;IACd,gCAAgC;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC;IACnB,qFAAqF;IACrF,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAmBtD,CAAC;AAeF;;GAEG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAGxF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,OAAO,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,gBAAgB,CAQjG;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,SAAS,EAAE,OAAO,GAAG,QAAQ,GAC5B,YAAY,CASd;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAC7B,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,MAAM,GACZ;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,gBAAgB,EAAE,MAAM,CAAA;CAAE,CAI9C"}
@@ -8,22 +8,25 @@
8
8
  * Limitation: actual token counts differ by model tokenizer. This is
9
9
  * accurate enough for budget tracking and context window management.
10
10
  */
11
- // Cost per 1M tokens (USD) - input/output pricing
12
- const MODEL_PRICING = {
13
- // Anthropic
14
- 'claude-opus-4-6': { input: 15.0, output: 75.0 },
15
- 'claude-sonnet-4-6': { input: 3.0, output: 15.0 },
16
- 'claude-haiku-4-5-20251001': { input: 0.25, output: 1.25 },
11
+ export const MODEL_PRICING = {
12
+ // Anthropic (current)
13
+ 'claude-opus-4-6': { input: 15.0, output: 75.0, cacheWrite: 18.75, cacheRead: 1.5 },
14
+ 'claude-sonnet-4-6': { input: 3.0, output: 15.0, cacheWrite: 3.75, cacheRead: 0.3 },
15
+ 'claude-haiku-4-5-20251001': { input: 0.25, output: 1.25, cacheWrite: 0.3125, cacheRead: 0.025 },
16
+ // Anthropic (legacy 2024 - retained for cache-cost callers/examples)
17
+ 'claude-3-5-sonnet-20241022': { input: 3.0, output: 15.0, cacheWrite: 3.75, cacheRead: 0.3 },
18
+ 'claude-3-5-haiku-20241022': { input: 1.0, output: 5.0, cacheWrite: 1.25, cacheRead: 0.1 },
19
+ 'claude-3-opus-20240229': { input: 15.0, output: 75.0, cacheWrite: 18.75, cacheRead: 1.5 },
17
20
  // OpenAI
18
- 'gpt-4o': { input: 5.0, output: 15.0 },
19
- 'gpt-4o-mini': { input: 0.15, output: 0.6 },
21
+ 'gpt-4o': { input: 5.0, output: 15.0, cacheWrite: 0, cacheRead: 0 },
22
+ 'gpt-4o-mini': { input: 0.15, output: 0.6, cacheWrite: 0, cacheRead: 0 },
20
23
  // Groq (Qwen - Apache 2.0)
21
- 'qwen/qwen3-32b': { input: 0.59, output: 0.79 },
24
+ 'qwen/qwen3-32b': { input: 0.59, output: 0.79, cacheWrite: 0, cacheRead: 0 },
22
25
  // Ollama (self-hosted - no cost)
23
- 'gemma4:e2b': { input: 0, output: 0 },
24
- 'gemma4:e4b': { input: 0, output: 0 },
25
- 'gemma4:26b': { input: 0, output: 0 },
26
- 'nomic-embed-text': { input: 0, output: 0 },
26
+ 'gemma4:e2b': { input: 0, output: 0, cacheWrite: 0, cacheRead: 0 },
27
+ 'gemma4:e4b': { input: 0, output: 0, cacheWrite: 0, cacheRead: 0 },
28
+ 'gemma4:26b': { input: 0, output: 0, cacheWrite: 0, cacheRead: 0 },
29
+ 'nomic-embed-text': { input: 0, output: 0, cacheWrite: 0, cacheRead: 0 },
27
30
  };
28
31
  function charsPerToken(model) {
29
32
  const lower = model.toLowerCase();
@@ -4,24 +4,18 @@
4
4
  * Executes agent tasks with tool execution, memory management, and error handling
5
5
  */
6
6
  import type { LLMClient } from '../llm/client.js';
7
+ import type { ReasoningEffort } from '../llm/providers/base.js';
7
8
  import type { AgentSkillProvider } from '../skills/integration/agent-skill-provider.js';
8
9
  import type { ApprovalCallback } from '../tools/base.js';
9
10
  import type { MCPToolSource, McpClientLike } from '../tools/mcp-adapter.js';
10
11
  import type { Agent, AgentResult, Task } from './agent.js';
11
12
  /**
12
- * Controls how much of the model's token budget is allocated to internal reasoning.
13
- * Applies to Anthropic Claude only - ignored by other providers.
14
- *
15
- * | Level | Budget (tokens) | Use case |
16
- * |---------|-----------------|-----------------------------------|
17
- * | off | 0 | Disabled (default) |
18
- * | minimal | 512 | Simple tasks, cost-sensitive |
19
- * | low | 2 048 | Moderate complexity |
20
- * | medium | 8 000 | Multi-step reasoning |
21
- * | high | 16 000 | Complex planning |
22
- * | xhigh | 31 999 | Maximum depth (expensive) |
13
+ * Reasoning-depth hint for a task. Alias of the neutral `ReasoningEffort` the agnostic
14
+ * Reasoner port's control vocabulary. Mapping a level to a provider's native control
15
+ * (e.g. a thinking-token budget) is the adapter's job; a provider that advertises
16
+ * `reasoningEffort: false` treats it as a no-op.
23
17
  */
24
- export type ThinkingLevel = 'off' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh';
18
+ export type ThinkingLevel = ReasoningEffort;
25
19
  export interface RuntimeConfig {
26
20
  maxIterations?: number;
27
21
  timeout?: number;
@@ -1 +1 @@
1
- {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/orchestration/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAGlD,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,aAAa,GAAG,KAAK,GAAG,SAAS,GAAG,KAAK,GAAG,QAAQ,GAAG,MAAM,GAAG,OAAO,CAAC;AAWpF,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IACpE;;;;OAIG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,gCAAgC,EAAE,SAAS,CAAC;IAC/D;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AAED,qBAAa,YAAY;IACvB,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC;IAChC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,GAAE,aAAkB;IA0BtC;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;YAqBzE,OAAO;IAoPrB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI7B;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAc9E;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B9B;;OAEG;IACH,SAAS,IAAI;QACX,cAAc,EAAE,OAAO,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB;CAOF"}
1
+ {"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/orchestration/runtime.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAIH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAClD,OAAO,KAAK,EAAW,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,+CAA+C,CAAC;AACxF,OAAO,KAAK,EAAE,gBAAgB,EAAoB,MAAM,kBAAkB,CAAC;AAE3E,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG5E,OAAO,KAAK,EAAE,KAAK,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,YAAY,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,MAAM,aAAa,GAAG,eAAe,CAAC;AAE5C,MAAM,WAAW,aAAa;IAC5B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;;;;OASG;IACH,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAAU,CAAC,EAAE,aAAa,CAAC;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,aAAa,CAAA;KAAE,CAAC,CAAC;IACpE;;;;OAIG;IACH,aAAa,CAAC,EAAE,kBAAkB,CAAC;IACnC;;;;OAIG;IACH,SAAS,CAAC,EAAE,OAAO,gCAAgC,EAAE,SAAS,CAAC;IAC/D;;;;OAIG;IACH,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC;;;;OAIG;IACH,qBAAqB,CAAC,EAAE,MAAM,EAAE,CAAC;CAClC;AAED,qBAAa,YAAY;IACvB,SAAS,CAAC,MAAM,EAAE,aAAa,CAAC;IAChC,OAAO,CAAC,SAAS,CAAc;IAC/B,OAAO,CAAC,cAAc,CAAgD;IACtE,OAAO,CAAC,cAAc,CAAS;gBAEnB,MAAM,GAAE,aAAkB;IA0BtC;;OAEG;IACG,WAAW,CAAC,KAAK,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,CAAC;YAqBzE,OAAO;IA8OrB;;OAEG;IACH,WAAW,CAAC,IAAI,EAAE,IAAI,GAAG,IAAI;IAI7B;;OAEG;IACG,YAAY,CAAC,KAAK,EAAE,KAAK,EAAE,SAAS,EAAE,SAAS,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IAc9E;;OAEG;IACG,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IA+B9B;;OAEG;IACH,SAAS,IAAI;QACX,cAAc,EAAE,OAAO,CAAC;QACxB,WAAW,EAAE,MAAM,CAAC;QACpB,cAAc,EAAE,MAAM,CAAC;KACxB;CAOF"}
@@ -9,14 +9,6 @@ import { estimateCost } from '../llm/token-counter.js';
9
9
  import { ToolCallDeduplicator } from '../tools/deduplicator.js';
10
10
  import { createToolsFromMcpClient, discoverMCPTools } from '../tools/mcp-adapter.js';
11
11
  import { createWebSearchTool } from '../tools/web/duck-duck-go.js';
12
- const THINKING_BUDGETS = {
13
- off: 0,
14
- minimal: 512,
15
- low: 2048,
16
- medium: 8000,
17
- high: 16000,
18
- xhigh: 31999,
19
- };
20
12
  export class AgentRuntime {
21
13
  config;
22
14
  taskQueue = [];
@@ -101,8 +93,8 @@ export class AgentRuntime {
101
93
  {
102
94
  role: 'system',
103
95
  content: agent.instructions,
104
- // Cache agent instructions for cost savings (Anthropic only)
105
- cacheControl: this.config.enableCache ? { type: 'ephemeral' } : undefined,
96
+ // Cache agent instructions for cost savings (effective where promptCache is supported)
97
+ cache: this.config.enableCache || undefined,
106
98
  },
107
99
  {
108
100
  role: 'user',
@@ -130,10 +122,6 @@ export class AgentRuntime {
130
122
  },
131
123
  };
132
124
  }
133
- // Resolve thinking budget if a level is configured
134
- const thinkingBudget = this.config.thinkingLevel && this.config.thinkingLevel !== 'off'
135
- ? THINKING_BUDGETS[this.config.thinkingLevel]
136
- : undefined;
137
125
  // Get LLM response (with caching for agent instructions and tools)
138
126
  const response = await llmClient.chat(messages, {
139
127
  tools: allTools.map((tool) => ({
@@ -144,8 +132,8 @@ export class AgentRuntime {
144
132
  parameters: z.toJSONSchema(tool.parameters),
145
133
  },
146
134
  })),
147
- enableCache: this.config.enableCache,
148
- thinkingBudget,
135
+ cacheHint: this.config.enableCache,
136
+ effort: this.config.thinkingLevel,
149
137
  });
150
138
  // Accumulate token usage and cost
151
139
  const iterationTokens = response.usage?.totalTokens ?? 0;
@@ -36,7 +36,7 @@ export class StreamingAgentRuntime extends AgentRuntime {
36
36
  {
37
37
  role: 'system',
38
38
  content: agent.instructions,
39
- cacheControl: { type: 'ephemeral' },
39
+ cache: true,
40
40
  },
41
41
  {
42
42
  role: 'user',
@@ -27,13 +27,13 @@ export declare const SkillMetadataSchema: z.ZodObject<{
27
27
  repository: z.ZodOptional<z.ZodString>;
28
28
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
29
29
  compatibility: z.ZodOptional<z.ZodArray<z.ZodEnum<{
30
+ anthropic: "anthropic";
31
+ openai: "openai";
30
32
  "claude-code": "claude-code";
31
33
  cursor: "cursor";
32
34
  windsurf: "windsurf";
33
35
  cline: "cline";
34
36
  copilot: "copilot";
35
- openai: "openai";
36
- anthropic: "anthropic";
37
37
  universal: "universal";
38
38
  }>>>;
39
39
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -78,13 +78,13 @@ export declare const SkillSchema: z.ZodObject<{
78
78
  repository: z.ZodOptional<z.ZodString>;
79
79
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
80
80
  compatibility: z.ZodOptional<z.ZodArray<z.ZodEnum<{
81
+ anthropic: "anthropic";
82
+ openai: "openai";
81
83
  "claude-code": "claude-code";
82
84
  cursor: "cursor";
83
85
  windsurf: "windsurf";
84
86
  cline: "cline";
85
87
  copilot: "copilot";
86
- openai: "openai";
87
- anthropic: "anthropic";
88
88
  universal: "universal";
89
89
  }>>>;
90
90
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
@@ -143,13 +143,13 @@ export declare const SkillActivationResultSchema: z.ZodObject<{
143
143
  repository: z.ZodOptional<z.ZodString>;
144
144
  tags: z.ZodOptional<z.ZodArray<z.ZodString>>;
145
145
  compatibility: z.ZodOptional<z.ZodArray<z.ZodEnum<{
146
+ anthropic: "anthropic";
147
+ openai: "openai";
146
148
  "claude-code": "claude-code";
147
149
  cursor: "cursor";
148
150
  windsurf: "windsurf";
149
151
  cline: "cline";
150
152
  copilot: "copilot";
151
- openai: "openai";
152
- anthropic: "anthropic";
153
153
  universal: "universal";
154
154
  }>>>;
155
155
  allowedTools: z.ZodOptional<z.ZodArray<z.ZodString>>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revealui/ai",
3
- "version": "0.6.3",
3
+ "version": "0.7.0",
4
4
  "description": "AI runtime for agent-driven products — agents, memory, LLM providers (Inference Snaps, Ollama, OpenAI-compatible), tools, and orchestration. Anthropic-SDK-free.",
5
5
  "keywords": [
6
6
  "agent",
@@ -25,20 +25,20 @@
25
25
  "dependencies": {
26
26
  "lru-cache": "^11.5.1",
27
27
  "zod": "^4.4.3",
28
- "@revealui/contracts": "0.6.1",
29
- "@revealui/core": "0.10.2",
30
- "@revealui/db": "0.7.2",
28
+ "@revealui/contracts": "0.7.0",
29
+ "@revealui/core": "0.11.1",
30
+ "@revealui/db": "0.8.0",
31
31
  "@revealui/resilience": "0.2.4"
32
32
  },
33
33
  "devDependencies": {
34
- "@electric-sql/pglite": "^0.5.2",
34
+ "@electric-sql/pglite": "^0.5.4",
35
35
  "@testing-library/react": "^16.3.2",
36
- "@vitest/coverage-v8": "^4.1.8",
36
+ "@vitest/coverage-v8": "^4.1.10",
37
37
  "jsdom": "29.1.1",
38
38
  "react": "^19.2.7",
39
39
  "react-dom": "^19.2.7",
40
40
  "typescript": "^6.0.3",
41
- "vitest": "^4.1.8",
41
+ "vitest": "^4.1.10",
42
42
  "@revealui/dev": "0.1.0"
43
43
  },
44
44
  "engines": {