{"_id":"@agentaily/agent-loop-client","name":"@agentaily/agent-loop-client","dist-tags":{"latest":"0.1.0"},"versions":{"0.1.0":{"name":"@agentaily/agent-loop-client","version":"0.1.0","description":"Run the agentaily agent loop directly in the browser — DeepSeek direct, localStorage-backed sessions + memory, no server. Companion to @agentaily/agent-loop.","type":"module","license":"MIT","author":{"name":"agentaily"},"homepage":"https://github.com/agentaily/agent-loop-client#readme","repository":{"type":"git","url":"git+https://github.com/agentaily/agent-loop-client.git"},"bugs":{"url":"https://github.com/agentaily/agent-loop-client/issues"},"keywords":["agent","agent-loop","llm","browser","client","localstorage","deepseek","byok","skills","memory","sessions"],"sideEffects":false,"main":"./dist/index.js","module":"./dist/index.js","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"},"./adapters/local":{"types":"./dist/adapters/local.d.ts","import":"./dist/adapters/local.js"}},"scripts":{"build":"tsup","dev":"tsup --watch","typecheck":"tsc --noEmit","test":"vitest run","test:watch":"vitest","changeset":"changeset","release":"changeset publish","prepublishOnly":"npm run build"},"dependencies":{"@agentaily/agent-loop":"^0.1.0"},"devDependencies":{"@changesets/changelog-github":"^0.7.0","@changesets/cli":"^2.31.0","tsup":"^8.3.5","typescript":"^5.6.3","vitest":"^2.1.8"},"engines":{"node":">=18"},"publishConfig":{"access":"public"},"gitHead":"a4ee17262637b00a62f498b215101a4a96718b45","_id":"@agentaily/agent-loop-client@0.1.0","_nodeVersion":"26.0.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-5O9UH84/u3PrX7YblyhR5r1hB4NWwhsWYSWRk/nfgmCTNmLQgS+Z1bK7dtCUkMwP8qBCQRmUo7+02jhgazqHJw==","shasum":"f55af047ec3af6974eccf9c9cd38e7ded59390a9","tarball":"https://registry.npmjs.org/@agentaily/agent-loop-client/-/agent-loop-client-0.1.0.tgz","fileCount":11,"unpackedSize":30862,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIQDTroaDaQ98tr+ykhSYbOaOiTnva8itjrrrO3KO21xjowIgPeCKYHqDYxikT8FJ3BJ3H6vfZTsGVRDwlj6Km6uLUI4="}]},"_npmUser":{"name":"yarnovo","email":"yarnb@qq.com"},"directories":{},"maintainers":[{"name":"yarnovo","email":"yarnb@qq.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/agent-loop-client_0.1.0_1782987781695_0.5749981375577871"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-02T10:23:01.567Z","0.1.0":"2026-07-02T10:23:01.902Z","modified":"2026-07-02T10:23:02.110Z"},"maintainers":[{"name":"yarnovo","email":"yarnb@qq.com"}],"description":"Run the agentaily agent loop directly in the browser — DeepSeek direct, localStorage-backed sessions + memory, no server. Companion to @agentaily/agent-loop.","homepage":"https://github.com/agentaily/agent-loop-client#readme","keywords":["agent","agent-loop","llm","browser","client","localstorage","deepseek","byok","skills","memory","sessions"],"repository":{"type":"git","url":"git+https://github.com/agentaily/agent-loop-client.git"},"author":{"name":"agentaily"},"bugs":{"url":"https://github.com/agentaily/agent-loop-client/issues"},"license":"MIT","readme":"# @agentaily/agent-loop-client\n\nRun the agentaily **agent loop in the browser** — DeepSeek direct, `localStorage`-backed sessions + memory, **no server**.\n\nA thin companion to [`@agentaily/agent-loop`](https://github.com/agentaily/agent-loop): same loop, skills, memory, and sessions, wired for the client. The model call goes **straight to `api.deepseek.com`** (which allows browser CORS) and all conversation + memory state persists **on the device**.\n\n- **No server hop** — DeepSeek is a domestic (China) service; a direct call is much faster than routing through a Cloudflare Worker, especially on mobile networks in China.\n- **Data stays local** — sessions and memory live in `localStorage`; nothing is sent anywhere but the model API.\n- **One import** — re-exports the whole `@agentaily/agent-loop` surface, so consumers usually import just this package.\n\n## Key handling — two ways to supply the DeepSeek key\n\nWhatever key you pass to `createClientAgent` **runs in the browser and is visible in network traffic.** That's inherent to the no-server design. There are two legitimate ways to supply it — pick per product:\n\n**1. Embed the app's own key (default — what `2bti` does).** Inject a shared, app-owned DeepSeek key at **build time** (e.g. a `VITE_DEEPSEEK_KEY` from a CI/build secret — kept out of git source, but it does ship in the public bundle). Simplest UX: users just chat, no setup. You accept that the key is exposed, and **mitigate**:\n\n- use a **dedicated, low-budget key** (not your main account key) so the blast radius of abuse is capped;\n- **monitor spend** and set alerts;\n- **rotate** the key on a schedule (and immediately if you see abuse).\n\n> Heads-up: a key that ships in a public bundle can be scraped, and DeepSeek may auto-disable a key it detects as publicly leaked — the rotation + monitoring above are exactly how you stay ahead of that. Don't use a key you can't afford to have leaked or disabled.\n\n**2. Per-user BYOK (more secure, optional).** The end user pastes **their own** DeepSeek key at runtime (a settings field); you store it in **their** `localStorage`. Nothing app-owned is exposed and there's no shared key to abuse — at the cost of asking each user for a key. Good when you can't or don't want to fund usage centrally.\n\nEither way the API is the same — `createClientAgent({ apiKey })`; only where `apiKey` comes from differs. If a key must stay secret (app-owned and you can't tolerate exposure), don't put it in the browser at all: keep it **server-side** behind a proxy / Worker running `@agentaily/agent-loop`.\n\nFirst consumer: the [`2bti`](https://2bti.agentaily.com) SPA (embedded app key).\n\n## Install\n\n```bash\nnpm i @agentaily/agent-loop-client\n```\n\n`@agentaily/agent-loop` comes along as a dependency — you don't install it separately.\n\n## Quick start\n\n```ts\nimport { createClientAgent } from '@agentaily/agent-loop-client'\n\n// Default: the app's own key, injected at build time (kept out of git source).\n// For per-user BYOK, read the user's key from localStorage instead — same call.\nconst apiKey = import.meta.env.VITE_DEEPSEEK_KEY\n\nconst agent = createClientAgent({\n  apiKey,\n  instructions: 'You are a concise, friendly assistant.',\n})\n\nconst res = await agent.run('what can you do?')\nconsole.log(res.text)\n\n// Resume the same conversation later (history is in localStorage):\nawait agent.run({ message: 'and again', sessionId: res.session.id })\n```\n\n`createClientAgent` returns a plain `Agent` from `@agentaily/agent-loop`, so its\nwhole API (`run`, `onStep`, tools, skills, …) is available.\n\n## What it wires for you\n\n```ts\nnew Agent({\n  provider: deepseek({ apiKey }),                 // straight to api.deepseek.com\n  sessions: new LocalSessionStore(storage),       // localStorage, prefix 'session:'\n  memory: new LocalMemoryStore(storage),          // localStorage, prefix 'memory:'\n  instructions, tools, skills, builtins, maxSteps, temperature, maxTokens, onStep,\n})\n```\n\n### `createClientAgent(opts)`\n\n| option | default | notes |\n| --- | --- | --- |\n| `apiKey` | — | **required**; DeepSeek key — an embedded app key or the user's own (see [Key handling](#key-handling--two-ways-to-supply-the-deepseek-key)) |\n| `model` | `deepseek()` default | DeepSeek model id |\n| `instructions` | — | base system prompt (persona / rules) |\n| `storage` | `globalThis.localStorage` | any `StorageLike`; inject for SSR / tests |\n| `sessionPrefix` | `'session:'` | key prefix for stored sessions |\n| `memoryPrefix` | `'memory:'` | key prefix for stored memory records |\n| `tools` | — | always-available app tools |\n| `skills` | — | `Skill[]` / `SkillRegistry`, progressive disclosure |\n| `builtins` | `true` | inject `load_skill` / `remember` / `recall` |\n| `maxSteps` | `8` | provider round-trips before bailing |\n| `temperature`, `maxTokens` | — | forwarded to the provider |\n| `onStep` | — | `(event) => void` per loop step |\n\n## Storage adapters\n\nTwo `localStorage`-backed stores implementing the core `SessionStore` /\n`MemoryStore` interfaces. `createClientAgent` uses them for you; import directly\nif you want to build the `Agent` yourself.\n\n```ts\nimport { LocalSessionStore, LocalMemoryStore } from '@agentaily/agent-loop-client/adapters/local'\nimport { Agent, deepseek } from '@agentaily/agent-loop-client'\n\nconst agent = new Agent({\n  provider: deepseek({ apiKey }),\n  sessions: new LocalSessionStore(),      // defaults to globalThis.localStorage\n  memory: new LocalMemoryStore(),\n})\n```\n\nBoth accept an optional `StorageLike` (a subset of the Web Storage API) and a\nkey prefix. Pass your own `StorageLike` for SSR, Node, or tests — if none is\ngiven and `globalThis.localStorage` is absent, the constructor throws a clear\nerror rather than failing later.\n\n## Re-exported from `@agentaily/agent-loop`\n\nSo you can import everything from here: `Agent`, `defineTool`, `SkillRegistry`,\n`parseSkill`, `InMemorySessionStore`, `InMemoryMemoryStore`, `createSession`,\n`renderMemoryIndex`, `buildSystemPrompt`, `openaiCompatible`, `deepseek`, plus\nall the shared types (`LLMProvider`, `Tool`, `Skill`, `Session`,\n`MemoryRecord`, `SessionStore`, `MemoryStore`, …).\n\n## Migrating from a server `/agent` endpoint to client-direct\n\nIf you currently `POST /agent { message, sessionId } → { text, sessionId }` at\na Worker that runs `@agentaily/agent-loop`, moving the loop into the browser is\na straight swap:\n\n```ts\n// before — over the network to your Worker\nconst r = await fetch('/agent', { method: 'POST', body: JSON.stringify({ message, sessionId }) })\nconst { text, sessionId } = await r.json()\n\n// after — no server; loop runs in the page\nconst agent = createClientAgent({ apiKey: DEEPSEEK_KEY })\nconst { text, session } = await agent.run({ message, sessionId })\n```\n\nYou trade a server round-trip (and key secrecy) for latency and offline-friendly\nlocal state. The key then lives in the browser — supply it as an embedded app\nkey (with a dedicated low-budget key + monitoring + rotation) or via per-user\nBYOK (see [Key handling](#key-handling--two-ways-to-supply-the-deepseek-key)).\nIf a key must stay secret and you can't tolerate exposure, keep the Worker path.\n\n## Develop\n\n```bash\nnpm install\nnpm test          # vitest (fake storage — no network, no browser)\nnpm run typecheck\nnpm run build     # tsup -> dist (ESM + d.ts)\n```\n\n## License\n\nMIT © agentaily\n","readmeFilename":"README.md","_rev":"1-dbcca4c9d187c99ce2d6abc03473ab13"}