@a3s-lab/code 0.1.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/LICENSE +21 -0
- package/README.md +902 -0
- package/dist/client.d.ts +1107 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +830 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +106 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +142 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +15 -0
- package/dist/index.js.map +1 -0
- package/dist/openai-compat.d.ts +186 -0
- package/dist/openai-compat.d.ts.map +1 -0
- package/dist/openai-compat.js +263 -0
- package/dist/openai-compat.js.map +1 -0
- package/package.json +43 -0
- package/proto/code_agent.proto +1512 -0
package/README.md
ADDED
|
@@ -0,0 +1,902 @@
|
|
|
1
|
+
# A3S Code TypeScript SDK
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<strong>TypeScript/JavaScript Client for A3S Code Agent</strong>
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<em>Full-featured gRPC client for building AI coding agent applications</em>
|
|
9
|
+
</p>
|
|
10
|
+
|
|
11
|
+
<p align="center">
|
|
12
|
+
<img src="https://img.shields.io/badge/API_Coverage-100%25-brightgreen" alt="API Coverage">
|
|
13
|
+
<img src="https://img.shields.io/badge/Methods-53-blue" alt="Methods">
|
|
14
|
+
<img src="https://img.shields.io/badge/TypeScript-5.3+-blue" alt="TypeScript">
|
|
15
|
+
<img src="https://img.shields.io/badge/License-MIT-green" alt="License">
|
|
16
|
+
</p>
|
|
17
|
+
|
|
18
|
+
<p align="center">
|
|
19
|
+
<a href="#features">Features</a> •
|
|
20
|
+
<a href="#installation">Installation</a> •
|
|
21
|
+
<a href="#quick-start">Quick Start</a> •
|
|
22
|
+
<a href="#api-reference">API Reference</a> •
|
|
23
|
+
<a href="./examples">Examples</a>
|
|
24
|
+
</p>
|
|
25
|
+
|
|
26
|
+
---
|
|
27
|
+
|
|
28
|
+
## Overview
|
|
29
|
+
|
|
30
|
+
**@a3s-lab/code** is the official TypeScript SDK for [A3S Code](https://github.com/a3s-lab/a3s), providing a complete gRPC client implementation for the CodeAgentService API. Build AI-powered coding assistants, IDE integrations, and automation tools with full access to A3S Code's capabilities.
|
|
31
|
+
|
|
32
|
+
### Why This SDK?
|
|
33
|
+
|
|
34
|
+
- **100% API Coverage**: All 53 RPCs from CodeAgentService fully implemented
|
|
35
|
+
- **Type-Safe**: Full TypeScript definitions for all types and enums
|
|
36
|
+
- **Async/Await**: Modern Promise-based API with streaming support
|
|
37
|
+
- **Flexible Configuration**: Environment variables, config files, or programmatic setup
|
|
38
|
+
- **Real-World Examples**: Comprehensive examples with real LLM API integration
|
|
39
|
+
|
|
40
|
+
## Features
|
|
41
|
+
|
|
42
|
+
| Category | Features |
|
|
43
|
+
|----------|----------|
|
|
44
|
+
| **Lifecycle** | Health check, capabilities, initialization, shutdown |
|
|
45
|
+
| **Sessions** | Create, list, get, configure, destroy with persistence |
|
|
46
|
+
| **Generation** | Streaming/non-streaming responses, structured output, context compaction |
|
|
47
|
+
| **Tools** | Load/unload skills, list available tools, custom tool registration |
|
|
48
|
+
| **Context** | Add/clear context, manage conversation history, usage monitoring |
|
|
49
|
+
| **Control** | Abort operations, pause/resume, cancel confirmations |
|
|
50
|
+
| **Events** | Subscribe to real-time agent events, tool execution tracking |
|
|
51
|
+
| **HITL** | Human-in-the-loop confirmations, approval workflows |
|
|
52
|
+
| **Permissions** | Fine-grained permission policies, tool access control |
|
|
53
|
+
| **Todos** | Task tracking for multi-step workflows, goal management |
|
|
54
|
+
| **Providers** | Multi-provider LLM configuration (Anthropic, OpenAI, KIMI, etc.) |
|
|
55
|
+
| **Planning** | Execution plans, goal extraction, achievement checking |
|
|
56
|
+
| **Memory** | Episodic/semantic/procedural memory storage and retrieval |
|
|
57
|
+
| **Storage** | Configurable session storage (memory, file, custom) |
|
|
58
|
+
|
|
59
|
+
## Installation
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
npm install @a3s-lab/code
|
|
63
|
+
# or
|
|
64
|
+
yarn add @a3s-lab/code
|
|
65
|
+
# or
|
|
66
|
+
pnpm add @a3s-lab/code
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Quick Start
|
|
70
|
+
|
|
71
|
+
### Basic Usage
|
|
72
|
+
|
|
73
|
+
```typescript
|
|
74
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
75
|
+
|
|
76
|
+
// Create client with default config
|
|
77
|
+
const client = new A3sClient();
|
|
78
|
+
|
|
79
|
+
// Or with explicit address
|
|
80
|
+
const client = new A3sClient({ address: 'localhost:4088' });
|
|
81
|
+
|
|
82
|
+
// Or load from config file
|
|
83
|
+
const client = new A3sClient({ configDir: '/path/to/.a3s' });
|
|
84
|
+
|
|
85
|
+
async function main() {
|
|
86
|
+
// Check health
|
|
87
|
+
const health = await client.healthCheck();
|
|
88
|
+
console.log('Agent status:', health.status);
|
|
89
|
+
|
|
90
|
+
// Create a session
|
|
91
|
+
const session = await client.createSession({
|
|
92
|
+
name: 'my-session',
|
|
93
|
+
workspace: '/path/to/project',
|
|
94
|
+
systemPrompt: 'You are a helpful coding assistant.',
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// Generate a response (streaming)
|
|
98
|
+
for await (const chunk of client.streamGenerate(session.sessionId, [
|
|
99
|
+
{ role: 'user', content: 'Explain this codebase structure' }
|
|
100
|
+
])) {
|
|
101
|
+
if (chunk.type === 'CHUNK_TYPE_CONTENT' && chunk.content) {
|
|
102
|
+
process.stdout.write(chunk.content);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// Clean up
|
|
107
|
+
await client.destroySession(session.sessionId);
|
|
108
|
+
client.close();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
main().catch(console.error);
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 📚 Complete Examples
|
|
115
|
+
|
|
116
|
+
See the [examples](./examples) directory for comprehensive, runnable examples:
|
|
117
|
+
|
|
118
|
+
| Example | Description | Run |
|
|
119
|
+
|---------|-------------|-----|
|
|
120
|
+
| [kimi-test.ts](./examples/src/kimi-test.ts) | Test with KIMI K2.5 model | `npm run kimi-test` |
|
|
121
|
+
| [chat-simulation.ts](./examples/src/chat-simulation.ts) | Multi-turn chat with skills | `npm run chat` |
|
|
122
|
+
| [code-generation-interactive.ts](./examples/src/code-generation-interactive.ts) | Interactive code generation | `npm run code-gen` |
|
|
123
|
+
| [skill-usage-demo.ts](./examples/src/skill-usage-demo.ts) | Skill loading and usage | `npm run skill-demo` |
|
|
124
|
+
| [simple-test.ts](./examples/src/simple-test.ts) | Basic SDK usage | `npm run dev` |
|
|
125
|
+
| [storage-configuration.ts](./examples/src/storage-configuration.ts) | Memory vs file storage | `npm run storage` |
|
|
126
|
+
| [hitl-confirmation.ts](./examples/src/hitl-confirmation.ts) | Human-in-the-loop | `npm run hitl` |
|
|
127
|
+
| [provider-config.ts](./examples/src/provider-config.ts) | Provider management | `npm run provider` |
|
|
128
|
+
| [context-management.ts](./examples/src/context-management.ts) | Context monitoring | `npm run context` |
|
|
129
|
+
| [code-review-agent.ts](./examples/src/code-review-agent.ts) | Complete production example | `npm run code-review` |
|
|
130
|
+
|
|
131
|
+
**Quick start with examples:**
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
cd examples
|
|
135
|
+
npm install
|
|
136
|
+
|
|
137
|
+
# Test with KIMI model (recommended)
|
|
138
|
+
npm run kimi-test
|
|
139
|
+
|
|
140
|
+
# Try chat simulation
|
|
141
|
+
npm run chat
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
See [examples/README.md](./examples/README.md) for detailed documentation and [TESTING_WITH_REAL_MODELS.md](./examples/TESTING_WITH_REAL_MODELS.md) for API configuration guide.
|
|
145
|
+
|
|
146
|
+
## Usage Examples
|
|
147
|
+
|
|
148
|
+
### Multi-Turn Conversations
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
152
|
+
|
|
153
|
+
const client = new A3sClient({ configDir: '~/.a3s' });
|
|
154
|
+
|
|
155
|
+
async function multiTurnChat() {
|
|
156
|
+
await client.connect();
|
|
157
|
+
|
|
158
|
+
const { sessionId } = await client.createSession({
|
|
159
|
+
name: 'chat-session',
|
|
160
|
+
workspace: '/path/to/project',
|
|
161
|
+
});
|
|
162
|
+
|
|
163
|
+
// First turn
|
|
164
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
165
|
+
{ role: 'user', content: 'List all TypeScript files in this project' }
|
|
166
|
+
])) {
|
|
167
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Second turn - context is preserved
|
|
171
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
172
|
+
{ role: 'user', content: 'Now analyze the main entry point' }
|
|
173
|
+
])) {
|
|
174
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Get conversation history
|
|
178
|
+
const { messages } = await client.getMessages(sessionId, { limit: 10 });
|
|
179
|
+
console.log(`\nConversation has ${messages.length} messages`);
|
|
180
|
+
|
|
181
|
+
await client.destroySession(sessionId);
|
|
182
|
+
client.close();
|
|
183
|
+
}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
### Event Subscription
|
|
187
|
+
|
|
188
|
+
```typescript
|
|
189
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
190
|
+
|
|
191
|
+
const client = new A3sClient();
|
|
192
|
+
|
|
193
|
+
async function subscribeToEvents() {
|
|
194
|
+
await client.connect();
|
|
195
|
+
|
|
196
|
+
const { sessionId } = await client.createSession({
|
|
197
|
+
name: 'event-demo',
|
|
198
|
+
workspace: '/tmp/workspace',
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
// Subscribe to all events
|
|
202
|
+
const eventStream = client.subscribeEvents(sessionId);
|
|
203
|
+
|
|
204
|
+
// Handle events in background
|
|
205
|
+
(async () => {
|
|
206
|
+
for await (const event of eventStream) {
|
|
207
|
+
console.log(`[${event.type}] ${event.message}`);
|
|
208
|
+
|
|
209
|
+
if (event.type === 'EVENT_TYPE_TOOL_CALLED') {
|
|
210
|
+
console.log(` Tool: ${event.metadata?.tool_name}`);
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (event.type === 'EVENT_TYPE_CONFIRMATION_REQUIRED') {
|
|
214
|
+
console.log(` Confirmation needed for: ${event.metadata?.tool_name}`);
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
})();
|
|
218
|
+
|
|
219
|
+
// Generate with tool usage
|
|
220
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
221
|
+
{ role: 'user', content: 'Read the README.md file' }
|
|
222
|
+
])) {
|
|
223
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
await client.destroySession(sessionId);
|
|
227
|
+
client.close();
|
|
228
|
+
}
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
### Human-in-the-Loop (HITL)
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
235
|
+
|
|
236
|
+
const client = new A3sClient();
|
|
237
|
+
|
|
238
|
+
async function hitlDemo() {
|
|
239
|
+
await client.connect();
|
|
240
|
+
|
|
241
|
+
const { sessionId } = await client.createSession({
|
|
242
|
+
name: 'hitl-demo',
|
|
243
|
+
workspace: '/path/to/project',
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
// Set confirmation policy - require approval for bash commands
|
|
247
|
+
await client.setConfirmationPolicy(sessionId, {
|
|
248
|
+
defaultAction: 'TIMEOUT_ACTION_REJECT',
|
|
249
|
+
timeoutMs: 30000,
|
|
250
|
+
rules: [
|
|
251
|
+
{
|
|
252
|
+
toolPattern: 'bash',
|
|
253
|
+
action: 'TIMEOUT_ACTION_REJECT',
|
|
254
|
+
requireConfirmation: true,
|
|
255
|
+
}
|
|
256
|
+
]
|
|
257
|
+
});
|
|
258
|
+
|
|
259
|
+
// Subscribe to events to detect confirmation requests
|
|
260
|
+
const eventStream = client.subscribeEvents(sessionId);
|
|
261
|
+
|
|
262
|
+
(async () => {
|
|
263
|
+
for await (const event of eventStream) {
|
|
264
|
+
if (event.type === 'EVENT_TYPE_CONFIRMATION_REQUIRED') {
|
|
265
|
+
const toolName = event.metadata?.tool_name;
|
|
266
|
+
const toolArgs = event.metadata?.tool_args;
|
|
267
|
+
|
|
268
|
+
console.log(`\nConfirmation required:`);
|
|
269
|
+
console.log(` Tool: ${toolName}`);
|
|
270
|
+
console.log(` Args: ${toolArgs}`);
|
|
271
|
+
|
|
272
|
+
// Auto-approve for demo (in real app, prompt user)
|
|
273
|
+
const approved = true;
|
|
274
|
+
|
|
275
|
+
await client.confirmToolExecution(sessionId, {
|
|
276
|
+
approved,
|
|
277
|
+
reason: approved ? 'User approved' : 'User rejected',
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
})();
|
|
282
|
+
|
|
283
|
+
// This will trigger confirmation
|
|
284
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
285
|
+
{ role: 'user', content: 'Run "ls -la" command' }
|
|
286
|
+
])) {
|
|
287
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
await client.destroySession(sessionId);
|
|
291
|
+
client.close();
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### Permission Policies
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
299
|
+
|
|
300
|
+
const client = new A3sClient();
|
|
301
|
+
|
|
302
|
+
async function permissionDemo() {
|
|
303
|
+
await client.connect();
|
|
304
|
+
|
|
305
|
+
const { sessionId } = await client.createSession({
|
|
306
|
+
name: 'permission-demo',
|
|
307
|
+
workspace: '/path/to/project',
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
// Set permission policy - read-only mode
|
|
311
|
+
await client.setPermissionPolicy(sessionId, {
|
|
312
|
+
defaultDecision: 'PERMISSION_DECISION_DENY',
|
|
313
|
+
rules: [
|
|
314
|
+
{
|
|
315
|
+
toolPattern: 'read',
|
|
316
|
+
decision: 'PERMISSION_DECISION_ALLOW',
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
toolPattern: 'grep',
|
|
320
|
+
decision: 'PERMISSION_DECISION_ALLOW',
|
|
321
|
+
},
|
|
322
|
+
{
|
|
323
|
+
toolPattern: 'glob',
|
|
324
|
+
decision: 'PERMISSION_DECISION_ALLOW',
|
|
325
|
+
},
|
|
326
|
+
{
|
|
327
|
+
toolPattern: 'ls',
|
|
328
|
+
decision: 'PERMISSION_DECISION_ALLOW',
|
|
329
|
+
},
|
|
330
|
+
{
|
|
331
|
+
toolPattern: 'write',
|
|
332
|
+
decision: 'PERMISSION_DECISION_DENY',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
toolPattern: 'bash',
|
|
336
|
+
decision: 'PERMISSION_DECISION_ASK',
|
|
337
|
+
}
|
|
338
|
+
]
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
// Check permission before operation
|
|
342
|
+
const canWrite = await client.checkPermission(sessionId, {
|
|
343
|
+
toolName: 'write',
|
|
344
|
+
args: { file_path: '/tmp/test.txt' }
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
console.log(`Can write: ${canWrite.decision === 'PERMISSION_DECISION_ALLOW'}`);
|
|
348
|
+
|
|
349
|
+
// This will be allowed (read-only tools)
|
|
350
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
351
|
+
{ role: 'user', content: 'List all files in the current directory' }
|
|
352
|
+
])) {
|
|
353
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
await client.destroySession(sessionId);
|
|
357
|
+
client.close();
|
|
358
|
+
}
|
|
359
|
+
```
|
|
360
|
+
|
|
361
|
+
### Provider Configuration
|
|
362
|
+
|
|
363
|
+
```typescript
|
|
364
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
365
|
+
|
|
366
|
+
const client = new A3sClient();
|
|
367
|
+
|
|
368
|
+
async function providerDemo() {
|
|
369
|
+
await client.connect();
|
|
370
|
+
|
|
371
|
+
// List available providers
|
|
372
|
+
const { providers } = await client.listProviders();
|
|
373
|
+
console.log('Available providers:', providers.map(p => p.name));
|
|
374
|
+
|
|
375
|
+
// Add a new provider
|
|
376
|
+
await client.addProvider({
|
|
377
|
+
name: 'openai',
|
|
378
|
+
apiKey: 'sk-...',
|
|
379
|
+
baseUrl: 'https://api.openai.com/v1',
|
|
380
|
+
models: [
|
|
381
|
+
{
|
|
382
|
+
id: 'gpt-4',
|
|
383
|
+
name: 'GPT-4',
|
|
384
|
+
family: 'gpt',
|
|
385
|
+
toolCall: true,
|
|
386
|
+
}
|
|
387
|
+
]
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
// Set default model
|
|
391
|
+
await client.setDefaultModel('openai', 'gpt-4');
|
|
392
|
+
|
|
393
|
+
// Get current default
|
|
394
|
+
const { provider, model } = await client.getDefaultModel();
|
|
395
|
+
console.log(`Default: ${provider}/${model}`);
|
|
396
|
+
|
|
397
|
+
// Create session with specific model
|
|
398
|
+
const { sessionId } = await client.createSession({
|
|
399
|
+
name: 'openai-session',
|
|
400
|
+
workspace: '/tmp/workspace',
|
|
401
|
+
llmConfig: {
|
|
402
|
+
provider: 'openai',
|
|
403
|
+
model: 'gpt-4',
|
|
404
|
+
temperature: 0.7,
|
|
405
|
+
}
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
await client.destroySession(sessionId);
|
|
409
|
+
client.close();
|
|
410
|
+
}
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
### Context Management
|
|
414
|
+
|
|
415
|
+
```typescript
|
|
416
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
417
|
+
|
|
418
|
+
const client = new A3sClient();
|
|
419
|
+
|
|
420
|
+
async function contextDemo() {
|
|
421
|
+
await client.connect();
|
|
422
|
+
|
|
423
|
+
const { sessionId } = await client.createSession({
|
|
424
|
+
name: 'context-demo',
|
|
425
|
+
workspace: '/path/to/project',
|
|
426
|
+
});
|
|
427
|
+
|
|
428
|
+
// Have a long conversation...
|
|
429
|
+
for (let i = 0; i < 10; i++) {
|
|
430
|
+
await client.generate(sessionId, [
|
|
431
|
+
{ role: 'user', content: `Question ${i + 1}: Tell me about this project` }
|
|
432
|
+
]);
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
// Check context usage
|
|
436
|
+
const usage = await client.getContextUsage(sessionId);
|
|
437
|
+
console.log(`Context tokens: ${usage.totalTokens}/${usage.maxTokens}`);
|
|
438
|
+
console.log(`Messages: ${usage.messageCount}`);
|
|
439
|
+
|
|
440
|
+
if (usage.totalTokens > usage.maxTokens * 0.8) {
|
|
441
|
+
console.log('Context is getting full, compacting...');
|
|
442
|
+
|
|
443
|
+
// Compact context using LLM summarization
|
|
444
|
+
const result = await client.compactContext(sessionId);
|
|
445
|
+
console.log(`Compacted: ${result.originalMessages} → ${result.compactedMessages} messages`);
|
|
446
|
+
console.log(`Saved: ${result.tokensSaved} tokens`);
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
await client.destroySession(sessionId);
|
|
450
|
+
client.close();
|
|
451
|
+
}
|
|
452
|
+
```
|
|
453
|
+
|
|
454
|
+
### Skills Management
|
|
455
|
+
|
|
456
|
+
```typescript
|
|
457
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
458
|
+
import { readFileSync } from 'fs';
|
|
459
|
+
|
|
460
|
+
const client = new A3sClient();
|
|
461
|
+
|
|
462
|
+
async function skillsDemo() {
|
|
463
|
+
await client.connect();
|
|
464
|
+
|
|
465
|
+
const { sessionId } = await client.createSession({
|
|
466
|
+
name: 'skills-demo',
|
|
467
|
+
workspace: '/path/to/project',
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
// Load a custom skill from markdown file
|
|
471
|
+
const skillContent = readFileSync('./my-skill.md', 'utf-8');
|
|
472
|
+
|
|
473
|
+
await client.loadSkill(sessionId, 'my-custom-tool', skillContent);
|
|
474
|
+
|
|
475
|
+
// List all available skills
|
|
476
|
+
const { skills } = await client.listSkills(sessionId);
|
|
477
|
+
console.log('Available skills:', skills.map(s => s.name));
|
|
478
|
+
|
|
479
|
+
// Use the custom skill
|
|
480
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
481
|
+
{ role: 'user', content: 'Use my-custom-tool to process data' }
|
|
482
|
+
])) {
|
|
483
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
484
|
+
}
|
|
485
|
+
|
|
486
|
+
// Unload the skill
|
|
487
|
+
await client.unloadSkill(sessionId, 'my-custom-tool');
|
|
488
|
+
|
|
489
|
+
await client.destroySession(sessionId);
|
|
490
|
+
client.close();
|
|
491
|
+
}
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### Todo/Task Tracking
|
|
495
|
+
|
|
496
|
+
```typescript
|
|
497
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
498
|
+
|
|
499
|
+
const client = new A3sClient();
|
|
500
|
+
|
|
501
|
+
async function todoDemo() {
|
|
502
|
+
await client.connect();
|
|
503
|
+
|
|
504
|
+
const { sessionId } = await client.createSession({
|
|
505
|
+
name: 'todo-demo',
|
|
506
|
+
workspace: '/path/to/project',
|
|
507
|
+
});
|
|
508
|
+
|
|
509
|
+
// Set initial todos
|
|
510
|
+
await client.setTodos(sessionId, [
|
|
511
|
+
{
|
|
512
|
+
id: '1',
|
|
513
|
+
title: 'Analyze codebase structure',
|
|
514
|
+
description: 'Understand the project layout',
|
|
515
|
+
completed: false,
|
|
516
|
+
},
|
|
517
|
+
{
|
|
518
|
+
id: '2',
|
|
519
|
+
title: 'Fix bug in authentication',
|
|
520
|
+
description: 'User login fails with invalid token',
|
|
521
|
+
completed: false,
|
|
522
|
+
}
|
|
523
|
+
]);
|
|
524
|
+
|
|
525
|
+
// Agent works on tasks...
|
|
526
|
+
await client.generate(sessionId, [
|
|
527
|
+
{ role: 'user', content: 'Complete the first todo item' }
|
|
528
|
+
]);
|
|
529
|
+
|
|
530
|
+
// Get updated todos
|
|
531
|
+
const { todos } = await client.getTodos(sessionId);
|
|
532
|
+
console.log('Todos:');
|
|
533
|
+
todos.forEach(todo => {
|
|
534
|
+
const status = todo.completed ? '✓' : '○';
|
|
535
|
+
console.log(` ${status} ${todo.title}`);
|
|
536
|
+
});
|
|
537
|
+
|
|
538
|
+
await client.destroySession(sessionId);
|
|
539
|
+
client.close();
|
|
540
|
+
}
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
### Operation Control
|
|
544
|
+
|
|
545
|
+
```typescript
|
|
546
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
547
|
+
|
|
548
|
+
const client = new A3sClient();
|
|
549
|
+
|
|
550
|
+
async function controlDemo() {
|
|
551
|
+
await client.connect();
|
|
552
|
+
|
|
553
|
+
const { sessionId } = await client.createSession({
|
|
554
|
+
name: 'control-demo',
|
|
555
|
+
workspace: '/path/to/project',
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Start a long-running operation
|
|
559
|
+
const generatePromise = (async () => {
|
|
560
|
+
for await (const chunk of client.streamGenerate(sessionId, [
|
|
561
|
+
{ role: 'user', content: 'Analyze all files in this large project' }
|
|
562
|
+
])) {
|
|
563
|
+
if (chunk.content) process.stdout.write(chunk.content);
|
|
564
|
+
}
|
|
565
|
+
})();
|
|
566
|
+
|
|
567
|
+
// Cancel after 5 seconds
|
|
568
|
+
setTimeout(async () => {
|
|
569
|
+
console.log('\nCancelling operation...');
|
|
570
|
+
await client.cancel(sessionId);
|
|
571
|
+
}, 5000);
|
|
572
|
+
|
|
573
|
+
try {
|
|
574
|
+
await generatePromise;
|
|
575
|
+
} catch (error) {
|
|
576
|
+
console.log('Operation was cancelled');
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
// Pause and resume
|
|
580
|
+
await client.pause(sessionId);
|
|
581
|
+
console.log('Session paused');
|
|
582
|
+
|
|
583
|
+
await client.resume(sessionId);
|
|
584
|
+
console.log('Session resumed');
|
|
585
|
+
|
|
586
|
+
await client.destroySession(sessionId);
|
|
587
|
+
client.close();
|
|
588
|
+
}
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
## Configuration
|
|
592
|
+
|
|
593
|
+
### Using Real LLM APIs
|
|
594
|
+
|
|
595
|
+
The SDK requires a running A3S Code service configured with real LLM API credentials. See [examples/TESTING_WITH_REAL_MODELS.md](./examples/TESTING_WITH_REAL_MODELS.md) for detailed setup instructions.
|
|
596
|
+
|
|
597
|
+
**Quick setup:**
|
|
598
|
+
|
|
599
|
+
1. **Configure A3S Code** - Edit `a3s/.a3s/config.json`:
|
|
600
|
+
|
|
601
|
+
```json
|
|
602
|
+
{
|
|
603
|
+
"defaultProvider": "openai",
|
|
604
|
+
"defaultModel": "kimi-k2.5",
|
|
605
|
+
"providers": [
|
|
606
|
+
{
|
|
607
|
+
"name": "anthropic",
|
|
608
|
+
"apiKey": "sk-ant-xxx",
|
|
609
|
+
"baseUrl": "https://api.anthropic.com",
|
|
610
|
+
"models": [
|
|
611
|
+
{
|
|
612
|
+
"id": "claude-sonnet-4-20250514",
|
|
613
|
+
"name": "Claude Sonnet 4",
|
|
614
|
+
"family": "claude-sonnet",
|
|
615
|
+
"toolCall": true
|
|
616
|
+
}
|
|
617
|
+
]
|
|
618
|
+
},
|
|
619
|
+
{
|
|
620
|
+
"name": "openai",
|
|
621
|
+
"models": [
|
|
622
|
+
{
|
|
623
|
+
"id": "kimi-k2.5",
|
|
624
|
+
"name": "KIMI K2.5",
|
|
625
|
+
"apiKey": "sk-xxx",
|
|
626
|
+
"baseUrl": "http://your-endpoint/v1",
|
|
627
|
+
"toolCall": true
|
|
628
|
+
}
|
|
629
|
+
]
|
|
630
|
+
}
|
|
631
|
+
]
|
|
632
|
+
}
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
2. **Start A3S Code service:**
|
|
636
|
+
|
|
637
|
+
```bash
|
|
638
|
+
cd /path/to/a3s
|
|
639
|
+
./target/debug/a3s-code -d .a3s -w /tmp/a3s-workspace
|
|
640
|
+
```
|
|
641
|
+
|
|
642
|
+
3. **Use SDK with config:**
|
|
643
|
+
|
|
644
|
+
```typescript
|
|
645
|
+
import { A3sClient } from '@a3s-lab/code';
|
|
646
|
+
|
|
647
|
+
// Load configuration from A3S Code config directory
|
|
648
|
+
const client = new A3sClient({
|
|
649
|
+
address: 'localhost:4088',
|
|
650
|
+
configDir: '/path/to/a3s/.a3s'
|
|
651
|
+
});
|
|
652
|
+
|
|
653
|
+
// Create session - will use default model from config
|
|
654
|
+
const session = await client.createSession({
|
|
655
|
+
name: 'my-session',
|
|
656
|
+
workspace: '/tmp/workspace'
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
// Or specify model explicitly
|
|
660
|
+
const session = await client.createSession({
|
|
661
|
+
name: 'my-session',
|
|
662
|
+
workspace: '/tmp/workspace',
|
|
663
|
+
llm: {
|
|
664
|
+
provider: 'openai',
|
|
665
|
+
model: 'kimi-k2.5'
|
|
666
|
+
}
|
|
667
|
+
});
|
|
668
|
+
```
|
|
669
|
+
|
|
670
|
+
### Environment Variables
|
|
671
|
+
|
|
672
|
+
| Variable | Description | Default |
|
|
673
|
+
|----------|-------------|---------|
|
|
674
|
+
| `A3S_ADDRESS` | gRPC server address | `localhost:4088` |
|
|
675
|
+
| `A3S_CONFIG_DIR` | Configuration directory | - |
|
|
676
|
+
|
|
677
|
+
### Programmatic Configuration
|
|
678
|
+
|
|
679
|
+
```typescript
|
|
680
|
+
import { A3sClient, loadConfigFromDir } from '@a3s-lab/code';
|
|
681
|
+
|
|
682
|
+
// Load config from directory
|
|
683
|
+
const config = loadConfigFromDir('/path/to/.a3s');
|
|
684
|
+
|
|
685
|
+
// Create client with loaded config
|
|
686
|
+
const client = new A3sClient({
|
|
687
|
+
address: config.address || 'localhost:4088',
|
|
688
|
+
configDir: '/path/to/.a3s'
|
|
689
|
+
});
|
|
690
|
+
|
|
691
|
+
// Access config values
|
|
692
|
+
console.log('Default provider:', config.defaultProvider);
|
|
693
|
+
console.log('Default model:', config.defaultModel);
|
|
694
|
+
console.log('API key:', config.apiKey ? '(set)' : '(not set)');
|
|
695
|
+
```
|
|
696
|
+
|
|
697
|
+
### Legacy Config File Format
|
|
698
|
+
|
|
699
|
+
```json
|
|
700
|
+
{
|
|
701
|
+
"address": "localhost:4088",
|
|
702
|
+
"defaultProvider": "anthropic",
|
|
703
|
+
"defaultModel": "claude-sonnet-4-20250514",
|
|
704
|
+
"providers": [
|
|
705
|
+
{
|
|
706
|
+
"name": "anthropic",
|
|
707
|
+
"apiKey": "sk-ant-...",
|
|
708
|
+
"models": [
|
|
709
|
+
{ "id": "claude-sonnet-4-20250514", "name": "Claude Sonnet 4" }
|
|
710
|
+
]
|
|
711
|
+
}
|
|
712
|
+
]
|
|
713
|
+
}
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
## API Reference
|
|
717
|
+
|
|
718
|
+
### Client Methods
|
|
719
|
+
|
|
720
|
+
#### Lifecycle (4 methods)
|
|
721
|
+
|
|
722
|
+
| Method | Description |
|
|
723
|
+
|--------|-------------|
|
|
724
|
+
| `healthCheck()` | Check agent health status |
|
|
725
|
+
| `getCapabilities()` | Get agent capabilities |
|
|
726
|
+
| `initialize(workspace, env?)` | Initialize the agent |
|
|
727
|
+
| `shutdown()` | Shutdown the agent |
|
|
728
|
+
|
|
729
|
+
#### Sessions (6 methods)
|
|
730
|
+
|
|
731
|
+
| Method | Description |
|
|
732
|
+
|--------|-------------|
|
|
733
|
+
| `createSession(config)` | Create a new session |
|
|
734
|
+
| `destroySession(id)` | Destroy a session |
|
|
735
|
+
| `listSessions()` | List all sessions |
|
|
736
|
+
| `getSession(id)` | Get session by ID |
|
|
737
|
+
| `configureSession(id, config)` | Update session configuration |
|
|
738
|
+
| `getMessages(id, limit?)` | Get conversation history |
|
|
739
|
+
|
|
740
|
+
#### Generation (4 methods)
|
|
741
|
+
|
|
742
|
+
| Method | Description |
|
|
743
|
+
|--------|-------------|
|
|
744
|
+
| `generate(sessionId, messages)` | Generate response (non-streaming) |
|
|
745
|
+
| `streamGenerate(sessionId, messages)` | Generate response (streaming) |
|
|
746
|
+
| `generateStructured(sessionId, messages, schema)` | Generate structured output |
|
|
747
|
+
| `streamGenerateStructured(sessionId, messages, schema)` | Stream structured output |
|
|
748
|
+
|
|
749
|
+
#### Context Management (3 methods)
|
|
750
|
+
|
|
751
|
+
| Method | Description |
|
|
752
|
+
|--------|-------------|
|
|
753
|
+
| `getContextUsage(sessionId)` | Get context token usage |
|
|
754
|
+
| `compactContext(sessionId)` | Compact session context |
|
|
755
|
+
| `clearContext(sessionId)` | Clear session context |
|
|
756
|
+
|
|
757
|
+
#### Skills (3 methods)
|
|
758
|
+
|
|
759
|
+
| Method | Description |
|
|
760
|
+
|--------|-------------|
|
|
761
|
+
| `loadSkill(sessionId, name)` | Load a skill |
|
|
762
|
+
| `unloadSkill(sessionId, name)` | Unload a skill |
|
|
763
|
+
| `listSkills(sessionId?)` | List available/loaded skills |
|
|
764
|
+
|
|
765
|
+
#### Control (3 methods)
|
|
766
|
+
|
|
767
|
+
| Method | Description |
|
|
768
|
+
|--------|-------------|
|
|
769
|
+
| `cancel(sessionId)` | Cancel running operation |
|
|
770
|
+
| `pause(sessionId)` | Pause session |
|
|
771
|
+
| `resume(sessionId)` | Resume session |
|
|
772
|
+
|
|
773
|
+
#### Events (1 method)
|
|
774
|
+
|
|
775
|
+
| Method | Description |
|
|
776
|
+
|--------|-------------|
|
|
777
|
+
| `subscribeEvents(sessionId)` | Subscribe to real-time events |
|
|
778
|
+
|
|
779
|
+
#### HITL (3 methods)
|
|
780
|
+
|
|
781
|
+
| Method | Description |
|
|
782
|
+
|--------|-------------|
|
|
783
|
+
| `confirmToolExecution(sessionId, response)` | Respond to confirmation request |
|
|
784
|
+
| `setConfirmationPolicy(sessionId, policy)` | Set confirmation policy |
|
|
785
|
+
| `getConfirmationPolicy(sessionId)` | Get confirmation policy |
|
|
786
|
+
|
|
787
|
+
#### Permissions (4 methods)
|
|
788
|
+
|
|
789
|
+
| Method | Description |
|
|
790
|
+
|--------|-------------|
|
|
791
|
+
| `setPermissionPolicy(sessionId, policy)` | Set permission policy |
|
|
792
|
+
| `getPermissionPolicy(sessionId)` | Get permission policy |
|
|
793
|
+
| `checkPermission(sessionId, request)` | Check tool permission |
|
|
794
|
+
| `addPermissionRule(sessionId, rule)` | Add permission rule |
|
|
795
|
+
|
|
796
|
+
#### External Tasks (4 methods)
|
|
797
|
+
|
|
798
|
+
| Method | Description |
|
|
799
|
+
|--------|-------------|
|
|
800
|
+
| `setLaneHandler(sessionId, lane, handler)` | Set lane handler |
|
|
801
|
+
| `getLaneHandler(sessionId, lane)` | Get lane handler |
|
|
802
|
+
| `completeExternalTask(sessionId, taskId, result)` | Complete external task |
|
|
803
|
+
| `listPendingExternalTasks(sessionId)` | List pending tasks |
|
|
804
|
+
|
|
805
|
+
#### Todos (2 methods)
|
|
806
|
+
|
|
807
|
+
| Method | Description |
|
|
808
|
+
|--------|-------------|
|
|
809
|
+
| `getTodos(sessionId)` | Get todo list |
|
|
810
|
+
| `setTodos(sessionId, todos)` | Set todo list |
|
|
811
|
+
|
|
812
|
+
#### Providers (7 methods)
|
|
813
|
+
|
|
814
|
+
| Method | Description |
|
|
815
|
+
|--------|-------------|
|
|
816
|
+
| `listProviders()` | List available providers |
|
|
817
|
+
| `getProvider(name)` | Get provider details |
|
|
818
|
+
| `addProvider(provider)` | Add a provider |
|
|
819
|
+
| `updateProvider(name, provider)` | Update provider |
|
|
820
|
+
| `removeProvider(name)` | Remove provider |
|
|
821
|
+
| `setDefaultModel(provider, model)` | Set default model |
|
|
822
|
+
| `getDefaultModel()` | Get default model |
|
|
823
|
+
|
|
824
|
+
#### Planning & Goals (4 methods)
|
|
825
|
+
|
|
826
|
+
| Method | Description |
|
|
827
|
+
|--------|-------------|
|
|
828
|
+
| `createPlan(sessionId, prompt, context?)` | Create execution plan |
|
|
829
|
+
| `getPlan(sessionId, planId)` | Get existing plan |
|
|
830
|
+
| `extractGoal(sessionId, prompt)` | Extract goal from prompt |
|
|
831
|
+
| `checkGoalAchievement(sessionId, goal, state)` | Check goal completion |
|
|
832
|
+
|
|
833
|
+
#### Memory System (5 methods)
|
|
834
|
+
|
|
835
|
+
| Method | Description |
|
|
836
|
+
|--------|-------------|
|
|
837
|
+
| `storeMemory(sessionId, memory)` | Store memory item |
|
|
838
|
+
| `retrieveMemory(sessionId, memoryId)` | Retrieve memory by ID |
|
|
839
|
+
| `searchMemories(sessionId, query, tags?, limit?)` | Search memories |
|
|
840
|
+
| `getMemoryStats(sessionId)` | Get memory statistics |
|
|
841
|
+
| `clearMemories(sessionId, type?)` | Clear memories |
|
|
842
|
+
|
|
843
|
+
**Total: 53 methods (100% API coverage)**
|
|
844
|
+
|
|
845
|
+
### Types
|
|
846
|
+
|
|
847
|
+
See `ts/types.ts` for complete type definitions including:
|
|
848
|
+
|
|
849
|
+
- `SessionConfig`, `Session`
|
|
850
|
+
- `Message`, `MessageRole`
|
|
851
|
+
- `GenerateResponse`, `GenerateChunk`
|
|
852
|
+
- `HealthStatus`, `HealthStatusCode`
|
|
853
|
+
- `ProviderInfo`, `ModelInfo`
|
|
854
|
+
- `Todo`, `Skill`, `AgentEvent`
|
|
855
|
+
|
|
856
|
+
## Development
|
|
857
|
+
|
|
858
|
+
```bash
|
|
859
|
+
# Install dependencies
|
|
860
|
+
just install
|
|
861
|
+
|
|
862
|
+
# Build
|
|
863
|
+
just build
|
|
864
|
+
|
|
865
|
+
# Run tests
|
|
866
|
+
just test
|
|
867
|
+
|
|
868
|
+
# Run tests with coverage
|
|
869
|
+
just test-cov
|
|
870
|
+
|
|
871
|
+
# Type check
|
|
872
|
+
just check
|
|
873
|
+
|
|
874
|
+
# Lint
|
|
875
|
+
just lint
|
|
876
|
+
|
|
877
|
+
# Format
|
|
878
|
+
just fmt
|
|
879
|
+
|
|
880
|
+
# All checks
|
|
881
|
+
just ci
|
|
882
|
+
```
|
|
883
|
+
|
|
884
|
+
## A3S Ecosystem
|
|
885
|
+
|
|
886
|
+
This SDK is part of the A3S ecosystem:
|
|
887
|
+
|
|
888
|
+
| Project | Package | Purpose |
|
|
889
|
+
|---------|---------|---------|
|
|
890
|
+
| [a3s](https://github.com/a3s-lab/a3s) | `a3s-code` | AI coding agent framework |
|
|
891
|
+
| [sdk/typescript](.) | `@a3s-lab/code` | TypeScript SDK (this package) |
|
|
892
|
+
| [sdk/python](../python) | `a3s-code` | Python SDK |
|
|
893
|
+
|
|
894
|
+
## License
|
|
895
|
+
|
|
896
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
897
|
+
|
|
898
|
+
---
|
|
899
|
+
|
|
900
|
+
<p align="center">
|
|
901
|
+
Built by <a href="https://github.com/a3s-lab">A3S Lab</a>
|
|
902
|
+
</p>
|