diff --git a/packages/@n8n/agents/src/runtime/observation-log-defaults.ts b/packages/@n8n/agents/src/runtime/observation-log-defaults.ts index 63a4335e466..8c2eef90ed1 100644 --- a/packages/@n8n/agents/src/runtime/observation-log-defaults.ts +++ b/packages/@n8n/agents/src/runtime/observation-log-defaults.ts @@ -332,7 +332,7 @@ EXAMPLES Example 1: Log under budget. Return empty arrays. Input: -[obs_001] CRITICAL (14:30) User is migrating @n8n/agents from Mastra to internal SDK +[obs_001] CRITICAL (14:30) User is migrating the backend from REST to gRPC [obs_002] IMPORTANT (14:35) User adopted two-stage compression model (Observer + Reflector) Budget: 5000 tokens. Current: 600 tokens. @@ -421,13 +421,13 @@ BAD: Merging across topics. Input: [obs_001] CRITICAL User works at Acme -[obs_002] CRITICAL User is migrating @n8n/agents from Mastra +[obs_002] CRITICAL User is migrating the backend to gRPC Wrong merge: { "supersedes": ["obs_001", "obs_002"], "marker": "CRITICAL", - "text": "User works at Acme and is migrating @n8n/agents from Mastra" + "text": "User works at Acme and is migrating the backend to gRPC" } These are about different topics. Do NOT merge them. Leave both as separate observations. diff --git a/packages/@n8n/computer-use/spec/technical-spec.md b/packages/@n8n/computer-use/spec/technical-spec.md index 120113c4dbc..4bdd6e437a1 100644 --- a/packages/@n8n/computer-use/spec/technical-spec.md +++ b/packages/@n8n/computer-use/spec/technical-spec.md @@ -277,7 +277,7 @@ When the AI agent needs to invoke a local tool the call flows through ```mermaid sequenceDiagram - participant A as AI Agent (Mastra tool) + participant A as AI Agent (@n8n/agents tool) participant GW as LocalGateway participant SRV as Controller (SSE) participant D as computer-use Daemon @@ -304,7 +304,7 @@ rejects all outstanding promises immediately with `"Local gateway disconnected"` When a tool group operates in `Ask` mode and no stored rule matches the resource, the daemon returns a `GATEWAY_CONFIRMATION_REQUIRED` error instead -of a result. The Mastra tool layer handles this by suspending the agent — +of a result. The `@n8n/agents` tool layer handles this by suspending the agent — persisting its state to the database — and resuming it after the user responds. This means the confirmation survives page reloads and server restarts. @@ -316,7 +316,7 @@ sequenceDiagram participant DB as Database participant D as computer-use Daemon - Note over SRV: First invocation — tool execute() called by Mastra + Note over SRV: First invocation — tool execute() called by @n8n/agents SRV->>D: callTool({ name, args }) via LocalGateway D-->>SRV: { isError: true, content: ["GATEWAY_CONFIRMATION_REQUIRED::..."] } SRV->>SRV: parse GatewayConfirmationRequiredPayload diff --git a/packages/@n8n/instance-ai/docs/ENGINEERING.md b/packages/@n8n/instance-ai/docs/ENGINEERING.md index 4ad23154f78..5ada43f5f22 100644 --- a/packages/@n8n/instance-ai/docs/ENGINEERING.md +++ b/packages/@n8n/instance-ai/docs/ENGINEERING.md @@ -30,7 +30,7 @@ const data: ExecutionResult = parseExecutionResult(response); ### Zod schemas are the source of truth Every tool has an input schema (what the LLM sends) and an output schema -(what the tool returns). Mastra uses these schemas to generate tool +(what the tool returns). `@n8n/agents` uses these schemas to generate tool descriptions for the LLM, validate inputs at runtime, and type-check the execute function. If the TypeScript type and the Zod schema are defined separately, they drift — the LLM sees one contract, the code enforces @@ -120,7 +120,7 @@ it('should stream tool-call event when agent uses a tool', async () => { The clean interface boundary (ADR-002) makes each layer testable in isolation. Verify the contract at each boundary — not the wiring between -them. Tools can be tested without Mastra, the reducer without SSE, adapters +them. Tools can be tested without `@n8n/agents`, the reducer without SSE, adapters without the agent. For each tool, test: @@ -203,15 +203,15 @@ When backend and frontend both switch on event types with duplicated logic, a change to the format requires updating both in lockstep. Extract the shared part into `@n8n/api-types` or a shared utility. -## Mastra Patterns +## Agent SDK Patterns ### Tool definitions -Mastra uses Zod schemas for both runtime validation and LLM tool +`@n8n/agents` uses Zod schemas for both runtime validation and LLM tool descriptions. The `.describe()` strings on schema fields become the parameter descriptions the LLM sees when deciding how to call a tool. Missing or vague descriptions lead to bad tool calls. The `outputSchema` -lets Mastra validate return values and gives the LLM structured expectations. +lets `@n8n/agents` validate return values and gives the LLM structured expectations. - Always define both `inputSchema` and `outputSchema` - Use `.describe()` on Zod fields — these are the LLM's parameter docs diff --git a/packages/@n8n/instance-ai/docs/architecture.md b/packages/@n8n/instance-ai/docs/architecture.md index bb551c56b10..d2d7bde0f41 100644 --- a/packages/@n8n/instance-ai/docs/architecture.md +++ b/packages/@n8n/instance-ai/docs/architecture.md @@ -119,7 +119,7 @@ directly to the event bus (ADR-014). They cannot spawn their own sub-agents. ### 3. Observational Memory -Mastra's observational memory compresses old messages into dense observations via +`@n8n/agents` observational memory compresses old messages into dense observations via background Observer and Reflector agents. Tool-heavy workloads (workflow definitions, execution results) get 5–40x compression. This prevents context degradation over 50+ step autonomous loops (see ADR-016). @@ -197,7 +197,7 @@ The agent package — framework-agnostic business logic. - **Storage** (`storage/`) — iteration logs, task storage, planned task storage, workflow loop storage, agent tree snapshots - **MCP client** (`mcp/`) — manages connections to external MCP servers, schema sanitization for Anthropic compatibility - **Domain access** (`domain-access/`) — domain gating and access tracking for external URL approval -- **Stream mapping** (`stream/`) — Mastra chunk → canonical event translation, HITL consumption +- **Stream mapping** (`stream/`) — agent chunk → canonical event translation, HITL consumption - **Event bus interface** (`event-bus/`) — publishing agent events to the thread channel - **Tracing** (`tracing/`) — LangSmith integration for step-level observability - **System prompt** (`agent/`) — dynamic context-aware prompt based on instance configuration @@ -292,19 +292,19 @@ Instance AI uses n8n's module system (`@BackendModule`). This means: ## Runtime & Streaming -The agent runtime is built on Mastra's streaming primitives with added +The agent runtime is built on `@n8n/agents` streaming primitives with added resumability, HITL suspension, and background task management. ### Stream Execution ``` streamAgentRun() → agent.stream() → executeResumableStream() - ├─ for each chunk: mapMastraChunkToEvent() → eventBus.publish() + ├─ for each chunk: mapAgentChunkToEvent() → eventBus.publish() ├─ on suspension: wait for confirmation → agent.resumeStream() → loop - └─ return StreamRunResult {status, mastraRunId, text} + └─ return StreamRunResult {status, agentRunId, text} ``` -The `executeResumableStream()` loop consumes Mastra chunks, translates them to +The `executeResumableStream()` loop consumes agent chunks, translates them to canonical `InstanceAiEvent` schema, publishes to the event bus, and handles HITL suspension/resume cycles. Two control modes: diff --git a/packages/@n8n/instance-ai/docs/sandboxing.md b/packages/@n8n/instance-ai/docs/sandboxing.md index 178a75e670f..702de708f3e 100644 --- a/packages/@n8n/instance-ai/docs/sandboxing.md +++ b/packages/@n8n/instance-ai/docs/sandboxing.md @@ -6,15 +6,15 @@ Today the main consumer is the workflow builder. The agent writes TypeScript fil ## How the Pieces Fit Together -There are three layers between the agent and actual code execution: a workspace abstraction from Mastra, a sandbox provider (n8n sandbox service or Daytona), and the execution runtime inside the sandbox. Here is how they relate: +There are three layers between the agent and actual code execution: a workspace abstraction from `@n8n/agents`, a sandbox provider (n8n sandbox service or Daytona), and the execution runtime inside the sandbox. Here is how they relate: ```mermaid graph TB subgraph Agent ["Agent Layer"] - LLM[LLM] --> AgentRuntime["Agent Runtime (Mastra)"] + LLM[LLM] --> AgentRuntime["Agent Runtime (@n8n/agents)"] end - subgraph WorkspaceLayer ["Workspace Abstraction (Mastra)"] + subgraph WorkspaceLayer ["Workspace Abstraction (@n8n/agents)"] AgentRuntime --> Workspace["Workspace"] Workspace --> FS["Filesystem Interface
(read, write, list, edit files)"] Workspace --> Sandbox["Sandbox Interface
(execute shell commands)"] @@ -42,14 +42,14 @@ graph TB The agent never talks to Daytona, the n8n sandbox service, or the host filesystem directly. It only sees the Workspace, which exposes two capabilities: a filesystem (read/write/list files) and a sandbox (run shell commands). The Workspace routes those operations to whichever provider is configured. -## Mastra Workspaces +## Workspaces -Mastra is the agent framework that Instance AI uses. A Mastra **Workspace** is a pairing of two things: +`@n8n/agents` is the agent SDK that Instance AI uses. A **Workspace** is a pairing of two things: 1. **A Sandbox** — an interface for executing shell commands. It accepts a command string and returns stdout, stderr, and an exit code. Think of it as a remote terminal. 2. **A Filesystem** — an interface for file operations: read, write, list, delete, copy, move. Think of it as a remote disk. -When a Workspace is attached to an agent, Mastra automatically exposes built-in tools to the LLM: `read_file`, `write_file`, `edit_file`, `list_files`, `grep`, `execute_command`, and others. The agent uses these tools naturally in its reasoning loop — it writes a file, runs a command, reads the output, and decides what to do next. +When a Workspace is attached to an agent, `@n8n/agents` automatically exposes built-in tools to the LLM: `read_file`, `write_file`, `edit_file`, `list_files`, `grep`, `execute_command`, and others. The agent uses these tools naturally in its reasoning loop — it writes a file, runs a command, reads the output, and decides what to do next. The key design property is that the Workspace abstraction is provider-agnostic. The agent's code and prompts are identical regardless of whether the workspace is backed by n8n sandbox service or Daytona. The provider choice is purely an infrastructure decision. @@ -106,7 +106,7 @@ sequenceDiagram D-->>n8n: Sandbox ID n8n->>S: Write node-types catalog via filesystem API - n8n->>n8n: Wrap sandbox as Mastra Workspace + n8n->>n8n: Wrap sandbox as Workspace n8n->>n8n: Inject Workspace into builder agent Note over S: Agent works inside sandbox @@ -124,7 +124,7 @@ The process starts with a **pre-warmed image**. On first use, n8n builds a Dayto One thing that cannot be baked into the image is the **node-types catalog** (a searchable index of all available n8n nodes). It is too large for the image build API, so it is written to each sandbox after creation via the filesystem API. -Once the sandbox is provisioned and the catalog is written, n8n wraps it in a Mastra Workspace and hands it to the builder agent. From that point, the agent works autonomously inside the sandbox — writing files, running the compiler, fixing errors, iterating — until it produces a valid workflow. +Once the sandbox is provisioned and the catalog is written, n8n wraps it in a Workspace and hands it to the builder agent. From that point, the agent works autonomously inside the sandbox — writing files, running the compiler, fixing errors, iterating — until it produces a valid workflow. ### What is inside a Daytona sandbox @@ -139,7 +139,7 @@ Once the sandbox is provisioned and the catalog is written, n8n wraps it in a Ma ## n8n Sandbox Service: Default Provider -The n8n sandbox service exposes a simple HTTP API for creating sandboxes, executing shell commands, and manipulating files. Instance AI uses it through a custom Mastra sandbox and filesystem adapter. +The n8n sandbox service exposes a simple HTTP API for creating sandboxes, executing shell commands, and manipulating files. Instance AI uses it through a custom `@n8n/agents` sandbox and filesystem adapter. This provider supports the builder's file and command workflow, but it does not expose interactive process handles. That means `execute_command` works, while process-manager-backed features such as long-lived spawned subprocesses are out of scope for this provider. diff --git a/packages/@n8n/instance-ai/docs/streaming-protocol.md b/packages/@n8n/instance-ai/docs/streaming-protocol.md index a130941edb3..223a9b9ae02 100644 --- a/packages/@n8n/instance-ai/docs/streaming-protocol.md +++ b/packages/@n8n/instance-ai/docs/streaming-protocol.md @@ -482,14 +482,14 @@ replaying all SSE events. ### How It Works -1. **Mastra V2 messages** — Mastra persists tool invocations, reasoning, and - text in its V2 message format. The backend parses these into rich +1. **Persisted messages** — `@n8n/agents` persists tool invocations, reasoning, and + text in its message format. The backend parses these into rich `InstanceAiMessage[]` objects with tool calls and flat agent trees. 2. **Agent tree snapshots** — after each `run-finish`, the backend replays events through `buildAgentTreeFromEvents()` and stores the resulting tree in thread metadata. This preserves the full sub-agent hierarchy (tool - calls, text, reasoning) that the V2 message format alone cannot capture. + calls, text, reasoning) that the message format alone cannot capture. 3. **SSE cursor** — the messages response includes `nextEventId`. The frontend sets its SSE cursor to `nextEventId - 1` so the SSE connection only receives diff --git a/packages/@n8n/instance-ai/docs/tools.md b/packages/@n8n/instance-ai/docs/tools.md index 395088a11aa..61e1133f246 100644 --- a/packages/@n8n/instance-ai/docs/tools.md +++ b/packages/@n8n/instance-ai/docs/tools.md @@ -720,11 +720,11 @@ everything; sub-agents receive only what they need. 1. Create a file in `src/tools//` following the naming convention `-.tool.ts` 2. Define input/output schemas with Zod (`.describe()` on fields — these are the LLM's parameter docs) -3. Export a factory function that takes the service context and returns a Mastra tool +3. Export a factory function that takes the service context and returns an `@n8n/agents` tool 4. Register the tool in `src/tools/index.ts` (in `createAllTools` or `createOrchestrationTools`) 5. If the tool requires a new service method, add it to the interface in `src/types.ts` and implement it in the backend adapter 6. New native domain tools are automatically available for delegation — the orchestrator can include them in sub-agent tool subsets via `delegate` -7. For HITL tools, define `suspendSchema` and `resumeSchema` — Mastra handles +7. For HITL tools, define `suspendSchema` and `resumeSchema` — `@n8n/agents` handles the suspension/resume lifecycle automatically diff --git a/packages/@n8n/instance-ai/src/source-map-filter.ts b/packages/@n8n/instance-ai/src/source-map-filter.ts index 840c6c841b6..7861eb56fd5 100644 --- a/packages/@n8n/instance-ai/src/source-map-filter.ts +++ b/packages/@n8n/instance-ai/src/source-map-filter.ts @@ -19,7 +19,6 @@ function loadSourceMapSupport(): SourceMapSupportModule | undefined { } const FILTERED_PATH_FRAGMENTS = [ - '/node_modules/@mastra/core/dist/chunk-', '/node_modules/@ai-sdk/', '/node_modules/langsmith/', '/node_modules/zod/', diff --git a/packages/@n8n/instance-ai/src/tools/filesystem/create-tools-from-mcp-server.ts b/packages/@n8n/instance-ai/src/tools/filesystem/create-tools-from-mcp-server.ts index 686566f0049..522bf876f88 100644 --- a/packages/@n8n/instance-ai/src/tools/filesystem/create-tools-from-mcp-server.ts +++ b/packages/@n8n/instance-ai/src/tools/filesystem/create-tools-from-mcp-server.ts @@ -307,10 +307,9 @@ export function createToolsFromLocalMcpServer( try { if (toolName === 'browser_create_credential') { // when converting json schema the `inputSchema` has the correct shape and parsed to correct output - // but during execution all unspecified key from `data` and `resolveData` are stripped. - // somewhere in mastra core the inputSchema is converted multiple times back and forth and - // gets transformed to jsonSchema with `additionalProperties=false` - // this does not happen when passing the schema directly + // but during execution all unspecified keys from `data` and `resolveData` are stripped, + // because the schema is converted back and forth and transformed to jsonSchema with + // `additionalProperties=false`. Passing the schema directly avoids this. inputSchema = loadMcpBrowserCredential().browserCreateCredentialSchema; } else { // Convert JSON Schema → Zod (v3) so the LLM sees the actual parameter shapes. diff --git a/packages/frontend/@n8n/i18n/src/locales/en.json b/packages/frontend/@n8n/i18n/src/locales/en.json index 82bec317975..267756e7979 100644 --- a/packages/frontend/@n8n/i18n/src/locales/en.json +++ b/packages/frontend/@n8n/i18n/src/locales/en.json @@ -6001,7 +6001,7 @@ "instanceAi.debug.threads.title": "Thread Inspector", "instanceAi.debug.threads.current": "Current", "instanceAi.debug.threads.messages": "Messages", - "instanceAi.debug.threads.noThreads": "No threads found in Mastra storage", + "instanceAi.debug.threads.noThreads": "No threads found in storage", "instanceAi.debug.threads.noMessages": "No messages stored", "instanceAi.debug.threads.refresh": "Refresh", "instanceAi.debug.threads.fetchError": "Failed to load thread data", diff --git a/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.store.ts b/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.store.ts index c427afe38f1..3d04c57f4a2 100644 --- a/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.store.ts +++ b/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.store.ts @@ -39,7 +39,7 @@ export const useInstanceAiStore = defineStore('instanceAi', () => { const thread = threads.value.find((t) => t.id === threadId); if (thread) thread.title = title; }, - // Refresh thread list to pick up Mastra-generated titles + // Refresh thread list to pick up auto-generated titles onRunFinish: () => { void loadThreads(); }, diff --git a/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.threadRuntime.ts b/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.threadRuntime.ts index 62dd09ba05c..0730842cd99 100644 --- a/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.threadRuntime.ts +++ b/packages/frontend/editor-ui/src/features/ai/instanceAi/instanceAi.threadRuntime.ts @@ -523,7 +523,7 @@ export function createThreadRuntime( if (parsed.data.type === 'run-start' || parsed.data.type === 'run-finish') { triggerRef(messages); } - // When a run finishes, refresh thread list to pick up Mastra-generated titles + // When a run finishes, refresh thread list to pick up auto-generated titles if (previousRunId && activeRunId.value === null) { hooks.onRunFinish(); }