@4onstudios/iris-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.
- package/LICENSE +21 -0
- package/README.md +690 -0
- package/dist/api/acp/acpServer.d.ts +23 -0
- package/dist/api/acp/acpServer.js +814 -0
- package/dist/api/acp/index.d.ts +2 -0
- package/dist/api/acp/index.js +2 -0
- package/dist/api/acp/irisClient.d.ts +58 -0
- package/dist/api/acp/irisClient.js +214 -0
- package/dist/api/agent.d.ts +14 -0
- package/dist/api/agent.js +4171 -0
- package/dist/api/backendService.d.ts +4 -0
- package/dist/api/backendService.js +14 -0
- package/dist/api/core/agent/host/AgentContract.d.ts +82 -0
- package/dist/api/core/agent/host/AgentContract.js +1 -0
- package/dist/api/core/agent/host/AgentRegistry.d.ts +24 -0
- package/dist/api/core/agent/host/AgentRegistry.js +125 -0
- package/dist/api/core/agent/host/defaultRegistry.d.ts +15 -0
- package/dist/api/core/agent/host/defaultRegistry.js +46 -0
- package/dist/api/core/agent/host/externalAgentLifecycle.d.ts +65 -0
- package/dist/api/core/agent/host/externalAgentLifecycle.js +117 -0
- package/dist/api/core/agent/host/hostSessionManager.d.ts +111 -0
- package/dist/api/core/agent/host/hostSessionManager.js +352 -0
- package/dist/api/core/agent/host/index.d.ts +5 -0
- package/dist/api/core/agent/host/index.js +5 -0
- package/dist/api/core/agent/index.d.ts +87 -0
- package/dist/api/core/agent/index.js +1024 -0
- package/dist/api/core/agent/publicContracts.d.ts +35 -0
- package/dist/api/core/agent/publicContracts.js +103 -0
- package/dist/api/core/agent/tools/applyDiff.d.ts +51 -0
- package/dist/api/core/agent/tools/applyDiff.js +131 -0
- package/dist/api/core/agent/tools/backgroundTasks.d.ts +240 -0
- package/dist/api/core/agent/tools/backgroundTasks.js +313 -0
- package/dist/api/core/agent/tools/createDirectory.d.ts +43 -0
- package/dist/api/core/agent/tools/createDirectory.js +77 -0
- package/dist/api/core/agent/tools/deleteFile.d.ts +37 -0
- package/dist/api/core/agent/tools/deleteFile.js +66 -0
- package/dist/api/core/agent/tools/editFile.d.ts +73 -0
- package/dist/api/core/agent/tools/editFile.js +173 -0
- package/dist/api/core/agent/tools/executeCommand.d.ts +59 -0
- package/dist/api/core/agent/tools/executeCommand.js +250 -0
- package/dist/api/core/agent/tools/fileContent.d.ts +54 -0
- package/dist/api/core/agent/tools/fileContent.js +227 -0
- package/dist/api/core/agent/tools/findDefinition.d.ts +72 -0
- package/dist/api/core/agent/tools/findDefinition.js +109 -0
- package/dist/api/core/agent/tools/findReferences.d.ts +86 -0
- package/dist/api/core/agent/tools/findReferences.js +135 -0
- package/dist/api/core/agent/tools/formatDocument.d.ts +67 -0
- package/dist/api/core/agent/tools/formatDocument.js +90 -0
- package/dist/api/core/agent/tools/getCodeActions.d.ts +77 -0
- package/dist/api/core/agent/tools/getCodeActions.js +97 -0
- package/dist/api/core/agent/tools/getCodeCompletion.d.ts +77 -0
- package/dist/api/core/agent/tools/getCodeCompletion.js +174 -0
- package/dist/api/core/agent/tools/getCodeContext.d.ts +14 -0
- package/dist/api/core/agent/tools/getCodeContext.js +282 -0
- package/dist/api/core/agent/tools/getSignatureHelp.d.ts +61 -0
- package/dist/api/core/agent/tools/getSignatureHelp.js +85 -0
- package/dist/api/core/agent/tools/getSymbols.d.ts +50 -0
- package/dist/api/core/agent/tools/getSymbols.js +164 -0
- package/dist/api/core/agent/tools/getSymbolsLSP.d.ts +58 -0
- package/dist/api/core/agent/tools/getSymbolsLSP.js +147 -0
- package/dist/api/core/agent/tools/getTypeInfo.d.ts +70 -0
- package/dist/api/core/agent/tools/getTypeInfo.js +84 -0
- package/dist/api/core/agent/tools/getWorkspaceInfo.d.ts +80 -0
- package/dist/api/core/agent/tools/getWorkspaceInfo.js +281 -0
- package/dist/api/core/agent/tools/getWorkspaceSymbols.d.ts +53 -0
- package/dist/api/core/agent/tools/getWorkspaceSymbols.js +97 -0
- package/dist/api/core/agent/tools/grepSearch.d.ts +100 -0
- package/dist/api/core/agent/tools/grepSearch.js +211 -0
- package/dist/api/core/agent/tools/languageModelToolsIntegration.d.ts +13 -0
- package/dist/api/core/agent/tools/languageModelToolsIntegration.js +22 -0
- package/dist/api/core/agent/tools/listDirectory.d.ts +66 -0
- package/dist/api/core/agent/tools/listDirectory.js +161 -0
- package/dist/api/core/agent/tools/mcpTools.d.ts +48 -0
- package/dist/api/core/agent/tools/mcpTools.js +442 -0
- package/dist/api/core/agent/tools/queryKnowledgeGraph.d.ts +120 -0
- package/dist/api/core/agent/tools/queryKnowledgeGraph.js +306 -0
- package/dist/api/core/agent/tools/readFile.d.ts +92 -0
- package/dist/api/core/agent/tools/readFile.js +337 -0
- package/dist/api/core/agent/tools/renameFile.d.ts +49 -0
- package/dist/api/core/agent/tools/renameFile.js +86 -0
- package/dist/api/core/agent/tools/renameSymbol.d.ts +70 -0
- package/dist/api/core/agent/tools/renameSymbol.js +106 -0
- package/dist/api/core/agent/tools/runTerminalCommand.d.ts +72 -0
- package/dist/api/core/agent/tools/runTerminalCommand.js +69 -0
- package/dist/api/core/agent/tools/searchFiles.d.ts +82 -0
- package/dist/api/core/agent/tools/searchFiles.js +280 -0
- package/dist/api/core/agent/tools/terminalAutoApprove.d.ts +3 -0
- package/dist/api/core/agent/tools/terminalAutoApprove.js +676 -0
- package/dist/api/core/agent/tools/treeTraversal.d.ts +60 -0
- package/dist/api/core/agent/tools/treeTraversal.js +217 -0
- package/dist/api/core/agent/tools/webSearch.d.ts +37 -0
- package/dist/api/core/agent/tools/webSearch.js +80 -0
- package/dist/api/core/agent/tools/writeFile.d.ts +59 -0
- package/dist/api/core/agent/tools/writeFile.js +97 -0
- package/dist/api/core/agent/utils/capturedWorkspaceMutationBridge.d.ts +12 -0
- package/dist/api/core/agent/utils/capturedWorkspaceMutationBridge.js +67 -0
- package/dist/api/core/agent/utils/diffUtils.d.ts +14 -0
- package/dist/api/core/agent/utils/diffUtils.js +39 -0
- package/dist/api/core/agent/utils/environmentSnapshot.d.ts +42 -0
- package/dist/api/core/agent/utils/environmentSnapshot.js +213 -0
- package/dist/api/core/agent/utils/errorRecovery.d.ts +49 -0
- package/dist/api/core/agent/utils/errorRecovery.js +229 -0
- package/dist/api/core/agent/utils/multimodalTokenLimiter.d.ts +8 -0
- package/dist/api/core/agent/utils/multimodalTokenLimiter.js +238 -0
- package/dist/api/core/agent/utils/openRouterModelSettings.d.ts +12 -0
- package/dist/api/core/agent/utils/openRouterModelSettings.js +34 -0
- package/dist/api/core/agent/utils/pathRecovery.d.ts +1 -0
- package/dist/api/core/agent/utils/pathRecovery.js +29 -0
- package/dist/api/core/agent/utils/repoMapIndex.d.ts +3 -0
- package/dist/api/core/agent/utils/repoMapIndex.js +197 -0
- package/dist/api/core/agent/utils/skillsDiscovery.d.ts +10 -0
- package/dist/api/core/agent/utils/skillsDiscovery.js +50 -0
- package/dist/api/core/agent/utils/toolCallBudget.d.ts +9 -0
- package/dist/api/core/agent/utils/toolCallBudget.js +55 -0
- package/dist/api/core/agent/utils/toolLifecycle.d.ts +30 -0
- package/dist/api/core/agent/utils/toolLifecycle.js +361 -0
- package/dist/api/core/agent/utils/toolResultSafetyProcessor.d.ts +12 -0
- package/dist/api/core/agent/utils/toolResultSafetyProcessor.js +57 -0
- package/dist/api/core/agent/utils/workspaceMutationBridge.d.ts +13 -0
- package/dist/api/core/agent/utils/workspaceMutationBridge.js +149 -0
- package/dist/api/core/agent/utils/workspacePathGuard.d.ts +7 -0
- package/dist/api/core/agent/utils/workspacePathGuard.js +79 -0
- package/dist/api/core/containers/chat/toolResultSerialization.d.ts +8 -0
- package/dist/api/core/containers/chat/toolResultSerialization.js +71 -0
- package/dist/api/core/library/BrowserManager.d.ts +11 -0
- package/dist/api/core/library/BrowserManager.js +66 -0
- package/dist/api/core/library/desktopWorkspace.d.ts +1 -0
- package/dist/api/core/library/desktopWorkspace.js +3 -0
- package/dist/api/core/library/extensionManager.d.ts +10 -0
- package/dist/api/core/library/extensionManager.js +27 -0
- package/dist/api/core/library/knowledgeGraph.d.ts +268 -0
- package/dist/api/core/library/knowledgeGraph.js +989 -0
- package/dist/api/core/library/languageModelTools.d.ts +141 -0
- package/dist/api/core/library/languageModelTools.js +207 -0
- package/dist/api/core/library/localRuntime.d.ts +23 -0
- package/dist/api/core/library/localRuntime.js +144 -0
- package/dist/api/core/library/lsp/coreLsp.d.ts +367 -0
- package/dist/api/core/library/lsp/coreLsp.js +2076 -0
- package/dist/api/core/library/lsp/protocol.d.ts +25 -0
- package/dist/api/core/library/lsp/protocol.js +1 -0
- package/dist/api/core/library/lsp/serverManager.d.ts +37 -0
- package/dist/api/core/library/lsp/serverManager.js +427 -0
- package/dist/api/core/library/mcpServerProvider.d.ts +69 -0
- package/dist/api/core/library/mcpServerProvider.js +152 -0
- package/dist/api/core/library/mcpSettings.d.ts +20 -0
- package/dist/api/core/library/mcpSettings.js +131 -0
- package/dist/api/core/library/patternMatcher.d.ts +66 -0
- package/dist/api/core/library/patternMatcher.js +284 -0
- package/dist/api/core/library/regexEscape.d.ts +4 -0
- package/dist/api/core/library/regexEscape.js +4 -0
- package/dist/api/core/library/runtimeEventBus.d.ts +27 -0
- package/dist/api/core/library/runtimeEventBus.js +78 -0
- package/dist/api/core/library/safetyMiddleware.d.ts +98 -0
- package/dist/api/core/library/safetyMiddleware.js +215 -0
- package/dist/api/core/library/tauri.d.ts +71 -0
- package/dist/api/core/library/tauri.js +222 -0
- package/dist/api/core/library/tauriImport.d.ts +5 -0
- package/dist/api/core/library/tauriImport.js +7 -0
- package/dist/api/core/library/terminalAutoApproveSettings.d.ts +32 -0
- package/dist/api/core/library/terminalAutoApproveSettings.js +529 -0
- package/dist/api/core/library/workspaceIdentity.d.ts +10 -0
- package/dist/api/core/library/workspaceIdentity.js +49 -0
- package/dist/api/core/library/workspaceSummary.d.ts +19 -0
- package/dist/api/core/library/workspaceSummary.js +35 -0
- package/dist/api/core/skills/agent-customization/SKILL.md +27 -0
- package/dist/api/core/skills/bug-fix/SKILL.md +21 -0
- package/dist/api/core/skills/create-pr/SKILL.md +32 -0
- package/dist/api/core/skills/dev-server/SKILL.md +20 -0
- package/dist/api/core/skills/fix-suggestions/SKILL.md +21 -0
- package/dist/api/core/skills/github-search/SKILL.md +21 -0
- package/dist/api/core/skills/github-summary/SKILL.md +25 -0
- package/dist/api/core/skills/integration-tests/SKILL.md +29 -0
- package/dist/api/core/skills/pr-comments/SKILL.md +23 -0
- package/dist/api/core/skills/project-setup/SKILL.md +20 -0
- package/dist/api/core/skills/search-integration/SKILL.md +19 -0
- package/dist/api/core/skills/search-results/SKILL.md +19 -0
- package/dist/api/core/skills/typescript-upgrade/SKILL.md +21 -0
- package/dist/api/data/runStore.d.ts +46 -0
- package/dist/api/data/runStore.js +244 -0
- package/dist/api/helpers/agentUtils.d.ts +11 -0
- package/dist/api/helpers/agentUtils.js +23 -0
- package/dist/api/helpers/modelTokenLimits.d.ts +2 -0
- package/dist/api/helpers/modelTokenLimits.js +158 -0
- package/dist/api/helpers/observationalMemory.d.ts +10 -0
- package/dist/api/helpers/observationalMemory.js +36 -0
- package/dist/api/helpers/promptBudget.d.ts +30 -0
- package/dist/api/helpers/promptBudget.js +216 -0
- package/dist/api/helpers/resolveImageMessageParts.d.ts +9 -0
- package/dist/api/helpers/resolveImageMessageParts.js +140 -0
- package/dist/api/helpers/slashCommands.d.ts +31 -0
- package/dist/api/helpers/slashCommands.js +129 -0
- package/dist/api/helpers/tokenUsage.d.ts +19 -0
- package/dist/api/helpers/tokenUsage.js +81 -0
- package/dist/api/routes/fileRoutes.d.ts +2 -0
- package/dist/api/routes/fileRoutes.js +108 -0
- package/dist/api/routes/lspDocumentRoutes.d.ts +4 -0
- package/dist/api/routes/lspDocumentRoutes.js +84 -0
- package/dist/api/routes/lspHierarchyRoutes.d.ts +4 -0
- package/dist/api/routes/lspHierarchyRoutes.js +122 -0
- package/dist/api/routes/lspPositionRoutes.d.ts +4 -0
- package/dist/api/routes/lspPositionRoutes.js +263 -0
- package/dist/api/routes/lspQueryRoutes.d.ts +4 -0
- package/dist/api/routes/lspQueryRoutes.js +679 -0
- package/dist/api/routes/lspResolveRoutes.d.ts +4 -0
- package/dist/api/routes/lspResolveRoutes.js +143 -0
- package/dist/api/routes/lspSemanticDocumentRoutes.d.ts +4 -0
- package/dist/api/routes/lspSemanticDocumentRoutes.js +98 -0
- package/dist/api/routes/semanticRoutes.d.ts +2 -0
- package/dist/api/routes/semanticRoutes.js +126 -0
- package/dist/cli.d.ts +8 -0
- package/dist/cli.js +160 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/server.d.ts +2 -0
- package/dist/server.js +38 -0
- package/package.json +100 -0
package/README.md
ADDED
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
<p align="center">
|
|
2
|
+
<img src="assets/iris-agent-logo.svg" alt="Iris Agent logo" width="180">
|
|
3
|
+
</p>
|
|
4
|
+
|
|
5
|
+
<h1 align="center">Iris Agent</h1>
|
|
6
|
+
|
|
7
|
+
<p align="center">
|
|
8
|
+
<a href="https://4onstudios.com/">Built by 4onStudios</a>
|
|
9
|
+
·
|
|
10
|
+
<a href="https://github.com/4onstudios/iris-agent/issues">Issues</a>
|
|
11
|
+
·
|
|
12
|
+
<a href="https://github.com/4onstudios/iris-agent/pulls">Contribute</a>
|
|
13
|
+
</p>
|
|
14
|
+
|
|
15
|
+
<p align="center">
|
|
16
|
+
<a href="https://github.com/4onstudios/iris-agent/actions/workflows/ci.yml"><img src="https://github.com/4onstudios/iris-agent/actions/workflows/ci.yml/badge.svg" alt="CI status"></a>
|
|
17
|
+
<a href="https://www.npmjs.com/package/@4onstudios/iris-agent"><img src="https://img.shields.io/npm/v/%404onstudios%2Firis-agent" alt="npm version"></a>
|
|
18
|
+
<a href="https://github.com/4onstudios/iris-agent/blob/main/LICENSE"><img src="https://img.shields.io/github/license/4onstudios/iris-agent" alt="MIT License"></a>
|
|
19
|
+
</p>
|
|
20
|
+
|
|
21
|
+
Iris Agent is the standalone coding-agent service used by [AIRIS](https://github.com/4onstudios/iris).
|
|
22
|
+
|
|
23
|
+
It provides streaming chat, workspace tools, LSP routes, MCP integration, command approvals, and run lifecycle APIs. It can run as:
|
|
24
|
+
|
|
25
|
+
- **HTTP Service** - RESTful API under `/api/agent`
|
|
26
|
+
- **CLI** - Interactive chat in the terminal
|
|
27
|
+
- **ACP Server** - Agent Client Protocol via stdio for seamless IDE integration
|
|
28
|
+
|
|
29
|
+
The SDK and ACP server require Node.js `>=22.13.0`. `IrisClient` is a
|
|
30
|
+
Node.js API for IDE desktop or backend processes; it is not intended to run in
|
|
31
|
+
a browser renderer.
|
|
32
|
+
|
|
33
|
+
## Quick Start
|
|
34
|
+
|
|
35
|
+
This project can be installed and run with either npm or Yarn. Configure your provider API key (such as `OPENROUTER_API_KEY` or `OPENAI_API_KEY`). By default, Iris Agent routes through OpenRouter (`openrouter/openai/gpt-4o`) when `OPENROUTER_API_KEY` is provided or configured.
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
# npm
|
|
39
|
+
npm install
|
|
40
|
+
OPENROUTER_API_KEY=... npm start
|
|
41
|
+
|
|
42
|
+
# yarn
|
|
43
|
+
yarn install
|
|
44
|
+
yarn start
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
### HTTP Service
|
|
48
|
+
|
|
49
|
+
```sh
|
|
50
|
+
npm install
|
|
51
|
+
OPENROUTER_API_KEY=... npm start
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
The service listens on port `8080` by default. Set `PORT` to change it. `GET /health` reports service readiness.
|
|
55
|
+
|
|
56
|
+
### Using Iris Agent in an IDE
|
|
57
|
+
|
|
58
|
+
To run the standalone agent service for an IDE integration:
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
git clone https://github.com/4onstudios/iris-agent.git
|
|
62
|
+
cd iris-agent
|
|
63
|
+
npm install
|
|
64
|
+
npm start
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
The service listens on port `8080` by default and exposes its API under
|
|
68
|
+
`/api/agent`. Set `PORT` to use another port and configure
|
|
69
|
+
`AGENT_ALLOWED_ORIGINS` with the IDE's origin when browser CORS is required:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
PORT=8080 AGENT_ALLOWED_ORIGINS=http://localhost:3000 npm start
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The HTTP API is mounted below `/api/agent`. The main endpoints are:
|
|
76
|
+
|
|
77
|
+
| Endpoint | Purpose |
|
|
78
|
+
| --- | --- |
|
|
79
|
+
| `POST /api/agent/chat` | Send a message and optional workspace, model, history, tools, skills, MCP, and approval settings. |
|
|
80
|
+
| `GET /api/agent/runs/:runId` | Read the current run lifecycle snapshot. |
|
|
81
|
+
| `GET /api/agent/runs/:runId/events` | Read persisted run events. Supports `afterSequence` and `limit` (1-500). |
|
|
82
|
+
| `POST /api/agent/runs/:runId/cancel` | Request cancellation of a run. |
|
|
83
|
+
| `POST /api/agent/command-confirmation` | Approve or skip a pending command execution. |
|
|
84
|
+
| `GET /api/agent/skills` | List discovered skills. |
|
|
85
|
+
| `GET /api/agent/tools` | List native and MCP tools with their input schemas. |
|
|
86
|
+
| `GET /api/agent/slash-commands` | List enabled slash commands. |
|
|
87
|
+
| `POST /api/agent/mcp/inspect` | Inspect the tools exposed by one MCP server. |
|
|
88
|
+
| `POST /api/agent/mcp/call` | Invoke an MCP tool. |
|
|
89
|
+
|
|
90
|
+
The service also exposes file, chat-session, semantic-search, and LSP routes under
|
|
91
|
+
`/api/agent`. Those routes are intended for the AIRIS desktop client and are
|
|
92
|
+
implemented in [`api/`](./api/); use `GET /api/agent/tools` and
|
|
93
|
+
`GET /api/agent/skills` for runtime discovery.
|
|
94
|
+
|
|
95
|
+
Example chat request:
|
|
96
|
+
|
|
97
|
+
```sh
|
|
98
|
+
curl -X POST http://localhost:8080/api/agent/chat \
|
|
99
|
+
-H 'Content-Type: application/json' \
|
|
100
|
+
-d '{"message":"Explain this project","workspaceRoot":"/path/to/project"}'
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
Run lifecycle states and event payloads are returned by the run endpoints. Store
|
|
104
|
+
the returned `runId` from a chat response if the client needs polling,
|
|
105
|
+
progress-event retrieval, or cancellation.
|
|
106
|
+
|
|
107
|
+
Persisted `tool_call` and `tool_result` events carry the redacted action
|
|
108
|
+
details needed to render a replayable tool timeline: `name` (and the deprecated
|
|
109
|
+
compatibility alias `toolName`), `args`, `toolCallId`, and `status`. Completed
|
|
110
|
+
actions also include `result` when its JSON representation is at most 16 KiB.
|
|
111
|
+
Larger or non-JSON-representable results are replaced with a bounded summary:
|
|
112
|
+
`{ truncated: true, reason?: string, originalByteLength?: number, preview?: string }`.
|
|
113
|
+
For oversized object results, scalar metadata such as `success`, `status`,
|
|
114
|
+
`error`, `exitCode`, paths, and search counts may also be retained with long
|
|
115
|
+
strings shortened. Legacy stored action events are normalized when read so both
|
|
116
|
+
tool-name labels remain available. This lets clients show, for example, the
|
|
117
|
+
path and line range read or the search query, matched files, and result counts
|
|
118
|
+
without relying on the live stream.
|
|
119
|
+
|
|
120
|
+
### CLI Mode
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
# Interactive chat with default model (openrouter/openai/gpt-4o)
|
|
124
|
+
OPENROUTER_API_KEY=... npm run cli -- --workspace /path/to/project --chat
|
|
125
|
+
|
|
126
|
+
# Interactive chat with a specific model
|
|
127
|
+
OPENROUTER_API_KEY=... npm run cli -- --workspace /path/to/project --chat --modelId openrouter/anthropic/claude-3.7-sonnet
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
This starts an interactive streaming chat session in your terminal with access to the workspace and tools.
|
|
131
|
+
|
|
132
|
+
### ACP Server
|
|
133
|
+
|
|
134
|
+
```sh
|
|
135
|
+
OPENROUTER_API_KEY=... npm run cli -- --workspace /path/to/project --acp
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
This starts an ACP (Agent Client Protocol) server over stdio, allowing IDE
|
|
139
|
+
integrations and other ACP clients to communicate with the agent. Models can be configured at startup or dynamically per-session / per-prompt. Standard
|
|
140
|
+
output is reserved for newline-delimited JSON-RPC messages; logs are written to
|
|
141
|
+
standard error. Each ACP process is bound to the workspace supplied at startup.
|
|
142
|
+
To switch workspaces, close the process and respawn `iris-agent` with the new
|
|
143
|
+
`--workspace` path.
|
|
144
|
+
|
|
145
|
+
## CLI Usage
|
|
146
|
+
|
|
147
|
+
```sh
|
|
148
|
+
iris-agent --workspace <path> [--acp | --chat] [--modelId <model>]
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Options:**
|
|
152
|
+
|
|
153
|
+
- `--workspace` (required, `-w`) - Path to the workspace/project root
|
|
154
|
+
- `--acp` (`-a`) - Start ACP protocol server (stdio-based)
|
|
155
|
+
- `--chat` (`-c`) - Start interactive chat mode
|
|
156
|
+
- `--modelId` - Model identifier used for chat/ACP sessions (default: `openrouter/openai/gpt-4o` or `MODEL_ID` / `OPENROUTER_MODEL` env vars)
|
|
157
|
+
|
|
158
|
+
Running the CLI without `--chat` or `--acp` prints help.
|
|
159
|
+
|
|
160
|
+
**Examples:**
|
|
161
|
+
|
|
162
|
+
```sh
|
|
163
|
+
# Interactive chat
|
|
164
|
+
npm run cli -- --workspace . --chat
|
|
165
|
+
|
|
166
|
+
# Interactive chat with custom model
|
|
167
|
+
npm run cli -- --workspace . --chat --modelId openrouter/anthropic/claude-3.7-sonnet
|
|
168
|
+
|
|
169
|
+
# ACP server for IDE integration
|
|
170
|
+
npm run cli -- --workspace . --acp
|
|
171
|
+
|
|
172
|
+
# ACP server with custom default model
|
|
173
|
+
npm run cli -- --workspace . --acp --modelId openrouter/openai/gpt-4o
|
|
174
|
+
|
|
175
|
+
# HTTP service (default)
|
|
176
|
+
npm start
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
## Browser Client
|
|
180
|
+
|
|
181
|
+
Configure the precise browser origins permitted to call this service:
|
|
182
|
+
|
|
183
|
+
```sh
|
|
184
|
+
AGENT_ALLOWED_ORIGINS=https://airis.4onstudios.com npm start
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
Multiple origins may be supplied as a comma-separated list. Requests without an `Origin` header (such as a local CLI or reverse proxy) are accepted; browser origins are denied unless explicitly configured.
|
|
188
|
+
|
|
189
|
+
## Providers
|
|
190
|
+
|
|
191
|
+
Configure the API key for the model provider selected by the client:
|
|
192
|
+
|
|
193
|
+
- `OPENAI_API_KEY`
|
|
194
|
+
- `ANTHROPIC_API_KEY`
|
|
195
|
+
- `GOOGLE_GENERATIVE_AI_API_KEY`
|
|
196
|
+
- `OPENROUTER_API_KEY`
|
|
197
|
+
- `OLLAMA_API_KEY`
|
|
198
|
+
|
|
199
|
+
Provider-specific configuration:
|
|
200
|
+
|
|
201
|
+
| Variable | Description |
|
|
202
|
+
| --- | --- |
|
|
203
|
+
| `OLLAMA_BASE_URL` | Ollama-compatible server URL. |
|
|
204
|
+
| `OPENROUTER_BASE_URL` | OpenRouter-compatible API URL. |
|
|
205
|
+
| `OPENROUTER_SITE_URL` / `OPENROUTER_SITE_NAME` | Optional OpenRouter request metadata. |
|
|
206
|
+
| `ANTHROPIC_BETA` / `ANTHROPIC_BETAS` | Optional Anthropic beta headers. |
|
|
207
|
+
| `HF_TOKEN` | Hugging Face authentication where required by a configured provider. |
|
|
208
|
+
|
|
209
|
+
### Runtime configuration
|
|
210
|
+
|
|
211
|
+
| Variable | Description |
|
|
212
|
+
| --- | --- |
|
|
213
|
+
| `PORT` | HTTP listening port; defaults to `8080`. |
|
|
214
|
+
| `AGENT_ALLOWED_ORIGINS` | Comma-separated browser origins allowed by CORS. Requests without an `Origin` header are allowed. |
|
|
215
|
+
| `DATABASE_URL` | Database connection URL used by the configured agent storage. |
|
|
216
|
+
| `IRIS_AGENT_RUNS_DB_PATH` | SQLite path for persisted run lifecycle data. |
|
|
217
|
+
| `IRIS_BACKEND_SERVICE` | Selects the backend service integration. |
|
|
218
|
+
| `IRIS_AGENT_PREFERRED_AGENT_ID` | Preferred external agent identifier. |
|
|
219
|
+
| `IRIS_AGENT_EXTERNAL_AGENT_MANIFEST_PATH` | Path to an external-agent manifest. |
|
|
220
|
+
| `IRIS_AGENT_GIT_SAFETY_MODE` | Git safety policy; defaults to `suggest`. |
|
|
221
|
+
| `IRIS_AGENT_AUTO_LINT` / `IRIS_AGENT_AUTO_TEST` | Enable automatic lint/test validation. |
|
|
222
|
+
| `IRIS_AGENT_LINT_CMD` / `IRIS_AGENT_TEST_CMD` | Override validation commands. |
|
|
223
|
+
| `IRIS_AGENT_AUTO_FIX_VALIDATION` | Enable automatic validation fixes. |
|
|
224
|
+
| `IRIS_AGENT_INPUT_TOKEN_LIMIT` / `IRIS_AGENT_MAX_OUTPUT_TOKENS` | Token-budget controls. |
|
|
225
|
+
| `IRIS_AGENT_PROMPT_TOKEN_BUDGET_RATIO` | Prompt budget ratio. |
|
|
226
|
+
| `IRIS_AGENT_MODEL_RETRY_ATTEMPTS` | Model request retry count. |
|
|
227
|
+
| `IRIS_AGENT_REFLECTION_MAX` / `IRIS_AGENT_REFLECTION_MAX_STEPS` | Reflection-loop limits. |
|
|
228
|
+
| `IRIS_AGENT_REFLECTION_RETRY_ATTEMPTS` | Reflection retry count. |
|
|
229
|
+
| `IRIS_AGENT_REFLECTION_NO_PROGRESS_REPEATS` | Maximum repeated no-progress reflection cycles. |
|
|
230
|
+
| `IRIS_ENABLE_SLASH_COMMANDS` | Enable slash-command handling. |
|
|
231
|
+
| `IRIS_DEBUG_TOKEN_USAGE_SOURCE` | Enable token-usage diagnostics. |
|
|
232
|
+
| `IRIS_AGENT_STREAM_RETRY_ENABLED` | Enable stream retries. Related retry delay and limit variables are supported by the runtime. |
|
|
233
|
+
| `IRIS_VERBOSE_SKILL_DISCOVERY` | Enable verbose skill-discovery logging. |
|
|
234
|
+
| `BROWSER_NO_SANDBOX` | Set to `true` only when browser automation must run without a sandbox. |
|
|
235
|
+
|
|
236
|
+
Environment values can be supplied in a local `.env` file for the HTTP server
|
|
237
|
+
because it loads `dotenv/config`. Do not commit `.env` files or API keys.
|
|
238
|
+
|
|
239
|
+
### Desktop authentication
|
|
240
|
+
|
|
241
|
+
Desktop-only routes require both `TAURI_BUNDLED=1` and `IRIS_DESKTOP_TOKEN`.
|
|
242
|
+
Clients send the token in the `X-Desktop-Token` header. These protected routes
|
|
243
|
+
include key management, file operations, remote chat-session synchronization,
|
|
244
|
+
and MCP inspection/calls. Do not expose the desktop token to browsers.
|
|
245
|
+
|
|
246
|
+
### Persistence
|
|
247
|
+
|
|
248
|
+
Run lifecycle data is stored in SQLite. Set `IRIS_AGENT_RUNS_DB_PATH` to choose
|
|
249
|
+
the database location; otherwise it is stored at `~/.iris/agent-runs.sqlite`.
|
|
250
|
+
Chat sessions are stored as JSON files under `~/.iris/chat-sessions/` and are
|
|
251
|
+
managed through the desktop synchronization routes.
|
|
252
|
+
|
|
253
|
+
### MCP and approvals
|
|
254
|
+
|
|
255
|
+
MCP servers are supplied in chat requests or MCP route payloads. Use
|
|
256
|
+
`POST /api/agent/mcp/inspect` to discover tools before calling
|
|
257
|
+
`POST /api/agent/mcp/call`. MCP tool names must start with `mcp_`.
|
|
258
|
+
Commands that require approval pause until the client submits
|
|
259
|
+
`POST /api/agent/command-confirmation` with a `confirmationId` and boolean
|
|
260
|
+
`approved` value.
|
|
261
|
+
|
|
262
|
+
## ACP Protocol
|
|
263
|
+
|
|
264
|
+
The stdio server implements the standard ACP v1 lifecycle:
|
|
265
|
+
|
|
266
|
+
- `initialize`
|
|
267
|
+
- `session/new` - supports initial `modelId` specification in `_meta` or parameters
|
|
268
|
+
- `session/load` - load existing session history with optional model override
|
|
269
|
+
- `session/set_config_option` - dynamically change session options such as model (`configId: "model"`)
|
|
270
|
+
- `session/prompt` - execute prompts with optional per-turn `modelId` override in `_meta`
|
|
271
|
+
- `session/cancel` - abort active turn
|
|
272
|
+
- `session/close` - clean up session resources
|
|
273
|
+
- `session/update` notifications for assistant text, reasoning, and tool status
|
|
274
|
+
|
|
275
|
+
The server supports dynamic model resolution and caching across ACP requests.
|
|
276
|
+
|
|
277
|
+
### Specifying Models in ACP Mode
|
|
278
|
+
|
|
279
|
+
Clients can specify and change models at multiple levels:
|
|
280
|
+
|
|
281
|
+
1. **Server Default**: Pass `--modelId <model>` to `iris-agent --acp` or set the `MODEL_ID` / `OPENROUTER_MODEL` environment variable.
|
|
282
|
+
2. **Session Creation / Load**: Pass `modelId` in `_meta.iris.modelId` or `_meta.modelId` during `session/new` or `session/load`.
|
|
283
|
+
3. **Dynamic Switch**: Call `session/set_config_option` with `configId: "model"` and `value: "<modelId>"` to change the active model for subsequent prompts.
|
|
284
|
+
4. **Per-Prompt Override**: Include `_meta.iris.modelId` or `_meta.modelId` in the `session/prompt` payload to run a single prompt turn with a specific model.
|
|
285
|
+
|
|
286
|
+
### IrisClient SDK
|
|
287
|
+
|
|
288
|
+
Install the published package in the Node.js process that owns your IDE's
|
|
289
|
+
agent integration:
|
|
290
|
+
|
|
291
|
+
```sh
|
|
292
|
+
npm install @4onstudios/iris-agent
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
The spawned agent uses the provider credentials from its environment. For
|
|
296
|
+
example:
|
|
297
|
+
|
|
298
|
+
```sh
|
|
299
|
+
OPENROUTER_API_KEY=... npm run your-ide-backend
|
|
300
|
+
```
|
|
301
|
+
|
|
302
|
+
When using a local checkout instead of the published package, build it before
|
|
303
|
+
starting the compiled CLI:
|
|
304
|
+
|
|
305
|
+
```sh
|
|
306
|
+
npm install
|
|
307
|
+
npm run build
|
|
308
|
+
```
|
|
309
|
+
|
|
310
|
+
When installing from a Git branch or commit, npm runs this package's
|
|
311
|
+
`prepare` script to build `dist/` during installation, so root exports such as
|
|
312
|
+
`IrisClient` are available without manually committing generated artifacts.
|
|
313
|
+
|
|
314
|
+
The ACP subprocess writes protocol messages to stdout and diagnostic logs to
|
|
315
|
+
stderr. Never merge logs into stdout or pipe stdout through a text logger;
|
|
316
|
+
doing so corrupts the ACP stream.
|
|
317
|
+
|
|
318
|
+
IDE extensions written for Node.js can use the exported `IrisClient` instead of
|
|
319
|
+
managing ACP messages or the agent subprocess directly:
|
|
320
|
+
|
|
321
|
+
```ts
|
|
322
|
+
import { IrisClient } from "@4onstudios/iris-agent";
|
|
323
|
+
|
|
324
|
+
const { client } = await IrisClient.spawn({
|
|
325
|
+
cwd: workspaceRoot,
|
|
326
|
+
onSessionUpdate(notification) {
|
|
327
|
+
renderAgentUpdate(notification.update);
|
|
328
|
+
},
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
try {
|
|
332
|
+
// Open session with an optional specific model
|
|
333
|
+
await client.openSession(workspaceRoot, {
|
|
334
|
+
modelId: "openrouter/anthropic/claude-3.7-sonnet",
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
// Prompt the agent
|
|
338
|
+
const result = await client.prompt("Explain the selected code");
|
|
339
|
+
console.log(result.stopReason);
|
|
340
|
+
|
|
341
|
+
// Switch model dynamically mid-session
|
|
342
|
+
await client.setModel("openrouter/openai/gpt-4o");
|
|
343
|
+
|
|
344
|
+
// Or override model for a single prompt
|
|
345
|
+
await client.prompt("Refactor this function", {
|
|
346
|
+
modelId: "openrouter/google/gemini-2.0-flash",
|
|
347
|
+
});
|
|
348
|
+
} finally {
|
|
349
|
+
await client.close();
|
|
350
|
+
}
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
`IrisClient.spawn()` starts `iris-agent --workspace <cwd> --acp`, initializes the
|
|
354
|
+
ACP connection, and owns process cleanup. The `cwd` must be the workspace path
|
|
355
|
+
the agent is allowed to access. The package's `iris-agent` executable must be
|
|
356
|
+
available on `PATH`; use `command` and `args` when your IDE starts a local
|
|
357
|
+
checkout or a custom launcher:
|
|
358
|
+
|
|
359
|
+
```ts
|
|
360
|
+
const { client } = await IrisClient.spawn({
|
|
361
|
+
command: "node",
|
|
362
|
+
args: ["/path/to/iris-agent/dist/cli.js", "--workspace", workspaceRoot, "--acp"],
|
|
363
|
+
cwd: workspaceRoot,
|
|
364
|
+
env: { OPENAI_API_KEY: process.env.OPENAI_API_KEY },
|
|
365
|
+
});
|
|
366
|
+
```
|
|
367
|
+
|
|
368
|
+
One `IrisClient` owns one active ACP session. Call `openSession()` before
|
|
369
|
+
`prompt()`, use `cancel()` to stop the active turn, and call `closeSession()`
|
|
370
|
+
to end a session in the current workspace. An ACP process is bound to its
|
|
371
|
+
startup workspace: to switch workspaces, call `close()` and use `spawn()` to
|
|
372
|
+
create a new client for the new workspace. `close()` also terminates a process
|
|
373
|
+
created by `spawn()` and is safe to call repeatedly.
|
|
374
|
+
|
|
375
|
+
`IrisClient.connect()` accepts an existing ACP stream or in-process ACP agent
|
|
376
|
+
when the IDE manages the process or transport itself. Use this for IDEs that
|
|
377
|
+
already have a process supervisor or ACP transport. `spawn()` rejects if the
|
|
378
|
+
agent executable cannot start or initialization fails, so handle startup errors
|
|
379
|
+
before enabling agent commands in the UI.
|
|
380
|
+
|
|
381
|
+
The `onSessionUpdate` callback receives standard ACP session notifications:
|
|
382
|
+
|
|
383
|
+
| Update | Typical UI behavior |
|
|
384
|
+
| --- | --- |
|
|
385
|
+
| `agent_message_chunk` | Append assistant text. |
|
|
386
|
+
| `agent_thought_chunk` | Show or hide reasoning according to IDE policy. |
|
|
387
|
+
| `tool_call` | Show a tool as running. |
|
|
388
|
+
| `tool_call_update` | Update tool status and output. |
|
|
389
|
+
|
|
390
|
+
Do not expose provider API keys or raw ACP stdio streams to a browser renderer.
|
|
391
|
+
Keep the client in the trusted desktop/backend process and forward only the
|
|
392
|
+
events and commands your IDE UI needs.
|
|
393
|
+
|
|
394
|
+
### Direct ACP JSON-RPC Client
|
|
395
|
+
|
|
396
|
+
Use `IrisClient` unless your integration must own the ACP process and
|
|
397
|
+
JSON-RPC transport. The following Node.js example starts the published CLI
|
|
398
|
+
with `npx`, performs the ACP v1 handshake, streams updates, and closes the
|
|
399
|
+
session and child process reliably:
|
|
400
|
+
|
|
401
|
+
```ts
|
|
402
|
+
import { spawn } from "node:child_process";
|
|
403
|
+
import readline from "node:readline";
|
|
404
|
+
|
|
405
|
+
type JsonRpcResponse = {
|
|
406
|
+
id?: number;
|
|
407
|
+
result?: unknown;
|
|
408
|
+
error?: { code: number; message: string };
|
|
409
|
+
method?: string;
|
|
410
|
+
params?: {
|
|
411
|
+
update?: {
|
|
412
|
+
sessionUpdate?: string;
|
|
413
|
+
content?: { text?: string };
|
|
414
|
+
title?: string;
|
|
415
|
+
};
|
|
416
|
+
};
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
async function connectToIrisAcp() {
|
|
420
|
+
const workspaceRoot = process.cwd();
|
|
421
|
+
const agentProcess = spawn(
|
|
422
|
+
"npx",
|
|
423
|
+
["--yes", "@4onstudios/iris-agent", "--workspace", workspaceRoot, "--acp"],
|
|
424
|
+
{
|
|
425
|
+
cwd: workspaceRoot,
|
|
426
|
+
stdio: ["pipe", "pipe", "inherit"],
|
|
427
|
+
env: process.env,
|
|
428
|
+
},
|
|
429
|
+
);
|
|
430
|
+
|
|
431
|
+
let nextMessageId = 1;
|
|
432
|
+
const pendingRequests = new Map<
|
|
433
|
+
number,
|
|
434
|
+
{ resolve: (result: unknown) => void; reject: (error: Error) => void }
|
|
435
|
+
>();
|
|
436
|
+
|
|
437
|
+
const rejectPendingRequests = (error: Error) => {
|
|
438
|
+
for (const { reject } of pendingRequests.values()) reject(error);
|
|
439
|
+
pendingRequests.clear();
|
|
440
|
+
};
|
|
441
|
+
|
|
442
|
+
agentProcess.once("error", rejectPendingRequests);
|
|
443
|
+
agentProcess.once("exit", (code, signal) => {
|
|
444
|
+
rejectPendingRequests(
|
|
445
|
+
new Error(`Iris ACP process exited (${signal ?? `code ${code ?? "unknown"}`})`),
|
|
446
|
+
);
|
|
447
|
+
});
|
|
448
|
+
|
|
449
|
+
const sendRequest = (method: string, params?: unknown): Promise<unknown> => {
|
|
450
|
+
const id = nextMessageId++;
|
|
451
|
+
agentProcess.stdin.write(
|
|
452
|
+
`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}\n`,
|
|
453
|
+
);
|
|
454
|
+
return new Promise((resolve, reject) => {
|
|
455
|
+
pendingRequests.set(id, { resolve, reject });
|
|
456
|
+
});
|
|
457
|
+
};
|
|
458
|
+
|
|
459
|
+
const lines = readline.createInterface({ input: agentProcess.stdout });
|
|
460
|
+
lines.on("line", (line) => {
|
|
461
|
+
if (!line.trim()) return;
|
|
462
|
+
|
|
463
|
+
const message = JSON.parse(line) as JsonRpcResponse;
|
|
464
|
+
if (typeof message.id === "number" && pendingRequests.has(message.id)) {
|
|
465
|
+
const request = pendingRequests.get(message.id)!;
|
|
466
|
+
pendingRequests.delete(message.id);
|
|
467
|
+
if (message.error) {
|
|
468
|
+
request.reject(new Error(message.error.message));
|
|
469
|
+
} else {
|
|
470
|
+
request.resolve(message.result);
|
|
471
|
+
}
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
const update = message.params?.update;
|
|
476
|
+
if (message.method === "session/update") {
|
|
477
|
+
if (update?.sessionUpdate === "agent_message_chunk") {
|
|
478
|
+
process.stdout.write(update.content?.text ?? "");
|
|
479
|
+
} else if (update?.sessionUpdate === "tool_call") {
|
|
480
|
+
console.log(`\n[Executing tool: ${update.title ?? "unknown"}]`);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
});
|
|
484
|
+
|
|
485
|
+
try {
|
|
486
|
+
await sendRequest("initialize", {
|
|
487
|
+
protocolVersion: 1,
|
|
488
|
+
clientInfo: { name: "my-custom-service", version: "1.0.0" },
|
|
489
|
+
clientCapabilities: {},
|
|
490
|
+
});
|
|
491
|
+
|
|
492
|
+
const session = (await sendRequest("session/new", {
|
|
493
|
+
cwd: workspaceRoot,
|
|
494
|
+
mcpServers: [],
|
|
495
|
+
})) as { sessionId: string };
|
|
496
|
+
|
|
497
|
+
await sendRequest("session/prompt", {
|
|
498
|
+
sessionId: session.sessionId,
|
|
499
|
+
prompt: [
|
|
500
|
+
{
|
|
501
|
+
type: "text",
|
|
502
|
+
text: "List all files in the root folder and summarize the project.",
|
|
503
|
+
},
|
|
504
|
+
],
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
await sendRequest("session/close", { sessionId: session.sessionId });
|
|
508
|
+
} finally {
|
|
509
|
+
lines.close();
|
|
510
|
+
if (!agentProcess.killed) agentProcess.kill();
|
|
511
|
+
}
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
connectToIrisAcp().catch(console.error);
|
|
515
|
+
```
|
|
516
|
+
|
|
517
|
+
Set `OPENAI_API_KEY`, `OPENROUTER_API_KEY`, or the API key for the selected
|
|
518
|
+
provider in the environment before starting the client. Keep those credentials
|
|
519
|
+
in the trusted Node.js process; do not pass them to a browser renderer.
|
|
520
|
+
|
|
521
|
+
The CLI does not load MCP definitions from `AIRIS_MCP_SERVERS`. In the current
|
|
522
|
+
ACP server, custom MCP servers are not yet applied from `session/new` either,
|
|
523
|
+
so leave `mcpServers` empty as shown. To use custom MCP tools today, configure
|
|
524
|
+
them through the authenticated HTTP agent API rather than this ACP example.
|
|
525
|
+
|
|
526
|
+
#### Troubleshooting
|
|
527
|
+
|
|
528
|
+
- `ENOENT` when calling `spawn()` means the configured `command` is not on
|
|
529
|
+
`PATH`. Set `command` and `args` to the compiled CLI, or install the package
|
|
530
|
+
globally for the IDE process.
|
|
531
|
+
- An initialization failure usually means the subprocess exited early, the
|
|
532
|
+
provider key is missing, or stdout contains non-ACP output. Inspect stderr
|
|
533
|
+
and verify the provider environment passed through `env`.
|
|
534
|
+
- A prompt requires an open session. Call `openSession()` once per workspace.
|
|
535
|
+
To switch workspaces, call `close()` to terminate the current ACP process,
|
|
536
|
+
then use `spawn()` to create a client bound to the new workspace.
|
|
537
|
+
- `IrisClient` requires a Node.js desktop/backend process. Browser-only IDE
|
|
538
|
+
clients should call their backend over HTTPS/WebSocket/IPC instead of
|
|
539
|
+
spawning the agent in the renderer.
|
|
540
|
+
|
|
541
|
+
### Custom IDE Backend
|
|
542
|
+
|
|
543
|
+
For a custom IDE, keep `IrisClient` in the desktop or backend process and
|
|
544
|
+
forward agent updates to the UI over WebSocket, IPC, or the IDE's event bus:
|
|
545
|
+
|
|
546
|
+
```ts
|
|
547
|
+
import { IrisClient } from "@4onstudios/iris-agent";
|
|
548
|
+
|
|
549
|
+
export class IrisAgentController {
|
|
550
|
+
private client?: IrisClient;
|
|
551
|
+
|
|
552
|
+
async start(workspaceRoot: string, onUpdate: (update: unknown) => void) {
|
|
553
|
+
const spawned = await IrisClient.spawn({
|
|
554
|
+
cwd: workspaceRoot,
|
|
555
|
+
clientName: "my-custom-ide",
|
|
556
|
+
clientVersion: "1.0.0",
|
|
557
|
+
onSessionUpdate(notification) {
|
|
558
|
+
onUpdate(notification.update);
|
|
559
|
+
},
|
|
560
|
+
});
|
|
561
|
+
|
|
562
|
+
this.client = spawned.client;
|
|
563
|
+
await this.client.openSession(workspaceRoot);
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
async prompt(prompt: string) {
|
|
567
|
+
if (!this.client) throw new Error("Iris agent is not running");
|
|
568
|
+
return this.client.prompt(prompt);
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
async cancel() {
|
|
572
|
+
await this.client?.cancel();
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
async stop() {
|
|
576
|
+
await this.client?.close();
|
|
577
|
+
this.client = undefined;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
```
|
|
581
|
+
|
|
582
|
+
Example backend routes can forward updates to the custom IDE client:
|
|
583
|
+
|
|
584
|
+
```ts
|
|
585
|
+
const iris = new IrisAgentController();
|
|
586
|
+
|
|
587
|
+
await iris.start(workspaceRoot, (update) => {
|
|
588
|
+
websocket.broadcast({ type: "agent-update", update });
|
|
589
|
+
});
|
|
590
|
+
|
|
591
|
+
app.post("/api/agent/prompt", async (request, response) => {
|
|
592
|
+
response.json(await iris.prompt(request.body.prompt));
|
|
593
|
+
});
|
|
594
|
+
|
|
595
|
+
app.post("/api/agent/cancel", async (_request, response) => {
|
|
596
|
+
await iris.cancel();
|
|
597
|
+
response.sendStatus(204);
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
app.post("/api/agent/stop", async (_request, response) => {
|
|
601
|
+
await iris.stop();
|
|
602
|
+
response.sendStatus(204);
|
|
603
|
+
});
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
Handle forwarded updates in the IDE UI using `sessionUpdate`:
|
|
607
|
+
|
|
608
|
+
```ts
|
|
609
|
+
function handleAgentUpdate(update: any) {
|
|
610
|
+
switch (update.sessionUpdate) {
|
|
611
|
+
case "agent_message_chunk":
|
|
612
|
+
appendAssistantText(update.content.text);
|
|
613
|
+
break;
|
|
614
|
+
case "agent_thought_chunk":
|
|
615
|
+
appendReasoning(update.content.text);
|
|
616
|
+
break;
|
|
617
|
+
case "tool_call":
|
|
618
|
+
showToolStarted(update.title, update.toolCallId);
|
|
619
|
+
break;
|
|
620
|
+
case "tool_call_update":
|
|
621
|
+
updateToolStatus(update.toolCallId, update.status);
|
|
622
|
+
break;
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
The integration flow is:
|
|
628
|
+
|
|
629
|
+
```text
|
|
630
|
+
Custom IDE UI -> IDE backend -> IrisClient.spawn()
|
|
631
|
+
-> iris-agent --acp -> ACP session/update events
|
|
632
|
+
-> IDE backend -> WebSocket/IPC -> Custom IDE UI
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
## Development
|
|
636
|
+
|
|
637
|
+
```sh
|
|
638
|
+
npm run typecheck
|
|
639
|
+
npm run build
|
|
640
|
+
npm test
|
|
641
|
+
```
|
|
642
|
+
|
|
643
|
+
The repository also provides Make targets:
|
|
644
|
+
|
|
645
|
+
```sh
|
|
646
|
+
make test # npm test with Jest's serial/forced-exit flags
|
|
647
|
+
make run # npm start
|
|
648
|
+
make dev # npm run dev
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
For production, run the compiled output from a process supervisor, restrict
|
|
652
|
+
`AGENT_ALLOWED_ORIGINS`, keep provider credentials in a secret store, protect
|
|
653
|
+
the HTTP service behind TLS/authentication, and use a writable persistent
|
|
654
|
+
location for the run database.
|
|
655
|
+
|
|
656
|
+
## Contributing
|
|
657
|
+
|
|
658
|
+
Contributions are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md) for setup,
|
|
659
|
+
validation, and pull request guidance. Use the repository's issue templates for
|
|
660
|
+
bug reports and feature requests. See [CODE_OF_CONDUCT.md](./CODE_OF_CONDUCT.md)
|
|
661
|
+
for community expectations and [SECURITY.md](./SECURITY.md) for private
|
|
662
|
+
vulnerability reporting.
|
|
663
|
+
|
|
664
|
+
The project logo is available at
|
|
665
|
+
[`assets/iris-agent-logo.svg`](./assets/iris-agent-logo.svg) for repository and
|
|
666
|
+
community references. Keep the logo unchanged when using it as the project
|
|
667
|
+
mark.
|
|
668
|
+
|
|
669
|
+
## Package publishing
|
|
670
|
+
|
|
671
|
+
The package is configured for public npm publication:
|
|
672
|
+
|
|
673
|
+
```sh
|
|
674
|
+
npm login
|
|
675
|
+
npm publish
|
|
676
|
+
```
|
|
677
|
+
|
|
678
|
+
Yarn users can install the published package with:
|
|
679
|
+
|
|
680
|
+
```sh
|
|
681
|
+
yarn global add @4onstudios/iris-agent
|
|
682
|
+
```
|
|
683
|
+
|
|
684
|
+
Publishing requires access to the `@4onstudios` npm scope. The package is
|
|
685
|
+
configured with public access, but npm credentials and organization
|
|
686
|
+
permissions must be supplied by the publisher.
|
|
687
|
+
|
|
688
|
+
See [RELEASING.md](./RELEASING.md) for npm publication and versioning steps.
|
|
689
|
+
|
|
690
|
+
This project is released under the [MIT License](LICENSE).
|