indusagi-coding-agent 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (240) hide show
  1. package/CHANGELOG.md +2249 -0
  2. package/README.md +546 -0
  3. package/dist/cli/args.js +282 -0
  4. package/dist/cli/config-selector.js +30 -0
  5. package/dist/cli/file-processor.js +78 -0
  6. package/dist/cli/list-models.js +91 -0
  7. package/dist/cli/session-picker.js +31 -0
  8. package/dist/cli.js +10 -0
  9. package/dist/config.js +158 -0
  10. package/dist/core/agent-session.js +2097 -0
  11. package/dist/core/auth-storage.js +278 -0
  12. package/dist/core/bash-executor.js +211 -0
  13. package/dist/core/compaction/branch-summarization.js +241 -0
  14. package/dist/core/compaction/compaction.js +606 -0
  15. package/dist/core/compaction/index.js +6 -0
  16. package/dist/core/compaction/utils.js +137 -0
  17. package/dist/core/diagnostics.js +1 -0
  18. package/dist/core/event-bus.js +24 -0
  19. package/dist/core/exec.js +70 -0
  20. package/dist/core/export-html/ansi-to-html.js +248 -0
  21. package/dist/core/export-html/index.js +221 -0
  22. package/dist/core/export-html/template.css +905 -0
  23. package/dist/core/export-html/template.html +54 -0
  24. package/dist/core/export-html/template.js +1549 -0
  25. package/dist/core/export-html/tool-renderer.js +56 -0
  26. package/dist/core/export-html/vendor/highlight.min.js +1213 -0
  27. package/dist/core/export-html/vendor/marked.min.js +6 -0
  28. package/dist/core/extensions/index.js +8 -0
  29. package/dist/core/extensions/loader.js +395 -0
  30. package/dist/core/extensions/runner.js +499 -0
  31. package/dist/core/extensions/types.js +31 -0
  32. package/dist/core/extensions/wrapper.js +101 -0
  33. package/dist/core/footer-data-provider.js +133 -0
  34. package/dist/core/index.js +8 -0
  35. package/dist/core/keybindings.js +140 -0
  36. package/dist/core/messages.js +122 -0
  37. package/dist/core/model-registry.js +454 -0
  38. package/dist/core/model-resolver.js +309 -0
  39. package/dist/core/package-manager.js +1142 -0
  40. package/dist/core/prompt-templates.js +250 -0
  41. package/dist/core/resource-loader.js +569 -0
  42. package/dist/core/sdk.js +225 -0
  43. package/dist/core/session-manager.js +1078 -0
  44. package/dist/core/settings-manager.js +430 -0
  45. package/dist/core/skills.js +339 -0
  46. package/dist/core/system-prompt.js +136 -0
  47. package/dist/core/timings.js +24 -0
  48. package/dist/core/tools/bash.js +226 -0
  49. package/dist/core/tools/edit-diff.js +242 -0
  50. package/dist/core/tools/edit.js +145 -0
  51. package/dist/core/tools/find.js +205 -0
  52. package/dist/core/tools/grep.js +238 -0
  53. package/dist/core/tools/index.js +60 -0
  54. package/dist/core/tools/ls.js +117 -0
  55. package/dist/core/tools/path-utils.js +52 -0
  56. package/dist/core/tools/read.js +165 -0
  57. package/dist/core/tools/truncate.js +204 -0
  58. package/dist/core/tools/write.js +77 -0
  59. package/dist/index.js +41 -0
  60. package/dist/main.js +565 -0
  61. package/dist/migrations.js +260 -0
  62. package/dist/modes/index.js +7 -0
  63. package/dist/modes/interactive/components/armin.js +328 -0
  64. package/dist/modes/interactive/components/assistant-message.js +86 -0
  65. package/dist/modes/interactive/components/bash-execution.js +155 -0
  66. package/dist/modes/interactive/components/bordered-loader.js +47 -0
  67. package/dist/modes/interactive/components/branch-summary-message.js +41 -0
  68. package/dist/modes/interactive/components/compaction-summary-message.js +42 -0
  69. package/dist/modes/interactive/components/config-selector.js +458 -0
  70. package/dist/modes/interactive/components/countdown-timer.js +27 -0
  71. package/dist/modes/interactive/components/custom-editor.js +61 -0
  72. package/dist/modes/interactive/components/custom-message.js +80 -0
  73. package/dist/modes/interactive/components/diff.js +132 -0
  74. package/dist/modes/interactive/components/dynamic-border.js +19 -0
  75. package/dist/modes/interactive/components/extension-editor.js +96 -0
  76. package/dist/modes/interactive/components/extension-input.js +54 -0
  77. package/dist/modes/interactive/components/extension-selector.js +70 -0
  78. package/dist/modes/interactive/components/footer.js +213 -0
  79. package/dist/modes/interactive/components/index.js +31 -0
  80. package/dist/modes/interactive/components/keybinding-hints.js +60 -0
  81. package/dist/modes/interactive/components/login-dialog.js +138 -0
  82. package/dist/modes/interactive/components/model-selector.js +253 -0
  83. package/dist/modes/interactive/components/oauth-selector.js +91 -0
  84. package/dist/modes/interactive/components/scoped-models-selector.js +262 -0
  85. package/dist/modes/interactive/components/session-selector-search.js +145 -0
  86. package/dist/modes/interactive/components/session-selector.js +698 -0
  87. package/dist/modes/interactive/components/settings-selector.js +250 -0
  88. package/dist/modes/interactive/components/show-images-selector.js +33 -0
  89. package/dist/modes/interactive/components/skill-invocation-message.js +44 -0
  90. package/dist/modes/interactive/components/theme-selector.js +43 -0
  91. package/dist/modes/interactive/components/thinking-selector.js +45 -0
  92. package/dist/modes/interactive/components/tool-execution.js +608 -0
  93. package/dist/modes/interactive/components/tree-selector.js +892 -0
  94. package/dist/modes/interactive/components/user-message-selector.js +109 -0
  95. package/dist/modes/interactive/components/user-message.js +15 -0
  96. package/dist/modes/interactive/components/visual-truncate.js +32 -0
  97. package/dist/modes/interactive/interactive-mode.js +3576 -0
  98. package/dist/modes/interactive/theme/dark.json +85 -0
  99. package/dist/modes/interactive/theme/light.json +84 -0
  100. package/dist/modes/interactive/theme/theme-schema.json +335 -0
  101. package/dist/modes/interactive/theme/theme.js +938 -0
  102. package/dist/modes/print-mode.js +96 -0
  103. package/dist/modes/rpc/rpc-client.js +390 -0
  104. package/dist/modes/rpc/rpc-mode.js +448 -0
  105. package/dist/modes/rpc/rpc-types.js +7 -0
  106. package/dist/utils/changelog.js +86 -0
  107. package/dist/utils/clipboard-image.js +116 -0
  108. package/dist/utils/clipboard.js +58 -0
  109. package/dist/utils/frontmatter.js +25 -0
  110. package/dist/utils/git.js +5 -0
  111. package/dist/utils/image-convert.js +34 -0
  112. package/dist/utils/image-resize.js +180 -0
  113. package/dist/utils/mime.js +25 -0
  114. package/dist/utils/photon.js +120 -0
  115. package/dist/utils/shell.js +164 -0
  116. package/dist/utils/sleep.js +16 -0
  117. package/dist/utils/tools-manager.js +186 -0
  118. package/docs/compaction.md +390 -0
  119. package/docs/custom-provider.md +538 -0
  120. package/docs/development.md +69 -0
  121. package/docs/extensions.md +1733 -0
  122. package/docs/images/doom-extension.png +0 -0
  123. package/docs/images/interactive-mode.png +0 -0
  124. package/docs/images/tree-view.png +0 -0
  125. package/docs/json.md +79 -0
  126. package/docs/keybindings.md +162 -0
  127. package/docs/models.md +193 -0
  128. package/docs/packages.md +163 -0
  129. package/docs/prompt-templates.md +67 -0
  130. package/docs/providers.md +147 -0
  131. package/docs/rpc.md +1048 -0
  132. package/docs/sdk.md +957 -0
  133. package/docs/session.md +412 -0
  134. package/docs/settings.md +216 -0
  135. package/docs/shell-aliases.md +13 -0
  136. package/docs/skills.md +226 -0
  137. package/docs/terminal-setup.md +65 -0
  138. package/docs/themes.md +295 -0
  139. package/docs/tree.md +219 -0
  140. package/docs/tui.md +887 -0
  141. package/docs/windows.md +17 -0
  142. package/examples/README.md +25 -0
  143. package/examples/extensions/README.md +192 -0
  144. package/examples/extensions/antigravity-image-gen.ts +414 -0
  145. package/examples/extensions/auto-commit-on-exit.ts +49 -0
  146. package/examples/extensions/bookmark.ts +50 -0
  147. package/examples/extensions/claude-rules.ts +86 -0
  148. package/examples/extensions/confirm-destructive.ts +59 -0
  149. package/examples/extensions/custom-compaction.ts +115 -0
  150. package/examples/extensions/custom-footer.ts +65 -0
  151. package/examples/extensions/custom-header.ts +73 -0
  152. package/examples/extensions/custom-provider-anthropic/index.ts +605 -0
  153. package/examples/extensions/custom-provider-anthropic/package-lock.json +24 -0
  154. package/examples/extensions/custom-provider-anthropic/package.json +19 -0
  155. package/examples/extensions/custom-provider-gitlab-duo/index.ts +350 -0
  156. package/examples/extensions/custom-provider-gitlab-duo/package.json +16 -0
  157. package/examples/extensions/custom-provider-gitlab-duo/test.ts +83 -0
  158. package/examples/extensions/dirty-repo-guard.ts +56 -0
  159. package/examples/extensions/doom-overlay/README.md +46 -0
  160. package/examples/extensions/doom-overlay/doom/build/doom.js +21 -0
  161. package/examples/extensions/doom-overlay/doom/build/doom.wasm +0 -0
  162. package/examples/extensions/doom-overlay/doom/build.sh +152 -0
  163. package/examples/extensions/doom-overlay/doom/doomgeneric_pi.c +72 -0
  164. package/examples/extensions/doom-overlay/doom-component.ts +133 -0
  165. package/examples/extensions/doom-overlay/doom-engine.ts +173 -0
  166. package/examples/extensions/doom-overlay/doom-keys.ts +105 -0
  167. package/examples/extensions/doom-overlay/index.ts +74 -0
  168. package/examples/extensions/doom-overlay/wad-finder.ts +51 -0
  169. package/examples/extensions/event-bus.ts +43 -0
  170. package/examples/extensions/file-trigger.ts +41 -0
  171. package/examples/extensions/git-checkpoint.ts +53 -0
  172. package/examples/extensions/handoff.ts +151 -0
  173. package/examples/extensions/hello.ts +25 -0
  174. package/examples/extensions/inline-bash.ts +94 -0
  175. package/examples/extensions/input-transform.ts +43 -0
  176. package/examples/extensions/interactive-shell.ts +196 -0
  177. package/examples/extensions/mac-system-theme.ts +47 -0
  178. package/examples/extensions/message-renderer.ts +60 -0
  179. package/examples/extensions/modal-editor.ts +86 -0
  180. package/examples/extensions/model-status.ts +31 -0
  181. package/examples/extensions/notify.ts +25 -0
  182. package/examples/extensions/overlay-qa-tests.ts +882 -0
  183. package/examples/extensions/overlay-test.ts +151 -0
  184. package/examples/extensions/permission-gate.ts +34 -0
  185. package/examples/extensions/pirate.ts +47 -0
  186. package/examples/extensions/plan-mode/README.md +65 -0
  187. package/examples/extensions/plan-mode/index.ts +341 -0
  188. package/examples/extensions/plan-mode/utils.ts +168 -0
  189. package/examples/extensions/preset.ts +399 -0
  190. package/examples/extensions/protected-paths.ts +30 -0
  191. package/examples/extensions/qna.ts +120 -0
  192. package/examples/extensions/question.ts +265 -0
  193. package/examples/extensions/questionnaire.ts +428 -0
  194. package/examples/extensions/rainbow-editor.ts +88 -0
  195. package/examples/extensions/sandbox/index.ts +318 -0
  196. package/examples/extensions/sandbox/package-lock.json +92 -0
  197. package/examples/extensions/sandbox/package.json +19 -0
  198. package/examples/extensions/send-user-message.ts +97 -0
  199. package/examples/extensions/session-name.ts +27 -0
  200. package/examples/extensions/shutdown-command.ts +63 -0
  201. package/examples/extensions/snake.ts +344 -0
  202. package/examples/extensions/space-invaders.ts +561 -0
  203. package/examples/extensions/ssh.ts +220 -0
  204. package/examples/extensions/status-line.ts +40 -0
  205. package/examples/extensions/subagent/README.md +172 -0
  206. package/examples/extensions/subagent/agents/planner.md +37 -0
  207. package/examples/extensions/subagent/agents/reviewer.md +35 -0
  208. package/examples/extensions/subagent/agents/scout.md +50 -0
  209. package/examples/extensions/subagent/agents/worker.md +24 -0
  210. package/examples/extensions/subagent/agents.ts +127 -0
  211. package/examples/extensions/subagent/index.ts +964 -0
  212. package/examples/extensions/subagent/prompts/implement-and-review.md +10 -0
  213. package/examples/extensions/subagent/prompts/implement.md +10 -0
  214. package/examples/extensions/subagent/prompts/scout-and-plan.md +9 -0
  215. package/examples/extensions/summarize.ts +196 -0
  216. package/examples/extensions/timed-confirm.ts +70 -0
  217. package/examples/extensions/todo.ts +300 -0
  218. package/examples/extensions/tool-override.ts +144 -0
  219. package/examples/extensions/tools.ts +147 -0
  220. package/examples/extensions/trigger-compact.ts +40 -0
  221. package/examples/extensions/truncated-tool.ts +193 -0
  222. package/examples/extensions/widget-placement.ts +17 -0
  223. package/examples/extensions/with-deps/index.ts +36 -0
  224. package/examples/extensions/with-deps/package-lock.json +31 -0
  225. package/examples/extensions/with-deps/package.json +22 -0
  226. package/examples/sdk/01-minimal.ts +22 -0
  227. package/examples/sdk/02-custom-model.ts +50 -0
  228. package/examples/sdk/03-custom-prompt.ts +55 -0
  229. package/examples/sdk/04-skills.ts +46 -0
  230. package/examples/sdk/05-tools.ts +56 -0
  231. package/examples/sdk/06-extensions.ts +88 -0
  232. package/examples/sdk/07-context-files.ts +40 -0
  233. package/examples/sdk/08-prompt-templates.ts +47 -0
  234. package/examples/sdk/09-api-keys-and-oauth.ts +48 -0
  235. package/examples/sdk/10-settings.ts +38 -0
  236. package/examples/sdk/11-sessions.ts +48 -0
  237. package/examples/sdk/12-full-control.ts +82 -0
  238. package/examples/sdk/13-codex-oauth.ts +37 -0
  239. package/examples/sdk/README.md +144 -0
  240. package/package.json +85 -0
package/docs/rpc.md ADDED
@@ -0,0 +1,1048 @@
1
+ # RPC Mode
2
+
3
+ RPC mode enables headless operation of the coding agent via a JSON protocol over stdin/stdout. This is useful for embedding the agent in other applications, IDEs, or custom UIs.
4
+
5
+ **Note for Node.js/TypeScript users**: If you're building a Node.js application, consider using `AgentSession` directly from `indusagi-coding-agent` instead of spawning a subprocess. See [`src/core/agent-session.ts`](../src/core/agent-session.ts) for the API. For a subprocess-based TypeScript client, see [`src/modes/rpc/rpc-client.ts`](../src/modes/rpc/rpc-client.ts).
6
+
7
+ ## Starting RPC Mode
8
+
9
+ ```bash
10
+ indusagi --mode rpc [options]
11
+ ```
12
+
13
+ Common options:
14
+ - `--provider <name>`: Set the LLM provider (anthropic, openai, google, etc.)
15
+ - `--model <id>`: Set the model ID
16
+ - `--no-session`: Disable session persistence
17
+ - `--session-dir <path>`: Custom session storage directory
18
+
19
+ ## Protocol Overview
20
+
21
+ - **Commands**: JSON objects sent to stdin, one per line
22
+ - **Responses**: JSON objects with `type: "response"` indicating command success/failure
23
+ - **Events**: Agent events streamed to stdout as JSON lines
24
+
25
+ All commands support an optional `id` field for request/response correlation. If provided, the corresponding response will include the same `id`.
26
+
27
+ ## Commands
28
+
29
+ ### Prompting
30
+
31
+ #### prompt
32
+
33
+ Send a user prompt to the agent. Returns immediately; events stream asynchronously.
34
+
35
+ ```json
36
+ {"id": "req-1", "type": "prompt", "message": "Hello, world!"}
37
+ ```
38
+
39
+ With images:
40
+ ```json
41
+ {"type": "prompt", "message": "What's in this image?", "images": [{"type": "image", "source": {"type": "base64", "mediaType": "image/png", "data": "..."}}]}
42
+ ```
43
+
44
+ **During streaming**: If the agent is already streaming, you must specify `streamingBehavior` to queue the message:
45
+
46
+ ```json
47
+ {"type": "prompt", "message": "New instruction", "streamingBehavior": "steer"}
48
+ ```
49
+
50
+ - `"steer"`: Interrupt the agent mid-run. Message is delivered after current tool execution, remaining tools are skipped.
51
+ - `"followUp"`: Wait until the agent finishes. Message is delivered only when agent stops.
52
+
53
+ If the agent is streaming and no `streamingBehavior` is specified, the command returns an error.
54
+
55
+ **Extension commands**: If the message is an extension command (e.g., `/mycommand`), it executes immediately even during streaming. Extension commands manage their own LLM interaction via `indusagi.sendMessage()`.
56
+
57
+ **Input expansion**: Skill commands (`/skill:name`) and prompt templates (`/template`) are expanded before sending/queueing.
58
+
59
+ Response:
60
+ ```json
61
+ {"id": "req-1", "type": "response", "command": "prompt", "success": true}
62
+ ```
63
+
64
+ The `images` field is optional. Each image uses `ImageContent` format with base64 or URL source.
65
+
66
+ #### steer
67
+
68
+ Queue a steering message to interrupt the agent mid-run. Delivered after current tool execution, remaining tools are skipped. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
69
+
70
+ ```json
71
+ {"type": "steer", "message": "Stop and do this instead"}
72
+ ```
73
+
74
+ Response:
75
+ ```json
76
+ {"type": "response", "command": "steer", "success": true}
77
+ ```
78
+
79
+ See [set_steering_mode](#set_steering_mode) for controlling how steering messages are processed.
80
+
81
+ #### follow_up
82
+
83
+ Queue a follow-up message to be processed after the agent finishes. Delivered only when agent has no more tool calls or steering messages. Skill commands and prompt templates are expanded. Extension commands are not allowed (use `prompt` instead).
84
+
85
+ ```json
86
+ {"type": "follow_up", "message": "After you're done, also do this"}
87
+ ```
88
+
89
+ Response:
90
+ ```json
91
+ {"type": "response", "command": "follow_up", "success": true}
92
+ ```
93
+
94
+ See [set_follow_up_mode](#set_follow_up_mode) for controlling how follow-up messages are processed.
95
+
96
+ #### abort
97
+
98
+ Abort the current agent operation.
99
+
100
+ ```json
101
+ {"type": "abort"}
102
+ ```
103
+
104
+ Response:
105
+ ```json
106
+ {"type": "response", "command": "abort", "success": true}
107
+ ```
108
+
109
+ #### new_session
110
+
111
+ Start a fresh session. Can be cancelled by a `session_before_switch` extension event handler.
112
+
113
+ ```json
114
+ {"type": "new_session"}
115
+ ```
116
+
117
+ With optional parent session tracking:
118
+ ```json
119
+ {"type": "new_session", "parentSession": "/path/to/parent-session.jsonl"}
120
+ ```
121
+
122
+ Response:
123
+ ```json
124
+ {"type": "response", "command": "new_session", "success": true, "data": {"cancelled": false}}
125
+ ```
126
+
127
+ If an extension cancelled:
128
+ ```json
129
+ {"type": "response", "command": "new_session", "success": true, "data": {"cancelled": true}}
130
+ ```
131
+
132
+ ### State
133
+
134
+ #### get_state
135
+
136
+ Get current session state.
137
+
138
+ ```json
139
+ {"type": "get_state"}
140
+ ```
141
+
142
+ Response:
143
+ ```json
144
+ {
145
+ "type": "response",
146
+ "command": "get_state",
147
+ "success": true,
148
+ "data": {
149
+ "model": {...},
150
+ "thinkingLevel": "medium",
151
+ "isStreaming": false,
152
+ "isCompacting": false,
153
+ "steeringMode": "all",
154
+ "followUpMode": "one-at-a-time",
155
+ "sessionFile": "/path/to/session.jsonl",
156
+ "sessionId": "abc123",
157
+ "autoCompactionEnabled": true,
158
+ "messageCount": 5,
159
+ "pendingMessageCount": 0
160
+ }
161
+ }
162
+ ```
163
+
164
+ The `model` field is a full [Model](#model) object or `null`.
165
+
166
+ #### get_messages
167
+
168
+ Get all messages in the conversation.
169
+
170
+ ```json
171
+ {"type": "get_messages"}
172
+ ```
173
+
174
+ Response:
175
+ ```json
176
+ {
177
+ "type": "response",
178
+ "command": "get_messages",
179
+ "success": true,
180
+ "data": {"messages": [...]}
181
+ }
182
+ ```
183
+
184
+ Messages are `AgentMessage` objects (see [Message Types](#message-types)).
185
+
186
+ ### Model
187
+
188
+ #### set_model
189
+
190
+ Switch to a specific model.
191
+
192
+ ```json
193
+ {"type": "set_model", "provider": "anthropic", "modelId": "claude-sonnet-4-20250514"}
194
+ ```
195
+
196
+ Response contains the full [Model](#model) object:
197
+ ```json
198
+ {
199
+ "type": "response",
200
+ "command": "set_model",
201
+ "success": true,
202
+ "data": {...}
203
+ }
204
+ ```
205
+
206
+ #### cycle_model
207
+
208
+ Cycle to the next available model. Returns `null` data if only one model available.
209
+
210
+ ```json
211
+ {"type": "cycle_model"}
212
+ ```
213
+
214
+ Response:
215
+ ```json
216
+ {
217
+ "type": "response",
218
+ "command": "cycle_model",
219
+ "success": true,
220
+ "data": {
221
+ "model": {...},
222
+ "thinkingLevel": "medium",
223
+ "isScoped": false
224
+ }
225
+ }
226
+ ```
227
+
228
+ The `model` field is a full [Model](#model) object.
229
+
230
+ #### get_available_models
231
+
232
+ List all configured models.
233
+
234
+ ```json
235
+ {"type": "get_available_models"}
236
+ ```
237
+
238
+ Response contains an array of full [Model](#model) objects:
239
+ ```json
240
+ {
241
+ "type": "response",
242
+ "command": "get_available_models",
243
+ "success": true,
244
+ "data": {
245
+ "models": [...]
246
+ }
247
+ }
248
+ ```
249
+
250
+ ### Thinking
251
+
252
+ #### set_thinking_level
253
+
254
+ Set the reasoning/thinking level for models that support it.
255
+
256
+ ```json
257
+ {"type": "set_thinking_level", "level": "high"}
258
+ ```
259
+
260
+ Levels: `"off"`, `"minimal"`, `"low"`, `"medium"`, `"high"`, `"xhigh"`
261
+
262
+ Note: `"xhigh"` is only supported by OpenAI codex-max models.
263
+
264
+ Response:
265
+ ```json
266
+ {"type": "response", "command": "set_thinking_level", "success": true}
267
+ ```
268
+
269
+ #### cycle_thinking_level
270
+
271
+ Cycle through available thinking levels. Returns `null` data if model doesn't support thinking.
272
+
273
+ ```json
274
+ {"type": "cycle_thinking_level"}
275
+ ```
276
+
277
+ Response:
278
+ ```json
279
+ {
280
+ "type": "response",
281
+ "command": "cycle_thinking_level",
282
+ "success": true,
283
+ "data": {"level": "high"}
284
+ }
285
+ ```
286
+
287
+ ### Queue Modes
288
+
289
+ #### set_steering_mode
290
+
291
+ Control how steering messages (from `steer`) are delivered.
292
+
293
+ ```json
294
+ {"type": "set_steering_mode", "mode": "one-at-a-time"}
295
+ ```
296
+
297
+ Modes:
298
+ - `"all"`: Deliver all steering messages at the next interruption point
299
+ - `"one-at-a-time"`: Deliver one steering message per interruption (default)
300
+
301
+ Response:
302
+ ```json
303
+ {"type": "response", "command": "set_steering_mode", "success": true}
304
+ ```
305
+
306
+ #### set_follow_up_mode
307
+
308
+ Control how follow-up messages (from `follow_up`) are delivered.
309
+
310
+ ```json
311
+ {"type": "set_follow_up_mode", "mode": "one-at-a-time"}
312
+ ```
313
+
314
+ Modes:
315
+ - `"all"`: Deliver all follow-up messages when agent finishes
316
+ - `"one-at-a-time"`: Deliver one follow-up message per agent completion (default)
317
+
318
+ Response:
319
+ ```json
320
+ {"type": "response", "command": "set_follow_up_mode", "success": true}
321
+ ```
322
+
323
+ ### Compaction
324
+
325
+ #### compact
326
+
327
+ Manually compact conversation context to reduce token usage.
328
+
329
+ ```json
330
+ {"type": "compact"}
331
+ ```
332
+
333
+ With custom instructions:
334
+ ```json
335
+ {"type": "compact", "customInstructions": "Focus on code changes"}
336
+ ```
337
+
338
+ Response:
339
+ ```json
340
+ {
341
+ "type": "response",
342
+ "command": "compact",
343
+ "success": true,
344
+ "data": {
345
+ "summary": "Summary of conversation...",
346
+ "firstKeptEntryId": "abc123",
347
+ "tokensBefore": 150000,
348
+ "details": {}
349
+ }
350
+ }
351
+ ```
352
+
353
+ #### set_auto_compaction
354
+
355
+ Enable or disable automatic compaction when context is nearly full.
356
+
357
+ ```json
358
+ {"type": "set_auto_compaction", "enabled": true}
359
+ ```
360
+
361
+ Response:
362
+ ```json
363
+ {"type": "response", "command": "set_auto_compaction", "success": true}
364
+ ```
365
+
366
+ ### Retry
367
+
368
+ #### set_auto_retry
369
+
370
+ Enable or disable automatic retry on transient errors (overloaded, rate limit, 5xx).
371
+
372
+ ```json
373
+ {"type": "set_auto_retry", "enabled": true}
374
+ ```
375
+
376
+ Response:
377
+ ```json
378
+ {"type": "response", "command": "set_auto_retry", "success": true}
379
+ ```
380
+
381
+ #### abort_retry
382
+
383
+ Abort an in-progress retry (cancel the delay and stop retrying).
384
+
385
+ ```json
386
+ {"type": "abort_retry"}
387
+ ```
388
+
389
+ Response:
390
+ ```json
391
+ {"type": "response", "command": "abort_retry", "success": true}
392
+ ```
393
+
394
+ ### Bash
395
+
396
+ #### bash
397
+
398
+ Execute a shell command and add output to conversation context.
399
+
400
+ ```json
401
+ {"type": "bash", "command": "ls -la"}
402
+ ```
403
+
404
+ Response:
405
+ ```json
406
+ {
407
+ "type": "response",
408
+ "command": "bash",
409
+ "success": true,
410
+ "data": {
411
+ "output": "total 48\ndrwxr-xr-x ...",
412
+ "exitCode": 0,
413
+ "cancelled": false,
414
+ "truncated": false
415
+ }
416
+ }
417
+ ```
418
+
419
+ If output was truncated, includes `fullOutputPath`:
420
+ ```json
421
+ {
422
+ "type": "response",
423
+ "command": "bash",
424
+ "success": true,
425
+ "data": {
426
+ "output": "truncated output...",
427
+ "exitCode": 0,
428
+ "cancelled": false,
429
+ "truncated": true,
430
+ "fullOutputPath": "/tmp/indusagi-bash-abc123.log"
431
+ }
432
+ }
433
+ ```
434
+
435
+ **How bash results reach the LLM:**
436
+
437
+ The `bash` command executes immediately and returns a `BashResult`. Internally, a `BashExecutionMessage` is created and stored in the agent's message state. This message does NOT emit an event.
438
+
439
+ When the next `prompt` command is sent, all messages (including `BashExecutionMessage`) are transformed before being sent to the LLM. The `BashExecutionMessage` is converted to a `UserMessage` with this format:
440
+
441
+ ```
442
+ Ran `ls -la`
443
+ \`\`\`
444
+ total 48
445
+ drwxr-xr-x ...
446
+ \`\`\`
447
+ ```
448
+
449
+ This means:
450
+ 1. Bash output is included in the LLM context on the **next prompt**, not immediately
451
+ 2. Multiple bash commands can be executed before a prompt; all outputs will be included
452
+ 3. No event is emitted for the `BashExecutionMessage` itself
453
+
454
+ #### abort_bash
455
+
456
+ Abort a running bash command.
457
+
458
+ ```json
459
+ {"type": "abort_bash"}
460
+ ```
461
+
462
+ Response:
463
+ ```json
464
+ {"type": "response", "command": "abort_bash", "success": true}
465
+ ```
466
+
467
+ ### Session
468
+
469
+ #### get_session_stats
470
+
471
+ Get token usage and cost statistics.
472
+
473
+ ```json
474
+ {"type": "get_session_stats"}
475
+ ```
476
+
477
+ Response:
478
+ ```json
479
+ {
480
+ "type": "response",
481
+ "command": "get_session_stats",
482
+ "success": true,
483
+ "data": {
484
+ "sessionFile": "/path/to/session.jsonl",
485
+ "sessionId": "abc123",
486
+ "userMessages": 5,
487
+ "assistantMessages": 5,
488
+ "toolCalls": 12,
489
+ "toolResults": 12,
490
+ "totalMessages": 22,
491
+ "tokens": {
492
+ "input": 50000,
493
+ "output": 10000,
494
+ "cacheRead": 40000,
495
+ "cacheWrite": 5000,
496
+ "total": 105000
497
+ },
498
+ "cost": 0.45
499
+ }
500
+ }
501
+ ```
502
+
503
+ #### export_html
504
+
505
+ Export session to an HTML file.
506
+
507
+ ```json
508
+ {"type": "export_html"}
509
+ ```
510
+
511
+ With custom path:
512
+ ```json
513
+ {"type": "export_html", "outputPath": "/tmp/session.html"}
514
+ ```
515
+
516
+ Response:
517
+ ```json
518
+ {
519
+ "type": "response",
520
+ "command": "export_html",
521
+ "success": true,
522
+ "data": {"path": "/tmp/session.html"}
523
+ }
524
+ ```
525
+
526
+ #### switch_session
527
+
528
+ Load a different session file. Can be cancelled by a `session_before_switch` extension event handler.
529
+
530
+ ```json
531
+ {"type": "switch_session", "sessionPath": "/path/to/session.jsonl"}
532
+ ```
533
+
534
+ Response:
535
+ ```json
536
+ {"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": false}}
537
+ ```
538
+
539
+ If an extension cancelled the switch:
540
+ ```json
541
+ {"type": "response", "command": "switch_session", "success": true, "data": {"cancelled": true}}
542
+ ```
543
+
544
+ #### fork
545
+
546
+ Create a new fork from a previous user message. Can be cancelled by a `session_before_fork` extension event handler. Returns the text of the message being forked from.
547
+
548
+ ```json
549
+ {"type": "fork", "entryId": "abc123"}
550
+ ```
551
+
552
+ Response:
553
+ ```json
554
+ {
555
+ "type": "response",
556
+ "command": "fork",
557
+ "success": true,
558
+ "data": {"text": "The original prompt text...", "cancelled": false}
559
+ }
560
+ ```
561
+
562
+ If an extension cancelled the fork:
563
+ ```json
564
+ {
565
+ "type": "response",
566
+ "command": "fork",
567
+ "success": true,
568
+ "data": {"text": "The original prompt text...", "cancelled": true}
569
+ }
570
+ ```
571
+
572
+ #### get_fork_messages
573
+
574
+ Get user messages available for forking.
575
+
576
+ ```json
577
+ {"type": "get_fork_messages"}
578
+ ```
579
+
580
+ Response:
581
+ ```json
582
+ {
583
+ "type": "response",
584
+ "command": "get_fork_messages",
585
+ "success": true,
586
+ "data": {
587
+ "messages": [
588
+ {"entryId": "abc123", "text": "First prompt..."},
589
+ {"entryId": "def456", "text": "Second prompt..."}
590
+ ]
591
+ }
592
+ }
593
+ ```
594
+
595
+ #### get_last_assistant_text
596
+
597
+ Get the text content of the last assistant message.
598
+
599
+ ```json
600
+ {"type": "get_last_assistant_text"}
601
+ ```
602
+
603
+ Response:
604
+ ```json
605
+ {
606
+ "type": "response",
607
+ "command": "get_last_assistant_text",
608
+ "success": true,
609
+ "data": {"text": "The assistant's response..."}
610
+ }
611
+ ```
612
+
613
+ Returns `{"text": null}` if no assistant messages exist.
614
+
615
+ ## Events
616
+
617
+ Events are streamed to stdout as JSON lines during agent operation. Events do NOT include an `id` field (only responses do).
618
+
619
+ ### Event Types
620
+
621
+ | Event | Description |
622
+ |-------|-------------|
623
+ | `agent_start` | Agent begins processing |
624
+ | `agent_end` | Agent completes (includes all generated messages) |
625
+ | `turn_start` | New turn begins |
626
+ | `turn_end` | Turn completes (includes assistant message and tool results) |
627
+ | `message_start` | Message begins |
628
+ | `message_update` | Streaming update (text/thinking/toolcall deltas) |
629
+ | `message_end` | Message completes |
630
+ | `tool_execution_start` | Tool begins execution |
631
+ | `tool_execution_update` | Tool execution progress (streaming output) |
632
+ | `tool_execution_end` | Tool completes |
633
+ | `auto_compaction_start` | Auto-compaction begins |
634
+ | `auto_compaction_end` | Auto-compaction completes |
635
+ | `auto_retry_start` | Auto-retry begins (after transient error) |
636
+ | `auto_retry_end` | Auto-retry completes (success or final failure) |
637
+ | `extension_error` | Extension threw an error |
638
+
639
+ ### agent_start
640
+
641
+ Emitted when the agent begins processing a prompt.
642
+
643
+ ```json
644
+ {"type": "agent_start"}
645
+ ```
646
+
647
+ ### agent_end
648
+
649
+ Emitted when the agent completes. Contains all messages generated during this run.
650
+
651
+ ```json
652
+ {
653
+ "type": "agent_end",
654
+ "messages": [...]
655
+ }
656
+ ```
657
+
658
+ ### turn_start / turn_end
659
+
660
+ A turn consists of one assistant response plus any resulting tool calls and results.
661
+
662
+ ```json
663
+ {"type": "turn_start"}
664
+ ```
665
+
666
+ ```json
667
+ {
668
+ "type": "turn_end",
669
+ "message": {...},
670
+ "toolResults": [...]
671
+ }
672
+ ```
673
+
674
+ ### message_start / message_end
675
+
676
+ Emitted when a message begins and completes. The `message` field contains an `AgentMessage`.
677
+
678
+ ```json
679
+ {"type": "message_start", "message": {...}}
680
+ {"type": "message_end", "message": {...}}
681
+ ```
682
+
683
+ ### message_update (Streaming)
684
+
685
+ Emitted during streaming of assistant messages. Contains both the partial message and a streaming delta event.
686
+
687
+ ```json
688
+ {
689
+ "type": "message_update",
690
+ "message": {...},
691
+ "assistantMessageEvent": {
692
+ "type": "text_delta",
693
+ "contentIndex": 0,
694
+ "delta": "Hello ",
695
+ "partial": {...}
696
+ }
697
+ }
698
+ ```
699
+
700
+ The `assistantMessageEvent` field contains one of these delta types:
701
+
702
+ | Type | Description |
703
+ |------|-------------|
704
+ | `start` | Message generation started |
705
+ | `text_start` | Text content block started |
706
+ | `text_delta` | Text content chunk |
707
+ | `text_end` | Text content block ended |
708
+ | `thinking_start` | Thinking block started |
709
+ | `thinking_delta` | Thinking content chunk |
710
+ | `thinking_end` | Thinking block ended |
711
+ | `toolcall_start` | Tool call started |
712
+ | `toolcall_delta` | Tool call arguments chunk |
713
+ | `toolcall_end` | Tool call ended (includes full `toolCall` object) |
714
+ | `done` | Message complete (reason: `"stop"`, `"length"`, `"toolUse"`) |
715
+ | `error` | Error occurred (reason: `"aborted"`, `"error"`) |
716
+
717
+ Example streaming a text response:
718
+ ```json
719
+ {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_start","contentIndex":0,"partial":{...}}}
720
+ {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":"Hello","partial":{...}}}
721
+ {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_delta","contentIndex":0,"delta":" world","partial":{...}}}
722
+ {"type":"message_update","message":{...},"assistantMessageEvent":{"type":"text_end","contentIndex":0,"content":"Hello world","partial":{...}}}
723
+ ```
724
+
725
+ ### tool_execution_start / tool_execution_update / tool_execution_end
726
+
727
+ Emitted when a tool begins, streams progress, and completes execution.
728
+
729
+ ```json
730
+ {
731
+ "type": "tool_execution_start",
732
+ "toolCallId": "call_abc123",
733
+ "toolName": "bash",
734
+ "args": {"command": "ls -la"}
735
+ }
736
+ ```
737
+
738
+ During execution, `tool_execution_update` events stream partial results (e.g., bash output as it arrives):
739
+
740
+ ```json
741
+ {
742
+ "type": "tool_execution_update",
743
+ "toolCallId": "call_abc123",
744
+ "toolName": "bash",
745
+ "args": {"command": "ls -la"},
746
+ "partialResult": {
747
+ "content": [{"type": "text", "text": "partial output so far..."}],
748
+ "details": {"truncation": null, "fullOutputPath": null}
749
+ }
750
+ }
751
+ ```
752
+
753
+ When complete:
754
+
755
+ ```json
756
+ {
757
+ "type": "tool_execution_end",
758
+ "toolCallId": "call_abc123",
759
+ "toolName": "bash",
760
+ "result": {
761
+ "content": [{"type": "text", "text": "total 48\n..."}],
762
+ "details": {...}
763
+ },
764
+ "isError": false
765
+ }
766
+ ```
767
+
768
+ Use `toolCallId` to correlate events. The `partialResult` in `tool_execution_update` contains the accumulated output so far (not just the delta), allowing clients to simply replace their display on each update.
769
+
770
+ ### auto_compaction_start / auto_compaction_end
771
+
772
+ Emitted when automatic compaction runs (when context is nearly full).
773
+
774
+ ```json
775
+ {"type": "auto_compaction_start", "reason": "threshold"}
776
+ ```
777
+
778
+ The `reason` field is `"threshold"` (context getting large) or `"overflow"` (context exceeded limit).
779
+
780
+ ```json
781
+ {
782
+ "type": "auto_compaction_end",
783
+ "result": {
784
+ "summary": "Summary of conversation...",
785
+ "firstKeptEntryId": "abc123",
786
+ "tokensBefore": 150000,
787
+ "details": {}
788
+ },
789
+ "aborted": false,
790
+ "willRetry": false
791
+ }
792
+ ```
793
+
794
+ If `reason` was `"overflow"` and compaction succeeds, `willRetry` is `true` and the agent will automatically retry the prompt.
795
+
796
+ If compaction was aborted, `result` is `null` and `aborted` is `true`.
797
+
798
+ If compaction failed (e.g., API quota exceeded), `result` is `null`, `aborted` is `false`, and `errorMessage` contains the error description.
799
+
800
+ ### auto_retry_start / auto_retry_end
801
+
802
+ Emitted when automatic retry is triggered after a transient error (overloaded, rate limit, 5xx).
803
+
804
+ ```json
805
+ {
806
+ "type": "auto_retry_start",
807
+ "attempt": 1,
808
+ "maxAttempts": 3,
809
+ "delayMs": 2000,
810
+ "errorMessage": "529 {\"type\":\"error\",\"error\":{\"type\":\"overloaded_error\",\"message\":\"Overloaded\"}}"
811
+ }
812
+ ```
813
+
814
+ ```json
815
+ {
816
+ "type": "auto_retry_end",
817
+ "success": true,
818
+ "attempt": 2
819
+ }
820
+ ```
821
+
822
+ On final failure (max retries exceeded):
823
+ ```json
824
+ {
825
+ "type": "auto_retry_end",
826
+ "success": false,
827
+ "attempt": 3,
828
+ "finalError": "529 overloaded_error: Overloaded"
829
+ }
830
+ ```
831
+
832
+ ### extension_error
833
+
834
+ Emitted when an extension throws an error.
835
+
836
+ ```json
837
+ {
838
+ "type": "extension_error",
839
+ "extensionPath": "/path/to/extension.ts",
840
+ "event": "tool_call",
841
+ "error": "Error message..."
842
+ }
843
+ ```
844
+
845
+ ## Error Handling
846
+
847
+ Failed commands return a response with `success: false`:
848
+
849
+ ```json
850
+ {
851
+ "type": "response",
852
+ "command": "set_model",
853
+ "success": false,
854
+ "error": "Model not found: invalid/model"
855
+ }
856
+ ```
857
+
858
+ Parse errors:
859
+
860
+ ```json
861
+ {
862
+ "type": "response",
863
+ "command": "parse",
864
+ "success": false,
865
+ "error": "Failed to parse command: Unexpected token..."
866
+ }
867
+ ```
868
+
869
+ ## Types
870
+
871
+ Source files:
872
+ - [`packages/ai/src/types.ts`](../../ai/src/types.ts) - `Model`, `UserMessage`, `AssistantMessage`, `ToolResultMessage`
873
+ - [`packages/agent/src/types.ts`](../../agent/src/types.ts) - `AgentMessage`, `AgentEvent`
874
+ - [`src/core/messages.ts`](../src/core/messages.ts) - `BashExecutionMessage`
875
+ - [`src/modes/rpc/rpc-types.ts`](../src/modes/rpc/rpc-types.ts) - RPC command/response types
876
+
877
+ ### Model
878
+
879
+ ```json
880
+ {
881
+ "id": "claude-sonnet-4-20250514",
882
+ "name": "Claude Sonnet 4",
883
+ "api": "anthropic-messages",
884
+ "provider": "anthropic",
885
+ "baseUrl": "https://api.anthropic.com",
886
+ "reasoning": true,
887
+ "input": ["text", "image"],
888
+ "contextWindow": 200000,
889
+ "maxTokens": 16384,
890
+ "cost": {
891
+ "input": 3.0,
892
+ "output": 15.0,
893
+ "cacheRead": 0.3,
894
+ "cacheWrite": 3.75
895
+ }
896
+ }
897
+ ```
898
+
899
+ ### UserMessage
900
+
901
+ ```json
902
+ {
903
+ "role": "user",
904
+ "content": "Hello!",
905
+ "timestamp": 1733234567890,
906
+ "attachments": []
907
+ }
908
+ ```
909
+
910
+ The `content` field can be a string or an array of `TextContent`/`ImageContent` blocks.
911
+
912
+ ### AssistantMessage
913
+
914
+ ```json
915
+ {
916
+ "role": "assistant",
917
+ "content": [
918
+ {"type": "text", "text": "Hello! How can I help?"},
919
+ {"type": "thinking", "thinking": "User is greeting me..."},
920
+ {"type": "toolCall", "id": "call_123", "name": "bash", "arguments": {"command": "ls"}}
921
+ ],
922
+ "api": "anthropic-messages",
923
+ "provider": "anthropic",
924
+ "model": "claude-sonnet-4-20250514",
925
+ "usage": {
926
+ "input": 100,
927
+ "output": 50,
928
+ "cacheRead": 0,
929
+ "cacheWrite": 0,
930
+ "cost": {"input": 0.0003, "output": 0.00075, "cacheRead": 0, "cacheWrite": 0, "total": 0.00105}
931
+ },
932
+ "stopReason": "stop",
933
+ "timestamp": 1733234567890
934
+ }
935
+ ```
936
+
937
+ Stop reasons: `"stop"`, `"length"`, `"toolUse"`, `"error"`, `"aborted"`
938
+
939
+ ### ToolResultMessage
940
+
941
+ ```json
942
+ {
943
+ "role": "toolResult",
944
+ "toolCallId": "call_123",
945
+ "toolName": "bash",
946
+ "content": [{"type": "text", "text": "total 48\ndrwxr-xr-x ..."}],
947
+ "isError": false,
948
+ "timestamp": 1733234567890
949
+ }
950
+ ```
951
+
952
+ ### BashExecutionMessage
953
+
954
+ Created by the `bash` RPC command (not by LLM tool calls):
955
+
956
+ ```json
957
+ {
958
+ "role": "bashExecution",
959
+ "command": "ls -la",
960
+ "output": "total 48\ndrwxr-xr-x ...",
961
+ "exitCode": 0,
962
+ "cancelled": false,
963
+ "truncated": false,
964
+ "fullOutputPath": null,
965
+ "timestamp": 1733234567890
966
+ }
967
+ ```
968
+
969
+ ### Attachment
970
+
971
+ ```json
972
+ {
973
+ "id": "img1",
974
+ "type": "image",
975
+ "fileName": "photo.jpg",
976
+ "mimeType": "image/jpeg",
977
+ "size": 102400,
978
+ "content": "base64-encoded-data...",
979
+ "extractedText": null,
980
+ "preview": null
981
+ }
982
+ ```
983
+
984
+ ## Example: Basic Client (Python)
985
+
986
+ ```python
987
+ import subprocess
988
+ import json
989
+
990
+ proc = subprocess.Popen(
991
+ ["indusagi", "--mode", "rpc", "--no-session"],
992
+ stdin=subprocess.PIPE,
993
+ stdout=subprocess.PIPE,
994
+ text=True
995
+ )
996
+
997
+ def send(cmd):
998
+ proc.stdin.write(json.dumps(cmd) + "\n")
999
+ proc.stdin.flush()
1000
+
1001
+ def read_events():
1002
+ for line in proc.stdout:
1003
+ yield json.loads(line)
1004
+
1005
+ # Send prompt
1006
+ send({"type": "prompt", "message": "Hello!"})
1007
+
1008
+ # Process events
1009
+ for event in read_events():
1010
+ if event.get("type") == "message_update":
1011
+ delta = event.get("assistantMessageEvent", {})
1012
+ if delta.get("type") == "text_delta":
1013
+ print(delta["delta"], end="", flush=True)
1014
+
1015
+ if event.get("type") == "agent_end":
1016
+ print()
1017
+ break
1018
+ ```
1019
+
1020
+ ## Example: Interactive Client (Node.js)
1021
+
1022
+ See [`test/rpc-example.ts`](../test/rpc-example.ts) for a complete interactive example, or [`src/modes/rpc/rpc-client.ts`](../src/modes/rpc/rpc-client.ts) for a typed client implementation.
1023
+
1024
+ ```javascript
1025
+ const { spawn } = require("child_process");
1026
+ const readline = require("readline");
1027
+
1028
+ const agent = spawn("indusagi", ["--mode", "rpc", "--no-session"]);
1029
+
1030
+ readline.createInterface({ input: agent.stdout }).on("line", (line) => {
1031
+ const event = JSON.parse(line);
1032
+
1033
+ if (event.type === "message_update") {
1034
+ const { assistantMessageEvent } = event;
1035
+ if (assistantMessageEvent.type === "text_delta") {
1036
+ process.stdout.write(assistantMessageEvent.delta);
1037
+ }
1038
+ }
1039
+ });
1040
+
1041
+ // Send prompt
1042
+ agent.stdin.write(JSON.stringify({ type: "prompt", message: "Hello" }) + "\n");
1043
+
1044
+ // Abort on Ctrl+C
1045
+ process.on("SIGINT", () => {
1046
+ agent.stdin.write(JSON.stringify({ type: "abort" }) + "\n");
1047
+ });
1048
+ ```