@factory/droid-sdk 0.2.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.
Files changed (41) hide show
  1. package/README.md +214 -82
  2. package/dist/index.cjs +2345 -692
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.d.cts +2570 -232
  5. package/dist/index.d.ts +2570 -232
  6. package/dist/index.js +2298 -697
  7. package/dist/index.js.map +1 -1
  8. package/docs/daemon-usage-guide.md +544 -0
  9. package/docs/sdk-usage-guide.md +748 -0
  10. package/examples/abort-session-stream.ts +23 -56
  11. package/examples/daemon-multi-session.ts +67 -0
  12. package/examples/droid-dev-structured-output.ts +5 -5
  13. package/examples/fork-session.ts +33 -7
  14. package/examples/hook-execution.ts +68 -0
  15. package/examples/init-metadata.ts +14 -66
  16. package/examples/interrupt-session.ts +23 -55
  17. package/examples/list-sessions.ts +9 -55
  18. package/examples/multi-turn-session.ts +27 -54
  19. package/examples/permission-handler.ts +27 -84
  20. package/examples/readme-structured-output.ts +26 -0
  21. package/examples/result-metadata.ts +2 -1
  22. package/examples/run.ts +2 -1
  23. package/examples/sdk-mcp-tool.ts +14 -8
  24. package/examples/session-stream.ts +57 -0
  25. package/examples/spec-mode-new-session.ts +39 -99
  26. package/examples/spec-mode-same-session.ts +50 -111
  27. package/examples/structured-output.ts +17 -10
  28. package/examples/test-compact.ts +9 -4
  29. package/examples/test-rewind.ts +49 -117
  30. package/examples/tool-controls.ts +23 -55
  31. package/package.json +3 -1
  32. package/docs/examples/init-metadata.md +0 -79
  33. package/docs/examples/list-sessions.md +0 -64
  34. package/docs/examples/multi-turn-session.md +0 -77
  35. package/docs/examples/one-shot-query.md +0 -73
  36. package/docs/examples/permission-handler.md +0 -102
  37. package/docs/examples/run.md +0 -52
  38. package/docs/examples/spec-mode.md +0 -101
  39. package/docs/examples/tool-controls.md +0 -90
  40. package/docs/typescript-sdk-reference.md +0 -372
  41. package/examples/simple-query.ts +0 -53
@@ -1,73 +0,0 @@
1
- # Example: one-shot query
2
-
3
- Use this when you want a single prompt and want to stream output as it arrives.
4
-
5
- ## What this example shows
6
-
7
- - starting a one-shot request with `query()`
8
- - streaming assistant text incrementally
9
- - observing tool activity and turn completion
10
-
11
- ## Key snippet: create the stream
12
-
13
- ```ts
14
- const stream = query({
15
- prompt: 'List all TypeScript files in this project',
16
- cwd: process.cwd(),
17
- });
18
- ```
19
-
20
- - `prompt` is the first user message
21
- - `cwd` is the directory Droid should operate in
22
-
23
- ## Key snippet: consume streamed messages
24
-
25
- ```ts
26
- import { DroidMessageType } from '@factory/droid-sdk';
27
-
28
- for await (const msg of stream) {
29
- if (msg.type === DroidMessageType.AssistantTextDelta) {
30
- process.stdout.write(msg.text);
31
- }
32
- }
33
- ```
34
-
35
- - `assistant_text_delta` gives you streaming text output
36
- - you can also handle `tool_use`, `tool_result`, and `turn_complete`
37
-
38
- ## Full script
39
-
40
- ```ts
41
- import { DroidMessageType, query } from '@factory/droid-sdk';
42
-
43
- async function main(): Promise<void> {
44
- const prompt = process.argv[2] ?? 'What files are in the current directory?';
45
-
46
- const stream = query({
47
- prompt,
48
- cwd: process.cwd(),
49
- });
50
-
51
- for await (const msg of stream) {
52
- switch (msg.type) {
53
- case DroidMessageType.AssistantTextDelta:
54
- process.stdout.write(msg.text);
55
- break;
56
- case DroidMessageType.ToolUse:
57
- console.log(`\n[Tool] ${msg.toolName}`);
58
- break;
59
- case DroidMessageType.ToolResult:
60
- console.log(`[Tool Result] ${msg.isError ? 'Error' : 'OK'}`);
61
- break;
62
- case DroidMessageType.TurnComplete:
63
- console.log('\n\n--- Turn complete ---');
64
- break;
65
- }
66
- }
67
- }
68
-
69
- main().catch((err: unknown) => {
70
- console.error('Error:', err);
71
- process.exit(1);
72
- });
73
- ```
@@ -1,102 +0,0 @@
1
- # Example: permission handler
2
-
3
- Use a `permissionHandler` when your app needs to inspect or approve tool calls.
4
-
5
- ## What this example shows
6
-
7
- - receiving tool confirmation requests
8
- - inspecting `params.toolUses`
9
- - approving each request with `ToolConfirmationOutcome.ProceedOnce`
10
-
11
- ## Key snippet: define the handler
12
-
13
- ```ts
14
- function permissionHandler(
15
- allowedFilePath: string,
16
- params: RequestPermissionRequestParams
17
- ): ToolConfirmationOutcome {
18
- const onlyAllowedCreate = params.toolUses.every(
19
- (item) =>
20
- item.details.type === ToolConfirmationType.Create &&
21
- item.details.filePath === allowedFilePath
22
- );
23
-
24
- return onlyAllowedCreate
25
- ? ToolConfirmationOutcome.ProceedOnce
26
- : ToolConfirmationOutcome.Cancel;
27
- }
28
- ```
29
-
30
- - `params.toolUses` describes the pending tool calls
31
- - `ProceedOnce` approves the current request only
32
-
33
- ## Key snippet: pass the handler to `query()`
34
-
35
- ```ts
36
- const stream = query({
37
- prompt: `Create a file called ${outputPath} with the text 'Hello, World!'`,
38
- cwd: process.cwd(),
39
- permissionHandler: (params) => permissionHandler(outputPath, params),
40
- });
41
- ```
42
-
43
- ## Full script
44
-
45
- ```ts
46
- import {
47
- DroidMessageType,
48
- query,
49
- ToolConfirmationOutcome,
50
- ToolConfirmationType,
51
- type RequestPermissionRequestParams,
52
- } from '@factory/droid-sdk';
53
- import { mkdtemp, rm } from 'node:fs/promises';
54
- import { tmpdir } from 'node:os';
55
- import { join } from 'node:path';
56
-
57
- function permissionHandler(
58
- allowedFilePath: string,
59
- params: RequestPermissionRequestParams
60
- ): ToolConfirmationOutcome {
61
- for (const item of params.toolUses) {
62
- console.log(`\n[Permission] Tool: ${item.toolUse.name}`);
63
- console.log(`Type: ${item.confirmationType}`);
64
- }
65
-
66
- const onlyAllowedCreate = params.toolUses.every(
67
- (item) =>
68
- item.details.type === ToolConfirmationType.Create &&
69
- item.details.filePath === allowedFilePath
70
- );
71
-
72
- return onlyAllowedCreate
73
- ? ToolConfirmationOutcome.ProceedOnce
74
- : ToolConfirmationOutcome.Cancel;
75
- }
76
-
77
- async function main(): Promise<void> {
78
- const tempDir = await mkdtemp(join(tmpdir(), 'droid-sdk-permission-'));
79
- const outputPath = join(tempDir, 'hello.txt');
80
-
81
- try {
82
- const stream = query({
83
- prompt: `Create a file called ${outputPath} with the text 'Hello, World!'`,
84
- cwd: process.cwd(),
85
- permissionHandler: (params) => permissionHandler(outputPath, params),
86
- });
87
-
88
- for await (const msg of stream) {
89
- if (msg.type === DroidMessageType.AssistantTextDelta) {
90
- process.stdout.write(msg.text);
91
- }
92
- }
93
- } finally {
94
- await rm(tempDir, { recursive: true, force: true });
95
- }
96
- }
97
-
98
- main().catch((err: unknown) => {
99
- console.error('Error:', err);
100
- process.exit(1);
101
- });
102
- ```
@@ -1,52 +0,0 @@
1
- # Example: one-shot run
2
-
3
- Use this when you want a single prompt and only need the final aggregated
4
- result.
5
-
6
- ## What this example shows
7
-
8
- - sending a one-shot request with `run()`
9
- - reading the final assistant text
10
- - inspecting collected messages and token usage
11
-
12
- ## Key snippet
13
-
14
- ```ts
15
- const result = await run('What files are in the current directory?', {
16
- cwd: process.cwd(),
17
- });
18
-
19
- console.log(result.text);
20
- ```
21
-
22
- `run()` creates a temporary session, sends the prompt, returns a
23
- `DroidResult`, and closes the session automatically.
24
-
25
- ## Full script
26
-
27
- ```ts
28
- import { run } from '@factory/droid-sdk';
29
-
30
- async function main(): Promise<void> {
31
- const text = process.argv.slice(2).join(' ') || 'What is 2 + 2?';
32
-
33
- const result = await run(text, {
34
- cwd: process.cwd(),
35
- });
36
-
37
- console.log(result.text);
38
- console.log(`Messages received: ${result.messages.length}`);
39
-
40
- if (result.tokenUsage) {
41
- console.log(
42
- `Tokens — input: ${result.tokenUsage.inputTokens}, ` +
43
- `output: ${result.tokenUsage.outputTokens}`
44
- );
45
- }
46
- }
47
-
48
- main().catch((err: unknown) => {
49
- console.error('Error:', err);
50
- process.exit(1);
51
- });
52
- ```
@@ -1,101 +0,0 @@
1
- # Example: spec mode approval flow
2
-
3
- Use spec mode when you want Droid to propose a plan first and only implement after approval.
4
-
5
- ## What this example shows
6
-
7
- - starting a query in `DroidInteractionMode.Spec`
8
- - detecting an `ExitSpecMode` confirmation request
9
- - choosing whether implementation stays in the same session or moves to a new one
10
-
11
- ## Key snippet: start in spec mode
12
-
13
- ```ts
14
- const stream = query({
15
- prompt,
16
- cwd: process.cwd(),
17
- interactionMode: DroidInteractionMode.Spec,
18
- specModeReasoningEffort: ReasoningEffort.High,
19
- permissionHandler(params) {
20
- return ToolConfirmationOutcome.ProceedOnce;
21
- },
22
- });
23
- ```
24
-
25
- ## Key snippet: detect the spec approval request
26
-
27
- ```ts
28
- const exitSpec = params.toolUses.find(
29
- (t) => t.confirmationType === ToolConfirmationType.ExitSpecMode
30
- );
31
- ```
32
-
33
- Choose the outcome you want:
34
-
35
- - `ToolConfirmationOutcome.ProceedOnce` keeps implementation in the same session
36
- - `ToolConfirmationOutcome.ProceedNewSessionHigh` hands implementation to a new session
37
-
38
- ## Full script
39
-
40
- ```ts
41
- import {
42
- DroidMessageType,
43
- DroidInteractionMode,
44
- query,
45
- ReasoningEffort,
46
- ToolConfirmationOutcome,
47
- ToolConfirmationType,
48
- } from '@factory/droid-sdk';
49
- import { mkdtemp, rm } from 'node:fs/promises';
50
- import { tmpdir } from 'node:os';
51
- import { join } from 'node:path';
52
-
53
- async function main(): Promise<void> {
54
- const tempDir = await mkdtemp(join(tmpdir(), 'droid-sdk-spec-'));
55
- const outputPath = join(tempDir, 'hello-from-droid.txt');
56
- const prompt =
57
- `Plan how to create a small ${outputPath} file containing the text ` +
58
- '"Hello from Droid". Keep the plan short and concrete.';
59
-
60
- try {
61
- const stream = query({
62
- prompt,
63
- cwd: process.cwd(),
64
- interactionMode: DroidInteractionMode.Spec,
65
- specModeReasoningEffort: ReasoningEffort.High,
66
- permissionHandler(params) {
67
- const exitSpec = params.toolUses.find(
68
- (item) => item.details.type === ToolConfirmationType.ExitSpecMode
69
- );
70
-
71
- if (exitSpec) {
72
- return ToolConfirmationOutcome.ProceedOnce;
73
- }
74
-
75
- const onlyAllowedCreate = params.toolUses.every(
76
- (item) =>
77
- item.details.type === ToolConfirmationType.Create &&
78
- item.details.filePath === outputPath
79
- );
80
-
81
- return onlyAllowedCreate
82
- ? ToolConfirmationOutcome.ProceedOnce
83
- : ToolConfirmationOutcome.Cancel;
84
- },
85
- });
86
-
87
- for await (const msg of stream) {
88
- if (msg.type === DroidMessageType.AssistantTextDelta) {
89
- process.stdout.write(msg.text);
90
- }
91
- }
92
- } finally {
93
- await rm(tempDir, { recursive: true, force: true });
94
- }
95
- }
96
-
97
- main().catch((err: unknown) => {
98
- console.error('Error:', err);
99
- process.exit(1);
100
- });
101
- ```
@@ -1,90 +0,0 @@
1
- # Example: tool controls
2
-
3
- Use this when you want to programmatically shape which built-in exec tools are available.
4
-
5
- ## What this example shows
6
-
7
- - setting initial tool overrides
8
- - inspecting the current tool catalog with `listTools()`
9
- - updating tool overrides later with `updateSettings()`
10
-
11
- ## Key snippet: set tool overrides at session creation
12
-
13
- ```ts
14
- const session = await createSession({
15
- cwd: process.cwd(),
16
- enabledToolIds: ['Read', 'Glob', 'Grep'],
17
- disabledToolIds: ['Execute'],
18
- });
19
- ```
20
-
21
- ## Key snippet: inspect tool state
22
-
23
- ```ts
24
- const result = await session.listTools();
25
- console.log(result.tools);
26
- ```
27
-
28
- ## Key snippet: update tool state later
29
-
30
- ```ts
31
- await session.updateSettings({
32
- disabledToolIds: ['Read', 'Execute'],
33
- });
34
- ```
35
-
36
- ## Full script
37
-
38
- ```ts
39
- import { createSession, type ExecToolInfo } from '@factory/droid-sdk';
40
-
41
- function printToolState(label: string, tool: ExecToolInfo | undefined): void {
42
- if (!tool) {
43
- console.log(`${label}: not present in tool catalog`);
44
- return;
45
- }
46
-
47
- console.log(
48
- `${label}: defaultAllowed=${tool.defaultAllowed}, currentlyAllowed=${tool.currentlyAllowed}`
49
- );
50
- }
51
-
52
- async function main(): Promise<void> {
53
- const session = await createSession({
54
- cwd: process.cwd(),
55
- enabledToolIds: ['Read', 'Glob', 'Grep'],
56
- disabledToolIds: ['Execute'],
57
- });
58
-
59
- try {
60
- const initial = await session.listTools();
61
- const initialRead = initial.tools.find((tool) => tool.llmId === 'Read');
62
- const initialExecute = initial.tools.find(
63
- (tool) => tool.llmId === 'Execute'
64
- );
65
-
66
- printToolState('Read', initialRead);
67
- printToolState('Execute', initialExecute);
68
-
69
- await session.updateSettings({
70
- disabledToolIds: ['Read', 'Execute'],
71
- });
72
-
73
- const updated = await session.listTools();
74
- const updatedRead = updated.tools.find((tool) => tool.llmId === 'Read');
75
- const updatedExecute = updated.tools.find(
76
- (tool) => tool.llmId === 'Execute'
77
- );
78
-
79
- printToolState('Read', updatedRead);
80
- printToolState('Execute', updatedExecute);
81
- } finally {
82
- await session.close();
83
- }
84
- }
85
-
86
- main().catch((err: unknown) => {
87
- console.error('Error:', err);
88
- process.exit(1);
89
- });
90
- ```