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
3 changes: 2 additions & 1 deletion .fallowrc.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
"ignoreDependencies": [
"@ai-sdk/anthropic",
"@ai-sdk/openai",
"ollama-ai-provider"
"ollama-ai-provider",
"prompts"
],
"usedClassMembers": [
{
Expand Down
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- README revamped into a short front page (LOU-D52); the details it dropped moved to `docs/` (new pages: tools, approvals, providers, cli, flows, guardrails, utilities).

### Changed
- Heavy dependencies are optional peers (LOU-D40): `dockerode` (Docker sandboxing, `SubprocessSandbox`), `@modelcontextprotocol/sdk` (`serveMcp`, `loushy mcp`, MCP clients) and `prompts` (the interactive questions of `loushy init`) moved from `dependencies` to `peerDependencies`, marked optional in `peerDependenciesMeta`. They were already loaded lazily; now a project that uses none of them does not install them. Using one without its package fails that call with `MissingPeerDependencyError`, which now also carries `feature` and names the exact command (for example `npm install dockerode@^5.0.1`). `loushy doctor` lists the three with what they enable (a missing `dockerode` fails the check when the agent spec uses a sandboxed tool), and its version lookup no longer returns `undefined` for packages whose `exports` map hides `package.json`. **Migration:** install the peer if you use Docker sandboxing (`npm install dockerode`), MCP (`npm install @modelcontextprotocol/sdk`), or interactive `loushy init` (`npm install prompts`; `npm create loushy-agent` already does, and `loushy init --yes` needs nothing). See docs/installation.md.
- The `http` tool no longer loads `undici` for default requests (LOU-D40): with TLS verification on (the default) it uses the runtime's global `fetch`; `undici` (still a regular dependency) is loaded only for `validateSSL: false`, whose per-request TLS dispatcher the global `fetch` cannot express. `yaml` stays a dependency (agent specs and skills need a YAML parser).
- Retries no longer stack (LOU-V7.2): the built-in providers (`OpenAIProvider`, `AnthropicProvider`, `OllamaProvider`, `OpenRouterProvider`) now pass `maxRetries` to the `ai` SDK calls: `config.maxRetries`, or 2 (the `ai` SDK's default, so behaviour is unchanged) when unset. `createAgent()` builds the providers it resolves from strings with `maxRetries: 0` and retries in its `withRetry()` wrapper instead, so retries happen in one place (at most 3 calls by default, as before) and each one is observable. If you wrap a built-in provider in `withRetry()` / `resilientProvider()` yourself, build it with `maxRetries: 0`; note that a `maxRetries` you already set in a provider config is now honoured by the `ai` SDK.
- `AgentType` is optional and deprecated (LOU-D34, not breaking): `AgentBuilder.build()` no longer requires `setType()` and `AgentConfig.agentType` is now optional (`createAgent()` and `specToAgent()` agents carry no type). `AgentType`, `setType()` and the `agent-types` registry/validators are marked `@deprecated`: they have no runtime effect and will be removed in the next minor; they stay exported for now. Drop your `setType(...)` calls.
- BREAKING: `encrypt()` now generates a random salt per call instead of a hardcoded one. Ciphertext produced before this change cannot be decrypted with the new code and must be re-encrypted.
Expand Down
4 changes: 2 additions & 2 deletions docs/deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ Workers have no Node.js builtins, so this target currently supports:
- tools: `current-date` and `day-name`. `http` is **not** supported: its
SSRF protection resolves the hostname via `node:dns` and checks *every*
resolved address against a denylist before connecting (closing a
DNS-rebinding gap), then pins TLS settings per request via a dedicated
`undici` `Agent`. Workers' native `fetch()` has no equivalent hook to
DNS-rebinding gap), then, for `validateSSL: false`, pins that TLS setting
per request via a dedicated `undici` `Agent`. Workers' native `fetch()` has no equivalent hook to
resolve a hostname up front and pin the connection to the verified IP, so
a Workers version of this tool built on plain `fetch()` would silently
drop that protection rather than just losing convenience functionality -
Expand Down
4 changes: 2 additions & 2 deletions docs/guardrails.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ await AgentExecutor.execute({ agent, input, provider, toolRegistry, sandbox: new
isolation.
- `SubprocessSandbox` runs each command in a new, network-isolated,
auto-removed Docker container, with no host directory mounted except the
`cwd` you pass. It needs a running Docker daemon and the `dockerode` package
(loaded on first use).
`cwd` you pass. It needs a running Docker daemon and the optional peer
`dockerode` (`npm install dockerode@^5.0.1`; loaded on first use).
- Implement `SandboxAdapter` (`name`, `run(cmd, args, opts)`, `writeFile(path, content)`)
for another backend.

Expand Down
32 changes: 29 additions & 3 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,35 @@ try {
}
```

The same applies to the dependencies the SDK ships with but only loads when a
feature needs them: `undici` (the built-in `http` tool), `dockerode`
(`SubprocessSandbox`) and `@modelcontextprotocol/sdk` (`serveMcp`).
### Optional peers

Three heavier packages are optional peers too. A project that never uses
Docker sandboxing, MCP or the `loushy init` questions installs none of them:

| Package | Range | Enables | Install |
| --------------------------- | --------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `dockerode` | `^5.0.1` | Docker sandboxing: `SubprocessSandbox` (and `loushy doctor`'s Docker ping) | `npm install dockerode@^5.0.1` |
| `@modelcontextprotocol/sdk` | `^1.30.1` | MCP: `serveMcp()`, `loushy mcp`, and the `Client` you connect before `loadMcpTools()` | `npm install @modelcontextprotocol/sdk@^1.30.1` |
| `prompts` | `^2.4.2` | The interactive questions of `loushy init` (`loushy init --yes` and flags need nothing) | `npm install prompts@^2.4.2` |

Like the provider packages, each is loaded on first use, never at import
time, and a missing one fails that call with a `MissingPeerDependencyError`
that names the feature and the exact command, for example:

```text
The optional package 'dockerode' is not installed, but Docker sandboxing (SubprocessSandbox) needs it. Run: npm install dockerode@^5.0.1
```

`npm create loushy-agent` installs `prompts` itself, so scaffolding with it
needs nothing extra. `loushy doctor` lists every optional peer, what it
enables and whether it is installed (a missing `dockerode` is an error only
when the agent spec uses a sandboxed tool).

`undici` and `yaml` stay regular dependencies. `yaml` parses agent specs,
`agent.yaml` files and skills, and Node has no built-in YAML parser. `undici`
is only loaded by the `http` tool when a request sets `validateSSL: false`
(a per-request TLS setting that the global `fetch` cannot express); every
other request uses the runtime's global `fetch`.

## Installing from a local build

Expand Down
40 changes: 33 additions & 7 deletions llms-full.txt
Original file line number Diff line number Diff line change
Expand Up @@ -317,9 +317,35 @@ try {
}
```

The same applies to the dependencies the SDK ships with but only loads when a
feature needs them: `undici` (the built-in `http` tool), `dockerode`
(`SubprocessSandbox`) and `@modelcontextprotocol/sdk` (`serveMcp`).
### Optional peers

Three heavier packages are optional peers too. A project that never uses
Docker sandboxing, MCP or the `loushy init` questions installs none of them:

| Package | Range | Enables | Install |
| --------------------------- | --------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------ |
| `dockerode` | `^5.0.1` | Docker sandboxing: `SubprocessSandbox` (and `loushy doctor`'s Docker ping) | `npm install dockerode@^5.0.1` |
| `@modelcontextprotocol/sdk` | `^1.30.1` | MCP: `serveMcp()`, `loushy mcp`, and the `Client` you connect before `loadMcpTools()` | `npm install @modelcontextprotocol/sdk@^1.30.1` |
| `prompts` | `^2.4.2` | The interactive questions of `loushy init` (`loushy init --yes` and flags need nothing) | `npm install prompts@^2.4.2` |

Like the provider packages, each is loaded on first use, never at import
time, and a missing one fails that call with a `MissingPeerDependencyError`
that names the feature and the exact command, for example:

```text
The optional package 'dockerode' is not installed, but Docker sandboxing (SubprocessSandbox) needs it. Run: npm install dockerode@^5.0.1
```

`npm create loushy-agent` installs `prompts` itself, so scaffolding with it
needs nothing extra. `loushy doctor` lists every optional peer, what it
enables and whether it is installed (a missing `dockerode` is an error only
when the agent spec uses a sandboxed tool).

`undici` and `yaml` stay regular dependencies. `yaml` parses agent specs,
`agent.yaml` files and skills, and Node has no built-in YAML parser. `undici`
is only loaded by the `http` tool when a request sets `validateSSL: false`
(a per-request TLS setting that the global `fetch` cannot express); every
other request uses the runtime's global `fetch`.

## Installing from a local build

Expand Down Expand Up @@ -2632,8 +2658,8 @@ Workers have no Node.js builtins, so this target currently supports:
- tools: `current-date` and `day-name`. `http` is **not** supported: its
SSRF protection resolves the hostname via `node:dns` and checks *every*
resolved address against a denylist before connecting (closing a
DNS-rebinding gap), then pins TLS settings per request via a dedicated
`undici` `Agent`. Workers' native `fetch()` has no equivalent hook to
DNS-rebinding gap), then, for `validateSSL: false`, pins that TLS setting
per request via a dedicated `undici` `Agent`. Workers' native `fetch()` has no equivalent hook to
resolve a hostname up front and pin the connection to the verified IP, so
a Workers version of this tool built on plain `fetch()` would silently
drop that protection rather than just losing convenience functionality -
Expand Down Expand Up @@ -3274,8 +3300,8 @@ await AgentExecutor.execute({ agent, input, provider, toolRegistry, sandbox: new
isolation.
- `SubprocessSandbox` runs each command in a new, network-isolated,
auto-removed Docker container, with no host directory mounted except the
`cwd` you pass. It needs a running Docker daemon and the `dockerode` package
(loaded on first use).
`cwd` you pass. It needs a running Docker daemon and the optional peer
`dockerode` (`npm install dockerode@^5.0.1`; loaded on first use).
- Implement `SandboxAdapter` (`name`, `run(cmd, args, opts)`, `writeFile(path, content)`)
for another backend.

Expand Down
Loading
Loading