@factory/droid-sdk 0.3.0 → 0.4.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/dist/index.cjs +1601 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +908 -13
- package/dist/index.d.ts +908 -13
- package/dist/index.js +1566 -70
- package/dist/index.js.map +1 -1
- package/docs/daemon-usage-guide.md +544 -0
- package/docs/sdk-usage-guide.md +103 -33
- package/examples/abort-session-stream.ts +4 -1
- package/examples/daemon-multi-session.ts +67 -0
- package/examples/droid-dev-structured-output.ts +1 -0
- package/examples/fork-session.ts +10 -3
- package/examples/hook-execution.ts +7 -1
- package/examples/init-metadata.ts +7 -2
- package/examples/interrupt-session.ts +7 -4
- package/examples/multi-turn-session.ts +7 -2
- package/examples/permission-handler.ts +1 -0
- package/examples/readme-structured-output.ts +1 -0
- package/examples/result-metadata.ts +1 -0
- package/examples/run.ts +1 -0
- package/examples/sdk-mcp-tool.ts +3 -1
- package/examples/session-stream.ts +4 -1
- package/examples/spec-mode-new-session.ts +1 -0
- package/examples/spec-mode-same-session.ts +1 -0
- package/examples/structured-output.ts +1 -0
- package/examples/test-compact.ts +4 -1
- package/examples/tool-controls.ts +1 -0
- package/package.json +3 -1
package/docs/sdk-usage-guide.md
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
npm install @factory/droid-sdk
|
|
7
7
|
```
|
|
8
8
|
|
|
9
|
-
Requires Node.js 18+ and the `droid` CLI on your PATH.
|
|
9
|
+
Requires Node.js 18+ and the `droid` CLI on your PATH. This guide covers **exec mode** (`run()`, `createSession()`), which spawns a subprocess per session. For WebSocket-based daemon mode with concurrent sessions, see the [Daemon Usage Guide](./daemon-usage-guide.md).
|
|
10
10
|
|
|
11
11
|
```ts
|
|
12
12
|
import { run } from '@factory/droid-sdk';
|
|
13
13
|
|
|
14
14
|
const result = await run('What files are in this directory?', {
|
|
15
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
15
16
|
cwd: process.cwd(),
|
|
16
17
|
});
|
|
17
18
|
console.log(result.text);
|
|
@@ -26,7 +27,10 @@ Send a prompt, get a result, done. The session is created and closed automatical
|
|
|
26
27
|
```ts
|
|
27
28
|
import { run } from '@factory/droid-sdk';
|
|
28
29
|
|
|
29
|
-
const result = await run('What is 2 + 2?', {
|
|
30
|
+
const result = await run('What is 2 + 2?', {
|
|
31
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
32
|
+
cwd: process.cwd(),
|
|
33
|
+
});
|
|
30
34
|
console.log(result.text);
|
|
31
35
|
```
|
|
32
36
|
|
|
@@ -38,6 +42,7 @@ Force the response to match a JSON schema. The validated object is available on
|
|
|
38
42
|
import { OutputFormatType, run } from '@factory/droid-sdk';
|
|
39
43
|
|
|
40
44
|
const result = await run('Pick a number between 1 and 42.', {
|
|
45
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
41
46
|
cwd: process.cwd(),
|
|
42
47
|
outputFormat: {
|
|
43
48
|
type: OutputFormatType.JsonSchema,
|
|
@@ -57,16 +62,19 @@ console.log((result.structuredOutput as { number: number }).number);
|
|
|
57
62
|
Create a session once, then call `stream()` multiple times. Context is preserved across turns.
|
|
58
63
|
|
|
59
64
|
```ts
|
|
60
|
-
import { createSession } from '@factory/droid-sdk';
|
|
65
|
+
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
61
66
|
|
|
62
|
-
const session = await createSession({
|
|
67
|
+
const session = await createSession({
|
|
68
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
69
|
+
cwd: process.cwd(),
|
|
70
|
+
});
|
|
63
71
|
|
|
64
72
|
for await (const msg of session.stream('Remember the word "mango".')) {
|
|
65
73
|
// consume first turn
|
|
66
74
|
}
|
|
67
75
|
|
|
68
76
|
for await (const msg of session.stream('What word did I say?')) {
|
|
69
|
-
if (msg.type ===
|
|
77
|
+
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
70
78
|
}
|
|
71
79
|
|
|
72
80
|
await session.close();
|
|
@@ -77,12 +85,14 @@ await session.close();
|
|
|
77
85
|
Reconnect to a previously created session by its ID.
|
|
78
86
|
|
|
79
87
|
```ts
|
|
80
|
-
import { resumeSession } from '@factory/droid-sdk';
|
|
88
|
+
import { resumeSession, DroidMessageType } from '@factory/droid-sdk';
|
|
81
89
|
|
|
82
|
-
const session = await resumeSession('existing-session-id'
|
|
90
|
+
const session = await resumeSession('existing-session-id', {
|
|
91
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
92
|
+
});
|
|
83
93
|
|
|
84
94
|
for await (const msg of session.stream('Continue where we left off.')) {
|
|
85
|
-
if (msg.type ===
|
|
95
|
+
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
86
96
|
}
|
|
87
97
|
|
|
88
98
|
await session.close();
|
|
@@ -95,7 +105,10 @@ await session.close();
|
|
|
95
105
|
```ts
|
|
96
106
|
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
97
107
|
|
|
98
|
-
const session = await createSession({
|
|
108
|
+
const session = await createSession({
|
|
109
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
110
|
+
cwd: process.cwd(),
|
|
111
|
+
});
|
|
99
112
|
|
|
100
113
|
for await (const msg of session.stream(
|
|
101
114
|
'List files in the current directory.'
|
|
@@ -126,7 +139,10 @@ Enable `includePartialMessages` to get token-by-token deltas, thinking blocks, a
|
|
|
126
139
|
```ts
|
|
127
140
|
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
128
141
|
|
|
129
|
-
const session = await createSession({
|
|
142
|
+
const session = await createSession({
|
|
143
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
144
|
+
cwd: process.cwd(),
|
|
145
|
+
});
|
|
130
146
|
|
|
131
147
|
for await (const msg of session.stream('Explain recursion.', {
|
|
132
148
|
includePartialMessages: true,
|
|
@@ -144,19 +160,25 @@ await session.close();
|
|
|
144
160
|
Use `session.interrupt()` to stop the current turn server-side, or pass an `AbortSignal` to cancel from the client.
|
|
145
161
|
|
|
146
162
|
```ts
|
|
147
|
-
import { createSession } from '@factory/droid-sdk';
|
|
163
|
+
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
148
164
|
|
|
149
165
|
// Interrupt after receiving some output
|
|
150
|
-
const session = await createSession({
|
|
166
|
+
const session = await createSession({
|
|
167
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
168
|
+
cwd: process.cwd(),
|
|
169
|
+
});
|
|
151
170
|
for await (const msg of session.stream('Write a long essay.')) {
|
|
152
|
-
if (msg.type ===
|
|
171
|
+
if (msg.type === DroidMessageType.Assistant) {
|
|
153
172
|
await session.interrupt();
|
|
154
173
|
}
|
|
155
174
|
}
|
|
156
175
|
await session.close();
|
|
157
176
|
|
|
158
177
|
// Or cancel with AbortSignal
|
|
159
|
-
const session2 = await createSession({
|
|
178
|
+
const session2 = await createSession({
|
|
179
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
180
|
+
cwd: process.cwd(),
|
|
181
|
+
});
|
|
160
182
|
const controller = new AbortController();
|
|
161
183
|
setTimeout(() => controller.abort(), 2000);
|
|
162
184
|
|
|
@@ -179,6 +201,7 @@ Define custom tools that Droid can call during a session. Tools are served via a
|
|
|
179
201
|
import {
|
|
180
202
|
createSession,
|
|
181
203
|
createSdkMcpServer,
|
|
204
|
+
DroidMessageType,
|
|
182
205
|
tool,
|
|
183
206
|
ToolConfirmationOutcome,
|
|
184
207
|
} from '@factory/droid-sdk';
|
|
@@ -199,13 +222,14 @@ const server = createSdkMcpServer({
|
|
|
199
222
|
});
|
|
200
223
|
|
|
201
224
|
const session = await createSession({
|
|
225
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
202
226
|
cwd: process.cwd(),
|
|
203
227
|
mcpServers: [server],
|
|
204
228
|
permissionHandler: () => ToolConfirmationOutcome.ProceedOnce,
|
|
205
229
|
});
|
|
206
230
|
|
|
207
231
|
for await (const msg of session.stream('Look up Alice.')) {
|
|
208
|
-
if (msg.type ===
|
|
232
|
+
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
209
233
|
}
|
|
210
234
|
|
|
211
235
|
await session.close();
|
|
@@ -219,6 +243,7 @@ Control what Droid can do without asking for permission. Set at session creation
|
|
|
219
243
|
import { createSession, AutonomyLevel } from '@factory/droid-sdk';
|
|
220
244
|
|
|
221
245
|
const session = await createSession({
|
|
246
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
222
247
|
cwd: process.cwd(),
|
|
223
248
|
autonomyLevel: AutonomyLevel.High, // Off | Low | Medium | High
|
|
224
249
|
});
|
|
@@ -236,6 +261,7 @@ Restrict which tools Droid can use. Accepts tool IDs like `'Read'`, `'Execute'`,
|
|
|
236
261
|
import { createSession } from '@factory/droid-sdk';
|
|
237
262
|
|
|
238
263
|
const session = await createSession({
|
|
264
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
239
265
|
cwd: process.cwd(),
|
|
240
266
|
enabledToolIds: ['Read', 'Grep'],
|
|
241
267
|
disabledToolIds: ['Execute'],
|
|
@@ -258,6 +284,7 @@ import {
|
|
|
258
284
|
} from '@factory/droid-sdk';
|
|
259
285
|
|
|
260
286
|
await run('Create hello.txt with "Hello, World!"', {
|
|
287
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
261
288
|
cwd: process.cwd(),
|
|
262
289
|
permissionHandler(params) {
|
|
263
290
|
const safe = params.toolUses.every(
|
|
@@ -283,6 +310,7 @@ import {
|
|
|
283
310
|
} from '@factory/droid-sdk';
|
|
284
311
|
|
|
285
312
|
const session = await createSession({
|
|
313
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
286
314
|
cwd: process.cwd(),
|
|
287
315
|
interactionMode: DroidInteractionMode.Spec,
|
|
288
316
|
permissionHandler(params) {
|
|
@@ -306,9 +334,12 @@ Send images or documents alongside your prompt. Images must be base64-encoded.
|
|
|
306
334
|
|
|
307
335
|
```ts
|
|
308
336
|
import { readFileSync } from 'node:fs';
|
|
309
|
-
import { createSession } from '@factory/droid-sdk';
|
|
337
|
+
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
310
338
|
|
|
311
|
-
const session = await createSession({
|
|
339
|
+
const session = await createSession({
|
|
340
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
341
|
+
cwd: process.cwd(),
|
|
342
|
+
});
|
|
312
343
|
|
|
313
344
|
for await (const msg of session.stream('Describe this image.', {
|
|
314
345
|
images: [
|
|
@@ -319,7 +350,7 @@ for await (const msg of session.stream('Describe this image.', {
|
|
|
319
350
|
},
|
|
320
351
|
],
|
|
321
352
|
})) {
|
|
322
|
-
if (msg.type ===
|
|
353
|
+
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
323
354
|
}
|
|
324
355
|
|
|
325
356
|
await session.close();
|
|
@@ -330,17 +361,26 @@ await session.close();
|
|
|
330
361
|
Create a copy of the current session with all context preserved. Useful for branching a conversation.
|
|
331
362
|
|
|
332
363
|
```ts
|
|
333
|
-
import {
|
|
364
|
+
import {
|
|
365
|
+
createSession,
|
|
366
|
+
DroidMessageType,
|
|
367
|
+
resumeSession,
|
|
368
|
+
} from '@factory/droid-sdk';
|
|
334
369
|
|
|
335
|
-
const session = await createSession({
|
|
370
|
+
const session = await createSession({
|
|
371
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
372
|
+
cwd: process.cwd(),
|
|
373
|
+
});
|
|
336
374
|
for await (const msg of session.stream('Remember: the password is "banana".')) {
|
|
337
375
|
}
|
|
338
376
|
|
|
339
377
|
const { newSessionId } = await session.forkSession();
|
|
340
|
-
const fork = await resumeSession(newSessionId
|
|
378
|
+
const fork = await resumeSession(newSessionId, {
|
|
379
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
380
|
+
});
|
|
341
381
|
|
|
342
382
|
for await (const msg of fork.stream('What is the password?')) {
|
|
343
|
-
if (msg.type ===
|
|
383
|
+
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
344
384
|
}
|
|
345
385
|
|
|
346
386
|
await fork.close();
|
|
@@ -354,7 +394,10 @@ Summarize and remove old messages to free up context window space.
|
|
|
354
394
|
```ts
|
|
355
395
|
import { createSession } from '@factory/droid-sdk';
|
|
356
396
|
|
|
357
|
-
const session = await createSession({
|
|
397
|
+
const session = await createSession({
|
|
398
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
399
|
+
cwd: process.cwd(),
|
|
400
|
+
});
|
|
358
401
|
|
|
359
402
|
// ... after many turns ...
|
|
360
403
|
const result = await session.compactSession();
|
|
@@ -376,7 +419,10 @@ import {
|
|
|
376
419
|
AutonomyLevel,
|
|
377
420
|
} from '@factory/droid-sdk';
|
|
378
421
|
|
|
379
|
-
const transport = new ProcessTransport({
|
|
422
|
+
const transport = new ProcessTransport({
|
|
423
|
+
cwd: process.cwd(),
|
|
424
|
+
env: { FACTORY_API_KEY: process.env.FACTORY_API_KEY! },
|
|
425
|
+
});
|
|
380
426
|
await transport.connect();
|
|
381
427
|
const client = new DroidClient({ transport });
|
|
382
428
|
|
|
@@ -423,6 +469,7 @@ Choose which model to use and how much reasoning effort to apply. Configurable a
|
|
|
423
469
|
import { createSession, ReasoningEffort } from '@factory/droid-sdk';
|
|
424
470
|
|
|
425
471
|
const session = await createSession({
|
|
472
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
426
473
|
cwd: process.cwd(),
|
|
427
474
|
modelId: 'claude-sonnet-4-20250514',
|
|
428
475
|
reasoningEffort: ReasoningEffort.High,
|
|
@@ -443,7 +490,10 @@ Observe file hooks (pre/post tool execution hooks) as they run during a session.
|
|
|
443
490
|
```ts
|
|
444
491
|
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
445
492
|
|
|
446
|
-
const session = await createSession({
|
|
493
|
+
const session = await createSession({
|
|
494
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
495
|
+
cwd: process.cwd(),
|
|
496
|
+
});
|
|
447
497
|
|
|
448
498
|
for await (const msg of session.stream('Create a new file.')) {
|
|
449
499
|
if (msg.type === DroidMessageType.Hook) {
|
|
@@ -463,9 +513,10 @@ await session.close();
|
|
|
463
513
|
Programmatically answer questions that Droid asks the user during execution.
|
|
464
514
|
|
|
465
515
|
```ts
|
|
466
|
-
import { createSession } from '@factory/droid-sdk';
|
|
516
|
+
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
467
517
|
|
|
468
518
|
const session = await createSession({
|
|
519
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
469
520
|
cwd: process.cwd(),
|
|
470
521
|
askUserHandler(params) {
|
|
471
522
|
return {
|
|
@@ -480,7 +531,7 @@ const session = await createSession({
|
|
|
480
531
|
});
|
|
481
532
|
|
|
482
533
|
for await (const msg of session.stream('Help me set up this project.')) {
|
|
483
|
-
if (msg.type ===
|
|
534
|
+
if (msg.type === DroidMessageType.Assistant) console.log(msg.text);
|
|
484
535
|
}
|
|
485
536
|
|
|
486
537
|
await session.close();
|
|
@@ -493,7 +544,10 @@ Add, remove, toggle, and list MCP servers at runtime within an active session.
|
|
|
493
544
|
```ts
|
|
494
545
|
import { createSession, McpServerType } from '@factory/droid-sdk';
|
|
495
546
|
|
|
496
|
-
const session = await createSession({
|
|
547
|
+
const session = await createSession({
|
|
548
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
549
|
+
cwd: process.cwd(),
|
|
550
|
+
});
|
|
497
551
|
|
|
498
552
|
await session.addMcpServer({
|
|
499
553
|
name: 'my-server',
|
|
@@ -514,7 +568,10 @@ Query current context window usage to understand how much capacity remains.
|
|
|
514
568
|
```ts
|
|
515
569
|
import { createSession } from '@factory/droid-sdk';
|
|
516
570
|
|
|
517
|
-
const session = await createSession({
|
|
571
|
+
const session = await createSession({
|
|
572
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
573
|
+
cwd: process.cwd(),
|
|
574
|
+
});
|
|
518
575
|
for await (const msg of session.stream('Hello')) {
|
|
519
576
|
}
|
|
520
577
|
|
|
@@ -533,7 +590,10 @@ Monitor token consumption in real-time via stream events, or read the final tota
|
|
|
533
590
|
```ts
|
|
534
591
|
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
535
592
|
|
|
536
|
-
const session = await createSession({
|
|
593
|
+
const session = await createSession({
|
|
594
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
595
|
+
cwd: process.cwd(),
|
|
596
|
+
});
|
|
537
597
|
|
|
538
598
|
for await (const msg of session.stream('Summarize this project.', {
|
|
539
599
|
includePartialMessages: true,
|
|
@@ -558,7 +618,10 @@ List all available skills in the current session.
|
|
|
558
618
|
```ts
|
|
559
619
|
import { createSession } from '@factory/droid-sdk';
|
|
560
620
|
|
|
561
|
-
const session = await createSession({
|
|
621
|
+
const session = await createSession({
|
|
622
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
623
|
+
cwd: process.cwd(),
|
|
624
|
+
});
|
|
562
625
|
const { skills } = await session.listSkills();
|
|
563
626
|
|
|
564
627
|
for (const skill of skills) {
|
|
@@ -575,7 +638,10 @@ Subscribe to raw protocol notifications for custom event handling beyond the str
|
|
|
575
638
|
```ts
|
|
576
639
|
import { createSession, SessionNotificationType } from '@factory/droid-sdk';
|
|
577
640
|
|
|
578
|
-
const session = await createSession({
|
|
641
|
+
const session = await createSession({
|
|
642
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
643
|
+
cwd: process.cwd(),
|
|
644
|
+
});
|
|
579
645
|
|
|
580
646
|
const unsubscribe = session.onNotification(
|
|
581
647
|
(notification) => {
|
|
@@ -604,7 +670,9 @@ import {
|
|
|
604
670
|
} from '@factory/droid-sdk';
|
|
605
671
|
|
|
606
672
|
try {
|
|
607
|
-
const session = await resumeSession('nonexistent-id'
|
|
673
|
+
const session = await resumeSession('nonexistent-id', {
|
|
674
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
675
|
+
});
|
|
608
676
|
} catch (error) {
|
|
609
677
|
if (error instanceof SessionNotFoundError) {
|
|
610
678
|
console.log(`Session not found: ${error.sessionId}`);
|
|
@@ -634,6 +702,7 @@ The package also exports its full Zod schema surface from `src/schemas/index.ts`
|
|
|
634
702
|
|
|
635
703
|
| Field | Type | Description |
|
|
636
704
|
| :------------------------ | :----------------------- | :---------------------------------------------------------- |
|
|
705
|
+
| `apiKey` | `string` | **Required.** Factory API key for authentication |
|
|
637
706
|
| `cwd` | `string` | Working directory for the session |
|
|
638
707
|
| `machineId` | `string` | Machine identifier for initialization |
|
|
639
708
|
| `modelId` | `string` | LLM model identifier |
|
|
@@ -646,6 +715,7 @@ The package also exports its full Zod schema surface from `src/schemas/index.ts`
|
|
|
646
715
|
| `enabledToolIds` | `string[]` | Tool allowlist |
|
|
647
716
|
| `disabledToolIds` | `string[]` | Tool denylist |
|
|
648
717
|
| `tags` | `SessionTag[]` | Session tags for categorization |
|
|
718
|
+
| `sessionSource` | `SessionSource` | Attribution metadata (e.g., integration origin) |
|
|
649
719
|
| `permissionHandler` | `PermissionHandler` | Tool confirmation callback |
|
|
650
720
|
| `askUserHandler` | `AskUserHandler` | Structured user-input callback |
|
|
651
721
|
| `execPath` | `string` | Path to `droid` executable (default: `"droid"`) |
|
|
@@ -7,7 +7,10 @@
|
|
|
7
7
|
|
|
8
8
|
import { createSession } from '@factory/droid-sdk';
|
|
9
9
|
|
|
10
|
-
const session = await createSession({
|
|
10
|
+
const session = await createSession({
|
|
11
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
12
|
+
cwd: process.cwd(),
|
|
13
|
+
});
|
|
11
14
|
const controller = new AbortController();
|
|
12
15
|
const timeout = setTimeout(
|
|
13
16
|
() => controller.abort(new Error('Stopped by AbortController')),
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual smoke test for the daemon SDK — multiple concurrent sessions.
|
|
3
|
+
*
|
|
4
|
+
* Spawns a local daemon, creates two sessions in separate /tmp directories,
|
|
5
|
+
* and runs them concurrently over a single WebSocket connection.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* npx tsx examples/daemon-multi-session.ts
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { connectDaemon, DroidMessageType } from '@factory/droid-sdk';
|
|
12
|
+
|
|
13
|
+
async function main(): Promise<void> {
|
|
14
|
+
console.log('Connecting to local daemon...\n');
|
|
15
|
+
const daemon = await connectDaemon({ apiKey: process.env.FACTORY_API_KEY! });
|
|
16
|
+
console.log('Connected!\n');
|
|
17
|
+
|
|
18
|
+
const frontend = await daemon.createSession({
|
|
19
|
+
cwd: '/tmp/daemon-test-frontend',
|
|
20
|
+
});
|
|
21
|
+
const backend = await daemon.createSession({
|
|
22
|
+
cwd: '/tmp/daemon-test-backend',
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
console.log('Two sessions created. Running concurrently...\n');
|
|
26
|
+
|
|
27
|
+
await Promise.all([
|
|
28
|
+
(async () => {
|
|
29
|
+
for await (const msg of frontend.stream(
|
|
30
|
+
'Create a file called hello.md with a short greeting message. Just a few lines.'
|
|
31
|
+
)) {
|
|
32
|
+
if (msg.type === DroidMessageType.Assistant) {
|
|
33
|
+
process.stdout.write(`[frontend] ${msg.text}\n`);
|
|
34
|
+
} else if (msg.type === DroidMessageType.ToolCall) {
|
|
35
|
+
console.log(`[frontend] [tool] ${msg.toolUse.name}`);
|
|
36
|
+
} else if (msg.type === DroidMessageType.Result) {
|
|
37
|
+
console.log(`[frontend] Done in ${msg.durationMs}ms`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
await frontend.close();
|
|
41
|
+
})(),
|
|
42
|
+
(async () => {
|
|
43
|
+
for await (const msg of backend.stream(
|
|
44
|
+
'Create a file called notes.md with 3 random fun facts. Keep it short.'
|
|
45
|
+
)) {
|
|
46
|
+
if (msg.type === DroidMessageType.Assistant) {
|
|
47
|
+
process.stdout.write(`[backend] ${msg.text}\n`);
|
|
48
|
+
} else if (msg.type === DroidMessageType.ToolCall) {
|
|
49
|
+
console.log(`[backend] [tool] ${msg.toolUse.name}`);
|
|
50
|
+
} else if (msg.type === DroidMessageType.Result) {
|
|
51
|
+
console.log(`[backend] Done in ${msg.durationMs}ms`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
await backend.close();
|
|
55
|
+
})(),
|
|
56
|
+
]);
|
|
57
|
+
|
|
58
|
+
await daemon.close();
|
|
59
|
+
console.log(
|
|
60
|
+
'\nDone. Check /tmp/daemon-test-frontend/hello.md and /tmp/daemon-test-backend/notes.md'
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
main().catch((err: unknown) => {
|
|
65
|
+
console.error('Error:', err);
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|
package/examples/fork-session.ts
CHANGED
|
@@ -21,7 +21,9 @@ async function streamText(
|
|
|
21
21
|
prompt: string
|
|
22
22
|
): Promise<string> {
|
|
23
23
|
let text = '';
|
|
24
|
-
for await (const msg of session.stream(prompt
|
|
24
|
+
for await (const msg of session.stream(prompt, {
|
|
25
|
+
includePartialMessages: true,
|
|
26
|
+
})) {
|
|
25
27
|
if (msg.type === DroidMessageType.AssistantTextDelta) {
|
|
26
28
|
text += msg.text;
|
|
27
29
|
}
|
|
@@ -30,7 +32,10 @@ async function streamText(
|
|
|
30
32
|
}
|
|
31
33
|
|
|
32
34
|
async function main(): Promise<void> {
|
|
33
|
-
const session = await createSession({
|
|
35
|
+
const session = await createSession({
|
|
36
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
37
|
+
cwd: process.cwd(),
|
|
38
|
+
});
|
|
34
39
|
let fork: Awaited<ReturnType<typeof resumeSession>> | null = null;
|
|
35
40
|
|
|
36
41
|
try {
|
|
@@ -40,7 +45,9 @@ async function main(): Promise<void> {
|
|
|
40
45
|
const { newSessionId } = await session.forkSession();
|
|
41
46
|
console.log(`Forked session: ${newSessionId}\n`);
|
|
42
47
|
|
|
43
|
-
fork = await resumeSession(newSessionId
|
|
48
|
+
fork = await resumeSession(newSessionId, {
|
|
49
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
50
|
+
});
|
|
44
51
|
|
|
45
52
|
const result = await streamText(
|
|
46
53
|
fork,
|
|
@@ -15,7 +15,13 @@ async function main(): Promise<void> {
|
|
|
15
15
|
console.log(`Sending prompt: "${prompt}"\n`);
|
|
16
16
|
|
|
17
17
|
// Note: To actually see hooks, you need to have hooks configured in your droid settings.
|
|
18
|
-
const
|
|
18
|
+
const apiKey = process.env.FACTORY_API_KEY;
|
|
19
|
+
if (!apiKey) {
|
|
20
|
+
console.error('Set FACTORY_API_KEY environment variable.');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
const session = await createSession({ apiKey, cwd: process.cwd() });
|
|
19
25
|
|
|
20
26
|
try {
|
|
21
27
|
for await (const msg of session.stream(prompt)) {
|
|
@@ -7,8 +7,13 @@
|
|
|
7
7
|
|
|
8
8
|
import { createSession, resumeSession } from '@factory/droid-sdk';
|
|
9
9
|
|
|
10
|
-
const session = await createSession({
|
|
11
|
-
|
|
10
|
+
const session = await createSession({
|
|
11
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
12
|
+
cwd: process.cwd(),
|
|
13
|
+
});
|
|
14
|
+
const resumed = await resumeSession(session.sessionId, {
|
|
15
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
16
|
+
});
|
|
12
17
|
|
|
13
18
|
console.log(`created session: ${session.sessionId}`);
|
|
14
19
|
console.log(`resumed session: ${resumed.sessionId}`);
|
|
@@ -7,13 +7,16 @@
|
|
|
7
7
|
|
|
8
8
|
import { createSession, DroidMessageType } from '@factory/droid-sdk';
|
|
9
9
|
|
|
10
|
-
const session = await createSession({
|
|
10
|
+
const session = await createSession({
|
|
11
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
12
|
+
cwd: process.cwd(),
|
|
13
|
+
});
|
|
11
14
|
let deltaCount = 0;
|
|
12
15
|
|
|
13
16
|
try {
|
|
14
|
-
for await (const msg of session.stream(
|
|
15
|
-
|
|
16
|
-
)) {
|
|
17
|
+
for await (const msg of session.stream('Write a long history of computing.', {
|
|
18
|
+
includePartialMessages: true,
|
|
19
|
+
})) {
|
|
17
20
|
if (msg.type !== DroidMessageType.AssistantTextDelta) {
|
|
18
21
|
continue;
|
|
19
22
|
}
|
|
@@ -12,7 +12,9 @@ async function streamText(
|
|
|
12
12
|
prompt: string
|
|
13
13
|
): Promise<string> {
|
|
14
14
|
let text = '';
|
|
15
|
-
for await (const msg of session.stream(prompt
|
|
15
|
+
for await (const msg of session.stream(prompt, {
|
|
16
|
+
includePartialMessages: true,
|
|
17
|
+
})) {
|
|
16
18
|
if (msg.type === DroidMessageType.AssistantTextDelta) {
|
|
17
19
|
text += msg.text;
|
|
18
20
|
}
|
|
@@ -20,7 +22,10 @@ async function streamText(
|
|
|
20
22
|
return text;
|
|
21
23
|
}
|
|
22
24
|
|
|
23
|
-
const session = await createSession({
|
|
25
|
+
const session = await createSession({
|
|
26
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
27
|
+
cwd: process.cwd(),
|
|
28
|
+
});
|
|
24
29
|
|
|
25
30
|
try {
|
|
26
31
|
console.log(`Session: ${session.sessionId}\n`);
|
|
@@ -20,6 +20,7 @@ const outputPath = join(tempDir, 'hello.txt');
|
|
|
20
20
|
|
|
21
21
|
try {
|
|
22
22
|
await run(`Create ${outputPath} with the text "Hello, World!"`, {
|
|
23
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
23
24
|
cwd: process.cwd(),
|
|
24
25
|
permissionHandler(params) {
|
|
25
26
|
const onlyCreatesExpectedFile = params.toolUses.every(
|
|
@@ -3,6 +3,7 @@ import { OutputFormatType, run } from '@factory/droid-sdk';
|
|
|
3
3
|
type FavoriteNumber = { favoriteNumber: number };
|
|
4
4
|
|
|
5
5
|
const result = await run('Pick a favorite number between 1 and 42.', {
|
|
6
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
6
7
|
cwd: process.cwd(),
|
|
7
8
|
outputFormat: {
|
|
8
9
|
type: OutputFormatType.JsonSchema,
|
package/examples/run.ts
CHANGED
package/examples/sdk-mcp-tool.ts
CHANGED
|
@@ -22,6 +22,7 @@ const sdkTools = createSdkMcpServer({
|
|
|
22
22
|
});
|
|
23
23
|
|
|
24
24
|
const session = await createSession({
|
|
25
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
25
26
|
execPath,
|
|
26
27
|
mcpServers: [sdkTools],
|
|
27
28
|
cwd: process.cwd(),
|
|
@@ -30,7 +31,8 @@ const session = await createSession({
|
|
|
30
31
|
|
|
31
32
|
try {
|
|
32
33
|
for await (const msg of session.stream(
|
|
33
|
-
'Use the favorite_number tool for Ada and tell me the answer.'
|
|
34
|
+
'Use the favorite_number tool for Ada and tell me the answer.',
|
|
35
|
+
{ includePartialMessages: true }
|
|
34
36
|
)) {
|
|
35
37
|
if (msg.type === DroidMessageType.AssistantTextDelta) {
|
|
36
38
|
process.stdout.write(msg.text);
|
|
@@ -15,7 +15,10 @@ async function main(): Promise<void> {
|
|
|
15
15
|
|
|
16
16
|
console.log(`Sending prompt: "${prompt}"\n`);
|
|
17
17
|
|
|
18
|
-
const session = await createSession({
|
|
18
|
+
const session = await createSession({
|
|
19
|
+
apiKey: process.env.FACTORY_API_KEY!,
|
|
20
|
+
cwd: process.cwd(),
|
|
21
|
+
});
|
|
19
22
|
|
|
20
23
|
try {
|
|
21
24
|
for await (const msg of session.stream(prompt)) {
|