Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions ts/.vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@
{
"type": "node",
"request": "launch",
"name": "CLI interactive",
"name": "CLI connect",
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}/packages/cli",
"program": "./bin/run.js",
"args": ["interactive"],
"args": ["connect"],
"console": "integratedTerminal",
"outFiles": ["${workspaceFolder}/**/*.js"]
},
Expand All @@ -76,11 +76,11 @@
{
"type": "node",
"request": "launch",
"name": "CLI (dev) interactive",
"name": "CLI (dev) connect",
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}/packages/cli",
"program": "./bin/dev.js",
"args": ["interactive"],
"args": ["connect"],
"runtimeArgs": [
"--loader",
"ts-node/esm",
Expand All @@ -92,11 +92,11 @@
{
"type": "node",
"request": "launch",
"name": "CLI (dev) interactive [intergrated terminal]",
"name": "CLI (dev) connect [integrated terminal]",
"skipFiles": ["<node_internals>/**"],
"cwd": "${workspaceFolder}/packages/cli",
"program": "./bin/dev.js",
"args": ["interactive"],
"args": ["connect"],
"runtimeArgs": [
"--loader",
"ts-node/esm",
Expand Down
2 changes: 1 addition & 1 deletion ts/CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ Detail architecture descriptions are located in the **`docs/architecture`** dire
- **`packages/knowPro/`** — Structured RAG implementation for conversational memory.
- **`packages/agents/`** — All application agents (player, calendar, email, list, browser, etc.).
- **`packages/shell/`** — Electron GUI app.
- **`packages/cli/`** — Console app.
- **`packages/cli/`** — Console app (connected-mode only; all commands route through `agent-server` via WebSocket RPC).

### Agent plugin structure

Expand Down
12 changes: 6 additions & 6 deletions ts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ Also, you can go to the shell directory `./packages/shell` and start from there.
[TypeAgent CLI](./packages/cli) provides a console based _interactive agents_ with _natural language interfaces_ experience. Additional console command is available to explore different part of TypeAgent functionalities.

- Run `pnpm run cli` to get the available command
- Run `pnpm run cli -- interactive` will start the interactive prompt
- Run `pnpm run cli -- connect` will start the interactive prompt (connecting to the agent server via WebSocket RPC)

Also, you can go to the CLI directory `./packages/cli` and start from there. Please see instruction in TypeAgent CLI's [README.md](./packages/cli/README.md) for more options and detail.

Expand Down Expand Up @@ -277,13 +277,13 @@ If you open this directory as a workspace in VSCode, multiple launch task is def

Common Debug Launch Task:

- CLI interactive - `./package/cli/bin/run.js interactive`
- CLI (dev) interactive - `./package/cli/bin/dev.js interactive` with a new command prompt
- CLI (dev) interactive [Integrated Terminal] - `./bin/dev.js interactive` using VSCode terminal (needed for WSL)
- CLI connect - `./package/cli/bin/run.js connect`
- CLI (dev) connect - `./package/cli/bin/dev.js connect` with a new command prompt
- CLI (dev) connect [Integrated Terminal] - `./bin/dev.js connect` using VSCode terminal (needed for WSL)

#### Attaching to running sessions

To attaching to an existing session with TypeAgent CLI's interactive mode or TypeAgent Shell, you can start inspector by issuing the command `@debug` and use the VSCode `Attach` debugger launch task to attach.
To attaching to an existing session with TypeAgent CLI's connect mode or TypeAgent Shell, you can start inspector by issuing the command `@debug` and use the VSCode `Attach` debugger launch task to attach.

#### TypeAgent Shell Browser Process

Expand All @@ -298,7 +298,7 @@ The project uses [debug](https://www.npmjs.com/package/debug) package to enable
For example (in Linux), to trace the GPT prompt that get sent when running the interactive CLI.

```bash
DEBUG=typeagent:prompt packages/cli/bin/run.js interactive
DEBUG=typeagent:prompt packages/cli/bin/run.js connect
```

**Option 2**: In the shell or CLI's interactive mode, you can issue the command `@trace <pattern>` to add to the list of namespace. Use "-" or "-\*" to disable all the trace.
Expand Down
14 changes: 14 additions & 0 deletions ts/docs/architecture/agentServerSessions.md
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,7 @@ agent-cli connect # connect to the 'CLI' session (created
agent-cli connect --resume # resume the last used session
agent-cli connect --session <id> # connect to a specific session by ID
agent-cli connect --port <port> # connect to a server on a non-default port (default: 8999)
agent-cli connect --hidden # start the server hidden (no visible window)
```

By default (no flags), `connect` targets a session named `"CLI"`. It calls `listSessions("CLI")` and joins the first match, or calls `createSession("CLI")` if none exists.
Expand All @@ -365,8 +366,21 @@ Pass `--resume` / `-r` to instead resume the last used session, whose ID is pers

Pass `--session` / `-s <id>` to connect to a specific session by UUID. This takes priority over `--resume` if both are provided; errors propagate as-is without the recovery prompt.

Pass `--hidden` to start the agent server without a visible window. Default is a visible window for interactive use.

On every successful connection the connected session ID is written to `~/.typeagent/cli-state.json` for use by future `--resume` invocations.

#### `run` — non-interactive commands

`agent-cli run request`, `run translate`, and `run explain` each accept `--session <id>` / `-s` to target a specific session. If omitted, they use the find-or-create `"CLI"` session. The server is started hidden by default for non-interactive commands; use `--show` to get a visible window.

#### `server` — manage the server process

```bash
agent-cli server status # show whether the server is running
agent-cli server stop # send a graceful shutdown to the running server
```

#### `sessions` topic — session CRUD

| Command | RPC call |
Expand Down
2 changes: 1 addition & 1 deletion ts/docs/architecture/completion.md
Original file line number Diff line number Diff line change
Expand Up @@ -888,7 +888,7 @@ needs shadow candidates".

## CLI integration

The CLI (`packages/cli/src/commands/interactive.ts`) follows the same
The CLI (`packages/cli/src/commands/connect.ts`) follows the same
contract but with simpler plumbing:

1. Sends full input and a `direction` (always `"forward"` for tab-completion,
Expand Down
54 changes: 42 additions & 12 deletions ts/packages/agentServer/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -105,17 +105,20 @@ Session dispatchers are automatically evicted from memory after 5 minutes with n
## Connection lifecycle

```
Client calls ensureAndConnectDispatcher(clientIO, port)
Client calls ensureAgentServer(port, hidden)
├─ Is server already listening on ws://localhost:<port>?
│ └─ No → spawnAgentServer() — detached child process, survives parent exit
└─ Is server already listening on ws://localhost:<port>?
└─ No → spawnAgentServer() — detached child process, survives parent exit
hidden=true suppresses the terminal/window

Client calls connectAgentServer(url)
├─ Open WebSocket → create RPC channels
├─ Send joinSession({ clientType, filter }) on agent-server channel
├─ Send joinSession({ sessionId, clientType, filter }) on agent-server channel
│ └─ Server assigns connectionId, returns { connectionId, sessionId }
└─ Return Dispatcher RPC proxy to caller
└─ Return AgentServerConnection (call .joinSession() to get a Dispatcher proxy)
```

On disconnect, the server removes all of that connection's sessions from its routing table.
Expand All @@ -142,10 +145,29 @@ Chat UI (renderer) ↔ IPC ↔ Main process ↔ WebSocket ↔ agentServer

## CLI integration

The CLI ([`packages/cli/src/commands/connect.ts`](../cli/src/commands/connect.ts)) always uses remote connection. It calls `ensureAndConnectDispatcher()`, which auto-spawns the server if not already running, then enters an interactive readline loop.
The CLI ([`packages/cli/`](../cli/)) always uses remote connection via WebSocket.

```
Terminal ↔ EnhancedConsoleClientIO ↔ WebSocket ↔ agentServer
Terminal ↔ ConsoleClientIO ↔ WebSocket ↔ agentServer
```

### `agent-cli connect` (interactive)

`connect` calls `ensureAgentServer(port, hidden, idleTimeout)` to auto-spawn the server if needed, then calls `connectAgentServer()` and `joinSession()` directly. By default the spawned server window is visible; pass `--hidden` to suppress it. Pass `--idle-timeout <seconds>` to enable idle shutdown when spawning (default: `0`, server stays alive indefinitely).

### `agent-cli run` (non-interactive)

The `run request`, `run translate`, and `run explain` subcommands also call `ensureAgentServer()` — but default to **hidden** (no window), with `--show` to opt into a visible window. All three support `--session <id>` to target a specific session instead of the default `"CLI"` session. When spawning, passes `--idle-timeout 600` so the server exits 10 minutes after the last client disconnects.

### `agent-cli replay`

`replay` always creates an ephemeral session (`cli-replay-<uuid>`) and deletes it on exit. Defaults to hidden; `--show` to opt in. Also passes `--idle-timeout 600` when spawning.

### `agent-cli server`

```bash
agent-cli server status # check whether the server is running
agent-cli server stop # send a graceful shutdown via RPC
```

---
Expand All @@ -161,17 +183,18 @@ Shell launches → createDispatcher() in-process → no server involved
**Shell or CLI — server already running**

```
Client → ensureAndConnectDispatcher(port=8999)
→ server already running → connect → joinSession() → Dispatcher proxy
Client → ensureAgentServer(port=8999, hidden)
→ server already running → no-op
Client → connectAgentServer() → joinSession() → Dispatcher proxy
```

**Shell or CLI — server not yet running**

```
Client → ensureAndConnectDispatcher(port=8999)
→ server not found → spawnAgentServer()
Client → ensureAgentServer(port=8999, hidden, idleTimeout)
→ server not found → spawnAgentServer() (hidden or visible window)
→ poll until ready (60 s timeout)
→ connect → joinSession() → Dispatcher proxy
Client → connectAgentServer() → joinSession() → Dispatcher proxy
```

**Headless server**
Expand All @@ -182,6 +205,13 @@ pnpm --filter agent-server start
→ any number of Shell/CLI clients can connect and share sessions
```

**Stopping the server**

```bash
agent-cli server stop # via CLI (recommended)
pnpm --filter agent-server stop # via pnpm script
```

---

## Session persistence
Expand Down
69 changes: 54 additions & 15 deletions ts/packages/agentServer/client/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,33 +40,72 @@ await connection.close();
| `deleteSession(sessionId)` | Delete a session and its persisted data |
| `close()` | Close the WebSocket connection |

### `ensureAndConnectDispatcher(clientIO, port?, options?, onDisconnect?)`
### `ensureAgentServer(port?, hidden?, idleTimeout?)`

Convenience wrapper that auto-spawns the server if needed and joins a session, returning a `Dispatcher` directly. Used by Shell and CLI.
Ensures the agentServer is running, spawning it if needed.

1. Checks whether a server is already listening on `ws://localhost:<port>` (default 8999).
2. If not, calls `spawnAgentServer()` to start it as a detached child process.
1. Calls `isServerRunning(url)` to check whether a server is already listening.
2. If not, calls `spawnAgentServer(hidden, idleTimeout)` to start it as a detached child process.
3. Polls until the server is ready (500 ms interval, 60 s timeout).
4. Calls `connectDispatcher()` and returns the `Dispatcher` proxy.

```typescript
const dispatcher = await ensureAndConnectDispatcher(
clientIO,
8999,
{ clientType: "shell" },
() => {
console.error("Disconnected");
process.exit(1);
},
);
// Start hidden with 10-minute idle shutdown — used by non-interactive CLI commands
await ensureAgentServer(8999, true, 600);

await dispatcher.processCommand("help");
// Start in a visible window, no idle shutdown — used by interactive connect
await ensureAgentServer(8999, false);

const connection = await connectAgentServer("ws://localhost:8999");
```

| Parameter | Type | Default | Description |
| ------------- | --------- | ------- | ------------------------------------------------------------------------------------ |
| `port` | `number` | `8999` | Port to check and spawn on |
| `hidden` | `boolean` | `false` | When spawning, suppress the terminal/window (`true` = hidden) |
| `idleTimeout` | `number` | `0` | Pass `--idle-timeout` to the spawned server; `0` disables (server runs indefinitely) |

### `isServerRunning(url)`

Returns `true` if a server is already listening at the given WebSocket URL.

```typescript
if (await isServerRunning("ws://localhost:8999")) {
console.log("Server is up");
}
```

### `stopAgentServer(port?)`

Connects to the running server on the given port and sends a `shutdown()` RPC.

### `ensureAndConnectSession(clientIO, port?, options?, onDisconnect?, hidden?, idleTimeout?)`

Convenience wrapper: ensures the server is running, connects, and joins a session in one call. Returns a `SessionDispatcher` directly.

```typescript
const session = await ensureAndConnectSession(
clientIO,
8999,
{ sessionId },
onDisconnect,
true,
600,
);
```

| Parameter | Type | Default | Description |
| -------------- | -------------------------- | ------------ | ----------------------------------------------------- |
| `clientIO` | `ClientIO` | _(required)_ | Client IO implementation |
| `port` | `number` | `8999` | Port to connect to |
| `options` | `DispatcherConnectOptions` | `undefined` | Session join options (e.g. `sessionId`) |
| `onDisconnect` | `() => void` | `undefined` | Called when the WebSocket disconnects |
| `hidden` | `boolean` | `false` | Suppress terminal/window when spawning |
| `idleTimeout` | `number` | `0` | Pass `--idle-timeout` to spawned server; `0` disables |

### `ensureAndConnectDispatcher(clientIO, port?, options?, onDisconnect?)` _(deprecated)_

Convenience wrapper that auto-spawns the server if needed and joins a session, returning a `Dispatcher` directly. Prefer calling `ensureAgentServer()` + `connectAgentServer()` + `joinSession()` separately for full control.

### `connectDispatcher(clientIO, url, options?, onDisconnect?)` _(deprecated)_

Backward-compatible wrapper: connects and immediately joins a session, returning a `Dispatcher`. Use `connectAgentServer()` for full multi-session support.
Expand Down
Loading
Loading