@factory/droid-sdk 0.9.0 → 0.9.1
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 +2 -2
- package/dist/{chunk-KXDG5ZWS.mjs → chunk-TWSTJMV7.mjs} +965 -684
- package/dist/chunk-TWSTJMV7.mjs.map +1 -0
- package/dist/{chunk-FJP5OKS5.js → chunk-YSKO6SPT.js} +1057 -776
- package/dist/chunk-YSKO6SPT.js.map +1 -0
- package/dist/{index-BowvC0_E.d.mts → index-C06W9tbN.d.mts} +1379 -828
- package/dist/{index-BowvC0_E.d.ts → index-C06W9tbN.d.ts} +1379 -828
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +3 -1
- package/dist/node.d.mts +2 -2
- package/dist/node.d.ts +2 -2
- package/dist/node.js +350 -349
- package/dist/node.js.map +1 -1
- package/dist/node.mjs +11 -10
- package/dist/node.mjs.map +1 -1
- package/package.json +1 -2
- package/dist/chunk-FJP5OKS5.js.map +0 -1
- package/dist/chunk-KXDG5ZWS.mjs.map +0 -1
- package/docs/typescript-sdk-reference.md +0 -1437
|
@@ -1,1437 +0,0 @@
|
|
|
1
|
-
# Factory TypeScript SDK
|
|
2
|
-
|
|
3
|
-
Use the Factory TypeScript SDK to run Droid from Node.js.
|
|
4
|
-
|
|
5
|
-
The public npm package is `@factory/droid-sdk`.
|
|
6
|
-
|
|
7
|
-
This guide covers the high-level public API. The package's exported TypeScript
|
|
8
|
-
declarations define the complete compile-time API.
|
|
9
|
-
|
|
10
|
-
## Overview
|
|
11
|
-
|
|
12
|
-
Import the SDK from `@factory/droid-sdk/node`. It starts a Droid CLI subprocess
|
|
13
|
-
and provides session management, streaming, local session discovery, and
|
|
14
|
-
in-process MCP tool APIs.
|
|
15
|
-
|
|
16
|
-
### Choose an API
|
|
17
|
-
|
|
18
|
-
| Goal | API |
|
|
19
|
-
| --------------------------------------- | ----------------- |
|
|
20
|
-
| Run one prompt and get the final result | `run()` |
|
|
21
|
-
| Keep context across prompts | `createSession()` |
|
|
22
|
-
| Continue a saved session | `resumeSession()` |
|
|
23
|
-
| Find saved sessions | `listSessions()` |
|
|
24
|
-
|
|
25
|
-
Start with `run()` for one prompt. Use a session when later prompts need the
|
|
26
|
-
same conversation history.
|
|
27
|
-
|
|
28
|
-
## Install and authenticate
|
|
29
|
-
|
|
30
|
-
Install the package:
|
|
31
|
-
|
|
32
|
-
```bash
|
|
33
|
-
npm install @factory/droid-sdk
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
The SDK requires Node.js 18 or later.
|
|
37
|
-
|
|
38
|
-
By default, the SDK starts the `droid` CLI from `PATH`. Pass `execPath` to use a
|
|
39
|
-
different `droid` executable.
|
|
40
|
-
|
|
41
|
-
Set an API key:
|
|
42
|
-
|
|
43
|
-
```bash
|
|
44
|
-
export FACTORY_API_KEY="your-key"
|
|
45
|
-
```
|
|
46
|
-
|
|
47
|
-
The SDK reads `FACTORY_API_KEY` from the process environment by default. You
|
|
48
|
-
can also pass `apiKey` to `run()`, `createSession()`, or `resumeSession()`.
|
|
49
|
-
|
|
50
|
-
## Quick start
|
|
51
|
-
|
|
52
|
-
### Run one prompt
|
|
53
|
-
|
|
54
|
-
```ts
|
|
55
|
-
import { run } from '@factory/droid-sdk/node';
|
|
56
|
-
|
|
57
|
-
const result = await run('Summarize this repository.');
|
|
58
|
-
|
|
59
|
-
if (!result.success) {
|
|
60
|
-
throw new Error(result.error?.message ?? `Run failed: ${result.subtype}`);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
console.log(result.text);
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
`run()` creates a session, consumes its complete message stream, returns the
|
|
67
|
-
terminal `DroidResult`, and closes the session.
|
|
68
|
-
|
|
69
|
-
### Continue a conversation
|
|
70
|
-
|
|
71
|
-
```ts
|
|
72
|
-
import { createSession, DroidMessageType } from '@factory/droid-sdk/node';
|
|
73
|
-
|
|
74
|
-
const session = await createSession();
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
for await (const message of session.stream('What does this project do?')) {
|
|
78
|
-
if (message.type === DroidMessageType.Assistant) {
|
|
79
|
-
console.log(message.text);
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
for await (const message of session.stream('What should I test first?')) {
|
|
84
|
-
if (message.type === DroidMessageType.Assistant) {
|
|
85
|
-
console.log(message.text);
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
} finally {
|
|
89
|
-
await session.close();
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
In the above example, the second prompt uses context from the first turn.
|
|
94
|
-
Remember to close sessions that your code creates.
|
|
95
|
-
|
|
96
|
-
## Core concepts
|
|
97
|
-
|
|
98
|
-
### Session
|
|
99
|
-
|
|
100
|
-
A session holds conversation history, settings, and a working directory. Create
|
|
101
|
-
one with `createSession()` or load a saved session with `resumeSession()`.
|
|
102
|
-
|
|
103
|
-
### Turn
|
|
104
|
-
|
|
105
|
-
A turn starts when you send one prompt with `session.stream()`. A session can
|
|
106
|
-
run one turn at a time.
|
|
107
|
-
|
|
108
|
-
### Stream message
|
|
109
|
-
|
|
110
|
-
`session.stream()` returns an async iterable of complete messages. Narrow each
|
|
111
|
-
message by its `type`. Messages can report user input, assistant output, tool
|
|
112
|
-
activity, hooks, errors, and a terminal `DroidResult`.
|
|
113
|
-
|
|
114
|
-
### Result
|
|
115
|
-
|
|
116
|
-
A normally completed turn ends with a `DroidResult`. `run()` consumes the stream and returns that same result type. See [Streaming and results](#streaming-and-results) for result handling, errors, token usage, and cancellation.
|
|
117
|
-
|
|
118
|
-
### Ownership and cleanup
|
|
119
|
-
|
|
120
|
-
Cleanup depends on how the session was created.
|
|
121
|
-
|
|
122
|
-
| API | Cleanup |
|
|
123
|
-
| ----------------- | -------------------------------- |
|
|
124
|
-
| `run()` | Closes its session automatically |
|
|
125
|
-
| `createSession()` | Call `await session.close()` |
|
|
126
|
-
| `resumeSession()` | Call `await session.close()` |
|
|
127
|
-
|
|
128
|
-
Use `finally` blocks so cleanup also runs after an error.
|
|
129
|
-
|
|
130
|
-
## Models
|
|
131
|
-
|
|
132
|
-
Model IDs are strings because availability depends on the account,
|
|
133
|
-
organization policy, and daemon configuration. Omit `modelId` to use the Droid
|
|
134
|
-
default.
|
|
135
|
-
|
|
136
|
-
### Discover available models
|
|
137
|
-
|
|
138
|
-
**Runtime: Node.js**
|
|
139
|
-
|
|
140
|
-
```ts
|
|
141
|
-
import { listModels } from '@factory/droid-sdk/node';
|
|
142
|
-
|
|
143
|
-
const models = await listModels();
|
|
144
|
-
const catalog = await listModels({ includeDisabled: true });
|
|
145
|
-
```
|
|
146
|
-
|
|
147
|
-
The Node helper starts a one-shot Droid process, requests the catalog without
|
|
148
|
-
creating a session, and closes the process before returning.
|
|
149
|
-
|
|
150
|
-
**Runtime: Daemon** (`droid` is a client returned by `connectToDaemon()`)
|
|
151
|
-
|
|
152
|
-
```ts
|
|
153
|
-
const models = await droid.models.list();
|
|
154
|
-
const catalog = await droid.models.list({ includeDisabled: true });
|
|
155
|
-
|
|
156
|
-
for (const model of models) {
|
|
157
|
-
console.log(model.id, model.supportedReasoningEfforts);
|
|
158
|
-
}
|
|
159
|
-
```
|
|
160
|
-
|
|
161
|
-
`includeDisabled` defaults to `false`, so both APIs return only selectable
|
|
162
|
-
models when options are omitted. When disabled models are requested, every
|
|
163
|
-
disabled entry includes a `disabledReason` for display. Regular organization
|
|
164
|
-
members cannot enable these models. An organization manager may be able to
|
|
165
|
-
change the model policy or complete a required opt-in.
|
|
166
|
-
|
|
167
|
-
Runnable examples:
|
|
168
|
-
|
|
169
|
-
- Node: [`examples/node/model-discovery.ts`](../examples/node/model-discovery.ts)
|
|
170
|
-
- Browser and daemon: [`examples/browser/daemon-model-discovery.ts`](../examples/browser/daemon-model-discovery.ts)
|
|
171
|
-
|
|
172
|
-
Each available model includes:
|
|
173
|
-
|
|
174
|
-
| Field | Meaning |
|
|
175
|
-
| --------------------------- | ---------------------------------------------- |
|
|
176
|
-
| `id` | Value accepted by `modelId` |
|
|
177
|
-
| `displayName` | Full display name |
|
|
178
|
-
| `shortDisplayName` | Compact display name |
|
|
179
|
-
| `modelProvider` | Model provider |
|
|
180
|
-
| `supportedReasoningEfforts` | Reasoning levels accepted by the model |
|
|
181
|
-
| `defaultReasoningEffort` | Reasoning level used when none is supplied |
|
|
182
|
-
| `isCustom` | Whether the model is user-configured |
|
|
183
|
-
| `disabled` | Whether policy prevents selecting the model |
|
|
184
|
-
| `disabledReason` | Required explanation when `disabled` is `true` |
|
|
185
|
-
| `noImageSupport` | Whether image input is unavailable |
|
|
186
|
-
| `supportsImageGeneration` | Whether the model can generate images |
|
|
187
|
-
| `kind` | Model or router classification, when present |
|
|
188
|
-
|
|
189
|
-
Other optional fields provide tier, token multiplier, and display badges.
|
|
190
|
-
|
|
191
|
-
### Node and daemon discovery
|
|
192
|
-
|
|
193
|
-
| Runtime | Discovery API | Lifecycle |
|
|
194
|
-
| ------- | --------------------- | ---------------------------------------- |
|
|
195
|
-
| Node | `listModels(options)` | Uses and closes a one-shot Droid process |
|
|
196
|
-
| Daemon | `droid.models.list()` | Reuses the connected daemon client |
|
|
197
|
-
|
|
198
|
-
Both APIs return the same `ModelInfo[]` type and include built-in models plus
|
|
199
|
-
configured custom models.
|
|
200
|
-
|
|
201
|
-
### Select a model
|
|
202
|
-
|
|
203
|
-
Pass a configured model ID when creating a session or running one prompt.
|
|
204
|
-
|
|
205
|
-
```ts
|
|
206
|
-
import {
|
|
207
|
-
createSession,
|
|
208
|
-
DroidMessageType,
|
|
209
|
-
ReasoningEffort,
|
|
210
|
-
} from '@factory/droid-sdk/node';
|
|
211
|
-
|
|
212
|
-
const session = await createSession({
|
|
213
|
-
modelId: 'model-id',
|
|
214
|
-
reasoningEffort: ReasoningEffort.High,
|
|
215
|
-
});
|
|
216
|
-
|
|
217
|
-
try {
|
|
218
|
-
for await (const message of session.stream('Review this repository.')) {
|
|
219
|
-
if (message.type === DroidMessageType.Assistant) {
|
|
220
|
-
console.log(message.text);
|
|
221
|
-
}
|
|
222
|
-
}
|
|
223
|
-
} finally {
|
|
224
|
-
await session.close();
|
|
225
|
-
}
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
For an existing session, call `updateSettings()`:
|
|
229
|
-
|
|
230
|
-
```ts
|
|
231
|
-
await session.updateSettings({
|
|
232
|
-
modelId: 'model-id',
|
|
233
|
-
reasoningEffort: ReasoningEffort.High,
|
|
234
|
-
});
|
|
235
|
-
```
|
|
236
|
-
|
|
237
|
-
Set `reasoningEffort` only to a level supported by the selected model. Omit it
|
|
238
|
-
to use the model's configured default.
|
|
239
|
-
|
|
240
|
-
Runnable example: [`examples/node/model-selection.ts`](../examples/node/model-selection.ts)
|
|
241
|
-
|
|
242
|
-
### Use Auto Router
|
|
243
|
-
|
|
244
|
-
Set `modelId` to `"auto"` to let Factory choose a model for each turn.
|
|
245
|
-
|
|
246
|
-
```ts
|
|
247
|
-
import { run } from '@factory/droid-sdk/node';
|
|
248
|
-
|
|
249
|
-
const result = await run('Find the cause of the failing tests.', {
|
|
250
|
-
modelId: 'auto',
|
|
251
|
-
});
|
|
252
|
-
|
|
253
|
-
if (!result.success) {
|
|
254
|
-
throw new Error(result.error?.message ?? `Run failed: ${result.subtype}`);
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
console.log(result.text);
|
|
258
|
-
```
|
|
259
|
-
|
|
260
|
-
The selected model can change between turns. Choose a fixed model ID when runs must use the same model.
|
|
261
|
-
|
|
262
|
-
### Choose a spec-mode model
|
|
263
|
-
|
|
264
|
-
The primary model handles normal turns. The spec-mode model handles turns in
|
|
265
|
-
spec mode.
|
|
266
|
-
|
|
267
|
-
```ts
|
|
268
|
-
import {
|
|
269
|
-
createSession,
|
|
270
|
-
DroidInteractionMode,
|
|
271
|
-
ReasoningEffort,
|
|
272
|
-
} from '@factory/droid-sdk/node';
|
|
273
|
-
|
|
274
|
-
const session = await createSession({
|
|
275
|
-
modelId: 'auto',
|
|
276
|
-
interactionMode: DroidInteractionMode.Spec,
|
|
277
|
-
specModeModelId: 'model-id',
|
|
278
|
-
specModeReasoningEffort: ReasoningEffort.High,
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
try {
|
|
282
|
-
for await (const _message of session.stream(
|
|
283
|
-
'Draft an implementation plan.'
|
|
284
|
-
)) {
|
|
285
|
-
// Consume messages.
|
|
286
|
-
}
|
|
287
|
-
} finally {
|
|
288
|
-
await session.close();
|
|
289
|
-
}
|
|
290
|
-
```
|
|
291
|
-
|
|
292
|
-
You can also choose the model when entering spec mode:
|
|
293
|
-
|
|
294
|
-
```ts
|
|
295
|
-
await session.enterSpecMode({
|
|
296
|
-
specModeModelId: 'model-id',
|
|
297
|
-
specModeReasoningEffort: ReasoningEffort.High,
|
|
298
|
-
});
|
|
299
|
-
```
|
|
300
|
-
|
|
301
|
-
### Use a custom model
|
|
302
|
-
|
|
303
|
-
Configure custom models in `~/.factory/settings.json`. See [Custom Models (BYOK)](https://docs.factory.ai/cli/byok/overview) for provider, credential, and model settings.
|
|
304
|
-
|
|
305
|
-
After configuration, pass the custom model ID anywhere the SDK accepts `modelId`. The ID uses `custom:` followed by the configured `model` value.
|
|
306
|
-
|
|
307
|
-
```ts
|
|
308
|
-
import { run } from '@factory/droid-sdk/node';
|
|
309
|
-
|
|
310
|
-
const result = await run('Summarize this repository.', {
|
|
311
|
-
modelId: 'custom:gpt-4o-mini',
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
if (!result.success) {
|
|
315
|
-
throw new Error(result.error?.message ?? `Run failed: ${result.subtype}`);
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
console.log(result.text);
|
|
319
|
-
```
|
|
320
|
-
|
|
321
|
-
## Sessions
|
|
322
|
-
|
|
323
|
-
Use a session when prompts need shared conversation history. A session owns its working directory, settings, and one active turn at a time.
|
|
324
|
-
|
|
325
|
-
### Create and use a session
|
|
326
|
-
|
|
327
|
-
```ts
|
|
328
|
-
import { createSession, DroidMessageType } from '@factory/droid-sdk/node';
|
|
329
|
-
|
|
330
|
-
const session = await createSession({
|
|
331
|
-
cwd: process.cwd(),
|
|
332
|
-
});
|
|
333
|
-
|
|
334
|
-
async function send(prompt: string) {
|
|
335
|
-
for await (const message of session.stream(prompt)) {
|
|
336
|
-
if (message.type === DroidMessageType.Assistant) {
|
|
337
|
-
console.log(message.text);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
|
|
342
|
-
try {
|
|
343
|
-
await send('What does this project do?');
|
|
344
|
-
await send('What should I test first?');
|
|
345
|
-
} finally {
|
|
346
|
-
await session.close();
|
|
347
|
-
}
|
|
348
|
-
```
|
|
349
|
-
|
|
350
|
-
The second turn uses context from the first. `cwd` defaults to `process.cwd()`. Model and reasoning defaults come from Droid settings.
|
|
351
|
-
|
|
352
|
-
Runnable example:
|
|
353
|
-
[`examples/node/multi-turn-session.ts`](../examples/node/multi-turn-session.ts)
|
|
354
|
-
|
|
355
|
-
### Resume a saved session
|
|
356
|
-
|
|
357
|
-
```ts
|
|
358
|
-
import { DroidMessageType, resumeSession } from '@factory/droid-sdk/node';
|
|
359
|
-
|
|
360
|
-
async function continueSession(sessionId: string) {
|
|
361
|
-
const session = await resumeSession(sessionId);
|
|
362
|
-
|
|
363
|
-
try {
|
|
364
|
-
for await (const message of session.stream(
|
|
365
|
-
'Continue from the last conversation.'
|
|
366
|
-
)) {
|
|
367
|
-
if (message.type === DroidMessageType.Assistant) {
|
|
368
|
-
console.log(message.text);
|
|
369
|
-
}
|
|
370
|
-
}
|
|
371
|
-
} finally {
|
|
372
|
-
await session.close();
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
```
|
|
376
|
-
|
|
377
|
-
`resumeSession()` restores the saved conversation, working directory, and session settings. It does not accept `cwd`, `modelId`, or reasoning options.
|
|
378
|
-
|
|
379
|
-
Resume options can provide new permission and AskUser handlers, disabled tools, MCP servers, an abort signal, and observability sinks.
|
|
380
|
-
|
|
381
|
-
### Customize the system prompt
|
|
382
|
-
|
|
383
|
-
Use `systemPrompt` to append instructions to Droid's effective built-in prompt
|
|
384
|
-
or replace the behavioral prompt:
|
|
385
|
-
|
|
386
|
-
```ts
|
|
387
|
-
const appended = await createSession({
|
|
388
|
-
systemPrompt: {
|
|
389
|
-
type: 'preset',
|
|
390
|
-
preset: 'droid',
|
|
391
|
-
append: 'Prioritize security findings and cite relevant files.',
|
|
392
|
-
},
|
|
393
|
-
});
|
|
394
|
-
|
|
395
|
-
const replaced = await createSession({
|
|
396
|
-
systemPrompt: 'Act as a focused dependency-analysis agent.',
|
|
397
|
-
});
|
|
398
|
-
```
|
|
399
|
-
|
|
400
|
-
The Droid preset retains the prompt that the session would normally use,
|
|
401
|
-
including specialized exec and mission prompts, and appends your instructions.
|
|
402
|
-
A string replaces that behavioral prompt. Both forms retain the mandatory
|
|
403
|
-
Droid identity block and required model/tool guidance.
|
|
404
|
-
|
|
405
|
-
The option is available to `run()`, `createSession()`, and
|
|
406
|
-
`droid.sessions.create()`. The prompt is fixed when the session is created.
|
|
407
|
-
It is saved in the session settings file, restored by `resumeSession()` and
|
|
408
|
-
`droid.sessions.resume()`, and inherited unchanged by forks.
|
|
409
|
-
|
|
410
|
-
The prompt configuration is stored in the sibling session settings file, not
|
|
411
|
-
serialized as a system event in the transcript JSONL. As with any instruction,
|
|
412
|
-
the model can still repeat prompt text in its generated messages or thinking,
|
|
413
|
-
which are part of the transcript. Treat both files as sensitive.
|
|
414
|
-
|
|
415
|
-
Runnable example: [`examples/node/custom-system-prompt.ts`](../examples/node/custom-system-prompt.ts)
|
|
416
|
-
|
|
417
|
-
### Read session state
|
|
418
|
-
|
|
419
|
-
Each handle exposes its ID, current working directory, and current settings.
|
|
420
|
-
|
|
421
|
-
```ts
|
|
422
|
-
console.log(session.id);
|
|
423
|
-
console.log(session.cwd);
|
|
424
|
-
console.log(session.settings.modelId);
|
|
425
|
-
console.log(session.settings.reasoningEffort);
|
|
426
|
-
console.log(session.settings.interactionMode);
|
|
427
|
-
```
|
|
428
|
-
|
|
429
|
-
`settings` is read-only. The SDK updates `settings` and `cwd` when Droid reports a change.
|
|
430
|
-
|
|
431
|
-
Runnable example: [`examples/node/init-metadata.ts`](../examples/node/init-metadata.ts)
|
|
432
|
-
|
|
433
|
-
### Update active-session settings
|
|
434
|
-
|
|
435
|
-
Use `updateSettings()` for changes that should apply to later turns in the current session.
|
|
436
|
-
|
|
437
|
-
```ts
|
|
438
|
-
import { AutonomyLevel, ReasoningEffort } from '@factory/droid-sdk/node';
|
|
439
|
-
|
|
440
|
-
await session.updateSettings({
|
|
441
|
-
modelId: 'model-id',
|
|
442
|
-
reasoningEffort: ReasoningEffort.High,
|
|
443
|
-
autonomyLevel: AutonomyLevel.Low,
|
|
444
|
-
disabledToolIds: ['Execute'],
|
|
445
|
-
});
|
|
446
|
-
```
|
|
447
|
-
|
|
448
|
-
Updatable settings include:
|
|
449
|
-
|
|
450
|
-
- model and reasoning effort
|
|
451
|
-
- interaction mode and autonomy level
|
|
452
|
-
- spec-mode model settings
|
|
453
|
-
- tool availability overrides
|
|
454
|
-
|
|
455
|
-
Interaction mode controls whether Droid operates normally in Auto mode or produces a read-only plan in Spec mode. Autonomy level controls which actions require approval while Droid is in Auto mode. Tool availability overrides can enable, disable, or restrict the tools available to the session.
|
|
456
|
-
|
|
457
|
-
When only changing interaction modes, use `enterSpecMode()` and `exitSpecMode()` instead of setting `interactionMode` directly.
|
|
458
|
-
|
|
459
|
-
The updated values are available through `session.settings`.
|
|
460
|
-
|
|
461
|
-
Runnable example: [`examples/node/session-settings.ts`](../examples/node/session-settings.ts)
|
|
462
|
-
|
|
463
|
-
### Rename a session
|
|
464
|
-
|
|
465
|
-
Use `rename()` after the first turn to replace the generated title.
|
|
466
|
-
|
|
467
|
-
```ts
|
|
468
|
-
await session.rename({ title: 'Authentication review' });
|
|
469
|
-
```
|
|
470
|
-
|
|
471
|
-
Runnable example:
|
|
472
|
-
[`examples/node/rename-session.ts`](../examples/node/rename-session.ts)
|
|
473
|
-
|
|
474
|
-
### List saved sessions
|
|
475
|
-
|
|
476
|
-
`listSessions()` reads local Droid session storage. It does not start Droid or
|
|
477
|
-
call the Factory API.
|
|
478
|
-
|
|
479
|
-
List sessions for the current working directory:
|
|
480
|
-
|
|
481
|
-
```ts
|
|
482
|
-
import { listSessions } from '@factory/droid-sdk/node';
|
|
483
|
-
|
|
484
|
-
const sessions = await listSessions({ limit: 10 });
|
|
485
|
-
|
|
486
|
-
for (const session of sessions) {
|
|
487
|
-
console.log(session.id, session.title, session.modifiedTime);
|
|
488
|
-
}
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
List sessions across all working directories:
|
|
492
|
-
|
|
493
|
-
```ts
|
|
494
|
-
const sessions = await listSessions({
|
|
495
|
-
fetchOutsideCWD: true,
|
|
496
|
-
limit: 10,
|
|
497
|
-
});
|
|
498
|
-
```
|
|
499
|
-
|
|
500
|
-
Results are sorted by `modifiedTime`, newest first. Each item includes its ID, title, owner, message count, creation time, modification time, and working directory when available.
|
|
501
|
-
|
|
502
|
-
Runnable example: [`examples/node/list-sessions.ts`](../examples/node/list-sessions.ts)
|
|
503
|
-
|
|
504
|
-
### What persists
|
|
505
|
-
|
|
506
|
-
Droid saves the session data needed to continue later.
|
|
507
|
-
|
|
508
|
-
| Restored from the saved session | Attach again when resuming |
|
|
509
|
-
| ------------------------------- | -------------------------- |
|
|
510
|
-
| Conversation history | Permission handler |
|
|
511
|
-
| Working directory | AskUser handler |
|
|
512
|
-
| Title | SDK MCP servers |
|
|
513
|
-
| Session settings | Observability sinks |
|
|
514
|
-
| | Abort signal |
|
|
515
|
-
|
|
516
|
-
Session settings include model, reasoning, Auto or Spec interaction mode, autonomy, spec-mode model settings, and tool availability overrides.
|
|
517
|
-
|
|
518
|
-
Handlers, observability sinks, abort signals, and SDK MCP servers are runtime objects. Droid cannot serialize them with the session, so attach them again when calling `resumeSession()`. They do not need to be the same object instances or implementations used when the session was created.
|
|
519
|
-
|
|
520
|
-
### Close sessions safely
|
|
521
|
-
|
|
522
|
-
Call `close()` in `finally` when your code creates or resumes a session.
|
|
523
|
-
Closing releases the subprocess, subscriptions, and SDK-owned MCP servers.
|
|
524
|
-
|
|
525
|
-
```ts
|
|
526
|
-
const session = await createSession();
|
|
527
|
-
|
|
528
|
-
try {
|
|
529
|
-
// Use the session.
|
|
530
|
-
} finally {
|
|
531
|
-
await session.close();
|
|
532
|
-
}
|
|
533
|
-
```
|
|
534
|
-
|
|
535
|
-
## Streaming and results
|
|
536
|
-
|
|
537
|
-
Each call to `session.stream()` starts one turn and returns an async iterable.
|
|
538
|
-
|
|
539
|
-
By default, it yields complete messages and ends with a terminal `DroidResult`.
|
|
540
|
-
|
|
541
|
-
### Complete messages
|
|
542
|
-
|
|
543
|
-
```ts
|
|
544
|
-
for await (const message of session.stream('Find the failing test.')) {
|
|
545
|
-
switch (message.type) {
|
|
546
|
-
case DroidMessageType.Assistant:
|
|
547
|
-
console.log(message.text);
|
|
548
|
-
break;
|
|
549
|
-
case DroidMessageType.ToolCall:
|
|
550
|
-
console.log(`Tool: ${message.name}`);
|
|
551
|
-
break;
|
|
552
|
-
case DroidMessageType.Result:
|
|
553
|
-
console.log(message.subtype);
|
|
554
|
-
break;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
```
|
|
558
|
-
|
|
559
|
-
Default message types:
|
|
560
|
-
|
|
561
|
-
| Type | Purpose |
|
|
562
|
-
| ------------- | ------------------------------------ |
|
|
563
|
-
| `assistant` | Complete assistant message |
|
|
564
|
-
| `user` | User message recorded by the session |
|
|
565
|
-
| `tool_call` | Complete tool request |
|
|
566
|
-
| `tool_result` | Complete tool result |
|
|
567
|
-
| `hook` | Hook execution |
|
|
568
|
-
| `error` | Runtime error event |
|
|
569
|
-
| `result` | Terminal `DroidResult` |
|
|
570
|
-
|
|
571
|
-
Runnable example: [`examples/node/session-stream.ts`](../examples/node/session-stream.ts)
|
|
572
|
-
|
|
573
|
-
### Handle the result
|
|
574
|
-
|
|
575
|
-
`DroidResult` is a discriminated union. Check `subtype` or `success` before using the response.
|
|
576
|
-
|
|
577
|
-
```ts
|
|
578
|
-
const result = await run('Run the test suite.');
|
|
579
|
-
|
|
580
|
-
switch (result.subtype) {
|
|
581
|
-
case 'success':
|
|
582
|
-
console.log(result.text);
|
|
583
|
-
break;
|
|
584
|
-
case 'interrupted':
|
|
585
|
-
console.log('The run was interrupted.');
|
|
586
|
-
break;
|
|
587
|
-
case 'error_during_execution':
|
|
588
|
-
case 'error_structured_output':
|
|
589
|
-
console.error(
|
|
590
|
-
result.structuredOutputError?.message ??
|
|
591
|
-
result.error?.message ??
|
|
592
|
-
'Unknown error'
|
|
593
|
-
);
|
|
594
|
-
break;
|
|
595
|
-
}
|
|
596
|
-
```
|
|
597
|
-
|
|
598
|
-
| Subtype | Meaning |
|
|
599
|
-
| ------------------------- | ------------------------------------------------- |
|
|
600
|
-
| `success` | The turn completed successfully |
|
|
601
|
-
| `interrupted` | The turn was cancelled or permission declined |
|
|
602
|
-
| `error_during_execution` | Droid could not complete the requested work |
|
|
603
|
-
| `error_structured_output` | Structured-output generation or validation failed |
|
|
604
|
-
|
|
605
|
-
Every result includes:
|
|
606
|
-
|
|
607
|
-
```ts
|
|
608
|
-
console.log(result.sessionId);
|
|
609
|
-
console.log(result.durationMs);
|
|
610
|
-
console.log(result.turnCount);
|
|
611
|
-
console.log(result.messages);
|
|
612
|
-
console.log(result.text);
|
|
613
|
-
console.log(result.tokenUsage);
|
|
614
|
-
```
|
|
615
|
-
|
|
616
|
-
`run()` returns the terminal result directly. When consuming `session.stream()`, handle the message whose type is `DroidMessageType.Result`.
|
|
617
|
-
|
|
618
|
-
Runnable example: [`examples/node/result-metadata.ts`](../examples/node/result-metadata.ts)
|
|
619
|
-
|
|
620
|
-
### Partial events
|
|
621
|
-
|
|
622
|
-
Enable partial events only when the application needs live text, thinking, tool progress, token usage, or state updates.
|
|
623
|
-
|
|
624
|
-
```ts
|
|
625
|
-
for await (const event of session.stream('Explain the test failure.', {
|
|
626
|
-
includePartialMessages: true,
|
|
627
|
-
})) {
|
|
628
|
-
if (event.type === DroidMessageType.AssistantTextDelta) {
|
|
629
|
-
process.stdout.write(event.text);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
```
|
|
633
|
-
|
|
634
|
-
Partial streams can also include thinking deltas, tool-call deltas, tool
|
|
635
|
-
progress, token updates, permission results, settings changes, working-state
|
|
636
|
-
changes, and MCP status.
|
|
637
|
-
|
|
638
|
-
Runnable example: [`examples/node/partial-stream.ts`](../examples/node/partial-stream.ts)
|
|
639
|
-
|
|
640
|
-
### Token and context usage
|
|
641
|
-
|
|
642
|
-
`DroidResult.tokenUsage` reports raw token counts for the current SDK turn and,
|
|
643
|
-
when available, the Factory Service Credits (FSC) charged for that turn. One
|
|
644
|
-
turn is one `run()` or `session.stream()` call. This is not the session's
|
|
645
|
-
lifetime total.
|
|
646
|
-
|
|
647
|
-
```ts
|
|
648
|
-
if (result.tokenUsage) {
|
|
649
|
-
console.log(`input: ${result.tokenUsage.inputTokens}`);
|
|
650
|
-
console.log(`output: ${result.tokenUsage.outputTokens}`);
|
|
651
|
-
console.log(`cache read: ${result.tokenUsage.cacheReadTokens}`);
|
|
652
|
-
console.log(`cache created: ${result.tokenUsage.cacheCreationTokens}`);
|
|
653
|
-
if (result.tokenUsage.factoryCredits !== undefined) {
|
|
654
|
-
console.log(`Factory Service Credits: ${result.tokenUsage.factoryCredits}`);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
```
|
|
658
|
-
|
|
659
|
-
| Field | What it measures during the turn |
|
|
660
|
-
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------- |
|
|
661
|
-
| `inputTokens` | Provider-reported input across model calls, which can include instructions, tools, conversation history, and the latest message |
|
|
662
|
-
| `outputTokens` | Output generated across model calls, not only the final visible response |
|
|
663
|
-
| `cacheReadTokens` | Input tokens reused from the prompt cache |
|
|
664
|
-
| `cacheCreationTokens` | Input tokens written to the prompt cache |
|
|
665
|
-
| `thinkingTokens` | Reasoning tokens reported separately when available |
|
|
666
|
-
| `factoryCredits` | Factory Service Credits charged, when available |
|
|
667
|
-
|
|
668
|
-
One turn can make several model calls while Droid uses tools. Their usage is combined in the result, along with usage from delegated work. Earlier conversation can be counted again when it is included as input to a later turn. Cached input is also reported through the separate cache fields. `tokenUsage` is `null` when usage is unavailable.
|
|
669
|
-
|
|
670
|
-
Partial streams can emit `DroidMessageType.TokenUsageUpdate`. Unlike the per-turn result, these events contain cumulative committed usage for the session.
|
|
671
|
-
|
|
672
|
-
`getContextStats()` measures current context occupancy, not cumulative token usage:
|
|
673
|
-
|
|
674
|
-
```ts
|
|
675
|
-
const stats = await session.getContextStats();
|
|
676
|
-
|
|
677
|
-
console.log(stats.used, stats.remaining, stats.limit, stats.accuracy);
|
|
678
|
-
```
|
|
679
|
-
|
|
680
|
-
| Field | Meaning |
|
|
681
|
-
| ----------- | ----------------------------------------------------------------------------------------------------- |
|
|
682
|
-
| `used` | Estimated tokens currently occupied by prompts, tools, instructions, and conversation history |
|
|
683
|
-
| `limit` | Active model's maximum input window; unresolved model IDs fall back to the effective compaction limit |
|
|
684
|
-
| `remaining` | `Math.max(0, limit - used)` |
|
|
685
|
-
| `accuracy` | Currently `estimated`, because Droid approximates tokens from character counts |
|
|
686
|
-
|
|
687
|
-
`remaining` estimates room in the model's input window. It does not
|
|
688
|
-
necessarily mean tokens remaining before compaction. Droid can compact at a
|
|
689
|
-
lower configured threshold, commonly 250,000 tokens, even when the active
|
|
690
|
-
model's input window is larger.
|
|
691
|
-
|
|
692
|
-
### Errors
|
|
693
|
-
|
|
694
|
-
An error event and a thrown exception mean different things:
|
|
695
|
-
|
|
696
|
-
- An `error` message reports a runtime problem during the turn. A terminal `DroidResult` normally follows and describes the final outcome.
|
|
697
|
-
- A failed `DroidResult` means the stream completed, but the requested work or structured output failed.
|
|
698
|
-
- A thrown exception means the SDK operation itself could not finish, such as an abort, connection failure, protocol error, or concurrent stream attempt.
|
|
699
|
-
|
|
700
|
-
Handle stream exceptions around the iteration:
|
|
701
|
-
|
|
702
|
-
```ts
|
|
703
|
-
try {
|
|
704
|
-
for await (const message of session.stream('Run the tests.')) {
|
|
705
|
-
if (message.type === DroidMessageType.Error) {
|
|
706
|
-
console.error(message.message);
|
|
707
|
-
}
|
|
708
|
-
}
|
|
709
|
-
} catch (error) {
|
|
710
|
-
console.error('The stream could not finish:', error);
|
|
711
|
-
}
|
|
712
|
-
```
|
|
713
|
-
|
|
714
|
-
`run()` follows the same distinction: agent failures are returned as failed results, while setup, transport, protocol, and abort failures are thrown.
|
|
715
|
-
|
|
716
|
-
### Stream concurrency
|
|
717
|
-
|
|
718
|
-
One session handle can have one active stream. Starting another active stream
|
|
719
|
-
throws `ConcurrentStreamError`.
|
|
720
|
-
|
|
721
|
-
### Cancellation and interruption
|
|
722
|
-
|
|
723
|
-
Use an abort signal to cancel one turn:
|
|
724
|
-
|
|
725
|
-
```ts
|
|
726
|
-
const controller = new AbortController();
|
|
727
|
-
|
|
728
|
-
setTimeout(
|
|
729
|
-
() => controller.abort(new Error('Timed out after 5 seconds')),
|
|
730
|
-
5_000
|
|
731
|
-
);
|
|
732
|
-
|
|
733
|
-
for await (const message of session.stream('Perform a long review.', {
|
|
734
|
-
abortSignal: controller.signal,
|
|
735
|
-
})) {
|
|
736
|
-
// Handle messages.
|
|
737
|
-
}
|
|
738
|
-
```
|
|
739
|
-
|
|
740
|
-
The stream interrupts the active turn and throws the abort reason.
|
|
741
|
-
|
|
742
|
-
Use `session.interrupt()` when another part of the application needs to stop
|
|
743
|
-
the active turn:
|
|
744
|
-
|
|
745
|
-
```ts
|
|
746
|
-
await session.interrupt();
|
|
747
|
-
```
|
|
748
|
-
|
|
749
|
-
The stream normally continues to a terminal result with subtype `interrupted`.
|
|
750
|
-
The session remains available for later prompts.
|
|
751
|
-
|
|
752
|
-
Breaking out of the stream also interrupts the active turn:
|
|
753
|
-
|
|
754
|
-
```ts
|
|
755
|
-
for await (const message of session.stream('Investigate every failing test.')) {
|
|
756
|
-
if (message.type === DroidMessageType.Assistant) {
|
|
757
|
-
console.log(message.text);
|
|
758
|
-
|
|
759
|
-
// Interrupt this turn instead of merely hiding its remaining output.
|
|
760
|
-
break;
|
|
761
|
-
}
|
|
762
|
-
}
|
|
763
|
-
```
|
|
764
|
-
|
|
765
|
-
Breaking out of the loop before the turn finishes sends an interrupt request
|
|
766
|
-
to Droid. This cancels the remaining model and tool work for that turn. The
|
|
767
|
-
session remains open and can accept another prompt, but this loop does not
|
|
768
|
-
receive the interrupted turn's terminal `DroidResult`.
|
|
769
|
-
|
|
770
|
-
A session-level abort signal passed to `createSession()` closes the entire
|
|
771
|
-
session when aborted.
|
|
772
|
-
|
|
773
|
-
Runnable examples:
|
|
774
|
-
|
|
775
|
-
- [`examples/node/abort-session-stream.ts`](../examples/node/abort-session-stream.ts)
|
|
776
|
-
- [`examples/node/interrupt-session.ts`](../examples/node/interrupt-session.ts)
|
|
777
|
-
|
|
778
|
-
## Inputs and outputs
|
|
779
|
-
|
|
780
|
-
Pass images, documents, or an output schema in the options for the turn that should use them. Both `run()` and `session.stream()` accept these options.
|
|
781
|
-
|
|
782
|
-
### Images
|
|
783
|
-
|
|
784
|
-
```ts
|
|
785
|
-
const result = await run('Describe this image.', {
|
|
786
|
-
images: [
|
|
787
|
-
{
|
|
788
|
-
type: 'base64',
|
|
789
|
-
data: base64Png,
|
|
790
|
-
mediaType: 'image/png',
|
|
791
|
-
},
|
|
792
|
-
],
|
|
793
|
-
});
|
|
794
|
-
```
|
|
795
|
-
|
|
796
|
-
`data` contains the base64-encoded image bytes. Supported media types are `image/jpeg`, `image/png`, `image/gif`, and `image/webp`.
|
|
797
|
-
|
|
798
|
-
Runnable example: [`examples/node/image-attachment.ts`](../examples/node/image-attachment.ts)
|
|
799
|
-
|
|
800
|
-
### Documents
|
|
801
|
-
|
|
802
|
-
```ts
|
|
803
|
-
const result = await run('Summarize this document.', {
|
|
804
|
-
files: [
|
|
805
|
-
{
|
|
806
|
-
type: 'text',
|
|
807
|
-
mediaType: 'text/plain',
|
|
808
|
-
data: report,
|
|
809
|
-
name: 'report.txt',
|
|
810
|
-
},
|
|
811
|
-
],
|
|
812
|
-
});
|
|
813
|
-
```
|
|
814
|
-
|
|
815
|
-
Document inputs support:
|
|
816
|
-
|
|
817
|
-
| Source | `type` | `mediaType` | `data` |
|
|
818
|
-
| ------------ | -------- | ----------------- | ----------------------------- |
|
|
819
|
-
| Plain text | `text` | `text/plain` | The document text |
|
|
820
|
-
| PDF document | `base64` | `application/pdf` | Base64-encoded PDF file bytes |
|
|
821
|
-
|
|
822
|
-
`name` is optional for both forms. Attach content through `data`; a filesystem path by itself is not a document upload.
|
|
823
|
-
|
|
824
|
-
Runnable example: [`examples/node/document-input.ts`](../examples/node/document-input.ts)
|
|
825
|
-
|
|
826
|
-
### Structured output
|
|
827
|
-
|
|
828
|
-
Use `outputFormat` when another system needs a JSON object that follows a schema.
|
|
829
|
-
|
|
830
|
-
```ts
|
|
831
|
-
import { OutputFormatType, run } from '@factory/droid-sdk/node';
|
|
832
|
-
|
|
833
|
-
const result = await run('Return the repository name and test command.', {
|
|
834
|
-
outputFormat: {
|
|
835
|
-
type: OutputFormatType.JsonSchema,
|
|
836
|
-
schema: {
|
|
837
|
-
type: 'object',
|
|
838
|
-
properties: {
|
|
839
|
-
repository: { type: 'string' },
|
|
840
|
-
testCommand: { type: 'string' },
|
|
841
|
-
},
|
|
842
|
-
required: ['repository', 'testCommand'],
|
|
843
|
-
additionalProperties: false,
|
|
844
|
-
},
|
|
845
|
-
},
|
|
846
|
-
});
|
|
847
|
-
|
|
848
|
-
if (!result.success) {
|
|
849
|
-
throw new Error(
|
|
850
|
-
result.structuredOutputError?.message ??
|
|
851
|
-
result.error?.message ??
|
|
852
|
-
`Structured output failed (${result.subtype}).`
|
|
853
|
-
);
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
if (!result.structuredOutput) {
|
|
857
|
-
throw new Error('No structured output was returned.');
|
|
858
|
-
}
|
|
859
|
-
|
|
860
|
-
console.log(JSON.stringify(result.structuredOutput, null, 2));
|
|
861
|
-
```
|
|
862
|
-
|
|
863
|
-
Invalid or missing schema output normally produces a failed result with subtype `error_structured_output`; `structuredOutputError` contains the available validation details.
|
|
864
|
-
|
|
865
|
-
`structuredOutput` is typed as `unknown`, because a JSON Schema does not provide a TypeScript runtime validator. Check that it is present and validate or narrow its shape before reading fields or passing it to another system. A successful result can still omit structured output, so do not use `result.success` as the only check.
|
|
866
|
-
|
|
867
|
-
Runnable example: [`examples/node/structured-output.ts`](../examples/node/structured-output.ts)
|
|
868
|
-
|
|
869
|
-
## Permissions and user input
|
|
870
|
-
|
|
871
|
-
### Autonomy
|
|
872
|
-
|
|
873
|
-
Autonomy controls which actions require approval in Auto mode.
|
|
874
|
-
|
|
875
|
-
```ts
|
|
876
|
-
import { AutonomyLevel } from '@factory/droid-sdk/node';
|
|
877
|
-
|
|
878
|
-
const session = await createSession({
|
|
879
|
-
autonomyLevel: AutonomyLevel.Off,
|
|
880
|
-
});
|
|
881
|
-
```
|
|
882
|
-
|
|
883
|
-
| Level | Behavior |
|
|
884
|
-
| -------- | --------------------------------------- |
|
|
885
|
-
| `Off` | Ask before every action |
|
|
886
|
-
| `Low` | Allow file edits and read-only commands |
|
|
887
|
-
| `Medium` | Allow reversible commands |
|
|
888
|
-
| `High` | Allow commands without approval prompts |
|
|
889
|
-
|
|
890
|
-
When omitted, Droid uses the configured default. Autonomy does not select Auto or Spec mode; `interactionMode` does that.
|
|
891
|
-
|
|
892
|
-
### Permission handler
|
|
893
|
-
|
|
894
|
-
Use `permissionHandler` to approve or reject requests that reach the client.
|
|
895
|
-
The handler may be synchronous or asynchronous.
|
|
896
|
-
|
|
897
|
-
```ts
|
|
898
|
-
import {
|
|
899
|
-
ToolConfirmationOutcome,
|
|
900
|
-
ToolConfirmationType,
|
|
901
|
-
} from '@factory/droid-sdk/node';
|
|
902
|
-
|
|
903
|
-
const session = await createSession({
|
|
904
|
-
autonomyLevel: AutonomyLevel.Off,
|
|
905
|
-
permissionHandler({ toolUses, options }) {
|
|
906
|
-
const createsOnly =
|
|
907
|
-
toolUses.length > 0 &&
|
|
908
|
-
toolUses.every((use) => use.details.type === ToolConfirmationType.Create);
|
|
909
|
-
|
|
910
|
-
const desired = createsOnly
|
|
911
|
-
? ToolConfirmationOutcome.ProceedOnce
|
|
912
|
-
: ToolConfirmationOutcome.Cancel;
|
|
913
|
-
|
|
914
|
-
const offered = options.find((option) => option.value === desired);
|
|
915
|
-
if (!offered) throw new Error(`Outcome not offered: ${desired}`);
|
|
916
|
-
|
|
917
|
-
return desired;
|
|
918
|
-
},
|
|
919
|
-
});
|
|
920
|
-
```
|
|
921
|
-
|
|
922
|
-
`toolUses` describes the pending actions. `options` contains the outcomes available for this request. Return one of those values. Common outcomes are:
|
|
923
|
-
|
|
924
|
-
| Outcome | Effect |
|
|
925
|
-
| --------------- | --------------------------------------- |
|
|
926
|
-
| `ProceedOnce` | Approve this request |
|
|
927
|
-
| `ProceedAlways` | Approve and persist the applicable rule |
|
|
928
|
-
| `Cancel` | Reject the request |
|
|
929
|
-
|
|
930
|
-
The available outcomes vary by request. Returning an unavailable value, throwing from the handler, or omitting the handler cancels the request.
|
|
931
|
-
|
|
932
|
-
Runnable example:
|
|
933
|
-
[`examples/node/permission-handler.ts`](../examples/node/permission-handler.ts)
|
|
934
|
-
|
|
935
|
-
### AskUser handler
|
|
936
|
-
|
|
937
|
-
`askUserHandler` answers questions Droid asks during a turn. Connect it to a form, prompt, or other application UI.
|
|
938
|
-
|
|
939
|
-
```ts
|
|
940
|
-
const result = await run('Ask me which environment to deploy.', {
|
|
941
|
-
askUserHandler({ questions }) {
|
|
942
|
-
return {
|
|
943
|
-
answers: questions.map((question) => ({
|
|
944
|
-
index: question.index,
|
|
945
|
-
question: question.question,
|
|
946
|
-
answer: question.options[0] ?? 'none',
|
|
947
|
-
})),
|
|
948
|
-
};
|
|
949
|
-
},
|
|
950
|
-
});
|
|
951
|
-
```
|
|
952
|
-
|
|
953
|
-
Each answer must copy the question's `index` and `question`. To decline the questionnaire:
|
|
954
|
-
|
|
955
|
-
```ts
|
|
956
|
-
return { cancelled: true, answers: [] };
|
|
957
|
-
```
|
|
958
|
-
|
|
959
|
-
Without a handler, AskUser requests are declined.
|
|
960
|
-
|
|
961
|
-
Runnable example:
|
|
962
|
-
[`examples/node/ask-user-elicitation.ts`](../examples/node/ask-user-elicitation.ts)
|
|
963
|
-
|
|
964
|
-
### Tool controls
|
|
965
|
-
|
|
966
|
-
Disable tools when creating, resuming, or updating a session:
|
|
967
|
-
|
|
968
|
-
```ts
|
|
969
|
-
const session = await createSession({
|
|
970
|
-
disabledToolIds: ['Execute'],
|
|
971
|
-
});
|
|
972
|
-
|
|
973
|
-
await session.updateSettings({
|
|
974
|
-
disabledToolIds: ['Execute', 'Edit'],
|
|
975
|
-
});
|
|
976
|
-
```
|
|
977
|
-
|
|
978
|
-
Tool IDs are strings. Use `listTools()` to inspect the tools available to the current session.
|
|
979
|
-
|
|
980
|
-
```ts
|
|
981
|
-
const tools = await session.listTools();
|
|
982
|
-
|
|
983
|
-
for (const tool of tools) {
|
|
984
|
-
console.log(tool.id, tool.allowed);
|
|
985
|
-
}
|
|
986
|
-
```
|
|
987
|
-
|
|
988
|
-
The public SDK provides subtractive `disabledToolIds`. It does not expose a
|
|
989
|
-
restrictive allowlist.
|
|
990
|
-
|
|
991
|
-
Runnable example: [`examples/node/tool-controls.ts`](../examples/node/tool-controls.ts)
|
|
992
|
-
|
|
993
|
-
## Tools and extensions
|
|
994
|
-
|
|
995
|
-
Use the extension that matches the job:
|
|
996
|
-
|
|
997
|
-
| Extension | Use it for |
|
|
998
|
-
| -------------------- | ------------------------------------------------ |
|
|
999
|
-
| Skills | Reusable instructions and supporting files |
|
|
1000
|
-
| SDK MCP tools | In-process TypeScript functions exposed to Droid |
|
|
1001
|
-
| External MCP servers | Tools provided by another process or service |
|
|
1002
|
-
| Hooks | Commands that run at defined lifecycle events |
|
|
1003
|
-
|
|
1004
|
-
### Skills
|
|
1005
|
-
|
|
1006
|
-
List the skills available to the session:
|
|
1007
|
-
|
|
1008
|
-
```ts
|
|
1009
|
-
const { skills } = await session.listSkills();
|
|
1010
|
-
|
|
1011
|
-
for (const skill of skills) {
|
|
1012
|
-
console.log(skill.name, skill.enabled);
|
|
1013
|
-
}
|
|
1014
|
-
```
|
|
1015
|
-
|
|
1016
|
-
Enable or disable a skill at the user or project level:
|
|
1017
|
-
|
|
1018
|
-
```ts
|
|
1019
|
-
import { SettingsLevel } from '@factory/droid-sdk/node';
|
|
1020
|
-
|
|
1021
|
-
await session.setSkillDisabled({
|
|
1022
|
-
skillName: 'skill-name',
|
|
1023
|
-
disabled: true,
|
|
1024
|
-
settingsLevel: SettingsLevel.Project,
|
|
1025
|
-
});
|
|
1026
|
-
```
|
|
1027
|
-
|
|
1028
|
-
Skills can come from project, personal, built-in, or automation settings.
|
|
1029
|
-
|
|
1030
|
-
Runnable example: [`examples/node/skills.ts`](../examples/node/skills.ts)
|
|
1031
|
-
|
|
1032
|
-
### SDK MCP tools
|
|
1033
|
-
|
|
1034
|
-
Use `tool()` to define an in-process TypeScript function with a Zod input schema.
|
|
1035
|
-
|
|
1036
|
-
```ts
|
|
1037
|
-
import { z } from 'zod';
|
|
1038
|
-
import {
|
|
1039
|
-
createSdkMcpServer,
|
|
1040
|
-
createSession,
|
|
1041
|
-
tool,
|
|
1042
|
-
} from '@factory/droid-sdk/node';
|
|
1043
|
-
|
|
1044
|
-
const server = createSdkMcpServer({
|
|
1045
|
-
name: 'review-tools',
|
|
1046
|
-
tools: [
|
|
1047
|
-
tool(
|
|
1048
|
-
'lookup_owner',
|
|
1049
|
-
'Returns the owner of a file',
|
|
1050
|
-
{ path: z.string() },
|
|
1051
|
-
({ path }) => `Owner for ${path}: platform-team`
|
|
1052
|
-
),
|
|
1053
|
-
],
|
|
1054
|
-
});
|
|
1055
|
-
|
|
1056
|
-
const session = await createSession({
|
|
1057
|
-
mcpServers: [server],
|
|
1058
|
-
});
|
|
1059
|
-
|
|
1060
|
-
try {
|
|
1061
|
-
for await (const _message of session.stream(
|
|
1062
|
-
'Find the owner of src/index.ts.'
|
|
1063
|
-
)) {
|
|
1064
|
-
// Consume messages.
|
|
1065
|
-
}
|
|
1066
|
-
} finally {
|
|
1067
|
-
await session.close();
|
|
1068
|
-
}
|
|
1069
|
-
```
|
|
1070
|
-
|
|
1071
|
-
The SDK starts an authenticated loopback MCP server and closes it with the session.
|
|
1072
|
-
Tool calls still follow the session's autonomy and permission rules.
|
|
1073
|
-
Attach SDK MCP servers again when resuming a saved session because they are runtime objects, not persisted session data.
|
|
1074
|
-
|
|
1075
|
-
Runnable example: [`examples/node/sdk-mcp-tool.ts`](../examples/node/sdk-mcp-tool.ts)
|
|
1076
|
-
|
|
1077
|
-
### External MCP servers
|
|
1078
|
-
|
|
1079
|
-
Pass external MCP configuration when creating or resuming a session:
|
|
1080
|
-
|
|
1081
|
-
```ts
|
|
1082
|
-
const session = await createSession({
|
|
1083
|
-
mcpServers: [
|
|
1084
|
-
{
|
|
1085
|
-
name: 'docs',
|
|
1086
|
-
type: 'http',
|
|
1087
|
-
url: 'https://example.com/mcp',
|
|
1088
|
-
headers: [],
|
|
1089
|
-
},
|
|
1090
|
-
],
|
|
1091
|
-
});
|
|
1092
|
-
```
|
|
1093
|
-
|
|
1094
|
-
Supported session configuration:
|
|
1095
|
-
|
|
1096
|
-
| Transport | `type` field | Required configuration |
|
|
1097
|
-
| ------------- | ------------ | ---------------------- |
|
|
1098
|
-
| Local process | Omit | `command` and `args` |
|
|
1099
|
-
| HTTP | `http` | `url` and `headers` |
|
|
1100
|
-
| SSE | `sse` | `url` and `headers` |
|
|
1101
|
-
|
|
1102
|
-
Inspect server status and discovered tools:
|
|
1103
|
-
|
|
1104
|
-
```ts
|
|
1105
|
-
try {
|
|
1106
|
-
const { servers, summary } = await session.listMcpServers();
|
|
1107
|
-
const tools = await session.listMcpTools();
|
|
1108
|
-
|
|
1109
|
-
console.log(servers, summary, tools);
|
|
1110
|
-
} finally {
|
|
1111
|
-
await session.close();
|
|
1112
|
-
}
|
|
1113
|
-
```
|
|
1114
|
-
|
|
1115
|
-
`addMcpServer()`, `removeMcpServer()`, and `toggleMcpServer()` change the user's Droid configuration.
|
|
1116
|
-
Use `authenticateMcpServer({ serverName })` when a server requires authentication.
|
|
1117
|
-
|
|
1118
|
-
Runnable example: [`examples/node/external-mcp.ts`](../examples/node/external-mcp.ts)
|
|
1119
|
-
|
|
1120
|
-
### Hooks
|
|
1121
|
-
|
|
1122
|
-
Hooks run shell commands at defined lifecycle events.
|
|
1123
|
-
Configure them in `.factory/hooks.json`:
|
|
1124
|
-
|
|
1125
|
-
```json
|
|
1126
|
-
{
|
|
1127
|
-
"PreToolUse": [
|
|
1128
|
-
{
|
|
1129
|
-
"matcher": "Execute",
|
|
1130
|
-
"hooks": [
|
|
1131
|
-
{
|
|
1132
|
-
"type": "command",
|
|
1133
|
-
"command": "echo before Execute"
|
|
1134
|
-
}
|
|
1135
|
-
]
|
|
1136
|
-
}
|
|
1137
|
-
]
|
|
1138
|
-
}
|
|
1139
|
-
```
|
|
1140
|
-
|
|
1141
|
-
Hooks can run before or after tools, when prompts are submitted, when notifications arrive, during compaction, and when sessions or subagents stop.
|
|
1142
|
-
|
|
1143
|
-
Hook events are available in the stream:
|
|
1144
|
-
|
|
1145
|
-
```ts
|
|
1146
|
-
for await (const message of session.stream('Run the tests.')) {
|
|
1147
|
-
if (message.type === DroidMessageType.Hook) {
|
|
1148
|
-
console.log(message.status, message.command);
|
|
1149
|
-
}
|
|
1150
|
-
}
|
|
1151
|
-
```
|
|
1152
|
-
|
|
1153
|
-
The SDK exposes hook schemas and stream events, but it does not provide a programmatic hook-registration API.
|
|
1154
|
-
|
|
1155
|
-
Runnable example: [`examples/node/hook-execution.ts`](../examples/node/hook-execution.ts)
|
|
1156
|
-
|
|
1157
|
-
## Session lifecycle
|
|
1158
|
-
|
|
1159
|
-
### Replacement handles
|
|
1160
|
-
|
|
1161
|
-
`fork()` returns a ready successor handle. `compact()` and `rewind()` return
|
|
1162
|
-
outcome objects containing a ready successor in `session`. Each operation
|
|
1163
|
-
retires its source wrapper.
|
|
1164
|
-
|
|
1165
|
-
```ts
|
|
1166
|
-
const forked = await session.fork();
|
|
1167
|
-
|
|
1168
|
-
const { session: compacted, removedCount } = await forked.compact();
|
|
1169
|
-
|
|
1170
|
-
const {
|
|
1171
|
-
session: rewound,
|
|
1172
|
-
restoredCount,
|
|
1173
|
-
deletedCount,
|
|
1174
|
-
} = await compacted.rewind({
|
|
1175
|
-
messageId,
|
|
1176
|
-
filesToRestore,
|
|
1177
|
-
filesToDelete,
|
|
1178
|
-
forkTitle: 'Before the failed change',
|
|
1179
|
-
});
|
|
1180
|
-
```
|
|
1181
|
-
|
|
1182
|
-
After a successful replacement, active operations on the source wrapper throw
|
|
1183
|
-
`SessionReplacedError`. Its `id`, `settings`, and `cwd` remain readable, and
|
|
1184
|
-
`close()` is a no-op. The persisted source session can still be loaded later
|
|
1185
|
-
with `resumeSession(sourceId)`.
|
|
1186
|
-
|
|
1187
|
-
Do not replace a session while it has an active stream.
|
|
1188
|
-
|
|
1189
|
-
## Spec mode
|
|
1190
|
-
|
|
1191
|
-
Spec mode lets Droid inspect the codebase and propose a plan without changing files. Start a session in Spec mode or switch an existing session with `enterSpecMode()`:
|
|
1192
|
-
|
|
1193
|
-
```ts
|
|
1194
|
-
const session = await createSession({
|
|
1195
|
-
interactionMode: DroidInteractionMode.Spec,
|
|
1196
|
-
});
|
|
1197
|
-
|
|
1198
|
-
// Or switch an existing Auto session.
|
|
1199
|
-
await session.enterSpecMode();
|
|
1200
|
-
```
|
|
1201
|
-
|
|
1202
|
-
`enterSpecMode()` can also set the model used for planning:
|
|
1203
|
-
|
|
1204
|
-
```ts
|
|
1205
|
-
await session.enterSpecMode({
|
|
1206
|
-
specModeModelId: 'model-id',
|
|
1207
|
-
specModeReasoningEffort: ReasoningEffort.High,
|
|
1208
|
-
});
|
|
1209
|
-
```
|
|
1210
|
-
|
|
1211
|
-
### Leave without approving a plan
|
|
1212
|
-
|
|
1213
|
-
Call `exitSpecMode()` to return the session to Auto mode without approving a plan or starting implementation:
|
|
1214
|
-
|
|
1215
|
-
```ts
|
|
1216
|
-
await session.enterSpecMode();
|
|
1217
|
-
|
|
1218
|
-
// Return to Auto mode without approving or implementing the plan.
|
|
1219
|
-
await session.exitSpecMode();
|
|
1220
|
-
```
|
|
1221
|
-
|
|
1222
|
-
`exitSpecMode()` changes the interaction mode only. It does not select a `ToolConfirmationOutcome` or approve an `ExitSpecMode` permission request.
|
|
1223
|
-
|
|
1224
|
-
The method is available on Node `DroidSession` handles returned by `createSession()`, `resumeSession()`, and replacement operations such as `fork()`, `compact()`, and `rewind()`. Daemon clients continue to change the mode with `droid.sessions.updateSettings()`.
|
|
1225
|
-
|
|
1226
|
-
### Approve a plan
|
|
1227
|
-
|
|
1228
|
-
When the plan is ready, Droid sends an `ExitSpecMode` permission request. Its
|
|
1229
|
-
details contain the plan. Unlike calling `exitSpecMode()`, approving it with `ProceedOnce` accepts the completed plan, returns to Auto mode, and continues implementation in the same session:
|
|
1230
|
-
|
|
1231
|
-
```ts
|
|
1232
|
-
import {
|
|
1233
|
-
AutonomyLevel,
|
|
1234
|
-
createSession,
|
|
1235
|
-
DroidInteractionMode,
|
|
1236
|
-
DroidMessageType,
|
|
1237
|
-
ToolConfirmationOutcome,
|
|
1238
|
-
ToolConfirmationType,
|
|
1239
|
-
} from '@factory/droid-sdk/node';
|
|
1240
|
-
|
|
1241
|
-
const session = await createSession({
|
|
1242
|
-
interactionMode: DroidInteractionMode.Auto,
|
|
1243
|
-
autonomyLevel: AutonomyLevel.Low,
|
|
1244
|
-
permissionHandler({ toolUses }) {
|
|
1245
|
-
const request = toolUses.find(
|
|
1246
|
-
({ details }) => details.type === ToolConfirmationType.ExitSpecMode
|
|
1247
|
-
);
|
|
1248
|
-
|
|
1249
|
-
if (request?.details.type === ToolConfirmationType.ExitSpecMode) {
|
|
1250
|
-
console.log(request.details.plan);
|
|
1251
|
-
|
|
1252
|
-
return ToolConfirmationOutcome.ProceedOnce;
|
|
1253
|
-
}
|
|
1254
|
-
|
|
1255
|
-
return ToolConfirmationOutcome.Cancel;
|
|
1256
|
-
},
|
|
1257
|
-
});
|
|
1258
|
-
|
|
1259
|
-
try {
|
|
1260
|
-
await session.enterSpecMode();
|
|
1261
|
-
|
|
1262
|
-
for await (const message of session.stream('Plan and update README.md.')) {
|
|
1263
|
-
if (message.type === DroidMessageType.Result) {
|
|
1264
|
-
console.log(message.subtype);
|
|
1265
|
-
}
|
|
1266
|
-
}
|
|
1267
|
-
} finally {
|
|
1268
|
-
await session.close();
|
|
1269
|
-
}
|
|
1270
|
-
```
|
|
1271
|
-
|
|
1272
|
-
The handler can be asynchronous. An interactive application should display the plan and wait for the user's decision before returning.
|
|
1273
|
-
|
|
1274
|
-
Return `Cancel` to reject the plan. The turn ends with an `interrupted` result, and the session remains available for another prompt.
|
|
1275
|
-
|
|
1276
|
-
Some `ExitSpecMode` requests offer `ProceedNewSession` variants. Return one of those offered values to hand implementation to a new session. Return only values present in the request's `options`.
|
|
1277
|
-
|
|
1278
|
-
Runnable example:
|
|
1279
|
-
[`examples/node/enter-spec-mode.ts`](../examples/node/enter-spec-mode.ts)
|
|
1280
|
-
|
|
1281
|
-
## Operations
|
|
1282
|
-
|
|
1283
|
-
### Observability
|
|
1284
|
-
|
|
1285
|
-
```ts
|
|
1286
|
-
import { run } from '@factory/droid-sdk/node';
|
|
1287
|
-
|
|
1288
|
-
const result = await run('Check the repository status.', {
|
|
1289
|
-
observability: {
|
|
1290
|
-
logger: {
|
|
1291
|
-
log(event) {
|
|
1292
|
-
console.log(event.level, event.name, event.attributes);
|
|
1293
|
-
},
|
|
1294
|
-
},
|
|
1295
|
-
},
|
|
1296
|
-
});
|
|
1297
|
-
|
|
1298
|
-
if (!result.success) {
|
|
1299
|
-
throw new Error(result.error?.message ?? `Run failed: ${result.subtype}`);
|
|
1300
|
-
}
|
|
1301
|
-
```
|
|
1302
|
-
|
|
1303
|
-
Pass `logger`, `metrics`, or `tracing` sinks through `observability`.
|
|
1304
|
-
Sink methods must not throw.
|
|
1305
|
-
The SDK excludes prompts, messages, tool inputs, raw output, and stack traces from observability events.
|
|
1306
|
-
Process startup emits telemetry before the first turn, and `close()` emits a request log.
|
|
1307
|
-
To verify turn-specific logs, snapshot the count after creating the session and check it before closing.
|
|
1308
|
-
|
|
1309
|
-
Runnable example:
|
|
1310
|
-
[`examples/node/observability.ts`](../examples/node/observability.ts)
|
|
1311
|
-
|
|
1312
|
-
### Low-level APIs
|
|
1313
|
-
|
|
1314
|
-
Use the high-level APIs unless your application owns the transport or protocol lifecycle.
|
|
1315
|
-
|
|
1316
|
-
| Need | Preferred API | Low-level alternative |
|
|
1317
|
-
| ---------------------------- | ------------------ | --------------------- |
|
|
1318
|
-
| Run a session | `createSession()` | `DroidClient` |
|
|
1319
|
-
| Consume typed session events | `session.stream()` | Raw notifications |
|
|
1320
|
-
|
|
1321
|
-
The `/node` entrypoint exports `DroidClient` for direct JSON-RPC integrations.
|
|
1322
|
-
Low-level methods return response envelopes, so successful payloads are under `response.result`.
|
|
1323
|
-
|
|
1324
|
-
Use `onNotification()` only when `session.stream()` does not expose the event you need:
|
|
1325
|
-
|
|
1326
|
-
```ts
|
|
1327
|
-
const unsubscribe = session.onNotification(
|
|
1328
|
-
(notification) => console.log(notification.type),
|
|
1329
|
-
{ type: 'settings_updated' }
|
|
1330
|
-
);
|
|
1331
|
-
|
|
1332
|
-
unsubscribe();
|
|
1333
|
-
```
|
|
1334
|
-
|
|
1335
|
-
## API reference
|
|
1336
|
-
|
|
1337
|
-
### Entrypoint
|
|
1338
|
-
|
|
1339
|
-
Import functions, classes, enums, and types from `@factory/droid-sdk/node`.
|
|
1340
|
-
|
|
1341
|
-
### Functions
|
|
1342
|
-
|
|
1343
|
-
| API | Returns |
|
|
1344
|
-
| ------------------------------------ | ---------------------------- |
|
|
1345
|
-
| `run(prompt, options?)` | `Promise<DroidResult>` |
|
|
1346
|
-
| `createSession(options?)` | `Promise<DroidSession>` |
|
|
1347
|
-
| `resumeSession(sessionId, options?)` | `Promise<DroidSession>` |
|
|
1348
|
-
| `listSessions(options?)` | `Promise<SessionMetadata[]>` |
|
|
1349
|
-
| `listModels(options?)` | `Promise<ModelInfo[]>` |
|
|
1350
|
-
| `createSdkMcpServer(options)` | `SdkMcpServer` |
|
|
1351
|
-
| `tool(...)` | `DroidTool` |
|
|
1352
|
-
|
|
1353
|
-
### `DroidSession`
|
|
1354
|
-
|
|
1355
|
-
| Member | Purpose |
|
|
1356
|
-
| ------------------------- | -------------------------------------------- |
|
|
1357
|
-
| `id` | Session ID |
|
|
1358
|
-
| `cwd` | Live working directory |
|
|
1359
|
-
| `settings` | Live read-only settings |
|
|
1360
|
-
| `stream()` | Run one turn |
|
|
1361
|
-
| `interrupt()` | Stop the active turn |
|
|
1362
|
-
| `updateSettings()` | Update session settings |
|
|
1363
|
-
| `enterSpecMode()` | Change to spec mode |
|
|
1364
|
-
| `exitSpecMode()` | Return to Auto mode without approving a plan |
|
|
1365
|
-
| `listTools()` | List normalized tools |
|
|
1366
|
-
| `listSkills()` | List skills |
|
|
1367
|
-
| `setSkillDisabled()` | Enable or disable a skill |
|
|
1368
|
-
| `addMcpServer()` | Add an MCP server |
|
|
1369
|
-
| `removeMcpServer()` | Remove an MCP server |
|
|
1370
|
-
| `toggleMcpServer()` | Enable or disable an MCP server |
|
|
1371
|
-
| `listMcpServers()` | List MCP servers |
|
|
1372
|
-
| `listMcpTools()` | List MCP tools |
|
|
1373
|
-
| `authenticateMcpServer()` | Start MCP authentication |
|
|
1374
|
-
| `getContextStats()` | Read context usage |
|
|
1375
|
-
| `getRewindInfo()` | Inspect rewindable file changes |
|
|
1376
|
-
| `rewind()` | Create a rewound successor |
|
|
1377
|
-
| `compact()` | Create a compacted successor |
|
|
1378
|
-
| `fork()` | Create a forked successor |
|
|
1379
|
-
| `rename()` | Change the session title |
|
|
1380
|
-
| `onNotification()` | Subscribe to raw notifications |
|
|
1381
|
-
| `close()` | Close the session and owned resources |
|
|
1382
|
-
|
|
1383
|
-
### Stream and model types
|
|
1384
|
-
|
|
1385
|
-
| Type | Purpose |
|
|
1386
|
-
| -------------------- | ------------------------------------------------- |
|
|
1387
|
-
| `DroidStreamMessage` | Complete messages returned by the default stream |
|
|
1388
|
-
| `DroidStreamEvent` | Complete messages plus partial events |
|
|
1389
|
-
| `DroidResult` | Terminal result returned by `run()` |
|
|
1390
|
-
| `DroidMessageType` | Runtime constants for narrowing stream messages |
|
|
1391
|
-
| `TokenUsage` | Token counts and optional Factory Service Credits |
|
|
1392
|
-
| `ModelInfo` | Model catalog entry returned by discovery APIs |
|
|
1393
|
-
|
|
1394
|
-
`session.stream()` yields `DroidStreamMessage` by default and `DroidStreamEvent` when `includePartialMessages` is `true`.
|
|
1395
|
-
|
|
1396
|
-
### Result states
|
|
1397
|
-
|
|
1398
|
-
| Subtype | `success` | `interrupted` | Meaning |
|
|
1399
|
-
| ------------------------- | --------- | ------------- | ------------------------- |
|
|
1400
|
-
| `success` | `true` | `false` | Turn completed |
|
|
1401
|
-
| `interrupted` | `false` | `true` | Turn was stopped |
|
|
1402
|
-
| `error_during_execution` | `false` | `false` | Runtime failure |
|
|
1403
|
-
| `error_structured_output` | `false` | `false` | Structured-output failure |
|
|
1404
|
-
|
|
1405
|
-
Every result includes `sessionId`, `durationMs`, `tokenUsage`, `messages`, `text`, and `turnCount`.
|
|
1406
|
-
Check `success` before using successful output.
|
|
1407
|
-
|
|
1408
|
-
### Main enums
|
|
1409
|
-
|
|
1410
|
-
| Enum | Values |
|
|
1411
|
-
| ---------------------- | -------------------------------------------------------------------------------- |
|
|
1412
|
-
| `AutonomyLevel` | `Off`, `Low`, `Medium`, `High` |
|
|
1413
|
-
| `DroidInteractionMode` | `Auto`, `Spec` |
|
|
1414
|
-
| `ReasoningEffort` | `None`, `Dynamic`, `Off`, `Minimal`, `Low`, `Medium`, `High`, `ExtraHigh`, `Max` |
|
|
1415
|
-
| `OutputFormatType` | `JsonSchema` |
|
|
1416
|
-
|
|
1417
|
-
Model IDs and tool IDs are strings rather than closed enums.
|
|
1418
|
-
|
|
1419
|
-
### Main errors
|
|
1420
|
-
|
|
1421
|
-
| Error | Meaning |
|
|
1422
|
-
| ------------------------- | --------------------------------------------- |
|
|
1423
|
-
| `ConcurrentStreamError` | A session handle already has an active stream |
|
|
1424
|
-
| `SessionReplacedError` | A source wrapper was replaced |
|
|
1425
|
-
| `SessionReplacementError` | Successor loading or rollback failed |
|
|
1426
|
-
| `DroidClientError` | Base client error |
|
|
1427
|
-
| `ConnectionError` | Droid process connection failed |
|
|
1428
|
-
| `TimeoutError` | A request timed out |
|
|
1429
|
-
| `ProtocolError` | Protocol or API response failed |
|
|
1430
|
-
| `SessionError` | Base session error |
|
|
1431
|
-
| `SessionNotFoundError` | Saved session was not found |
|
|
1432
|
-
| `InvalidSessionCwdError` | Saved working directory is invalid |
|
|
1433
|
-
| `ProcessExitError` | Droid subprocess exited unexpectedly |
|
|
1434
|
-
|
|
1435
|
-
## Known limitations
|
|
1436
|
-
|
|
1437
|
-
- New-session spec handoff IDs require raw notification inspection.
|