@factory/droid-sdk 0.6.0 → 0.8.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 +35 -482
- package/dist/chunk-4G2RKM2H.js +25831 -0
- package/dist/chunk-4G2RKM2H.js.map +1 -0
- package/dist/chunk-ROFAQUG4.mjs +25831 -0
- package/dist/chunk-ROFAQUG4.mjs.map +1 -0
- package/dist/{index-CwXX5IUH.d.cts → index-_nUPGHpH.d.mts} +92630 -79659
- package/dist/{index-CwXX5IUH.d.ts → index-_nUPGHpH.d.ts} +92630 -79659
- package/dist/index.d.mts +4 -0
- package/dist/index.d.ts +4 -93103
- package/dist/index.js +829 -11745
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +830 -0
- package/dist/index.mjs.map +1 -0
- package/dist/node.d.mts +757 -0
- package/dist/node.d.ts +757 -0
- package/dist/node.js +4731 -0
- package/dist/node.js.map +1 -0
- package/dist/node.mjs +4731 -0
- package/dist/node.mjs.map +1 -0
- package/docs/typescript-sdk-reference.md +1437 -0
- package/examples/browser/daemon-lifecycle.ts +95 -0
- package/examples/browser/daemon-model-discovery.ts +47 -0
- package/examples/browser/daemon-multi-session.ts +66 -0
- package/examples/browser/daemon-session.ts +73 -0
- package/examples/browser/index.html +69 -0
- package/examples/browser/list-sessions.ts +50 -0
- package/examples/node/abort-session-stream.ts +34 -0
- package/examples/node/ask-user-elicitation.ts +39 -0
- package/examples/node/compact-session.ts +63 -0
- package/examples/node/custom-system-prompt.ts +35 -0
- package/examples/node/document-input.ts +58 -0
- package/examples/node/enter-spec-mode.ts +87 -0
- package/examples/node/external-mcp.ts +45 -0
- package/examples/node/fork-session.ts +56 -0
- package/examples/node/hook-execution.ts +94 -0
- package/examples/node/image-attachment.ts +41 -0
- package/examples/node/init-metadata.ts +24 -0
- package/examples/node/interrupt-session.ts +55 -0
- package/examples/node/list-sessions.ts +20 -0
- package/examples/node/model-discovery.ts +28 -0
- package/examples/node/model-selection.ts +35 -0
- package/examples/node/multi-turn-session.ts +37 -0
- package/examples/node/observability.ts +75 -0
- package/examples/node/partial-stream.ts +56 -0
- package/examples/node/permission-handler.ts +60 -0
- package/examples/node/rename-session.ts +33 -0
- package/examples/node/result-metadata.ts +43 -0
- package/examples/node/resume-session.ts +41 -0
- package/examples/node/rewind-session.ts +79 -0
- package/examples/node/run.ts +32 -0
- package/examples/node/sdk-mcp-tool.ts +56 -0
- package/examples/node/session-settings.ts +35 -0
- package/examples/node/session-stream.ts +59 -0
- package/examples/node/skills.ts +24 -0
- package/examples/node/spec-mode-new-session.ts +120 -0
- package/examples/node/spec-mode-same-session.ts +119 -0
- package/examples/node/structured-output.ts +96 -0
- package/examples/node/tool-controls.ts +26 -0
- package/examples/package.json +3 -0
- package/package.json +20 -42
- package/dist/index.cjs +0 -12135
- package/dist/index.cjs.map +0 -1
- package/dist/index.d.cts +0 -93103
- package/dist/protocol/index.cjs +0 -6466
- package/dist/protocol/index.cjs.map +0 -1
- package/dist/protocol/index.d.cts +0 -2
- package/dist/protocol/index.d.ts +0 -2
- package/dist/protocol/index.js +0 -6078
- package/dist/protocol/index.js.map +0 -1
- package/docs/daemon-usage-guide.md +0 -544
- package/docs/sdk-usage-guide.md +0 -748
- package/examples/abort-session-stream.ts +0 -34
- package/examples/daemon-multi-session.ts +0 -67
- package/examples/droid-dev-structured-output.ts +0 -44
- package/examples/fork-session.ts +0 -68
- package/examples/hook-execution.ts +0 -68
- package/examples/init-metadata.ts +0 -24
- package/examples/interrupt-session.ts +0 -35
- package/examples/list-sessions.ts +0 -19
- package/examples/multi-turn-session.ts +0 -40
- package/examples/permission-handler.ts +0 -41
- package/examples/readme-structured-output.ts +0 -26
- package/examples/result-metadata.ts +0 -63
- package/examples/run.ts +0 -39
- package/examples/sdk-mcp-tool.ts +0 -44
- package/examples/session-stream.ts +0 -57
- package/examples/spec-mode-new-session.ts +0 -61
- package/examples/spec-mode-same-session.ts +0 -72
- package/examples/structured-output.ts +0 -60
- package/examples/test-compact.ts +0 -65
- package/examples/test-rewind.ts +0 -87
- package/examples/tool-controls.ts +0 -37
|
@@ -1,544 +0,0 @@
|
|
|
1
|
-
# Daemon SDK Usage Guide
|
|
2
|
-
|
|
3
|
-
The daemon SDK connects to a running `droid daemon` process over WebSocket instead of spawning a new subprocess per session. This enables multiple concurrent sessions over a single connection and is the transport used by Slack, Linear, REST API, and Automations integrations.
|
|
4
|
-
|
|
5
|
-
## Getting Started
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npm install @factory/droid-sdk
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
Requires a running `droid daemon` (the SDK will auto-start one locally) and a `FACTORY_API_KEY`. For simpler use cases that don't need concurrent sessions, see the [SDK Usage Guide](./sdk-usage-guide.md) which covers exec mode (`run()`, `createSession()`).
|
|
12
|
-
|
|
13
|
-
```ts
|
|
14
|
-
import { connectDaemon, DroidMessageType } from '@factory/droid-sdk';
|
|
15
|
-
|
|
16
|
-
const connection = await connectDaemon({
|
|
17
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
18
|
-
});
|
|
19
|
-
const session = await connection.createSession({ cwd: process.cwd() });
|
|
20
|
-
|
|
21
|
-
for await (const msg of session.stream('What files are in this directory?')) {
|
|
22
|
-
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
23
|
-
if (msg.type === DroidMessageType.Result)
|
|
24
|
-
console.log(`Done in ${msg.durationMs}ms`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
await session.close();
|
|
28
|
-
await connection.close();
|
|
29
|
-
```
|
|
30
|
-
|
|
31
|
-
---
|
|
32
|
-
|
|
33
|
-
## Daemon vs Exec Mode
|
|
34
|
-
|
|
35
|
-
| | Exec mode (`run`, `createSession`) | Daemon mode (`connectDaemon`) |
|
|
36
|
-
| --------- | -------------------------------------- | --------------------------------------------- |
|
|
37
|
-
| Transport | Spawns `droid exec` subprocess (stdio) | WebSocket to `droid daemon` |
|
|
38
|
-
| Sessions | One per subprocess | Multiple per connection |
|
|
39
|
-
| Auth | Explicit (`apiKey`) | Explicit (`apiKey`) |
|
|
40
|
-
| Use case | Simple scripts, CI | Server-side integrations, long-lived services |
|
|
41
|
-
|
|
42
|
-
Use daemon mode when you need multiple concurrent sessions, want to avoid subprocess overhead, or are building a server-side integration.
|
|
43
|
-
|
|
44
|
-
---
|
|
45
|
-
|
|
46
|
-
## Connect to Local Daemon
|
|
47
|
-
|
|
48
|
-
The simplest form -- the SDK spawns a local daemon and authenticates with the provided API key.
|
|
49
|
-
|
|
50
|
-
```ts
|
|
51
|
-
import { connectDaemon } from '@factory/droid-sdk';
|
|
52
|
-
|
|
53
|
-
const connection = await connectDaemon({
|
|
54
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
55
|
-
});
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
### Connect to Remote Machine
|
|
59
|
-
|
|
60
|
-
```ts
|
|
61
|
-
import { connectDaemon, MachineType } from '@factory/droid-sdk';
|
|
62
|
-
|
|
63
|
-
// Ephemeral sandbox (e2b)
|
|
64
|
-
const connection = await connectDaemon({
|
|
65
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
66
|
-
machine: {
|
|
67
|
-
type: MachineType.Ephemeral,
|
|
68
|
-
sandboxId: 'sandbox-abc123',
|
|
69
|
-
workspaceId: 'ws-xyz',
|
|
70
|
-
},
|
|
71
|
-
});
|
|
72
|
-
|
|
73
|
-
// Computer relay
|
|
74
|
-
const connection2 = await connectDaemon({
|
|
75
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
76
|
-
machine: {
|
|
77
|
-
type: MachineType.Computer,
|
|
78
|
-
computerId: 'comp-abc123',
|
|
79
|
-
},
|
|
80
|
-
});
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
### Direct URL
|
|
84
|
-
|
|
85
|
-
Skip machine-based resolution and connect to a specific WebSocket endpoint.
|
|
86
|
-
|
|
87
|
-
```ts
|
|
88
|
-
const connection = await connectDaemon({
|
|
89
|
-
url: 'ws://127.0.0.1:37643',
|
|
90
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
91
|
-
});
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Connection Retries
|
|
95
|
-
|
|
96
|
-
```ts
|
|
97
|
-
const connection = await connectDaemon({
|
|
98
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
99
|
-
maxRetries: 3, // Retry connect+authenticate cycle up to 3 times
|
|
100
|
-
});
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
---
|
|
104
|
-
|
|
105
|
-
## Create a Session
|
|
106
|
-
|
|
107
|
-
```ts
|
|
108
|
-
import {
|
|
109
|
-
connectDaemon,
|
|
110
|
-
AutonomyLevel,
|
|
111
|
-
ReasoningEffort,
|
|
112
|
-
} from '@factory/droid-sdk';
|
|
113
|
-
|
|
114
|
-
const connection = await connectDaemon({
|
|
115
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
116
|
-
});
|
|
117
|
-
|
|
118
|
-
const session = await connection.createSession({
|
|
119
|
-
cwd: '/path/to/project',
|
|
120
|
-
modelId: 'claude-sonnet-4-20250514',
|
|
121
|
-
autonomyLevel: AutonomyLevel.High,
|
|
122
|
-
reasoningEffort: ReasoningEffort.High,
|
|
123
|
-
});
|
|
124
|
-
```
|
|
125
|
-
|
|
126
|
-
---
|
|
127
|
-
|
|
128
|
-
## Stream a Response
|
|
129
|
-
|
|
130
|
-
`stream()` yields complete messages by default: assistant text, tool calls, tool results, and the final result.
|
|
131
|
-
|
|
132
|
-
```ts
|
|
133
|
-
import { DroidMessageType } from '@factory/droid-sdk';
|
|
134
|
-
|
|
135
|
-
for await (const msg of session.stream('Refactor the utils module.')) {
|
|
136
|
-
switch (msg.type) {
|
|
137
|
-
case DroidMessageType.Assistant:
|
|
138
|
-
console.log(msg.text);
|
|
139
|
-
break;
|
|
140
|
-
case DroidMessageType.ToolCall:
|
|
141
|
-
console.log(`[Tool] ${msg.toolUse.name}`);
|
|
142
|
-
break;
|
|
143
|
-
case DroidMessageType.ToolResult:
|
|
144
|
-
console.log(`[Result] ${msg.isError ? 'Error' : 'OK'}`);
|
|
145
|
-
break;
|
|
146
|
-
case DroidMessageType.Result:
|
|
147
|
-
console.log(`Done in ${msg.durationMs}ms, turns: ${msg.numTurns}`);
|
|
148
|
-
break;
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
```
|
|
152
|
-
|
|
153
|
-
## Partial Message Streaming
|
|
154
|
-
|
|
155
|
-
Enable `includePartialMessages` to get token-by-token deltas as they arrive.
|
|
156
|
-
|
|
157
|
-
```ts
|
|
158
|
-
import { DroidMessageType } from '@factory/droid-sdk';
|
|
159
|
-
|
|
160
|
-
for await (const msg of session.stream('Explain recursion.', {
|
|
161
|
-
includePartialMessages: true,
|
|
162
|
-
})) {
|
|
163
|
-
if (msg.type === DroidMessageType.AssistantTextDelta) {
|
|
164
|
-
process.stdout.write(msg.text);
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
---
|
|
170
|
-
|
|
171
|
-
## Fire-and-Forget with send()
|
|
172
|
-
|
|
173
|
-
`send()` dispatches a prompt and returns after the daemon acknowledges it. The agent runs in the background -- you don't wait for completion. Use this for delegation workflows (e.g., Slack bot triggers a task).
|
|
174
|
-
|
|
175
|
-
```ts
|
|
176
|
-
await session.send('Fix all lint errors in src/.');
|
|
177
|
-
// Returns immediately after daemon ACK.
|
|
178
|
-
// The agent works in the background.
|
|
179
|
-
```
|
|
180
|
-
|
|
181
|
-
---
|
|
182
|
-
|
|
183
|
-
## Multi-turn Session
|
|
184
|
-
|
|
185
|
-
Context is preserved across `stream()` calls on the same session.
|
|
186
|
-
|
|
187
|
-
```ts
|
|
188
|
-
import { DroidMessageType } from '@factory/droid-sdk';
|
|
189
|
-
|
|
190
|
-
const session = await connection.createSession({ cwd: process.cwd() });
|
|
191
|
-
|
|
192
|
-
for await (const msg of session.stream('Remember: the secret is 42.')) {
|
|
193
|
-
// consume first turn
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
for await (const msg of session.stream('What is the secret?')) {
|
|
197
|
-
if (msg.type === DroidMessageType.Assistant) console.log(msg.text); // "42"
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
await session.close();
|
|
201
|
-
```
|
|
202
|
-
|
|
203
|
-
---
|
|
204
|
-
|
|
205
|
-
## Resume a Previous Session
|
|
206
|
-
|
|
207
|
-
Reconnect to a session that was created earlier (on this connection or a previous one).
|
|
208
|
-
|
|
209
|
-
```ts
|
|
210
|
-
import { DroidMessageType } from '@factory/droid-sdk';
|
|
211
|
-
|
|
212
|
-
const session = await connection.resumeSession('existing-session-id');
|
|
213
|
-
|
|
214
|
-
for await (const msg of session.stream('Continue where we left off.')) {
|
|
215
|
-
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
await session.close();
|
|
219
|
-
```
|
|
220
|
-
|
|
221
|
-
---
|
|
222
|
-
|
|
223
|
-
## Concurrent Sessions
|
|
224
|
-
|
|
225
|
-
A single daemon connection supports multiple sessions running simultaneously. The SDK routes notifications to the correct session automatically.
|
|
226
|
-
|
|
227
|
-
```ts
|
|
228
|
-
import {
|
|
229
|
-
connectDaemon,
|
|
230
|
-
DaemonSession,
|
|
231
|
-
DroidMessageType,
|
|
232
|
-
} from '@factory/droid-sdk';
|
|
233
|
-
|
|
234
|
-
const connection = await connectDaemon({
|
|
235
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
236
|
-
});
|
|
237
|
-
|
|
238
|
-
const [session1, session2] = await Promise.all([
|
|
239
|
-
connection.createSession({ cwd: '/project-a' }),
|
|
240
|
-
connection.createSession({ cwd: '/project-b' }),
|
|
241
|
-
]);
|
|
242
|
-
|
|
243
|
-
// Stream on both concurrently
|
|
244
|
-
const [result1, result2] = await Promise.all([
|
|
245
|
-
collectResult(session1, 'Fix tests in project A.'),
|
|
246
|
-
collectResult(session2, 'Add logging to project B.'),
|
|
247
|
-
]);
|
|
248
|
-
|
|
249
|
-
await session1.close();
|
|
250
|
-
await session2.close();
|
|
251
|
-
await connection.close();
|
|
252
|
-
|
|
253
|
-
async function collectResult(
|
|
254
|
-
session: DaemonSession,
|
|
255
|
-
prompt: string
|
|
256
|
-
): Promise<string> {
|
|
257
|
-
let text = '';
|
|
258
|
-
for await (const msg of session.stream(prompt)) {
|
|
259
|
-
if (msg.type === DroidMessageType.Result) text = msg.result;
|
|
260
|
-
}
|
|
261
|
-
return text;
|
|
262
|
-
}
|
|
263
|
-
```
|
|
264
|
-
|
|
265
|
-
---
|
|
266
|
-
|
|
267
|
-
## Interrupt a Session
|
|
268
|
-
|
|
269
|
-
### From the session object
|
|
270
|
-
|
|
271
|
-
```ts
|
|
272
|
-
import { DroidMessageType } from '@factory/droid-sdk';
|
|
273
|
-
|
|
274
|
-
// Interrupt after receiving some output
|
|
275
|
-
for await (const msg of session.stream('Write a long essay.')) {
|
|
276
|
-
if (msg.type === DroidMessageType.Assistant) {
|
|
277
|
-
await session.interrupt();
|
|
278
|
-
break;
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### With AbortSignal
|
|
284
|
-
|
|
285
|
-
```ts
|
|
286
|
-
const controller = new AbortController();
|
|
287
|
-
setTimeout(() => controller.abort(), 5000);
|
|
288
|
-
|
|
289
|
-
try {
|
|
290
|
-
for await (const msg of session.stream('Write a long essay.', {
|
|
291
|
-
abortSignal: controller.signal,
|
|
292
|
-
})) {
|
|
293
|
-
// ...
|
|
294
|
-
}
|
|
295
|
-
} catch {
|
|
296
|
-
console.log('Aborted after 5 seconds');
|
|
297
|
-
}
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### From the connection (without a session object)
|
|
301
|
-
|
|
302
|
-
```ts
|
|
303
|
-
await connection.interruptSession('session-id-to-interrupt');
|
|
304
|
-
```
|
|
305
|
-
|
|
306
|
-
---
|
|
307
|
-
|
|
308
|
-
## Permission Handler
|
|
309
|
-
|
|
310
|
-
Programmatically approve or reject tool calls.
|
|
311
|
-
|
|
312
|
-
```ts
|
|
313
|
-
import {
|
|
314
|
-
ToolConfirmationOutcome,
|
|
315
|
-
ToolConfirmationType,
|
|
316
|
-
} from '@factory/droid-sdk';
|
|
317
|
-
|
|
318
|
-
const session = await connection.createSession({
|
|
319
|
-
cwd: process.cwd(),
|
|
320
|
-
permissionHandler(params) {
|
|
321
|
-
const safe = params.toolUses.every(
|
|
322
|
-
(item) => item.details.type === ToolConfirmationType.Create
|
|
323
|
-
);
|
|
324
|
-
return safe
|
|
325
|
-
? ToolConfirmationOutcome.ProceedOnce
|
|
326
|
-
: ToolConfirmationOutcome.Cancel;
|
|
327
|
-
},
|
|
328
|
-
});
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
---
|
|
332
|
-
|
|
333
|
-
## Ask-User Handler
|
|
334
|
-
|
|
335
|
-
Programmatically answer questions that Droid asks during execution.
|
|
336
|
-
|
|
337
|
-
```ts
|
|
338
|
-
const session = await connection.createSession({
|
|
339
|
-
cwd: process.cwd(),
|
|
340
|
-
askUserHandler(params) {
|
|
341
|
-
return {
|
|
342
|
-
cancelled: false,
|
|
343
|
-
answers: params.questions.map((q) => ({
|
|
344
|
-
index: q.index,
|
|
345
|
-
question: q.question,
|
|
346
|
-
answer: q.options[0] ?? 'yes',
|
|
347
|
-
})),
|
|
348
|
-
};
|
|
349
|
-
},
|
|
350
|
-
});
|
|
351
|
-
```
|
|
352
|
-
|
|
353
|
-
---
|
|
354
|
-
|
|
355
|
-
## SDK-backed MCP Tools
|
|
356
|
-
|
|
357
|
-
Define custom tools that Droid can call during a session.
|
|
358
|
-
|
|
359
|
-
```ts
|
|
360
|
-
import {
|
|
361
|
-
connectDaemon,
|
|
362
|
-
createSdkMcpServer,
|
|
363
|
-
DroidMessageType,
|
|
364
|
-
tool,
|
|
365
|
-
ToolConfirmationOutcome,
|
|
366
|
-
} from '@factory/droid-sdk';
|
|
367
|
-
import { z } from 'zod';
|
|
368
|
-
|
|
369
|
-
const server = createSdkMcpServer({
|
|
370
|
-
name: 'my-tools',
|
|
371
|
-
tools: [
|
|
372
|
-
tool(
|
|
373
|
-
'lookup',
|
|
374
|
-
'Look up a user by name',
|
|
375
|
-
{ name: z.string() },
|
|
376
|
-
({ name }) => `${name} is user #42.`
|
|
377
|
-
),
|
|
378
|
-
],
|
|
379
|
-
});
|
|
380
|
-
|
|
381
|
-
const connection = await connectDaemon({
|
|
382
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
383
|
-
});
|
|
384
|
-
const session = await connection.createSession({
|
|
385
|
-
cwd: process.cwd(),
|
|
386
|
-
mcpServers: [server],
|
|
387
|
-
permissionHandler: () => ToolConfirmationOutcome.ProceedOnce,
|
|
388
|
-
});
|
|
389
|
-
|
|
390
|
-
for await (const msg of session.stream('Look up Alice.')) {
|
|
391
|
-
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
392
|
-
}
|
|
393
|
-
|
|
394
|
-
await session.close();
|
|
395
|
-
await connection.close();
|
|
396
|
-
```
|
|
397
|
-
|
|
398
|
-
---
|
|
399
|
-
|
|
400
|
-
## Raw Notification Subscription
|
|
401
|
-
|
|
402
|
-
Subscribe to raw protocol notifications for custom event handling.
|
|
403
|
-
|
|
404
|
-
```ts
|
|
405
|
-
import { SessionNotificationType } from '@factory/droid-sdk';
|
|
406
|
-
|
|
407
|
-
const unsubscribe = session.onNotification(
|
|
408
|
-
(notification) => {
|
|
409
|
-
console.log('Notification:', notification);
|
|
410
|
-
},
|
|
411
|
-
{ type: SessionNotificationType.DROID_WORKING_STATE_CHANGED }
|
|
412
|
-
);
|
|
413
|
-
|
|
414
|
-
// ... use the session ...
|
|
415
|
-
|
|
416
|
-
unsubscribe();
|
|
417
|
-
```
|
|
418
|
-
|
|
419
|
-
---
|
|
420
|
-
|
|
421
|
-
## Error Handling
|
|
422
|
-
|
|
423
|
-
The daemon SDK throws the same typed errors as exec mode.
|
|
424
|
-
|
|
425
|
-
```ts
|
|
426
|
-
import {
|
|
427
|
-
connectDaemon,
|
|
428
|
-
ConnectionError,
|
|
429
|
-
TimeoutError,
|
|
430
|
-
SessionNotFoundError,
|
|
431
|
-
ProtocolError,
|
|
432
|
-
} from '@factory/droid-sdk';
|
|
433
|
-
|
|
434
|
-
try {
|
|
435
|
-
const connection = await connectDaemon({
|
|
436
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
437
|
-
});
|
|
438
|
-
const session = await connection.resumeSession('nonexistent-id');
|
|
439
|
-
} catch (error) {
|
|
440
|
-
if (error instanceof SessionNotFoundError) {
|
|
441
|
-
console.log(`Session not found: ${error.sessionId}`);
|
|
442
|
-
} else if (error instanceof TimeoutError) {
|
|
443
|
-
console.log('Request timed out');
|
|
444
|
-
} else if (error instanceof ConnectionError) {
|
|
445
|
-
console.log(`Connection failed: ${error.message}`);
|
|
446
|
-
} else if (error instanceof ProtocolError) {
|
|
447
|
-
console.log(`Protocol error ${error.code}: ${error.message}`);
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
```
|
|
451
|
-
|
|
452
|
-
---
|
|
453
|
-
|
|
454
|
-
## Lifecycle Pattern
|
|
455
|
-
|
|
456
|
-
Always close sessions and connections when done.
|
|
457
|
-
|
|
458
|
-
```ts
|
|
459
|
-
import { connectDaemon } from '@factory/droid-sdk';
|
|
460
|
-
|
|
461
|
-
const connection = await connectDaemon({
|
|
462
|
-
apiKey: process.env.FACTORY_API_KEY!,
|
|
463
|
-
});
|
|
464
|
-
|
|
465
|
-
try {
|
|
466
|
-
const session = await connection.createSession({ cwd: process.cwd() });
|
|
467
|
-
try {
|
|
468
|
-
for await (const msg of session.stream('Do the thing.')) {
|
|
469
|
-
// ...
|
|
470
|
-
}
|
|
471
|
-
} finally {
|
|
472
|
-
await session.close();
|
|
473
|
-
}
|
|
474
|
-
} finally {
|
|
475
|
-
await connection.close();
|
|
476
|
-
}
|
|
477
|
-
```
|
|
478
|
-
|
|
479
|
-
---
|
|
480
|
-
|
|
481
|
-
## Configuration Reference
|
|
482
|
-
|
|
483
|
-
### `ConnectDaemonOptions`
|
|
484
|
-
|
|
485
|
-
| Field | Type | Required | Description |
|
|
486
|
-
| :------------- | :----------------- | :------- | :--------------------------------------------------------------------- |
|
|
487
|
-
| `apiKey` | `string` | **Yes** | Factory API key for authentication. |
|
|
488
|
-
| `machine` | `SDKMachineConfig` | No | Machine target. Defaults to local daemon. |
|
|
489
|
-
| `url` | `string` | No | Direct WebSocket URL. Overrides machine resolution. |
|
|
490
|
-
| `maxRetries` | `number` | No | Retry budget for connect+authenticate cycle. |
|
|
491
|
-
| `daemonPort` | `number` | No | WebSocket port override. Default: `37643`. |
|
|
492
|
-
| `relayBaseUrl` | `string` | No | Relay URL for computer connections. Default: `wss://relay.factory.ai`. |
|
|
493
|
-
|
|
494
|
-
### `SDKMachineConfig`
|
|
495
|
-
|
|
496
|
-
| Variant | Fields | Description |
|
|
497
|
-
| :---------- | :--------------------------------- | :---------------------------- |
|
|
498
|
-
| `Local` | `{ type: MachineType.Local }` | Local daemon on this machine. |
|
|
499
|
-
| `Ephemeral` | `{ type, sandboxId, workspaceId }` | e2b sandbox. |
|
|
500
|
-
| `Computer` | `{ type, computerId }` | Remote computer via relay. |
|
|
501
|
-
|
|
502
|
-
### `DaemonSessionOptions`
|
|
503
|
-
|
|
504
|
-
| Field | Type | Description |
|
|
505
|
-
| :------------------------ | :----------------------- | :--------------------------------------------- |
|
|
506
|
-
| `cwd` | `string` | Working directory for the session. |
|
|
507
|
-
| `modelId` | `string` | LLM model identifier. |
|
|
508
|
-
| `autonomyLevel` | `AutonomyLevel` | `Off` \| `Low` \| `Medium` \| `High`. |
|
|
509
|
-
| `interactionMode` | `DroidInteractionMode` | `Auto` \| `Spec` \| `AGI`. |
|
|
510
|
-
| `reasoningEffort` | `ReasoningEffort` | `Off` \| `Low` \| `Medium` \| `High` \| `Max`. |
|
|
511
|
-
| `specModeModelId` | `string` | Override model for spec mode. |
|
|
512
|
-
| `specModeReasoningEffort` | `ReasoningEffort` | Override reasoning effort for spec mode. |
|
|
513
|
-
| `mcpServers` | `DroidMcpServerConfig[]` | MCP server configurations. |
|
|
514
|
-
| `enabledToolIds` | `string[]` | Tool allowlist. |
|
|
515
|
-
| `disabledToolIds` | `string[]` | Tool denylist. |
|
|
516
|
-
| `tags` | `SessionTag[]` | Session tags for categorization. |
|
|
517
|
-
| `permissionHandler` | `PermissionHandler` | Tool confirmation callback. |
|
|
518
|
-
| `askUserHandler` | `AskUserHandler` | Structured user-input callback. |
|
|
519
|
-
| `sessionSource` | `SessionSource` | Attribution metadata. |
|
|
520
|
-
|
|
521
|
-
### `DaemonResumeOptions`
|
|
522
|
-
|
|
523
|
-
| Field | Type | Description |
|
|
524
|
-
| :------------------ | :----------------------- | :------------------------------ |
|
|
525
|
-
| `permissionHandler` | `PermissionHandler` | Tool confirmation callback. |
|
|
526
|
-
| `askUserHandler` | `AskUserHandler` | Structured user-input callback. |
|
|
527
|
-
| `mcpServers` | `DroidMcpServerConfig[]` | MCP servers to attach. |
|
|
528
|
-
|
|
529
|
-
### `SendOptions`
|
|
530
|
-
|
|
531
|
-
| Field | Type | Description |
|
|
532
|
-
| :------------- | :-------------------- | :------------------------------------- |
|
|
533
|
-
| `images` | `Base64ImageSource[]` | Base64-encoded image attachments. |
|
|
534
|
-
| `files` | `DocumentSource[]` | Document/file attachments. |
|
|
535
|
-
| `outputFormat` | `OutputFormat` | Structured output JSON schema request. |
|
|
536
|
-
|
|
537
|
-
### Key Classes
|
|
538
|
-
|
|
539
|
-
| Class | Description |
|
|
540
|
-
| :------------------- | :------------------------------------------------------------------------- |
|
|
541
|
-
| `DaemonConnection` | Manages the WebSocket connection. Creates/resumes sessions. |
|
|
542
|
-
| `DaemonSession` | A single session. Provides `stream()`, `send()`, `interrupt()`, `close()`. |
|
|
543
|
-
| `DaemonClient` | Low-level RPC client. Used internally by `DaemonSession`. |
|
|
544
|
-
| `WebSocketTransport` | WebSocket transport with retry and reconnection. |
|