Resolves conflicts to keep:
- Apps toolset surface from toolchains-spike (registry, factory, normalizer,
AppDefinition, /catalog/apps/:kind/operations endpoint, FE registry +
modals + list panel + tool-step labels).
- Builder/integration polish from n8n-agents (i18n-keyed help/connected
copy, narrower default chat column, agent RBAC resource).
Drops the inline displayHelpText/displayConnectedText fields on
ChatIntegrationDescriptor and the per-platform classes — the strings now
live in the FE i18n catalog keyed by integration type.
Adds the missing 'agent' entry to rbac.store.ts scopesByResourceId so the
new Resource union type compiles.
Restore the agents SDK to a single canonical import path
(`from '@n8n/agents'`) for backend consumers, and decouple the editor-ui
from the SDK entirely so the package stays server-only.
The previous split via `exports` + `typesVersions` made `toolsets` a
second-class subpath while every other SDK export lived at the package
root. The asymmetry papered over the real issue: the SDK is server-side
(pulls undici via MCP/AI-SDK), so the editor-ui shouldn't depend on it.
- editor-ui: new `features/agents/utils/appToolsets.ts` mirrors the
registry data + walker + types the FE needs (~200 lines). Drop the
`@n8n/agents` workspace dep. Drift between this and the BE registry
is enforced by code review when adding new apps.
- `@n8n/agents`: drop the `exports` and `typesVersions` blocks. Restore
flat re-exports of `APP_REGISTRY`, `findAppDefinition`,
`buildOperationsFromDescription`, `buildManifest`, and toolsets types
from `src/index.ts` so cli can keep `from '@n8n/agents'` for
everything.
- cli: consolidate imports back to `@n8n/agents`. No subpath imports.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Three small follow-ups from the cleanup's final review:
- `app-toolset-factory.ts`: drop the hand-rolled `zodObjectToJson` /
`zodTypeNameToJson` helpers and use `zodToJsonSchema` from `@n8n/agents`.
The hand-rolled walker was non-recursive and dropped nested object
structure for `collection` / `fixedCollection` params; the shared
utility recurses correctly via `zod-to-json-schema`.
- `useCredentialScopes`: add a 30s TTL to the module-level scope cache so
re-opening the modal after re-OAuth surfaces refreshed scopes within
the window. Failures are still uncached. Also export an
`invalidateCredentialScopes(id)` for explicit invalidation when callers
know the scopes have changed.
- `buildOperationsFromDescription`: emit one OperationEntry per resource
when an operation group declares multiple in `displayOptions.show.resource`,
rather than dropping all but the first. Dedupe by `resource:operation`
to handle the rare case of overlapping operation groups. Two new tests
cover the multi-resource and dedupe paths.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The agents toolsets cleanup made editor-ui import from @n8n/agents for
the registry, which transitively bundled the full server SDK (MCP client,
AI SDK adapters) and pulled `undici` into the browser bundle, breaking
`pnpm build`. Tree-shaking can't help here — the package compiles to CJS
and isn't marked side-effect-free.
Declare the boundary at the package surface instead:
- `exports` field: `.` continues to expose the full SDK; new `./toolsets`
entry exposes only the pure-data + pure-algorithm surface
(`AppDefinition`, `OperationEntry`, `buildOperationsFromDescription`,
`buildManifest`, `APP_REGISTRY`, `findAppDefinition`).
- `typesVersions` mirrors the subpath so TypeScript resolves it under
the repo's `moduleResolution: "node"` (legacy mode ignores `exports`).
- Drop the flat re-exports of toolsets symbols from `src/index.ts`. The
registry now has exactly one canonical import path,
`@n8n/agents/toolsets`. Backend code that wants the namespace can keep
using `import { toolsets } from '@n8n/agents'`.
- Update cli (`agents.service`, `app-toolset-factory` + its test) and
editor-ui (`AgentAppsModal`, `AgentAppConfigModal`, `AgentAppsListPanel`,
`AgentChatToolSteps`) to import from `@n8n/agents/toolsets`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Restructure the Gmail-only "apps/toolsets" POC so adding a second app is a
one-file change. Each integration ships as an `AppDefinition` in
`@n8n/agents/src/toolsets/registry/`; backend and frontend consume the
registry through the same flat re-exports off `@n8n/agents`.
- New `@n8n/agents/toolsets/` module: `AppDefinition` + `OperationEntry`
types, `buildOperationsFromDescription` (single source of truth for the
registry walk + scope-based status classification), `buildManifest`
(string/function/default-deriver resolution), and `APP_REGISTRY` with
Gmail as the first entry.
- Generic `buildAppToolset` factory in cli replaces the Gmail-specific
`buildGmailToolset`. `agents.service.attachAppToolsets` now resolves
app kinds via `findAppDefinition` and skips unknown kinds with a warn
log instead of rejecting at save time.
- New `GET /credentials/:credentialId/oauth-scopes` endpoint +
`CredentialsService.getOAuthGrantedScopes` helper. Reads
`oauthTokenData.scope` (post-grant) with a fallback to declared
`scope` (pre-grant). Distinct from the existing RBAC `getCredentialScopes`.
- New `useCredentialScopes` FE composable feeds the App config modal so
per-operation status badges classify against the credential's
actually-granted scopes.
- `AgentJsonAppRef.kind` widened from the `'gmail'` literal to plain
string. Forward-compat: a config saved with an unknown kind loads
cleanly.
- Editor-ui: `AgentAppsModal` rebuilt on `Modal.vue` + `NodeCredentials`
(drops the hand-rolled backdrop and raw select). `AgentAppConfigModal`,
`AgentAppsListPanel`, and `AgentChatToolSteps` resolve icon, label, and
dispatcher names from the registry.
- Drop the Gmail-only `gmail-toolset.ts` and `gmailOperations.ts`.
Tests: 10 new in `@n8n/agents/toolsets`, 6 in
`cli/src/modules/agents/toolsets`, 4 in `cli/src/credentials`.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Stage 1 — frontend rendering
- Resolved interactive cards (ask_question / ask_credential / ask_llm) used to
vanish from chat history; now they leave a compact "→ tool · answer" trace
in AgentChatToolSteps, matching how non-interactive tool calls render.
- ToolCall carries an optional displaySummary populated on tool-result, on
the optimistic resume flip, and rolled back on resume failure.
- New summariseInteractiveOutput helper + 7 unit tests.
Stage 2 — server-side auto-resolve
- ask_question: auto-resolves when options.length === 1 (schema relaxed
from min(2) to min(1) so the LLM can actually pass single-option
questions).
- ask_credential: auto-resolves when exactly one credential of the
requested type is available to the user.
- ask_llm: auto-resolves when exactly one LLM-provider credential exists,
using a new LLM_PROVIDER_DEFAULTS table for the canonical default model
per provider (Anthropic, OpenAI, Google, xAI, Groq, Mistral, DeepSeek,
Cohere).
- CredentialProvider threaded through getJsonTools to the interactive
factories. 12 new unit tests (cli) covering suspend-vs-auto-resolve.
Lint
- AgentAdvancedPanel.test.ts: hoist @vueuse/core type alias to a top-level
`import type * as` so the inline `typeof import(...)` annotation goes
away (consistent-type-imports).
- AgentConfigJsonEditor.vue: move `void debouncedJsonSave(text)` from
expression to statement form so no-void stops complaining.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Schema is persisted as JSON; the as unknown as cast in two services rehydrates to the typed config. One-line comments make the rationale explicit so future readers don't try to tighten the type without addressing the storage boundary.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- CHAT_MESSAGE_STATUS / TOOL_CALL_STATE in features/agents/constants.ts; replace ~30 literal occurrences in useAgentChatStream, agentChatMessages, AgentChatMessageList. ToolCallState type now lives next to its values; agentChatMessages re-exports for callers.
- CONTINUE_SESSION_ID_PARAM for the URL-deeplink query key, used in AgentBuilderView and AgentSessionTimelineView.
- Backend: BUILDER_TOOLS + AGENT_THREAD_PREFIX in builder/builder-tool-names.ts; replace literals in agents.controller, agents-builder-tools.service, agents.service, agents-builder.service.
- Add missing agents.sort.* i18n keys (lastUpdated, lastCreated, nameAsc, nameDesc) — ResourcesListLayout looks them up via resource-key="agents".
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Add display metadata fields (displayLabel, displayIcon, displayHelpText,
displayConnectedText) to AgentChatIntegration abstract class and all
three platform implementations (Slack, Telegram, Linear)
- Add ChatIntegrationDescriptor DTO to @n8n/api-types
- Add GET /catalog/integrations endpoint on AgentsController backed by
AgentsService.listChatIntegrations()
- Add listAgentIntegrations() API client and useAgentIntegrationsCatalog
composable (module-scoped singleton with dedup in-flight logic)
- Replace hardcoded KNOWN_TRIGGER_TYPES in AgentBuilderView with dynamic
catalog fetch; add tests for the new composable and update view test mock
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>