@sw4rm/js-sdk 0.5.0 → 0.6.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # SW4RM JavaScript SDK
2
2
 
3
- Reference JavaScript SDK for the SW4RM Agentic Protocol. This is one of three SDKs in this repository (Python, Rust, JavaScript). 🚧 Under development: initial implementation includes a basic RegistryClient and core utilities.
3
+ Reference JavaScript SDK for the SW4RM Agentic Protocol. This is one of five SDKs in this repository (Python, Rust, JavaScript, Elixir, Common Lisp). 🚧 Under development: initial implementation includes a basic RegistryClient and core utilities.
4
4
 
5
5
  ## Install
6
6
 
@@ -66,6 +66,7 @@ await client.deregisterAgent('my-agent', 'Done');
66
66
 
67
67
  - ✅ Base gRPC client infrastructure
68
68
  - ✅ RegistryClient (agent registration, heartbeat, deregistration)
69
+ - ✅ LLM clients (Groq, Anthropic, Mock) with adaptive rate limiting
69
70
  - ✅ TypeScript type definitions
70
71
  - ✅ Unit tests
71
72
  - ⏳ Additional service clients (planned)
@@ -145,6 +146,169 @@ await persist.load();
145
146
  persist.startAutosave();
146
147
  ```
147
148
 
149
+ ## LLM Client
150
+
151
+ The SDK includes a provider-agnostic LLM client abstraction. Agents can query
152
+ language models through a unified interface without coupling to a specific vendor.
153
+
154
+ ### Import
155
+
156
+ ```ts
157
+ import {
158
+ createLlmClient,
159
+ GroqClient,
160
+ AnthropicClient,
161
+ MockLlmClient,
162
+ } from '@sw4rm/js-sdk';
163
+ ```
164
+
165
+ ### Factory
166
+
167
+ The `createLlmClient` factory selects a provider based on explicit options or
168
+ environment variables. When nothing is specified it defaults to the mock client,
169
+ so tests never hit a real API.
170
+
171
+ ```ts
172
+ // Auto-detect from LLM_CLIENT_TYPE env var (default: "mock")
173
+ const client = createLlmClient();
174
+
175
+ // Explicit provider
176
+ const groq = createLlmClient({ clientType: 'groq' });
177
+ const claude = createLlmClient({
178
+ clientType: 'anthropic',
179
+ model: 'claude-sonnet-4-20250514',
180
+ });
181
+
182
+ // Override API key and timeout
183
+ const custom = createLlmClient({
184
+ clientType: 'groq',
185
+ apiKey: 'gsk_...',
186
+ timeoutMs: 60_000,
187
+ });
188
+ ```
189
+
190
+ ### Credential resolution
191
+
192
+ Each provider resolves its API key in this order:
193
+
194
+ 1. `apiKey` constructor / factory parameter
195
+ 2. Environment variable (`GROQ_API_KEY` or `ANTHROPIC_API_KEY`)
196
+ 3. Dotfile in the home directory (`~/.groq` or `~/.anthropic`, plain text, one line)
197
+
198
+ If none of these are set the constructor throws `LlmAuthenticationError`.
199
+
200
+ ### Basic query
201
+
202
+ ```ts
203
+ import { createLlmClient } from '@sw4rm/js-sdk';
204
+
205
+ const client = createLlmClient({ clientType: 'groq' });
206
+
207
+ const response = await client.query(
208
+ 'Analyze this task and suggest next steps.',
209
+ {
210
+ systemPrompt: 'You are a helpful task-analysis agent.',
211
+ maxTokens: 2048,
212
+ temperature: 0.7,
213
+ },
214
+ );
215
+
216
+ console.log(response.content); // generated text
217
+ console.log(response.model); // e.g. "llama-3.3-70b-versatile"
218
+ console.log(response.usage); // { input_tokens, output_tokens }
219
+ ```
220
+
221
+ ### Streaming
222
+
223
+ `streamQuery` returns an `AsyncGenerator<string>` that yields text chunks as
224
+ they arrive over SSE.
225
+
226
+ ```ts
227
+ const client = createLlmClient({ clientType: 'anthropic' });
228
+
229
+ for await (const chunk of client.streamQuery('Write a status report.', {
230
+ systemPrompt: 'You are a concise technical writer.',
231
+ })) {
232
+ process.stdout.write(chunk);
233
+ }
234
+ ```
235
+
236
+ ### Mock client for testing
237
+
238
+ `MockLlmClient` never makes network calls. It records every query so tests
239
+ can assert on prompts, token counts, and call order.
240
+
241
+ ```ts
242
+ import { MockLlmClient } from '@sw4rm/js-sdk';
243
+
244
+ const mock = new MockLlmClient({
245
+ responses: ['First canned answer', 'Second canned answer'],
246
+ });
247
+
248
+ const r1 = await mock.query('Hello');
249
+ console.log(r1.content); // "First canned answer"
250
+ console.log(mock.callCount); // 1
251
+
252
+ // Custom generator
253
+ const mock2 = new MockLlmClient({
254
+ responseGenerator: (prompt) => `Echo: ${prompt}`,
255
+ });
256
+ ```
257
+
258
+ ### Rate limiting
259
+
260
+ All LLM clients share a process-wide token-bucket rate limiter. It is enabled
261
+ by default and adapts automatically:
262
+
263
+ - On **HTTP 429** the budget is reduced by a configurable factor (default 0.7x).
264
+ - After a cooldown period and enough consecutive successes the budget recovers.
265
+ - Callers block in `acquire()` until tokens are available; a timeout prevents
266
+ indefinite waits.
267
+
268
+ No application code is needed -- rate limiting is built into every `query` and
269
+ `streamQuery` call.
270
+
271
+ ### Error hierarchy
272
+
273
+ All LLM errors extend `LlmError`:
274
+
275
+ | Class | Trigger |
276
+ |---|---|
277
+ | `LlmAuthenticationError` | Invalid / missing API key, billing errors |
278
+ | `LlmRateLimitError` | HTTP 429 from the provider |
279
+ | `LlmTimeoutError` | Request exceeded timeout |
280
+ | `LlmContextLengthError` | Prompt exceeds model context window |
281
+
282
+ ```ts
283
+ import { LlmRateLimitError } from '@sw4rm/js-sdk';
284
+
285
+ try {
286
+ await client.query('...');
287
+ } catch (err) {
288
+ if (err instanceof LlmRateLimitError) {
289
+ // The rate limiter already reduced its budget; retry after a delay
290
+ }
291
+ }
292
+ ```
293
+
294
+ ### Environment variables
295
+
296
+ | Variable | Default | Description |
297
+ |---|---|---|
298
+ | `LLM_CLIENT_TYPE` | `mock` | Provider for the factory: `groq`, `anthropic`, or `mock` |
299
+ | `LLM_DEFAULT_MODEL` | per-provider | Override the default model for any provider |
300
+ | `GROQ_API_KEY` | -- | Groq API key |
301
+ | `GROQ_DEFAULT_MODEL` | `llama-3.3-70b-versatile` | Default model for the Groq client |
302
+ | `ANTHROPIC_API_KEY` | -- | Anthropic API key |
303
+ | `ANTHROPIC_DEFAULT_MODEL` | `claude-sonnet-4-20250514` | Default model for the Anthropic client |
304
+ | `LLM_RATE_LIMIT_ENABLED` | `1` | Set to `0` to disable the rate limiter |
305
+ | `LLM_RATE_LIMIT_TOKENS_PER_MIN` | `250000` | Token budget per minute |
306
+ | `LLM_RATE_LIMIT_ADAPTIVE` | `1` | Enable adaptive throttling on 429 |
307
+ | `LLM_RATE_LIMIT_REDUCTION_FACTOR` | `0.7` | Budget multiplier after a 429 |
308
+ | `LLM_RATE_LIMIT_RECOVERY_FACTOR` | `1.1` | Budget multiplier during recovery |
309
+ | `LLM_RATE_LIMIT_COOLDOWN_SECONDS` | `30` | Seconds to wait before recovery begins |
310
+ | `LLM_RATE_LIMIT_RECOVERY_SUCCESS_THRESHOLD` | `20` | Consecutive successes needed for recovery |
311
+
148
312
  ## Spec compliance
149
313
 
150
314
  - Envelope, ACK lifecycle, Scheduler (priority/Duration), Worktree, HITL, Negotiation, Reasoning, Connector, Logging clients implemented.