@tanstack-ai-browser/apfel 0.2.0 → 0.2.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.
@@ -1 +1 @@
1
- {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAGjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,MAAM,WAAW,GAAG;IACxB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC,CAAA;AAED,mGAAmG;AACnG,MAAM,MAAM,qBAAqB,GAAG;IAClC,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,2FAA2F;AAC3F,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,WAAW,CAAA;AAEvF,iFAAiF;AACjF,MAAM,MAAM,gBAAgB,GAAG,2BAA2B,CAAC,UAAU,EAAE,qBAAqB,CAAC,GAAG;IAC9F,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,SAAS,CAAA;IACrE,6EAA6E;IAC7E,YAAY,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACzD,uFAAuF;IACvF,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;CACtE,CAAA;AAID,+FAA+F;AAC/F,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAAA;AACjE,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAAA"}
1
+ {"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../src/adapter.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,gCAAgC,CAAA;AAIjF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAA;AAErD,MAAM,MAAM,WAAW,GAAG;IACxB,0FAA0F;IAC1F,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,qEAAqE;IACrE,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACxC,CAAA;AAED,mGAAmG;AACnG,MAAM,MAAM,qBAAqB,GAAG;IAClC,+BAA+B;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;CACd,CAAA;AAED,2FAA2F;AAC3F,MAAM,MAAM,YAAY,GAAG,aAAa,GAAG,cAAc,GAAG,aAAa,GAAG,WAAW,CAAA;AAEvF,iFAAiF;AACjF,MAAM,MAAM,gBAAgB,GAAG,2BAA2B,CAAC,UAAU,EAAE,qBAAqB,CAAC,GAAG;IAC9F,sEAAsE;IACtE,QAAQ,CAAC,eAAe,EAAE,aAAa,CAAC,MAAM,GAAG,OAAO,CAAC,GAAG,SAAS,CAAA;IACrE,6EAA6E;IAC7E,YAAY,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC,YAAY,CAAC,CAAA;IACzD,uFAAuF;IACvF,MAAM,CAAC,OAAO,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAA;CACtE,CAAA;AAID,+FAA+F;AAC/F,MAAM,MAAM,UAAU,GAAG,cAAc,GAAG,CAAC,MAAM,GAAG,EAAE,CAAC,CAAA;AAEvD;;;;;;;;;;GAUG;AACH,wBAAgB,SAAS,CAAC,MAAM,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAAA;AACjE,wBAAgB,SAAS,CAAC,KAAK,EAAE,UAAU,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,gBAAgB,CAAA"}
package/dist/adapter.js CHANGED
@@ -24,6 +24,15 @@ export function apfelText(modelOrConfig, maybeConfig = {}) {
24
24
  // apfel runs on the user's own machine: there's no secret key to expose.
25
25
  dangerouslyAllowBrowser: true
26
26
  });
27
+ const hooks = adapter;
28
+ const convert = hooks.chatCompletionsTokenUsage.bind(adapter);
29
+ hooks.chatCompletionsTokenUsage = (usage, source) => {
30
+ const result = convert(usage, source);
31
+ if (!result)
32
+ return result;
33
+ const cachedTokens = usage?.prompt_tokens_details?.cached_tokens ?? 0;
34
+ return { ...result, promptTokensDetails: { ...result.promptTokensDetails, cachedTokens } };
35
+ };
27
36
  const availability = async (signal) => {
28
37
  try {
29
38
  const timeout = AbortSignal.timeout(10_000);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tanstack-ai-browser/apfel",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "TanStack AI adapter for Apple's on-device Foundation Model, served by apfel",
5
5
  "license": "MIT",
6
6
  "author": "daveycodez",
@@ -47,6 +47,9 @@
47
47
  "nx": {
48
48
  "name": "apfel"
49
49
  },
50
+ "scripts": {
51
+ "test": "node --import @swc-node/register/esm-register --test \"src/**/*.test.ts\""
52
+ },
50
53
  "dependencies": {
51
54
  "@tanstack/ai-openai": "^1.1.1"
52
55
  },
@@ -56,8 +59,5 @@
56
59
  "devDependencies": {
57
60
  "@tanstack/ai": "1.4.0",
58
61
  "esbuild": "0.28.2"
59
- },
60
- "scripts": {
61
- "test": "node --import @swc-node/register/esm-register --test \"src/**/*.test.ts\""
62
62
  }
63
- }
63
+ }
package/src/adapter.ts CHANGED
@@ -8,6 +8,7 @@
8
8
  */
9
9
  import { openaiCompatibleText } from "@tanstack/ai-openai/compatible"
10
10
  import type { OpenAICompatibleChatAdapter } from "@tanstack/ai-openai/compatible"
11
+ import type { TokenUsage } from "@tanstack/ai"
11
12
 
12
13
  import { APFEL_MODEL_META } from "./model-meta.js"
13
14
  import type { ApfelChatModel } from "./model-meta.js"
@@ -75,6 +76,19 @@ export function apfelText(modelOrConfig?: ApfelModel | ApfelConfig, maybeConfig:
75
76
  dangerouslyAllowBrowser: true
76
77
  }) as OpenAICompatibleChatAdapter<ApfelModel, ApfelTextModelOptions>
77
78
 
79
+ // apfel answers each request from a new session holding its messages, so
80
+ // the whole prompt is read every time, and nothing is cached (apfel reports
81
+ // no count): cachedTokens 0, unless apfel counts some itself.
82
+ type Usage = (usage: { prompt_tokens_details?: { cached_tokens?: number } | null } | null | undefined, source?: unknown) => TokenUsage | undefined
83
+ const hooks = adapter as unknown as { chatCompletionsTokenUsage: Usage }
84
+ const convert = hooks.chatCompletionsTokenUsage.bind(adapter)
85
+ hooks.chatCompletionsTokenUsage = (usage, source) => {
86
+ const result = convert(usage, source)
87
+ if (!result) return result
88
+ const cachedTokens = usage?.prompt_tokens_details?.cached_tokens ?? 0
89
+ return { ...result, promptTokensDetails: { ...result.promptTokensDetails, cachedTokens } }
90
+ }
91
+
78
92
  const availability = async (signal?: AbortSignal): Promise<Availability> => {
79
93
  try {
80
94
  const timeout = AbortSignal.timeout(10_000)