chore: Remove remaining Mastra references from Instance AI (docs + source) (#32482)

This commit is contained in:
Albert Alises 2026-06-17 15:56:16 +02:00 committed by GitHub
parent ef148c6cab
commit 7b7a34993e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
12 changed files with 37 additions and 39 deletions

View File

@ -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.

View File

@ -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

View File

@ -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

View File

@ -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:

View File

@ -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<br/>(read, write, list, edit files)"]
Workspace --> Sandbox["Sandbox Interface<br/>(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.

View File

@ -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

View File

@ -720,11 +720,11 @@ everything; sub-agents receive only what they need.
1. Create a file in `src/tools/<domain>/` following the naming convention `<verb>-<noun>.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

View File

@ -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/',

View File

@ -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.

View File

@ -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",

View File

@ -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();
},

View File

@ -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();
}