anyclaude-sdk 0.7.1 → 0.7.3

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/README.md CHANGED
@@ -358,9 +358,43 @@ npm install anyclaude-react
358
358
 
359
359
  `useAgent()` plus restylable components — chat (`AgentChat`, `ChatPanel`, `Transcript`, `MarkdownMessage`, `Composer`, `Working`, `ToolCall`) and an IDE set (`Terminal`, `FileExplorer`, `CodeEditor`, `AskUser`). `createAgentClient` / `createEndpointClient` auto-stitch `paused` continuations and run `clientTools` in the browser.
360
360
 
361
+ ## Run Claude Code against any model — `anyclaude-sdk/anthropic-endpoint`
362
+
363
+ Stand up an Anthropic Messages API-compatible endpoint backed by any OpenAI-compatible model, so **Claude Code itself** (or any Anthropic-Messages client) runs against DeepSeek / Qwen / GLM / Kimi / local Ollama. Unlike a naive proxy, inline tool-call **dialects are recovered into proper `tool_use` blocks**, so tool use actually works on cheap models.
364
+
365
+ ```ts
366
+ import { createOpenAIClient } from 'anyclaude-sdk/llm'
367
+ import { anthropicToChat, anthropicSSE } from 'anyclaude-sdk/anthropic-endpoint'
368
+
369
+ const llm = createOpenAIClient({ baseUrl: 'https://api.deepseek.com/v1', model: 'deepseek-chat', apiKey })
370
+ // POST /v1/messages:
371
+ for await (const evt of anthropicSSE(llm, anthropicToChat(body), { model: 'deepseek-chat' })) res.write(evt)
372
+ // then: ANTHROPIC_BASE_URL=http://localhost:8787 claude
373
+ ```
374
+
375
+ Runnable: [`examples/claude-code-router`](examples/claude-code-router).
376
+
377
+ ## Reliable tool use on cheap / open models
378
+
379
+ Frontier models emit clean native function-calls; cheaper ones often don't. Three layers (in `anyclaude-sdk/llm`) close the gap: **tool-call dialects** (`parseToolCalls` — xml-function / hermes / json-fence), **auto-detected model profiles** (`profileForModel` — qwen/deepseek/moonshot/zhipu/mistral/llama), and **self-healing argument repair** (`query({ repairToolCalls })`, on by default — validates args and feeds the model a corrective tool_result instead of running with garbage). Prove it on your endpoints with [`scripts/compat-matrix.mjs`](scripts/compat-matrix.mjs) → [COMPATIBILITY.md](COMPATIBILITY.md).
380
+
381
+ ## Scaffold an in-browser AI IDE
382
+
383
+ ```bash
384
+ npm create anyclaude-app@latest my-app # template: bolt — WebContainer + chat + live preview, no backend
385
+ ```
386
+
387
+ The `bolt` template wires `useWebContainerPreview({ wc })` (boot a dev server → live preview URL) + a browser-side `query()` + the IDE components. See [`anyclaude-react`](#react-ui-kit--anyclaude-react).
388
+
389
+ ## Other niceties
390
+
391
+ - **Live compaction marker** — `autoCompact` emits a `compact_boundary` with `status: 'start'` *before* summarizing (for a live "compacting…" shimmer) and `status: 'end'` after with `post_tokens`.
392
+ - **Cancel a queued message** — `MessageQueue.push()` returns a stable id; `remove(id)` cancels a single pending message (per-pill ✕ in a UI).
393
+ - **BYO LLM client** — reuse the SDK's wire codec: `toOpenAIMessages`, `consumeSSE`, and the LLM types from `anyclaude-sdk/llm` (no bare-root import in browser bundles).
394
+
361
395
  ## Examples & live demo
362
396
 
363
- Runnable Vite projects in [`examples/`](examples/): **`browser-ide`** (WebContainer IDE — real shell + Node in the tab), `browser-chat`, `vercel-kv-survivor`, `vercel-supabase-survivor`, `vercel-indexeddb-survivor`, **`vercel-clienttools`** (server brain / browser hands). Try the **[live demo](https://anyclaude-docs.puter.site/demo/)**.
397
+ Runnable Vite projects in [`examples/`](examples/): **`browser-ide`** (WebContainer IDE — real shell + Node in the tab), `browser-chat`, `claude-code-router`, `vercel-kv-survivor`, `vercel-supabase-survivor`, `vercel-indexeddb-survivor`, **`vercel-clienttools`** (server brain / browser hands). Try the **[live demo](https://anyclaude-docs.puter.site/demo/)**.
364
398
 
365
399
  ## API
366
400
 
@@ -376,6 +410,10 @@ Runnable Vite projects in [`examples/`](examples/): **`browser-ide`** (WebContai
376
410
  - `WebContainerWorkspace`, `MemoryFileSystem`, `NoopCommandExecutor`, `LocalSandbox`, `composeWorkspace`
377
411
  - `defineTool` (custom tools), `projectMessages` (server-side stream redaction)
378
412
  - `ALL_CLAUDE_CODE_TOOLS`, individual tools, `toolDefs`, `toolByName`
413
+ - browser-clean subpaths: `anyclaude-sdk/{query,loop,llm,fs,workspace,tools,session,memory,compact,permissions,skills,queue,prompt,anthropic-endpoint,telemetry}`
414
+ - `anyclaude-sdk/llm`: `parseToolCalls` + dialects, `profileForModel` (model profiles), `validateToolArguments` (repair), `toOpenAIMessages` / `consumeSSE` (BYO-client codec)
415
+ - `anyclaude-sdk/anthropic-endpoint`: `anthropicToChat`, `anthropicSSE`, `streamResultToAnthropicMessage` (Claude-Code router)
416
+ - `runToolLoop` (`/loop`), `compactWithWindow` (`/compact`), `track`/`telemetryEnabled` (`/telemetry`)
379
417
  - All `SDK*` message types, `ContentBlockParam`, `LLMClient`, `ToolDef`, `SessionStoreLike`, etc.
380
418
 
381
419
  ## Differences from the official SDK
@@ -392,7 +430,7 @@ Runnable Vite projects in [`examples/`](examples/): **`browser-ide`** (WebContai
392
430
 
393
431
  ## Telemetry
394
432
 
395
- The SDK emits **anonymous, opt-out** usage telemetry (SDK version, runtime, a coarse model-family bucket, and which features are used) — never code, prompts, repo identity, paths, or keys, and a no-op unless you configure a collector. Disable with `ANYCLAUDE_TELEMETRY=0`, `DO_NOT_TRACK=1`, or `query({ disableTelemetry: true })`. Full disclosure: [TELEMETRY.md](TELEMETRY.md).
433
+ The SDK emits **anonymous, opt-out** usage telemetry (SDK version, runtime, a coarse model-family bucket, and which features are used) — never code, prompts, repo identity, paths, or keys. It sends to an aggregate-only collector (a Puter Worker; source in [`examples/telemetry-collector`](examples/telemetry-collector)). Disable with `ANYCLAUDE_TELEMETRY=0`, `DO_NOT_TRACK=1`, or `query({ disableTelemetry: true })`; repoint with `ANYCLAUDE_TELEMETRY_URL` (or set it to `''` to send nowhere). Full disclosure: [TELEMETRY.md](TELEMETRY.md).
396
434
 
397
435
  ## License
398
436
 
package/dist/query.js CHANGED
@@ -3,7 +3,7 @@
3
3
  // Returns an AsyncGenerator<SDKMessage>. Accepts either a single string prompt
4
4
  // or an async iterable of SDKUserMessage (for multi-turn / interactive use).
5
5
  import { runAgent } from './agent.js';
6
- import { track, telemetryEnabled } from './telemetry.js';
6
+ import { track, telemetryEnabled, tokenBucket } from './telemetry.js';
7
7
  import { profileForModel } from './llm/profiles.js';
8
8
  export function query(options) {
9
9
  const prompt = typeof options.prompt === 'string'
@@ -59,17 +59,18 @@ export function query(options) {
59
59
  settings: options.settings,
60
60
  skills: options.skills,
61
61
  });
62
- gen.interrupt = () => abortController.abort();
63
- // Anonymous, aggregate adoption signal one event per public run. Fire-and-forget,
64
- // never blocks the generator, no-ops unless enabled + a collector is configured.
65
- // Only booleans + a coarse model-family bucket leave the process (see telemetry.ts).
62
+ // Anonymous, aggregate adoption signal. Fire-and-forget, never blocks, no-ops
63
+ // unless enabled + a collector is configured. Only booleans + coarse buckets
64
+ // (model family, token-volume bucket) ever leave the process see telemetry.ts.
66
65
  const telemetry = {
67
66
  disabled: options.disableTelemetry,
68
67
  ...options.telemetry,
69
68
  };
70
- if (telemetryEnabled(telemetry)) {
69
+ const modelFamily = profileForModel(options.model).name;
70
+ const enabled = telemetryEnabled(telemetry);
71
+ if (enabled) {
71
72
  track('run', {
72
- model_family: profileForModel(options.model).name,
73
+ model_family: modelFamily,
73
74
  client_workspace_tools: !!options.clientWorkspaceTools,
74
75
  client_tools: !!options.clientTools?.length,
75
76
  survivor: options.maxDurationMs != null,
@@ -83,7 +84,29 @@ export function query(options) {
83
84
  resumed: !!options.continueRun || !!options.resume,
84
85
  }, telemetry);
85
86
  }
86
- return gen;
87
+ if (!enabled) {
88
+ gen.interrupt = () => abortController.abort();
89
+ return gen;
90
+ }
91
+ // Wrap to emit one `run_end` with a coarse token-volume bucket when the run
92
+ // finishes (tokens aren't known until the `result` message). Pass-through only.
93
+ const wrapped = (async function* () {
94
+ let totalTokens = 0;
95
+ try {
96
+ for await (const m of gen) {
97
+ if (m.type === 'result' && m.usage) {
98
+ const u = m.usage;
99
+ totalTokens = (u.input_tokens || 0) + (u.output_tokens || 0);
100
+ }
101
+ yield m;
102
+ }
103
+ }
104
+ finally {
105
+ track('run_end', { model_family: modelFamily, tokens_bucket: tokenBucket(totalTokens) }, telemetry);
106
+ }
107
+ })();
108
+ wrapped.interrupt = () => abortController.abort();
109
+ return wrapped;
87
110
  }
88
111
  /** Wrap a single text prompt into the async-iterable form runAgent expects. */
89
112
  export async function* singlePrompt(text) {
@@ -6,6 +6,8 @@ export interface TelemetryOptions {
6
6
  /** Collector URL. Defaults to `ANYCLAUDE_TELEMETRY_URL` then the built-in default. */
7
7
  url?: string;
8
8
  }
9
+ /** Coarse token-volume bucket — never an exact count, so a single run isn't fingerprintable. */
10
+ export declare function tokenBucket(total: number): string;
9
11
  /** Resolve whether telemetry may run, honoring every documented opt-out. */
10
12
  export declare function telemetryEnabled(opts?: TelemetryOptions): boolean;
11
13
  /** Coarse runtime bucket — never anything machine-identifying. */
package/dist/telemetry.js CHANGED
@@ -24,7 +24,21 @@ const DEFAULT_TELEMETRY_URL = 'https://anyclaude-telemetry.puter.work';
24
24
  // Only these prop keys are ever transmitted, and only with safe value types.
25
25
  // Booleans pass through; these specific string keys pass through as-is (they are
26
26
  // coarse buckets we set ourselves — never free-form / user data).
27
- const ALLOWED_STRING_KEYS = new Set(['model_family', 'event_detail']);
27
+ const ALLOWED_STRING_KEYS = new Set(['model_family', 'event_detail', 'tokens_bucket']);
28
+ /** Coarse token-volume bucket — never an exact count, so a single run isn't fingerprintable. */
29
+ export function tokenBucket(total) {
30
+ if (!Number.isFinite(total) || total <= 0)
31
+ return '0';
32
+ if (total < 1_000)
33
+ return '<1k';
34
+ if (total < 10_000)
35
+ return '1k-10k';
36
+ if (total < 100_000)
37
+ return '10k-100k';
38
+ if (total < 1_000_000)
39
+ return '100k-1m';
40
+ return '1m+';
41
+ }
28
42
  function readEnv(name) {
29
43
  const p = globalThis.process;
30
44
  return p?.env?.[name];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "anyclaude-sdk",
3
- "version": "0.7.1",
3
+ "version": "0.7.3",
4
4
  "description": "Standalone, browser-compatible SDK providing Claude Code agent capabilities (tools, tool loop, multi-turn, MCP, sub-agents, sessions) against any OpenAI/Anthropic-compatible LLM endpoint. Runs in the browser (WebContainer), Node, and Bun — no backend required.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",