@mindees/ai 0.14.0 → 0.15.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/cache.d.ts +19 -0
- package/dist/cache.d.ts.map +1 -0
- package/dist/cache.js +39 -0
- package/dist/cache.js.map +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/dist/cache.d.ts
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { AiBackend, GenerateRequest } from "./contract.js";
|
|
2
|
+
|
|
3
|
+
//#region src/cache.d.ts
|
|
4
|
+
/** Options for {@link withCache}. */
|
|
5
|
+
interface CacheOptions {
|
|
6
|
+
/** Max cached entries before least-recently-used eviction (default 100). */
|
|
7
|
+
readonly maxEntries?: number;
|
|
8
|
+
/** Entry lifetime in ms; omit/0 = no expiry. */
|
|
9
|
+
readonly ttlMs?: number;
|
|
10
|
+
/** Cache key for a request (default: stable JSON of the request). */
|
|
11
|
+
readonly keyOf?: (request: GenerateRequest) => string;
|
|
12
|
+
/** Clock for TTL (injectable for tests; default `Date.now`). */
|
|
13
|
+
readonly now?: () => number;
|
|
14
|
+
}
|
|
15
|
+
/** Wrap a backend so identical `generate` requests are served from an LRU+TTL cache. */
|
|
16
|
+
declare function withCache(backend: AiBackend, options?: CacheOptions): AiBackend;
|
|
17
|
+
//#endregion
|
|
18
|
+
export { CacheOptions, withCache };
|
|
19
|
+
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.d.ts","names":[],"sources":["../src/cache.ts"],"mappings":";;;;UAeiB,YAAA;EAQH;EAAA,SANH,UAAA;EAiBc;EAAA,SAfd,KAAA;EAewB;EAAA,SAbxB,KAAA,IAAS,OAAA,EAAS,eAAe;EAa+B;EAAA,SAXhE,GAAA;AAAA;;iBAWK,SAAA,CAAU,OAAA,EAAS,SAAA,EAAW,OAAA,GAAS,YAAA,GAAoB,SAAA"}
|
package/dist/cache.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
//#region src/cache.ts
|
|
2
|
+
const defaultNow = () => globalThis.Date?.now() ?? 0;
|
|
3
|
+
/** Wrap a backend so identical `generate` requests are served from an LRU+TTL cache. */
|
|
4
|
+
function withCache(backend, options = {}) {
|
|
5
|
+
const maxEntries = Math.max(1, options.maxEntries ?? 100);
|
|
6
|
+
const ttlMs = options.ttlMs ?? 0;
|
|
7
|
+
const keyOf = options.keyOf ?? ((request) => JSON.stringify(request));
|
|
8
|
+
const now = options.now ?? defaultNow;
|
|
9
|
+
const cache = /* @__PURE__ */ new Map();
|
|
10
|
+
return {
|
|
11
|
+
async generate(request) {
|
|
12
|
+
const key = keyOf(request);
|
|
13
|
+
const hit = cache.get(key);
|
|
14
|
+
if (hit && hit.expiresAt > now()) {
|
|
15
|
+
cache.delete(key);
|
|
16
|
+
cache.set(key, hit);
|
|
17
|
+
return hit.result;
|
|
18
|
+
}
|
|
19
|
+
if (hit) cache.delete(key);
|
|
20
|
+
const result = await backend.generate(request);
|
|
21
|
+
cache.set(key, {
|
|
22
|
+
result,
|
|
23
|
+
expiresAt: ttlMs > 0 ? now() + ttlMs : Number.POSITIVE_INFINITY
|
|
24
|
+
});
|
|
25
|
+
if (cache.size > maxEntries) {
|
|
26
|
+
const oldest = cache.keys().next().value;
|
|
27
|
+
if (oldest !== void 0) cache.delete(oldest);
|
|
28
|
+
}
|
|
29
|
+
return result;
|
|
30
|
+
},
|
|
31
|
+
stream(request) {
|
|
32
|
+
return backend.stream(request);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
//#endregion
|
|
37
|
+
export { withCache };
|
|
38
|
+
|
|
39
|
+
//# sourceMappingURL=cache.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cache.js","names":[],"sources":["../src/cache.ts"],"sourcesContent":["/**\n * Response caching for AI calls — wrap any {@link AiBackend} so identical one-shot `generate` requests\n * return a memoized result instead of re-hitting the provider (deterministic prompts, repeated renders,\n * dev loops). Cuts latency and token cost. Bounded (LRU eviction) with an optional TTL; `now` is\n * injectable so expiry is deterministically testable.\n *\n * Streaming passes through unwrapped (caching a stream is rarely what you want). Pairs with\n * {@link withRetry} — wrap `withCache(withRetry(backend))` to cache only successful results.\n *\n * @module\n */\n\nimport type { AiBackend, AiChunk, AiResult, GenerateRequest } from './contract'\n\n/** Options for {@link withCache}. */\nexport interface CacheOptions {\n /** Max cached entries before least-recently-used eviction (default 100). */\n readonly maxEntries?: number\n /** Entry lifetime in ms; omit/0 = no expiry. */\n readonly ttlMs?: number\n /** Cache key for a request (default: stable JSON of the request). */\n readonly keyOf?: (request: GenerateRequest) => string\n /** Clock for TTL (injectable for tests; default `Date.now`). */\n readonly now?: () => number\n}\n\ninterface Entry {\n readonly result: AiResult\n readonly expiresAt: number // Infinity when no TTL\n}\n\nconst defaultNow = (): number => (globalThis as { Date?: { now(): number } }).Date?.now() ?? 0\n\n/** Wrap a backend so identical `generate` requests are served from an LRU+TTL cache. */\nexport function withCache(backend: AiBackend, options: CacheOptions = {}): AiBackend {\n const maxEntries = Math.max(1, options.maxEntries ?? 100)\n const ttlMs = options.ttlMs ?? 0\n const keyOf = options.keyOf ?? ((request) => JSON.stringify(request))\n const now = options.now ?? defaultNow\n // Map preserves insertion order → re-insert on hit for LRU recency; oldest key is evicted first.\n const cache = new Map<string, Entry>()\n\n return {\n async generate(request: GenerateRequest): Promise<AiResult> {\n const key = keyOf(request)\n const hit = cache.get(key)\n if (hit && hit.expiresAt > now()) {\n cache.delete(key) // refresh recency\n cache.set(key, hit)\n return hit.result\n }\n if (hit) cache.delete(key) // expired\n const result = await backend.generate(request)\n cache.set(key, { result, expiresAt: ttlMs > 0 ? now() + ttlMs : Number.POSITIVE_INFINITY })\n if (cache.size > maxEntries) {\n const oldest = cache.keys().next().value\n if (oldest !== undefined) cache.delete(oldest)\n }\n return result\n },\n // Caching a stream is rarely desirable; pass through unwrapped.\n stream(request: GenerateRequest): AsyncIterable<AiChunk> {\n return backend.stream(request)\n },\n }\n}\n"],"mappings":";AA+BA,MAAM,mBAA4B,WAA4C,MAAM,IAAI,KAAK;;AAG7F,SAAgB,UAAU,SAAoB,UAAwB,CAAC,GAAc;CACnF,MAAM,aAAa,KAAK,IAAI,GAAG,QAAQ,cAAc,GAAG;CACxD,MAAM,QAAQ,QAAQ,SAAS;CAC/B,MAAM,QAAQ,QAAQ,WAAW,YAAY,KAAK,UAAU,OAAO;CACnE,MAAM,MAAM,QAAQ,OAAO;CAE3B,MAAM,wBAAQ,IAAI,IAAmB;CAErC,OAAO;EACL,MAAM,SAAS,SAA6C;GAC1D,MAAM,MAAM,MAAM,OAAO;GACzB,MAAM,MAAM,MAAM,IAAI,GAAG;GACzB,IAAI,OAAO,IAAI,YAAY,IAAI,GAAG;IAChC,MAAM,OAAO,GAAG;IAChB,MAAM,IAAI,KAAK,GAAG;IAClB,OAAO,IAAI;GACb;GACA,IAAI,KAAK,MAAM,OAAO,GAAG;GACzB,MAAM,SAAS,MAAM,QAAQ,SAAS,OAAO;GAC7C,MAAM,IAAI,KAAK;IAAE;IAAQ,WAAW,QAAQ,IAAI,IAAI,IAAI,QAAQ,OAAO;GAAkB,CAAC;GAC1F,IAAI,MAAM,OAAO,YAAY;IAC3B,MAAM,SAAS,MAAM,KAAK,EAAE,KAAK,EAAE;IACnC,IAAI,WAAW,KAAA,GAAW,MAAM,OAAO,MAAM;GAC/C;GACA,OAAO;EACT;EAEA,OAAO,SAAkD;GACvD,OAAO,QAAQ,OAAO,OAAO;EAC/B;CACF;AACF"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { AbortLike, Ai, AiBackend, AiChunk, AiResult, FinishReason, GenerateRequest, Message, Part, Role, TextPart, ToolCallPart, ToolDefinition, ToolResultPart, Usage, createAi, messageText } from "./contract.js";
|
|
2
|
+
import { CacheOptions, withCache } from "./cache.js";
|
|
2
3
|
import { StandardSchemaV1 } from "./standard-schema.js";
|
|
3
4
|
import { AiError, AiErrorCode, AiErrorOptions } from "./errors.js";
|
|
4
5
|
import { DEFAULT_MAX_INPUT_CHARS, ExtractResult, SanitizeLimits, ValidationOutcome, containsForbiddenKey, extractJson, formatIssues, lenientParseJson, sanitizeJson, validateStandard } from "./json.js";
|
|
@@ -13,7 +14,7 @@ import { Maturity, NotImplementedError, PackageInfo, notImplemented } from "@min
|
|
|
13
14
|
/** The npm package name. */
|
|
14
15
|
declare const name = "@mindees/ai";
|
|
15
16
|
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
16
|
-
declare const VERSION = "0.
|
|
17
|
+
declare const VERSION = "0.15.0";
|
|
17
18
|
/** Current maturity of this package. See the repository `STATUS.md`. */
|
|
18
19
|
declare const maturity: Maturity;
|
|
19
20
|
/**
|
|
@@ -23,5 +24,5 @@ declare const maturity: Maturity;
|
|
|
23
24
|
*/
|
|
24
25
|
declare const info: PackageInfo;
|
|
25
26
|
//#endregion
|
|
26
|
-
export { type AbortLike, type Ai, type AiBackend, type AiChunk, AiError, type AiErrorCode, type AiErrorOptions, type AiResult, DEFAULT_MAX_INPUT_CHARS, type ExtractResult, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateRequest, type GeneratingBackend, type Maturity, type Message, type MockBackendOptions, type MockReply, type MockResponse, NotImplementedError, type PackageInfo, type Part, type RetryOptions, type Role, type RunToolsOptions, type RunToolsResult, type SanitizeLimits, type StandardSchemaV1, type StreamObjectChunk, type StreamObjectOptions, type StreamingBackend, type TextPart, type Tool, type ToolCallPart, type ToolContext, type ToolDefinition, type ToolResultPart, type Usage, VERSION, type ValidationOutcome, containsForbiddenKey, createAi, createMockBackend, createOnDeviceBackend, extractJson, formatIssues, generateObject, info, lenientParseJson, maturity, messageText, name, notImplemented, runTools, sanitizeJson, streamObject, validateStandard, withRetry };
|
|
27
|
+
export { type AbortLike, type Ai, type AiBackend, type AiChunk, AiError, type AiErrorCode, type AiErrorOptions, type AiResult, type CacheOptions, DEFAULT_MAX_INPUT_CHARS, type ExtractResult, type FinishReason, type GenerateObjectOptions, type GenerateObjectResult, type GenerateRequest, type GeneratingBackend, type Maturity, type Message, type MockBackendOptions, type MockReply, type MockResponse, NotImplementedError, type PackageInfo, type Part, type RetryOptions, type Role, type RunToolsOptions, type RunToolsResult, type SanitizeLimits, type StandardSchemaV1, type StreamObjectChunk, type StreamObjectOptions, type StreamingBackend, type TextPart, type Tool, type ToolCallPart, type ToolContext, type ToolDefinition, type ToolResultPart, type Usage, VERSION, type ValidationOutcome, containsForbiddenKey, createAi, createMockBackend, createOnDeviceBackend, extractJson, formatIssues, generateObject, info, lenientParseJson, maturity, messageText, name, notImplemented, runTools, sanitizeJson, streamObject, validateStandard, withCache, withRetry };
|
|
27
28
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;;;;;;;;;AAoBiB;AAAA,cAAJ,IAAA;;cAGA,OAAA;;cAGA,QAAA,EAAU,QAAyB;AAAhD;;;;AAAgD;AAAhD,cAOa,IAAA,EAAM,WAAiE"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withCache } from "./cache.js";
|
|
1
2
|
import { createAi, messageText } from "./contract.js";
|
|
2
3
|
import { AiError } from "./errors.js";
|
|
3
4
|
import { DEFAULT_MAX_INPUT_CHARS, containsForbiddenKey, extractJson, formatIssues, lenientParseJson, sanitizeJson, validateStandard } from "./json.js";
|
|
@@ -11,7 +12,7 @@ import { NotImplementedError, notImplemented } from "@mindees/core";
|
|
|
11
12
|
/** The npm package name. */
|
|
12
13
|
const name = "@mindees/ai";
|
|
13
14
|
/** The package version. All `@mindees/*` packages share one locked version line. */
|
|
14
|
-
const VERSION = "0.
|
|
15
|
+
const VERSION = "0.15.0";
|
|
15
16
|
/** Current maturity of this package. See the repository `STATUS.md`. */
|
|
16
17
|
const maturity = "experimental";
|
|
17
18
|
/**
|
|
@@ -25,6 +26,6 @@ const info = Object.freeze({
|
|
|
25
26
|
maturity
|
|
26
27
|
});
|
|
27
28
|
//#endregion
|
|
28
|
-
export { AiError, DEFAULT_MAX_INPUT_CHARS, NotImplementedError, VERSION, containsForbiddenKey, createAi, createMockBackend, createOnDeviceBackend, extractJson, formatIssues, generateObject, info, lenientParseJson, maturity, messageText, name, notImplemented, runTools, sanitizeJson, streamObject, validateStandard, withRetry };
|
|
29
|
+
export { AiError, DEFAULT_MAX_INPUT_CHARS, NotImplementedError, VERSION, containsForbiddenKey, createAi, createMockBackend, createOnDeviceBackend, extractJson, formatIssues, generateObject, info, lenientParseJson, maturity, messageText, name, notImplemented, runTools, sanitizeJson, streamObject, validateStandard, withCache, withRetry };
|
|
29
30
|
|
|
30
31
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@mindees/ai` (Synapse) — provider-agnostic AI + dev-time intelligence.\n *\n * Phase 11 ships the **contract** ({@link createAi}, {@link AiBackend}, messages,\n * {@link GenerateRequest}/{@link AiResult}/{@link AiChunk}, {@link AiError}) with\n * streaming as `AsyncIterable` only (Node/browser/Hermes-safe), a deterministic\n * {@link createMockBackend mock backend} (the working, offline, no-keys fallback),\n * Standard-Schema structured output, bounded tool calling, an inject-`fetch` server\n * backend on the `@mindees/ai/server` subpath, and a dev-time error explainer on the\n * `@mindees/ai/devtools` subpath. The {@link createOnDeviceBackend on-device seam}\n * throws because on-device LLM inference is inherently native and stays a 🔬 research\n * track.\n *\n * @module\n */\n\nimport type { Maturity, PackageInfo } from '@mindees/core'\nimport { NotImplementedError, notImplemented } from '@mindees/core'\n\n/** The npm package name. */\nexport const name = '@mindees/ai'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["/**\n * `@mindees/ai` (Synapse) — provider-agnostic AI + dev-time intelligence.\n *\n * Phase 11 ships the **contract** ({@link createAi}, {@link AiBackend}, messages,\n * {@link GenerateRequest}/{@link AiResult}/{@link AiChunk}, {@link AiError}) with\n * streaming as `AsyncIterable` only (Node/browser/Hermes-safe), a deterministic\n * {@link createMockBackend mock backend} (the working, offline, no-keys fallback),\n * Standard-Schema structured output, bounded tool calling, an inject-`fetch` server\n * backend on the `@mindees/ai/server` subpath, and a dev-time error explainer on the\n * `@mindees/ai/devtools` subpath. The {@link createOnDeviceBackend on-device seam}\n * throws because on-device LLM inference is inherently native and stays a 🔬 research\n * track.\n *\n * @module\n */\n\nimport type { Maturity, PackageInfo } from '@mindees/core'\nimport { NotImplementedError, notImplemented } from '@mindees/core'\n\n/** The npm package name. */\nexport const name = '@mindees/ai'\n\n/** The package version. All `@mindees/*` packages share one locked version line. */\nexport const VERSION = '0.15.0'\n\n/** Current maturity of this package. See the repository `STATUS.md`. */\nexport const maturity: Maturity = 'experimental'\n\n/**\n * Static identity + maturity metadata for this package. Frozen so the\n * self-reported identity tooling introspects cannot be mutated at runtime,\n * matching the `readonly` fields of {@link PackageInfo}.\n */\nexport const info: PackageInfo = Object.freeze({ name, version: VERSION, maturity })\n\nexport { type CacheOptions, withCache } from './cache'\nexport {\n type AbortLike,\n type Ai,\n type AiBackend,\n type AiChunk,\n type AiResult,\n createAi,\n type FinishReason,\n type GenerateRequest,\n type Message,\n messageText,\n type Part,\n type Role,\n type TextPart,\n type ToolCallPart,\n type ToolDefinition,\n type ToolResultPart,\n type Usage,\n} from './contract'\nexport { AiError, type AiErrorCode, type AiErrorOptions } from './errors'\nexport {\n containsForbiddenKey,\n DEFAULT_MAX_INPUT_CHARS,\n type ExtractResult,\n extractJson,\n formatIssues,\n lenientParseJson,\n type SanitizeLimits,\n sanitizeJson,\n type ValidationOutcome,\n validateStandard,\n} from './json'\nexport {\n createMockBackend,\n type MockBackendOptions,\n type MockReply,\n type MockResponse,\n} from './mock'\nexport {\n type GenerateObjectOptions,\n type GenerateObjectResult,\n type GeneratingBackend,\n generateObject,\n type StreamingBackend,\n type StreamObjectChunk,\n type StreamObjectOptions,\n streamObject,\n} from './object'\nexport { createOnDeviceBackend } from './on-device'\nexport { type RetryOptions, withRetry } from './retry'\nexport type { StandardSchemaV1 } from './standard-schema'\nexport {\n type RunToolsOptions,\n type RunToolsResult,\n runTools,\n type Tool,\n type ToolContext,\n} from './tools'\n\nexport type { Maturity, PackageInfo }\nexport { NotImplementedError, notImplemented }\n"],"mappings":";;;;;;;;;;;;AAoBA,MAAa,OAAO;;AAGpB,MAAa,UAAU;;AAGvB,MAAa,WAAqB;;;;;;AAOlC,MAAa,OAAoB,OAAO,OAAO;CAAE;CAAM,SAAS;CAAS;AAAS,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mindees/ai",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.15.0",
|
|
4
4
|
"description": "MindeesNative Synapse - provider-agnostic AI: a pure-TS contract with mock + server backends, streaming via async iterables, structured output, and tool calling (on-device runtime is a research track).",
|
|
5
5
|
"license": "MIT OR Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -31,7 +31,7 @@
|
|
|
31
31
|
"directory": "packages/ai"
|
|
32
32
|
},
|
|
33
33
|
"dependencies": {
|
|
34
|
-
"@mindees/core": "0.
|
|
34
|
+
"@mindees/core": "0.15.0"
|
|
35
35
|
},
|
|
36
36
|
"scripts": {
|
|
37
37
|
"build": "tsdown",
|