From b53b7184d58740edb66bfe9495016812b705927f Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 17:30:36 +0300 Subject: [PATCH 01/28] docs: add agent tools expansion design spec Co-Authored-By: Claude Sonnet 4.6 --- ...2026-05-13-agent-tools-expansion-design.md | 280 ++++++++++++++++++ 1 file changed, 280 insertions(+) create mode 100644 docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md diff --git a/docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md b/docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md new file mode 100644 index 00000000..43605d76 --- /dev/null +++ b/docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md @@ -0,0 +1,280 @@ +# Agent Tools Expansion — Design Spec + +**Date:** 2026-05-13 +**Package:** `packages/agent-toolkit` +**Location:** `src/core/tools/platform-api-tools/agents-tools/` + +--- + +## Problem + +The existing agent tools (`get_agent`, `create_agent`, `delete_agent`) cover only basic CRUD. The agents subgraph exposes a much richer surface — skills, triggers, state management, knowledge/resource access — that agents cannot yet use via the toolkit. + +The core challenge is discoverability: consumers never know available skill IDs, trigger `block_reference_id` values, or the required `field_values` shape for a given trigger type. The catalog queries exist precisely to solve this, and the tool descriptions must encode the lookup-first workflow so agents know to consult them before acting. + +--- + +## Scope + +6 new tools covering all remaining agents subgraph operations: + +| Tool | Type | Operations | +|------|------|-----------| +| `get_agent_catalog` | READ | `agent_skills_catalog`, `agent_triggers_catalog` | +| `manage_agent_triggers` | WRITE | `agent_active_triggers` (list), `add_trigger_to_agent`, `remove_trigger_from_agent` | +| `manage_agent_skills` | WRITE | `add_skill_to_agent`, `remove_skill_from_agent` | +| `update_agent` | WRITE | `update_agent` | +| `manage_agent_state` | WRITE | `activate_agent`, `deactivate_agent`, `run_agent` | +| `manage_agent_knowledge` | WRITE | `agent_knowledge` (list), `add_agent_resource_access`, `remove_agent_resource_access`, `update_agent_resource_access` | + +Out of scope: `get_agent` is unchanged — the subgraph will be enhanced in a future iteration to include more fields (active triggers, knowledge) directly on the Agent type. + +--- + +## File Structure + +Each tool is co-located with its own `.graphql.dev.ts` file. The `shared/` directory keeps only the `AgentFields` fragment (used by the existing get/create/delete tools). + +``` +agents-tools/ +├── shared/ +│ └── agents.graphql.dev.ts ← AgentFields fragment only (unchanged) +├── get-agent-catalog/ +│ ├── get-agent-catalog-tool.ts +│ └── get-agent-catalog.graphql.dev.ts +├── manage-agent-triggers/ +│ ├── manage-agent-triggers-tool.ts +│ └── manage-agent-triggers.graphql.dev.ts +├── manage-agent-skills/ +│ ├── manage-agent-skills-tool.ts +│ └── manage-agent-skills.graphql.dev.ts +├── update-agent/ +│ ├── update-agent-tool.ts +│ └── update-agent.graphql.dev.ts +├── manage-agent-state/ +│ ├── manage-agent-state-tool.ts +│ └── manage-agent-state.graphql.dev.ts +└── manage-agent-knowledge/ + ├── manage-agent-knowledge-tool.ts + └── manage-agent-knowledge.graphql.dev.ts +``` + +--- + +## Tool Designs + +### `get_agent_catalog` (READ) + +**Purpose:** Account-wide discovery of available trigger types and skills. Always call this before adding a trigger or skill to an agent. + +**Input schema:** +```typescript +{ + type: z.enum(['triggers', 'skills']), + // For triggers only — fetches specific entries much faster than full catalog + block_reference_ids: z.array(z.string()).optional() +} +``` + +**Behavior:** +- `type: 'triggers'` → calls `agent_triggers_catalog`. Returns entries with `block_reference_id`, `name`, `description`, `field_schemas`, `required_fields`. `field_schemas` describes the shape of `field_values` required when adding (e.g. `{ board_id: }`). `required_fields` lists fields the user must supply. +- `type: 'skills'` → calls `agent_skills_catalog`. Returns entries with `id`, `name`, `description`. + +**Description preamble:** +> Call this tool first before adding a trigger or skill to an agent. For triggers: inspect `field_schemas` and `required_fields` to know what to collect from the user (e.g. board_id, column_id) before calling `manage_agent_triggers`. For skills: use the returned `id` to call `manage_agent_skills`. + +--- + +### `manage_agent_triggers` (WRITE) + +**Purpose:** List, add, and remove triggers on a specific agent. + +**Input schema (discriminated by `action`):** +```typescript +{ + action: z.enum(['list', 'add', 'remove']), + agent_id: z.string(), + // add only + block_reference_id: z.string().optional(), + field_values: z.record(z.unknown()).optional(), + // remove only + node_id: z.string().optional() +} +``` + +**Behavior:** +- `list` → calls `agent_active_triggers(agent_id)`. Returns active triggers with `node_id`, `block_reference_id`, `name`, `description`, `field_summary`. +- `add` → calls `add_trigger_to_agent`. Requires `block_reference_id` (from catalog) and optional `field_values` (shape determined by `field_schemas` in the catalog entry). +- `remove` → calls `remove_trigger_from_agent`. Requires `node_id` (from `action: list`). + +**Description — add workflow:** +> To add: first call `get_agent_catalog` with `type: triggers` to find the right entry by name/description. Inspect `field_schemas` and `required_fields` to know what information to collect from the user (e.g. which board, which column). Only then call this tool with `action: add`. + +**Description — remove workflow:** +> To remove: first call this tool with `action: list` to see the active triggers by name and `field_summary`. Match the trigger the user described, get its `node_id`, then call this tool with `action: remove`. + +--- + +### `manage_agent_skills` (WRITE) + +**Purpose:** Attach and detach skills from an agent. + +**Input schema:** +```typescript +{ + action: z.enum(['add', 'remove']), + agent_id: z.string(), + skill_id: z.string() +} +``` + +**Behavior:** +- `add` → calls `add_skill_to_agent` +- `remove` → calls `remove_skill_from_agent` + +**Description preamble:** +> Always call `get_agent_catalog` with `type: skills` first to discover available skills and resolve the correct `skill_id` — never guess or invent a skill ID. + +--- + +### `update_agent` (WRITE) + +**Purpose:** Update an agent's profile or execution plan. Creates a new draft internally and publishes in one call. + +**Input schema:** +```typescript +{ + id: z.string(), + name: z.string().optional(), + role: z.string().optional(), + role_description: z.string().optional(), + plan: z.string().optional(), // markdown + agent_model: z.string().optional() // discourage unless user explicitly named a model +} +``` + +**Behavior:** Calls `update_agent`. All profile fields are optional — only provided fields are changed. Mirrors the same `agent_model` guidance as `create_agent` (strongly discourage setting it; omit unless user explicitly named a model). + +--- + +### `manage_agent_state` (WRITE) + +**Purpose:** Activate, deactivate, or manually trigger a run for an agent. + +**Input schema:** +```typescript +{ + action: z.enum(['activate', 'deactivate', 'run']), + agent_id: z.string(), + // deactivate only + inactive_reason: z.enum(['DEACTIVATED_BY_USER', 'ACCOUNT_LEVEL_BLOCKING']).optional() +} +``` + +**Behavior:** +- `activate` → calls `activate_agent`. Agent transitions to ACTIVE and can receive triggers. +- `deactivate` → calls `deactivate_agent`. `inactive_reason` defaults to `DEACTIVATED_BY_USER` if omitted. +- `run` → calls `run_agent`. Fire-and-forget async operation. Returns `trigger_uuid` for downstream correlation. Success means the run was enqueued, not that it completed. + +--- + +### `manage_agent_knowledge` (WRITE) + +**Purpose:** List, grant, update, and revoke an agent's access to monday.com boards and docs. + +**Input schema (discriminated by `action`):** +```typescript +{ + action: z.enum(['list', 'add', 'update', 'remove']), + agent_id: z.string(), + // add, update, remove + resource_id: z.string().optional(), + scope_type: z.enum(['BOARD', 'DOC']).optional(), + // add, update + permission_type: z.enum(['READ', 'READ_WRITE']).optional() +} +``` + +**Behavior:** +- `list` → calls `agent_knowledge(agent_id)`. Returns current resources (boards/docs) with `resource_id`, `scope_type`, `permission_type`, plus uploaded files. +- `add` → calls `add_agent_resource_access`. Grants agent access to a board or doc with the specified permission level. +- `update` → calls `update_agent_resource_access`. Changes the permission level on an already-granted resource. +- `remove` → calls `remove_agent_resource_access`. Revokes access entirely. + +**Description preamble:** +> Call with `action: list` first to see the agent's current resource access before adding, updating, or removing. For `add`/`update`, `permission_type: READ` allows the agent to read the resource; `READ_WRITE` also allows writing. + +--- + +## Key Design Decisions + +**Catalog-first descriptions:** Tool descriptions are the primary mechanism for guiding agent behavior. Every WRITE tool that requires an ID from a catalog or list operation explicitly names the prerequisite call. This is more reliable than trying to enforce it in code. + +**`field_values` as record:** `add_trigger_to_agent` takes `field_values: JSON` in the schema. The Zod type is `z.record(z.unknown())` — flexible enough to accommodate any trigger type's shape. The `field_schemas` from the catalog entry describes the expected shape at runtime. + +**`manage_agent_triggers` and `manage_agent_knowledge` are typed WRITE:** Both include a `list` action that is read-only in effect, but the tools are typed WRITE because their primary purpose is mutation and the list actions exist specifically to support the write workflow (get `node_id` before remove, inspect resources before update). In `readOnlyMode`, WRITE tools are filtered out — this means `list` is unavailable in read-only configurations, which is an accepted trade-off. If this becomes a problem in practice, the list operations can be split into `get_agent` in a future iteration when the subgraph enhances the Agent type to include active triggers and knowledge directly. + +--- + +## GraphQL Operations (per tool) + +### `get-agent-catalog.graphql.dev.ts` +- `query getAgentTriggersCatalog($block_reference_ids: [ID!])` +- `query getAgentSkillsCatalog` + +### `manage-agent-triggers.graphql.dev.ts` +- `query getAgentActiveTriggers($agent_id: ID!)` +- `mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON)` +- `mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!)` + +### `manage-agent-skills.graphql.dev.ts` +- `mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!)` +- `mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!)` + +### `update-agent.graphql.dev.ts` +- `mutation updateAgent($id: ID!, $input: UpdateAgentInput!)` + +### `manage-agent-state.graphql.dev.ts` +- `mutation activateAgent($id: ID!)` +- `mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason)` +- `mutation runAgent($id: ID!)` + +### `manage-agent-knowledge.graphql.dev.ts` +- `query getAgentKnowledge($agent_id: ID!)` +- `mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!)` +- `mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!)` +- `mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!)` + +--- + +## Registration + +In `src/core/tools/platform-api-tools/index.ts`: +- 6 new imports +- 6 additions to `allGraphqlApiTools` array (grouped under existing agents comment) +- 6 new `export *` lines + +--- + +## Error Handling + +All tools use `rethrowWithContext(error, '')` in a try/catch, consistent with existing agent tools. + +--- + +## Testing + +One `.test.ts` per tool, co-located, using `createMockApiClient()`. Each test file covers: +- Happy path for each action +- Validation errors (missing required fields for wrong action) +- API error propagation via `rethrowWithContext` + +--- + +## Post-Implementation + +After all tool files are written: +1. Run `npm run fetch:generate dev` to regenerate dev types from new GraphQL operations +2. Run `npm test` to verify all tests pass +3. Run `npm run build` to verify compilation +4. Bump version in `package.json` From e4be478968bb33c95612ebcfd0df06255f4cb4b7 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 17:42:38 +0300 Subject: [PATCH 02/28] docs: add agent tools expansion implementation plan Co-Authored-By: Claude Sonnet 4.6 --- .../plans/2026-05-13-agent-tools-expansion.md | 2185 +++++++++++++++++ 1 file changed, 2185 insertions(+) create mode 100644 docs/superpowers/plans/2026-05-13-agent-tools-expansion.md diff --git a/docs/superpowers/plans/2026-05-13-agent-tools-expansion.md b/docs/superpowers/plans/2026-05-13-agent-tools-expansion.md new file mode 100644 index 00000000..b2e9540e --- /dev/null +++ b/docs/superpowers/plans/2026-05-13-agent-tools-expansion.md @@ -0,0 +1,2185 @@ +# Agent Tools Expansion Implementation Plan + +> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. + +**Goal:** Add 6 new MCP tools to the agent-toolkit that cover the full agents subgraph surface — catalog discovery, trigger management, skill management, agent updates, state management, and knowledge/resource access. + +**Architecture:** Each tool lives in its own folder under `src/core/tools/platform-api-tools/agents-tools/`, co-located with a `.graphql.dev.ts` file containing its GraphQL operations. All tools extend `BaseMondayApiTool`, use `versionOverride: 'dev'`, and follow the Zod + `rethrowWithContext` pattern established by the existing agent tools. Tool descriptions encode the catalog-first workflows so agents know which tools to call before acting. + +**Tech Stack:** TypeScript, graphql-request (gql tag), Zod, Jest, graphql-codegen (`npm run fetch:generate dev` in `packages/agent-toolkit`) + +--- + +## File Map + +**Modify:** +- `src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts` — export `agentFieldsFragment` (currently unexported) +- `src/core/tools/platform-api-tools/agents-tools/index.ts` — add 6 new exports +- `src/core/tools/platform-api-tools/index.ts` — add 6 new imports + registrations + +**Create:** +- `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts` +- `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts` +- `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts` +- `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts` +- `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts` +- `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts` +- `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts` + +--- + +## Task 1: Export agentFieldsFragment from shared + +The `update_agent` mutation returns a full `Agent` and needs the shared fragment. Currently `agentFieldsFragment` is a local `const` — make it `export const` so the update-agent graphql file can import it. + +**Files:** +- Modify: `src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts` + +- [ ] **Step 1: Change `const` to `export const` on the fragment** + +In `src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts`, change line 3: + +```typescript +// Before +const agentFieldsFragment = gql` +// After +export const agentFieldsFragment = gql` +``` + +- [ ] **Step 2: Verify nothing broke** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools --passWithNoTests 2>&1 | tail -5 +``` + +Expected: all existing agent tests pass (3 test suites). + +- [ ] **Step 3: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts +git commit -m "refactor(agent-toolkit): export agentFieldsFragment for reuse" +``` + +--- + +## Task 2: Write all GraphQL operation files + +Write all 6 `.graphql.dev.ts` files before running codegen so types are generated in a single pass. + +**Files:** All 6 new `*.graphql.dev.ts` files. + +- [ ] **Step 1: Create `get-agent-catalog.graphql.dev.ts`** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts +import { gql } from 'graphql-request'; + +export const getAgentTriggersCatalogQuery = gql` + query getAgentTriggersCatalog($block_reference_ids: [ID!]) { + agent_triggers_catalog(block_reference_ids: $block_reference_ids) { + block_reference_id + name + description + field_schemas { + field_key + value_schema + } + required_fields { + field_key + depends_on + optional + } + } + } +`; + +export const getAgentSkillsCatalogQuery = gql` + query getAgentSkillsCatalog { + agent_skills_catalog { + id + name + description + } + } +`; +``` + +- [ ] **Step 2: Create `manage-agent-triggers.graphql.dev.ts`** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts +import { gql } from 'graphql-request'; + +export const getAgentActiveTriggersQuery = gql` + query getAgentActiveTriggers($agent_id: ID!) { + agent_active_triggers(agent_id: $agent_id) { + node_id + block_reference_id + name + description + field_summary + } + } +`; + +export const addTriggerToAgentMutation = gql` + mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) { + add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) { + success + } + } +`; + +export const removeTriggerFromAgentMutation = gql` + mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) { + remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) { + success + } + } +`; +``` + +- [ ] **Step 3: Create `manage-agent-skills.graphql.dev.ts`** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts +import { gql } from 'graphql-request'; + +export const addSkillToAgentMutation = gql` + mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) { + add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) { + success + } + } +`; + +export const removeSkillFromAgentMutation = gql` + mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) { + remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) { + success + } + } +`; +``` + +- [ ] **Step 4: Create `update-agent.graphql.dev.ts`** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts +import { gql } from 'graphql-request'; +import { agentFieldsFragment } from '../shared/agents.graphql.dev'; + +export const updateAgentMutation = gql` + ${agentFieldsFragment} + + mutation updateAgent($id: ID!, $input: UpdateAgentInput!) { + update_agent(id: $id, input: $input) { + ...AgentFields + } + } +`; +``` + +- [ ] **Step 5: Create `manage-agent-state.graphql.dev.ts`** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts +import { gql } from 'graphql-request'; + +export const activateAgentMutation = gql` + mutation activateAgent($id: ID!) { + activate_agent(id: $id) { + success + } + } +`; + +export const deactivateAgentMutation = gql` + mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) { + deactivate_agent(id: $id, inactive_reason: $inactive_reason) { + success + } + } +`; + +export const runAgentMutation = gql` + mutation runAgent($id: ID!) { + run_agent(id: $id) { + trigger_uuid + } + } +`; +``` + +- [ ] **Step 6: Create `manage-agent-knowledge.graphql.dev.ts`** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts +import { gql } from 'graphql-request'; + +export const getAgentKnowledgeQuery = gql` + query getAgentKnowledge($id: ID!) { + agent_knowledge(id: $id) { + resources { + resource_id + scope_type + permission_type + } + files { + id + file_name + file_type + } + } + } +`; + +export const addAgentResourceAccessMutation = gql` + mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) { + add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) { + success + } + } +`; + +export const removeAgentResourceAccessMutation = gql` + mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) { + remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) { + success + } + } +`; + +export const updateAgentResourceAccessMutation = gql` + mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) { + update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) { + success + } + } +`; +``` + +- [ ] **Step 7: Commit all GraphQL files** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git commit -m "feat(agent-toolkit): add GraphQL operations for 6 new agent tools" +``` + +--- + +## Task 3: Run codegen + +Generate TypeScript types from the new GraphQL operations. + +**Files:** Auto-generated — `src/monday-graphql/generated/graphql.dev/graphql.ts` + +- [ ] **Step 1: Run codegen for the dev schema** + +```bash +cd packages/agent-toolkit && npm run fetch:generate dev +``` + +Expected: exits 0, no errors. The file `src/monday-graphql/generated/graphql.dev/graphql.ts` will be updated with new types including `GetAgentTriggersCatalogQuery`, `GetAgentSkillsCatalogQuery`, `GetAgentActiveTriggersQuery`, `GetAgentActiveTriggersQueryVariables`, `AddTriggerToAgentMutation`, `AddTriggerToAgentMutationVariables`, `RemoveTriggerFromAgentMutation`, `RemoveTriggerFromAgentMutationVariables`, `AddSkillToAgentMutation`, `AddSkillToAgentMutationVariables`, `RemoveSkillFromAgentMutation`, `RemoveSkillFromAgentMutationVariables`, `UpdateAgentMutation`, `UpdateAgentMutationVariables`, `ActivateAgentMutation`, `ActivateAgentMutationVariables`, `DeactivateAgentMutation`, `DeactivateAgentMutationVariables`, `RunAgentMutation`, `RunAgentMutationVariables`, `GetAgentKnowledgeQuery`, `GetAgentKnowledgeQueryVariables`, `AddAgentResourceAccessMutation`, `AddAgentResourceAccessMutationVariables`, `RemoveAgentResourceAccessMutation`, `RemoveAgentResourceAccessMutationVariables`, `UpdateAgentResourceAccessMutation`, `UpdateAgentResourceAccessMutationVariables`. + +- [ ] **Step 2: Verify types exist** + +```bash +grep -c "GetAgentTriggersCatalogQuery\|GetAgentSkillsCatalogQuery\|AddTriggerToAgentMutation\|AddSkillToAgentMutation\|UpdateAgentMutation\|ActivateAgentMutation\|GetAgentKnowledgeQuery\|AddAgentResourceAccessMutation" src/monday-graphql/generated/graphql.dev/graphql.ts +``` + +Expected: a number greater than 0 for each type (at least 8 matches total). + +- [ ] **Step 3: Commit generated types** + +```bash +git add src/monday-graphql/generated/graphql.dev/graphql.ts src/monday-graphql/schema.dev.graphql +git commit -m "chore(agent-toolkit): regenerate dev graphql types for new agent operations" +``` + +--- + +## Task 4: `get_agent_catalog` tool + +**Files:** +- Create: `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts` +- Create: `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts` +- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` +- Modify: `src/core/tools/platform-api-tools/index.ts` + +- [ ] **Step 1: Write the failing test** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { GetAgentTriggersCatalogQuery, GetAgentSkillsCatalogQuery } from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('GetAgentCatalogTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockTrigger = { + block_reference_id: 'status-change-ref', + name: 'Status Change', + description: 'Fires when a status column changes', + field_schemas: [{ field_key: 'board_id', value_schema: 'The ID of the board to watch' }], + required_fields: [{ field_key: 'board_id', depends_on: [], optional: false }], + }; + + const mockSkill = { + id: 'skill-1', + name: 'Board Manager', + description: 'Manages boards and items', + }; + + it('should return triggers catalog when type is triggers', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [mockTrigger] } as GetAgentTriggersCatalogQuery); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(1); + expect(parsed.triggers[0].block_reference_id).toBe('status-change-ref'); + }); + + it('should pass versionOverride dev when fetching triggers', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [] } as GetAgentTriggersCatalogQuery); + + await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentTriggersCatalog'), + expect.objectContaining({ block_reference_ids: undefined }), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should pass block_reference_ids when provided', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [mockTrigger] } as GetAgentTriggersCatalogQuery); + + await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers', block_reference_ids: ['status-change-ref'] }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + { block_reference_ids: ['status-change-ref'] }, + expect.anything(), + ); + }); + + it('should return skills catalog when type is skills', async () => { + mocks.setResponseOnce({ agent_skills_catalog: [mockSkill] } as GetAgentSkillsCatalogQuery); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(1); + expect(parsed.skills[0].id).toBe('skill-1'); + }); + + it('should pass versionOverride dev when fetching skills', async () => { + mocks.setResponseOnce({ agent_skills_catalog: [] } as GetAgentSkillsCatalogQuery); + + await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentSkillsCatalog'), + expect.anything(), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should return empty list with count 0 when no triggers exist', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [] } as GetAgentTriggersCatalogQuery); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(0); + expect(parsed.triggers).toEqual([]); + }); + + it('should propagate errors when fetching triggers catalog', async () => { + mocks.setError('Unauthorized'); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + + expect(result.content[0].text).toContain('Failed to fetch monday platform agent triggers catalog'); + }); + + it('should propagate errors when fetching skills catalog', async () => { + mocks.setError('Unauthorized'); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); + + expect(result.content[0].text).toContain('Failed to fetch monday platform agent skills catalog'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/get-agent-catalog --no-coverage 2>&1 | tail -10 +``` + +Expected: FAIL — `expect(toolNames).toContain('get_agent_catalog')` fails because the tool isn't registered yet. + +- [ ] **Step 3: Implement the tool** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts +import { z } from 'zod'; +import { + GetAgentTriggersCatalogQuery, + GetAgentTriggersCatalogQueryVariables, + GetAgentSkillsCatalogQuery, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { getAgentTriggersCatalogQuery, getAgentSkillsCatalogQuery } from './get-agent-catalog.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const getAgentCatalogToolSchema = { + type: z + .enum(['triggers', 'skills']) + .describe( + 'Which catalog to fetch. "triggers" returns available trigger types with block_reference_id, field_schemas, and required_fields — use before calling manage_agent_triggers with action:add. "skills" returns available skills with id — use before calling manage_agent_skills.', + ), + block_reference_ids: z + .array(z.string()) + .optional() + .describe( + 'Only applies when type is "triggers". Fetch specific entries by block_reference_id instead of the full catalog. Omit to return all trigger types.', + ), +}; + +export class GetAgentCatalogTool extends BaseMondayApiTool { + name = 'get_agent_catalog'; + type = ToolType.READ; + annotations = createMondayApiAnnotations({ + title: 'Get monday Platform Agent Catalog', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + }); + + getDescription(): string { + return `Fetch the account-wide catalog of available trigger types or skills for monday platform agents. + +ALWAYS call this tool first before adding a trigger or skill to an agent: +- type:"triggers" — returns entries with block_reference_id (required for manage_agent_triggers action:add), name, description, field_schemas (describes the field_values shape to pass when adding — e.g. { board_id: "" }), and required_fields (fields the user must supply before you can call add). +- type:"skills" — returns entries with id (required for manage_agent_skills), name, description. + +Never guess or invent a block_reference_id or skill id — always look them up here first. + +USAGE EXAMPLES: +- List all trigger types: { "type": "triggers" } +- Fetch a specific trigger type: { "type": "triggers", "block_reference_ids": ["some-block-ref-id"] } +- List all skills: { "type": "skills" }`; + } + + getInputSchema() { + return getAgentCatalogToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.type === 'triggers') { + try { + const variables: GetAgentTriggersCatalogQueryVariables = { + block_reference_ids: input.block_reference_ids ?? undefined, + }; + const res = await this.mondayApi.request( + getAgentTriggersCatalogQuery, + variables, + { versionOverride: 'dev' }, + ); + const catalog = res.agent_triggers_catalog ?? []; + return { + content: { + message: + 'Available trigger types for monday platform agents. Use block_reference_id and inspect field_schemas/required_fields before calling manage_agent_triggers with action:add.', + count: catalog.length, + triggers: catalog, + }, + }; + } catch (error) { + rethrowWithContext(error, 'fetch monday platform agent triggers catalog'); + } + } + + try { + const res = await this.mondayApi.request( + getAgentSkillsCatalogQuery, + {}, + { versionOverride: 'dev' }, + ); + const catalog = res.agent_skills_catalog ?? []; + return { + content: { + message: 'Available skills for monday platform agents. Use id when calling manage_agent_skills.', + count: catalog.length, + skills: catalog, + }, + }; + } catch (error) { + rethrowWithContext(error, 'fetch monday platform agent skills catalog'); + } + } +} +``` + +- [ ] **Step 4: Register the tool** + +In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: +```typescript +export * from './get-agent-catalog/get-agent-catalog-tool'; +``` + +In `src/core/tools/platform-api-tools/index.ts`, add the import after the existing agent imports (line ~70): +```typescript +import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; +``` + +And add to `allGraphqlApiTools` array after `DeleteAgentTool` (line ~143): +```typescript + GetAgentCatalogTool, +``` + +- [ ] **Step 5: Run tests to verify they pass** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/get-agent-catalog --no-coverage 2>&1 | tail -10 +``` + +Expected: PASS — all 8 tests green. + +- [ ] **Step 6: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git add src/core/tools/platform-api-tools/index.ts +git commit -m "feat(agent-toolkit): add get_agent_catalog tool" +``` + +--- + +## Task 5: `manage_agent_triggers` tool + +**Files:** +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts` +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts` +- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` +- Modify: `src/core/tools/platform-api-tools/index.ts` + +- [ ] **Step 1: Write the failing test** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + GetAgentActiveTriggersQuery, + AddTriggerToAgentMutation, + RemoveTriggerFromAgentMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentTriggersTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockActiveTrigger = { + node_id: 'node-abc', + block_reference_id: 'status-change-ref', + name: 'Status Change', + description: 'Fires when a status column changes', + field_summary: 'board_id=42', + }; + + it('should list active triggers for an agent', async () => { + mocks.setResponseOnce({ agent_active_triggers: [mockActiveTrigger] } as GetAgentActiveTriggersQuery); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(1); + expect(parsed.triggers[0].node_id).toBe('node-abc'); + }); + + it('should pass agent_id and versionOverride dev when listing', async () => { + mocks.setResponseOnce({ agent_active_triggers: [] } as GetAgentActiveTriggersQuery); + + await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentActiveTriggers'), + { agent_id: '7' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should add a trigger to an agent', async () => { + mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + field_values: { board_id: '42' }, + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass block_reference_id and field_values when adding trigger', async () => { + mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); + + await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + field_values: { board_id: '42' }, + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('addTriggerToAgent'), + { agent_id: '7', block_reference_id: 'status-change-ref', field_values: { board_id: '42' } }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should add a trigger without field_values when omitted', async () => { + mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); + + await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ field_values: undefined }), + expect.anything(), + ); + }); + + it('should remove a trigger from an agent', async () => { + mocks.setResponseOnce({ remove_trigger_from_agent: { success: true } } as RemoveTriggerFromAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { + action: 'remove', + agent_id: '7', + node_id: 'node-abc', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass node_id and versionOverride dev when removing', async () => { + mocks.setResponseOnce({ remove_trigger_from_agent: { success: true } } as RemoveTriggerFromAgentMutation); + + await callToolByNameRawAsync('manage_agent_triggers', { action: 'remove', agent_id: '7', node_id: 'node-abc' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('removeTriggerFromAgent'), + { agent_id: '7', node_id: 'node-abc' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should reject add action without block_reference_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'add', agent_id: '7' }); + + expect(result.content[0].text).toContain('block_reference_id is required'); + }); + + it('should reject remove action without node_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'remove', agent_id: '7' }); + + expect(result.content[0].text).toContain('node_id is required'); + }); + + it('should propagate errors with operation context', async () => { + mocks.setError('Not found'); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '999' }); + + expect(result.content[0].text).toContain('Failed to list active triggers'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers --no-coverage 2>&1 | tail -10 +``` + +Expected: FAIL — tool not registered yet. + +- [ ] **Step 3: Implement the tool** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts +import { z } from 'zod'; +import { + GetAgentActiveTriggersQuery, + GetAgentActiveTriggersQueryVariables, + AddTriggerToAgentMutation, + AddTriggerToAgentMutationVariables, + RemoveTriggerFromAgentMutation, + RemoveTriggerFromAgentMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { + getAgentActiveTriggersQuery, + addTriggerToAgentMutation, + removeTriggerFromAgentMutation, +} from './manage-agent-triggers.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentTriggersToolSchema = { + action: z + .enum(['list', 'add', 'remove']) + .describe( + '"list" — returns all triggers currently attached to the agent (includes node_id needed for remove). "add" — attaches a new trigger by block_reference_id. "remove" — detaches a trigger by node_id.', + ), + agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), + block_reference_id: z + .string() + .trim() + .min(1) + .optional() + .describe( + 'Required for action:add. The block_reference_id from get_agent_catalog (type:triggers) identifying the trigger type to attach. Never guess this value — look it up in the catalog first.', + ), + field_values: z + .record(z.unknown()) + .optional() + .describe( + 'Required for action:add when the trigger type has required_fields. A key/value object whose shape is described by field_schemas in the get_agent_catalog response. Example: { "board_id": "12345" }. For scheduler fields pass the structured config directly; for selection fields (e.g. board picker) pass { "value": "", "label": "" }.', + ), + node_id: z + .string() + .trim() + .min(1) + .optional() + .describe( + 'Required for action:remove. The node_id of the trigger instance to remove — get it from action:list. Each trigger instance has a unique node_id even if the same trigger type is attached multiple times.', + ), +}; + +export class ManageAgentTriggersTool extends BaseMondayApiTool { + name = 'manage_agent_triggers'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent Triggers', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `List, add, or remove triggers on a monday platform agent. + +Triggers define when an agent runs automatically — for example, when a board status changes, when a date arrives, or on a schedule. + +WORKFLOW FOR ADD: +1. Call get_agent_catalog with type:"triggers" to find the right trigger type by name/description. Note its block_reference_id and inspect field_schemas (describes what field_values to pass) and required_fields (fields you must collect from the user — e.g. which board, which column). +2. Collect any required field values from the user. +3. Call this tool with action:"add", the block_reference_id, and the assembled field_values. + +WORKFLOW FOR REMOVE: +1. Call this tool with action:"list" to see active triggers by name and field_summary. Match the trigger the user described, note its node_id. +2. Call this tool with action:"remove" and that node_id. + +USAGE EXAMPLES: +- List triggers: { "action": "list", "agent_id": "7" } +- Add trigger: { "action": "add", "agent_id": "7", "block_reference_id": "status-change-ref", "field_values": { "board_id": "42" } } +- Remove trigger: { "action": "remove", "agent_id": "7", "node_id": "node-abc" }`; + } + + getInputSchema() { + return manageAgentTriggersToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'list') { + try { + const variables: GetAgentActiveTriggersQueryVariables = { agent_id: input.agent_id }; + const res = await this.mondayApi.request( + getAgentActiveTriggersQuery, + variables, + { versionOverride: 'dev' }, + ); + const triggers = res.agent_active_triggers ?? []; + return { + content: { + message: 'Active triggers on this agent. Use node_id with action:remove to detach a trigger.', + count: triggers.length, + triggers, + }, + }; + } catch (error) { + rethrowWithContext(error, 'list active triggers for monday platform agent'); + } + } + + if (input.action === 'add') { + if (!input.block_reference_id) { + throw new Error('block_reference_id is required for action:add. Call get_agent_catalog with type:triggers first.'); + } + try { + const variables: AddTriggerToAgentMutationVariables = { + agent_id: input.agent_id, + block_reference_id: input.block_reference_id, + field_values: input.field_values ?? undefined, + }; + const res = await this.mondayApi.request( + addTriggerToAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Trigger added to agent. Call manage_agent_triggers with action:list to verify.', + success: res.add_trigger_to_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'add trigger to monday platform agent'); + } + } + + if (!input.node_id) { + throw new Error('node_id is required for action:remove. Call manage_agent_triggers with action:list first to get node_id values.'); + } + try { + const variables: RemoveTriggerFromAgentMutationVariables = { + agent_id: input.agent_id, + node_id: input.node_id, + }; + const res = await this.mondayApi.request( + removeTriggerFromAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Trigger removed from agent.', + success: res.remove_trigger_from_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'remove trigger from monday platform agent'); + } + } +} +``` + +- [ ] **Step 4: Register the tool** + +In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: +```typescript +export * from './manage-agent-triggers/manage-agent-triggers-tool'; +``` + +In `src/core/tools/platform-api-tools/index.ts`, add import: +```typescript +import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; +``` + +Add to `allGraphqlApiTools` array: +```typescript + ManageAgentTriggersTool, +``` + +- [ ] **Step 5: Run tests to verify they pass** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers --no-coverage 2>&1 | tail -10 +``` + +Expected: PASS — all 10 tests green. + +- [ ] **Step 6: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git add src/core/tools/platform-api-tools/index.ts +git commit -m "feat(agent-toolkit): add manage_agent_triggers tool" +``` + +--- + +## Task 6: `manage_agent_skills` tool + +**Files:** +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts` +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts` +- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` +- Modify: `src/core/tools/platform-api-tools/index.ts` + +- [ ] **Step 1: Write the failing test** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + AddSkillToAgentMutation, + RemoveSkillFromAgentMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentSkillsTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + it('should add a skill to an agent', async () => { + mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'skill-1', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass agent_id, skill_id and versionOverride dev when adding', async () => { + mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); + + await callToolByNameRawAsync('manage_agent_skills', { action: 'add', agent_id: '7', skill_id: 'skill-1' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('addSkillToAgent'), + { agent_id: '7', skill_id: 'skill-1' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should remove a skill from an agent', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'remove', + agent_id: '7', + skill_id: 'skill-1', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass agent_id, skill_id and versionOverride dev when removing', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + + await callToolByNameRawAsync('manage_agent_skills', { action: 'remove', agent_id: '7', skill_id: 'skill-1' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('removeSkillFromAgent'), + { agent_id: '7', skill_id: 'skill-1' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should propagate errors with operation context on add', async () => { + mocks.setError('Skill not found'); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'bad-id', + }); + + expect(result.content[0].text).toContain('Failed to add skill to monday platform agent'); + }); + + it('should propagate errors with operation context on remove', async () => { + mocks.setError('Skill not found'); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'remove', + agent_id: '7', + skill_id: 'bad-id', + }); + + expect(result.content[0].text).toContain('Failed to remove skill from monday platform agent'); + }); + + it('should reject whitespace-only skill_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: ' ', + }); + + expect(result.content[0].text).toContain('skill_id must be a non-empty string'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-skills --no-coverage 2>&1 | tail -10 +``` + +Expected: FAIL — tool not registered yet. + +- [ ] **Step 3: Implement the tool** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts +import { z } from 'zod'; +import { + AddSkillToAgentMutation, + AddSkillToAgentMutationVariables, + RemoveSkillFromAgentMutation, + RemoveSkillFromAgentMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { addSkillToAgentMutation, removeSkillFromAgentMutation } from './manage-agent-skills.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentSkillsToolSchema = { + action: z.enum(['add', 'remove']).describe('"add" — attach a skill to the agent. "remove" — detach a skill from the agent.'), + agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), + skill_id: z + .string() + .trim() + .min(1, 'skill_id must be a non-empty string') + .describe( + 'The skill id from get_agent_catalog (type:skills). Never guess this value — look it up in the catalog first.', + ), +}; + +export class ManageAgentSkillsTool extends BaseMondayApiTool { + name = 'manage_agent_skills'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent Skills', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Attach or detach a skill from a monday platform agent. + +Skills extend what an agent can do — they grant access to specific monday.com capabilities. + +ALWAYS call get_agent_catalog with type:"skills" first to discover available skills and resolve the correct skill_id. Never guess or invent a skill_id. + +To see which skills are already attached to an agent, call get_agent and inspect the skill_ids array, then cross-reference with get_agent_catalog to get names and descriptions. + +USAGE EXAMPLES: +- Attach a skill: { "action": "add", "agent_id": "7", "skill_id": "skill-1" } +- Detach a skill: { "action": "remove", "agent_id": "7", "skill_id": "skill-1" }`; + } + + getInputSchema() { + return manageAgentSkillsToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'add') { + try { + const variables: AddSkillToAgentMutationVariables = { + agent_id: input.agent_id, + skill_id: input.skill_id, + }; + const res = await this.mondayApi.request( + addSkillToAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: `Skill ${input.skill_id} added to agent ${input.agent_id}.`, + success: res.add_skill_to_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'add skill to monday platform agent'); + } + } + + try { + const variables: RemoveSkillFromAgentMutationVariables = { + agent_id: input.agent_id, + skill_id: input.skill_id, + }; + const res = await this.mondayApi.request( + removeSkillFromAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: `Skill ${input.skill_id} removed from agent ${input.agent_id}.`, + success: res.remove_skill_from_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'remove skill from monday platform agent'); + } + } +} +``` + +- [ ] **Step 4: Register the tool** + +In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: +```typescript +export * from './manage-agent-skills/manage-agent-skills-tool'; +``` + +In `src/core/tools/platform-api-tools/index.ts`, add import: +```typescript +import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; +``` + +Add to `allGraphqlApiTools` array: +```typescript + ManageAgentSkillsTool, +``` + +- [ ] **Step 5: Run tests to verify they pass** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-skills --no-coverage 2>&1 | tail -10 +``` + +Expected: PASS — all 7 tests green. + +- [ ] **Step 6: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git add src/core/tools/platform-api-tools/index.ts +git commit -m "feat(agent-toolkit): add manage_agent_skills tool" +``` + +--- + +## Task 7: `update_agent` tool + +**Files:** +- Create: `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts` +- Create: `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts` +- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` +- Modify: `src/core/tools/platform-api-tools/index.ts` + +- [ ] **Step 1: Write the failing test** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { UpdateAgentMutation } from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('UpdateAgentTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockAgent = { + id: '7', + kind: 'PERSONAL', + state: 'INACTIVE', + profile: { + name: 'Updated Bot', + role: 'Analyst', + role_description: 'Analyses data', + avatar_url: 'https://example.com/a.png', + background_color: '#000000', + }, + goal: 'Analyse stuff', + plan: '# Updated Plan', + user_prompt: null, + version_id: '2', + created_at: '2026-04-29T00:00:00Z', + updated_at: '2026-05-01T00:00:00Z', + }; + + it('should return the updated agent', async () => { + mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); + + const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'Updated Bot' }); + const parsed = parseToolResult(result); + + expect(parsed.agent.id).toBe('7'); + expect(parsed.agent.profile.name).toBe('Updated Bot'); + }); + + it('should pass id, input and versionOverride dev', async () => { + mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); + + await callToolByNameRawAsync('update_agent', { id: '7', name: 'Updated Bot', plan: '# New Plan' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('updateAgent'), + { id: '7', input: { name: 'Updated Bot', plan: '# New Plan' } }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should only include provided fields in input', async () => { + mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); + + await callToolByNameRawAsync('update_agent', { id: '7', plan: '# Plan only' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + { id: '7', input: { plan: '# Plan only' } }, + expect.anything(), + ); + }); + + it('should not include agent_model in input when omitted', async () => { + mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); + + await callToolByNameRawAsync('update_agent', { id: '7', name: 'Bot' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + { id: '7', input: { name: 'Bot' } }, + expect.anything(), + ); + }); + + it('should propagate GraphQL errors with operation context', async () => { + mocks.setError('Agent not found'); + + const result = await callToolByNameRawAsync('update_agent', { id: '999', name: 'x' }); + + expect(result.content[0].text).toContain('Failed to update monday platform agent'); + }); + + it('should throw a "returned no id" error when update_agent returns null', async () => { + mocks.setResponseOnce({ update_agent: null } as UpdateAgentMutation); + + const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'x' }); + + expect(result.content[0].text).toContain('returned no id'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/update-agent --no-coverage 2>&1 | tail -10 +``` + +Expected: FAIL — tool not registered yet. + +- [ ] **Step 3: Implement the tool** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts +import { z } from 'zod'; +import { + UpdateAgentMutation, + UpdateAgentMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { updateAgentMutation } from './update-agent.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const updateAgentToolSchema = { + id: z.string().trim().min(1, 'Agent id must be a non-empty string').describe('Unique identifier of the agent to update.'), + name: z.string().trim().min(1).optional().describe('New display name for the agent.'), + role: z.string().trim().min(1).optional().describe('New role for the agent.'), + role_description: z.string().trim().min(1).optional().describe('New role description for the agent.'), + plan: z + .string() + .trim() + .min(1) + .optional() + .describe('New execution plan for the agent, in markdown format. This is the agent\'s core instructions.'), + agent_model: z + .string() + .optional() + .describe( + 'STRONGLY DISCOURAGED — omit this field. Only set when the user explicitly names a monday-supported model. Do not invent or guess model identifiers. When omitted the existing model is kept.', + ), +}; + +export class UpdateAgentTool extends BaseMondayApiTool { + name = 'update_agent'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Update monday Platform Agent', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Update a monday platform agent's profile or execution plan. Creates a new draft internally and publishes in one call. + +All fields are optional — only provided fields are changed. Omit fields you do not want to update. + +The plan field is the most impactful: it contains the agent's execution instructions in markdown format. Updating it changes how the agent behaves on every future run. + +If the user refers to the agent by name rather than id, call get_agent first to resolve the correct id. + +USAGE EXAMPLES: +- Update plan only: { "id": "7", "plan": "# New Plan\\n- Step 1\\n- Step 2" } +- Rename the agent: { "id": "7", "name": "Improved Standup Bot" }`; + } + + getInputSchema() { + return updateAgentToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + try { + const updateInput: UpdateAgentMutationVariables['input'] = {}; + if (input.name !== undefined) updateInput.name = input.name; + if (input.role !== undefined) updateInput.role = input.role; + if (input.role_description !== undefined) updateInput.role_description = input.role_description; + if (input.plan !== undefined) updateInput.plan = input.plan; + if (input.agent_model !== undefined) updateInput.agent_model = input.agent_model as any; + + const variables: UpdateAgentMutationVariables = { id: input.id, input: updateInput }; + const res = await this.mondayApi.request(updateAgentMutation, variables, { + versionOverride: 'dev', + }); + + if (!res.update_agent?.id) { + throw new Error('monday platform agent update returned no id'); + } + + return { + content: { + message: `monday platform agent ${res.update_agent.id} updated`, + agent: res.update_agent, + }, + }; + } catch (error) { + rethrowWithContext(error, 'update monday platform agent'); + } + } +} +``` + +- [ ] **Step 4: Register the tool** + +In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: +```typescript +export * from './update-agent/update-agent-tool'; +``` + +In `src/core/tools/platform-api-tools/index.ts`, add import: +```typescript +import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; +``` + +Add to `allGraphqlApiTools` array: +```typescript + UpdateAgentTool, +``` + +- [ ] **Step 5: Run tests to verify they pass** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/update-agent --no-coverage 2>&1 | tail -10 +``` + +Expected: PASS — all 6 tests green. + +- [ ] **Step 6: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git add src/core/tools/platform-api-tools/index.ts +git commit -m "feat(agent-toolkit): add update_agent tool" +``` + +--- + +## Task 8: `manage_agent_state` tool + +**Files:** +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts` +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts` +- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` +- Modify: `src/core/tools/platform-api-tools/index.ts` + +- [ ] **Step 1: Write the failing test** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + ActivateAgentMutation, + DeactivateAgentMutation, + RunAgentMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentStateTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + it('should activate an agent', async () => { + mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { action: 'activate', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass id and versionOverride dev when activating', async () => { + mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { action: 'activate', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('activateAgent'), + { id: '7' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should deactivate an agent', async () => { + mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { action: 'deactivate', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass inactive_reason when deactivating', async () => { + mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { + action: 'deactivate', + agent_id: '7', + inactive_reason: 'DEACTIVATED_BY_USER', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('deactivateAgent'), + { id: '7', inactive_reason: 'DEACTIVATED_BY_USER' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should pass undefined inactive_reason when omitted', async () => { + mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { action: 'deactivate', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + { id: '7', inactive_reason: undefined }, + expect.anything(), + ); + }); + + it('should run an agent and return trigger_uuid', async () => { + mocks.setResponseOnce({ run_agent: { trigger_uuid: 'uuid-xyz' } } as RunAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { action: 'run', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.trigger_uuid).toBe('uuid-xyz'); + }); + + it('should pass id and versionOverride dev when running', async () => { + mocks.setResponseOnce({ run_agent: { trigger_uuid: 'uuid-xyz' } } as RunAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { action: 'run', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('runAgent'), + { id: '7' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should propagate errors with operation context on activate', async () => { + mocks.setError('Agent not found'); + + const result = await callToolByNameRawAsync('manage_agent_state', { action: 'activate', agent_id: '999' }); + + expect(result.content[0].text).toContain('Failed to activate monday platform agent'); + }); + + it('should propagate errors with operation context on run', async () => { + mocks.setError('Agent not active'); + + const result = await callToolByNameRawAsync('manage_agent_state', { action: 'run', agent_id: '7' }); + + expect(result.content[0].text).toContain('Failed to run monday platform agent'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-state --no-coverage 2>&1 | tail -10 +``` + +Expected: FAIL — tool not registered yet. + +- [ ] **Step 3: Implement the tool** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts +import { z } from 'zod'; +import { + ActivateAgentMutation, + ActivateAgentMutationVariables, + DeactivateAgentMutation, + DeactivateAgentMutationVariables, + RunAgentMutation, + RunAgentMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { activateAgentMutation, deactivateAgentMutation, runAgentMutation } from './manage-agent-state.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentStateToolSchema = { + action: z + .enum(['activate', 'deactivate', 'run']) + .describe( + '"activate" — transitions the agent to ACTIVE state so it can be triggered. "deactivate" — transitions the agent to INACTIVE. "run" — manually enqueues a one-off agent run (fire-and-forget; returns trigger_uuid for tracking).', + ), + agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), + inactive_reason: z + .enum(['DEACTIVATED_BY_USER', 'ACCOUNT_LEVEL_BLOCKING']) + .optional() + .describe('Only applies to action:deactivate. Defaults to DEACTIVATED_BY_USER when omitted.'), +}; + +export class ManageAgentStateTool extends BaseMondayApiTool { + name = 'manage_agent_state'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent State', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Activate, deactivate, or manually run a monday platform agent. + +Agents created by create_agent start in state INACTIVE and cannot be triggered until activated. + +action:"activate" — sets the agent to ACTIVE. The agent can now be triggered by its configured triggers or manually via action:"run". +action:"deactivate" — sets the agent to INACTIVE. Existing triggers stop firing. +action:"run" — fires a one-off manual run immediately. This is async (fire-and-forget): the response confirms the run was accepted and enqueued, not that it has completed. Use trigger_uuid to correlate the execution in logs or future status endpoints. The agent must be ACTIVE to run. + +USAGE EXAMPLES: +- Activate: { "action": "activate", "agent_id": "7" } +- Deactivate: { "action": "deactivate", "agent_id": "7" } +- Run manually: { "action": "run", "agent_id": "7" }`; + } + + getInputSchema() { + return manageAgentStateToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'activate') { + try { + const variables: ActivateAgentMutationVariables = { id: input.agent_id }; + const res = await this.mondayApi.request(activateAgentMutation, variables, { + versionOverride: 'dev', + }); + return { + content: { + message: `monday platform agent ${input.agent_id} activated`, + success: res.activate_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'activate monday platform agent'); + } + } + + if (input.action === 'deactivate') { + try { + const variables: DeactivateAgentMutationVariables = { + id: input.agent_id, + inactive_reason: input.inactive_reason ?? undefined, + }; + const res = await this.mondayApi.request(deactivateAgentMutation, variables, { + versionOverride: 'dev', + }); + return { + content: { + message: `monday platform agent ${input.agent_id} deactivated`, + success: res.deactivate_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'deactivate monday platform agent'); + } + } + + try { + const variables: RunAgentMutationVariables = { id: input.agent_id }; + const res = await this.mondayApi.request(runAgentMutation, variables, { + versionOverride: 'dev', + }); + return { + content: { + message: `monday platform agent ${input.agent_id} run enqueued — execution is async. Use trigger_uuid to track.`, + trigger_uuid: res.run_agent?.trigger_uuid, + }, + }; + } catch (error) { + rethrowWithContext(error, 'run monday platform agent'); + } + } +} +``` + +- [ ] **Step 4: Register the tool** + +In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: +```typescript +export * from './manage-agent-state/manage-agent-state-tool'; +``` + +In `src/core/tools/platform-api-tools/index.ts`, add import: +```typescript +import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; +``` + +Add to `allGraphqlApiTools` array: +```typescript + ManageAgentStateTool, +``` + +- [ ] **Step 5: Run tests to verify they pass** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-state --no-coverage 2>&1 | tail -10 +``` + +Expected: PASS — all 9 tests green. + +- [ ] **Step 6: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git add src/core/tools/platform-api-tools/index.ts +git commit -m "feat(agent-toolkit): add manage_agent_state tool" +``` + +--- + +## Task 9: `manage_agent_knowledge` tool + +**Files:** +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts` +- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts` +- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` +- Modify: `src/core/tools/platform-api-tools/index.ts` + +- [ ] **Step 1: Write the failing test** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + GetAgentKnowledgeQuery, + AddAgentResourceAccessMutation, + RemoveAgentResourceAccessMutation, + UpdateAgentResourceAccessMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentKnowledgeTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockKnowledge = { + resources: [{ resource_id: '42', scope_type: 'BOARD', permission_type: 'READ' }], + files: [{ id: 'f1', file_name: 'spec.pdf', file_type: 'pdf' }], + }; + + it('should list agent knowledge', async () => { + mocks.setResponseOnce({ agent_knowledge: mockKnowledge } as GetAgentKnowledgeQuery); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.resources[0].resource_id).toBe('42'); + expect(parsed.files[0].file_name).toBe('spec.pdf'); + }); + + it('should pass id and versionOverride dev when listing', async () => { + mocks.setResponseOnce({ agent_knowledge: { resources: [], files: [] } } as GetAgentKnowledgeQuery); + + await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentKnowledge'), + { id: '7' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should add a resource access', async () => { + mocks.setResponseOnce({ add_agent_resource_access: { success: true } } as AddAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass all fields and versionOverride dev when adding', async () => { + mocks.setResponseOnce({ add_agent_resource_access: { success: true } } as AddAgentResourceAccessMutation); + + await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ_WRITE', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('addAgentResourceAccess'), + { id: '7', resource_id: '42', scope_type: 'BOARD', permission_type: 'READ_WRITE' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should update a resource permission', async () => { + mocks.setResponseOnce({ update_agent_resource_access: { success: true } } as UpdateAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'update', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ_WRITE', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should remove a resource access', async () => { + mocks.setResponseOnce({ remove_agent_resource_access: { success: true } } as RemoveAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'remove', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass id, resource_id, scope_type and versionOverride dev when removing', async () => { + mocks.setResponseOnce({ remove_agent_resource_access: { success: true } } as RemoveAgentResourceAccessMutation); + + await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'remove', + agent_id: '7', + resource_id: '42', + scope_type: 'DOC', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('removeAgentResourceAccess'), + { id: '7', resource_id: '42', scope_type: 'DOC' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should reject add action without resource_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + scope_type: 'BOARD', + permission_type: 'READ', + }); + + expect(result.content[0].text).toContain('resource_id is required'); + }); + + it('should reject add action without permission_type', async () => { + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + }); + + expect(result.content[0].text).toContain('permission_type is required'); + }); + + it('should propagate errors with operation context', async () => { + mocks.setError('Board not found'); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '99', + scope_type: 'BOARD', + permission_type: 'READ', + }); + + expect(result.content[0].text).toContain('Failed to add resource access to monday platform agent'); + }); +}); +``` + +- [ ] **Step 2: Run test to verify it fails** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge --no-coverage 2>&1 | tail -10 +``` + +Expected: FAIL — tool not registered yet. + +- [ ] **Step 3: Implement the tool** + +```typescript +// src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts +import { z } from 'zod'; +import { + GetAgentKnowledgeQuery, + GetAgentKnowledgeQueryVariables, + AddAgentResourceAccessMutation, + AddAgentResourceAccessMutationVariables, + RemoveAgentResourceAccessMutation, + RemoveAgentResourceAccessMutationVariables, + UpdateAgentResourceAccessMutation, + UpdateAgentResourceAccessMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { + getAgentKnowledgeQuery, + addAgentResourceAccessMutation, + removeAgentResourceAccessMutation, + updateAgentResourceAccessMutation, +} from './manage-agent-knowledge.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentKnowledgeToolSchema = { + action: z + .enum(['list', 'add', 'update', 'remove']) + .describe( + '"list" — returns current resource access (boards/docs) and uploaded files. "add" — grants access to a board or doc. "update" — changes the permission level on an existing resource. "remove" — revokes access entirely.', + ), + agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), + resource_id: z + .string() + .trim() + .min(1) + .optional() + .describe('Required for action:add, update, and remove. The ID of the monday.com board or doc.'), + scope_type: z + .enum(['BOARD', 'DOC']) + .optional() + .describe('Required for action:add, update, and remove. Whether the resource is a board or a doc.'), + permission_type: z + .enum(['READ', 'READ_WRITE']) + .optional() + .describe( + 'Required for action:add and update. READ — agent can read the resource. READ_WRITE — agent can read and write.', + ), +}; + +export class ManageAgentKnowledgeTool extends BaseMondayApiTool { + name = 'manage_agent_knowledge'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent Knowledge', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `List, grant, update, or revoke a monday platform agent's access to boards and docs. + +Agent knowledge determines which monday.com resources the agent can read or write when it runs. + +Call with action:"list" first to see what resources the agent already has access to before adding, updating, or removing. + +action:"add" — grants the agent access to a board or doc. Requires resource_id (the board or doc id), scope_type (BOARD or DOC), and permission_type (READ or READ_WRITE). +action:"update" — changes the permission level on an already-granted resource. +action:"remove" — revokes access to a resource entirely. + +USAGE EXAMPLES: +- List resources: { "action": "list", "agent_id": "7" } +- Grant board access: { "action": "add", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD", "permission_type": "READ" } +- Upgrade to read-write: { "action": "update", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD", "permission_type": "READ_WRITE" } +- Revoke access: { "action": "remove", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD" }`; + } + + getInputSchema() { + return manageAgentKnowledgeToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'list') { + try { + const variables: GetAgentKnowledgeQueryVariables = { id: input.agent_id }; + const res = await this.mondayApi.request(getAgentKnowledgeQuery, variables, { + versionOverride: 'dev', + }); + return { + content: { + message: 'Current knowledge configuration for this agent.', + resources: res.agent_knowledge?.resources ?? [], + files: res.agent_knowledge?.files ?? [], + }, + }; + } catch (error) { + rethrowWithContext(error, 'list knowledge for monday platform agent'); + } + } + + if (!input.resource_id) { + throw new Error(`resource_id is required for action:${input.action}.`); + } + if (!input.scope_type) { + throw new Error(`scope_type is required for action:${input.action}.`); + } + + if (input.action === 'add') { + if (!input.permission_type) { + throw new Error('permission_type is required for action:add.'); + } + try { + const variables: AddAgentResourceAccessMutationVariables = { + id: input.agent_id, + resource_id: input.resource_id, + scope_type: input.scope_type as any, + permission_type: input.permission_type as any, + }; + const res = await this.mondayApi.request( + addAgentResourceAccessMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: `${input.scope_type} ${input.resource_id} granted to agent with ${input.permission_type} permission.`, + success: res.add_agent_resource_access?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'add resource access to monday platform agent'); + } + } + + if (input.action === 'update') { + if (!input.permission_type) { + throw new Error('permission_type is required for action:update.'); + } + try { + const variables: UpdateAgentResourceAccessMutationVariables = { + id: input.agent_id, + resource_id: input.resource_id, + scope_type: input.scope_type as any, + permission_type: input.permission_type as any, + }; + const res = await this.mondayApi.request( + updateAgentResourceAccessMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: `Permission on ${input.scope_type} ${input.resource_id} updated to ${input.permission_type}.`, + success: res.update_agent_resource_access?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'update resource access for monday platform agent'); + } + } + + try { + const variables: RemoveAgentResourceAccessMutationVariables = { + id: input.agent_id, + resource_id: input.resource_id, + scope_type: input.scope_type as any, + }; + const res = await this.mondayApi.request( + removeAgentResourceAccessMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: `Access to ${input.scope_type} ${input.resource_id} removed from agent.`, + success: res.remove_agent_resource_access?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'remove resource access from monday platform agent'); + } + } +} +``` + +- [ ] **Step 4: Register the tool** + +In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: +```typescript +export * from './manage-agent-knowledge/manage-agent-knowledge-tool'; +``` + +In `src/core/tools/platform-api-tools/index.ts`, add import: +```typescript +import { ManageAgentKnowledgeTool } from './agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool'; +``` + +Add to `allGraphqlApiTools` array: +```typescript + ManageAgentKnowledgeTool, +``` + +- [ ] **Step 5: Run tests to verify they pass** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge --no-coverage 2>&1 | tail -10 +``` + +Expected: PASS — all 10 tests green. + +- [ ] **Step 6: Commit** + +```bash +git add src/core/tools/platform-api-tools/agents-tools/ +git add src/core/tools/platform-api-tools/index.ts +git commit -m "feat(agent-toolkit): add manage_agent_knowledge tool" +``` + +--- + +## Task 10: Full test suite and build + +- [ ] **Step 1: Run all agents-tools tests** + +```bash +cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools --no-coverage 2>&1 | tail -20 +``` + +Expected: all 9 test suites pass (3 existing + 6 new). + +- [ ] **Step 2: Run full test suite** + +```bash +cd packages/agent-toolkit && npm test 2>&1 | tail -20 +``` + +Expected: all tests pass, no regressions. + +- [ ] **Step 3: Build** + +```bash +cd packages/agent-toolkit && npm run build 2>&1 | tail -10 +``` + +Expected: exits 0, `dist/` updated with no TypeScript errors. + +--- + +## Task 11: Bump version + +- [ ] **Step 1: Bump version in `package.json`** + +In `packages/agent-toolkit/package.json`, change: +```json +"version": "5.10.3" +``` +to: +```json +"version": "5.11.0" +``` + +(Minor bump — new tools are additive, non-breaking.) + +- [ ] **Step 2: Commit** + +```bash +git add packages/agent-toolkit/package.json +git commit -m "chore(agent-toolkit): bump version to 5.11.0" +``` From a75204b8c12a2f810eb5d423fe81eb51ef36bf3c Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 17:46:23 +0300 Subject: [PATCH 03/28] refactor(agent-toolkit): export agentFieldsFragment for reuse --- .../agents-tools/shared/agents.graphql.dev.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts index 2c335206..5edda44e 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts @@ -1,6 +1,6 @@ import { gql } from 'graphql-request'; -const agentFieldsFragment = gql` +export const agentFieldsFragment = gql` fragment AgentFields on Agent { id kind From ec0d01b294e0f9f848499f93b78556e9fa95bc67 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 17:50:52 +0300 Subject: [PATCH 04/28] feat(agent-toolkit): add GraphQL operations for 6 new agent tools --- .../get-agent-catalog.graphql.dev.ts | 30 +++++++++++++ .../manage-agent-knowledge.graphql.dev.ts | 42 +++++++++++++++++++ .../manage-agent-skills.graphql.dev.ts | 17 ++++++++ .../manage-agent-state.graphql.dev.ts | 25 +++++++++++ .../manage-agent-triggers.graphql.dev.ts | 29 +++++++++++++ .../update-agent/update-agent.graphql.dev.ts | 12 ++++++ 6 files changed, 155 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts new file mode 100644 index 00000000..597de684 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts @@ -0,0 +1,30 @@ +import { gql } from 'graphql-request'; + +export const getAgentTriggersCatalogQuery = gql` + query getAgentTriggersCatalog($block_reference_ids: [ID!]) { + agent_triggers_catalog(block_reference_ids: $block_reference_ids) { + block_reference_id + name + description + field_schemas { + field_key + value_schema + } + required_fields { + field_key + depends_on + optional + } + } + } +`; + +export const getAgentSkillsCatalogQuery = gql` + query getAgentSkillsCatalog { + agent_skills_catalog { + id + name + description + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts new file mode 100644 index 00000000..47e55644 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts @@ -0,0 +1,42 @@ +import { gql } from 'graphql-request'; + +export const getAgentKnowledgeQuery = gql` + query getAgentKnowledge($id: ID!) { + agent_knowledge(id: $id) { + resources { + resource_id + scope_type + permission_type + } + files { + id + file_name + file_type + } + } + } +`; + +export const addAgentResourceAccessMutation = gql` + mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) { + add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) { + success + } + } +`; + +export const removeAgentResourceAccessMutation = gql` + mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) { + remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) { + success + } + } +`; + +export const updateAgentResourceAccessMutation = gql` + mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) { + update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) { + success + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts new file mode 100644 index 00000000..d58f3fee --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts @@ -0,0 +1,17 @@ +import { gql } from 'graphql-request'; + +export const addSkillToAgentMutation = gql` + mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) { + add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) { + success + } + } +`; + +export const removeSkillFromAgentMutation = gql` + mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) { + remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) { + success + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts new file mode 100644 index 00000000..c4e103e4 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts @@ -0,0 +1,25 @@ +import { gql } from 'graphql-request'; + +export const activateAgentMutation = gql` + mutation activateAgent($id: ID!) { + activate_agent(id: $id) { + success + } + } +`; + +export const deactivateAgentMutation = gql` + mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) { + deactivate_agent(id: $id, inactive_reason: $inactive_reason) { + success + } + } +`; + +export const runAgentMutation = gql` + mutation runAgent($id: ID!) { + run_agent(id: $id) { + trigger_uuid + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts new file mode 100644 index 00000000..f022f765 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts @@ -0,0 +1,29 @@ +import { gql } from 'graphql-request'; + +export const getAgentActiveTriggersQuery = gql` + query getAgentActiveTriggers($agent_id: ID!) { + agent_active_triggers(agent_id: $agent_id) { + node_id + block_reference_id + name + description + field_summary + } + } +`; + +export const addTriggerToAgentMutation = gql` + mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) { + add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) { + success + } + } +`; + +export const removeTriggerFromAgentMutation = gql` + mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) { + remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) { + success + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts new file mode 100644 index 00000000..5d9eb74a --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts @@ -0,0 +1,12 @@ +import { gql } from 'graphql-request'; +import { agentFieldsFragment } from '../shared/agents.graphql.dev'; + +export const updateAgentMutation = gql` + ${agentFieldsFragment} + + mutation updateAgent($id: ID!, $input: UpdateAgentInput!) { + update_agent(id: $id, input: $input) { + ...AgentFields + } + } +`; From 6cf4680b754c7496d91eb3c140097785fc1b24d9 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 17:54:11 +0300 Subject: [PATCH 05/28] chore(agent-toolkit): regenerate dev graphql types for new agent operations --- .../generated/graphql.dev/graphql.ts | 688 +++++++++++++++++- .../src/monday-graphql/schema.dev.graphql | 448 +++++++++++- 2 files changed, 1110 insertions(+), 26 deletions(-) diff --git a/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts b/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts index a6c8956a..abb60a6d 100644 --- a/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts +++ b/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts @@ -254,6 +254,8 @@ export type AddedAllocatedResource = { /** An AI agent on the monday.com platform */ export type Agent = { __typename?: 'Agent'; + /** The LLM model the agent uses */ + agent_model?: Maybe; /** The timestamp when the agent was created. Null on create mutation responses — use the agent query to fetch it. */ created_at?: Maybe; /** The goal or objective of the agent */ @@ -262,10 +264,14 @@ export type Agent = { id: Scalars['ID']['output']; /** The kind of agent (personal, account-level, or external) */ kind?: Maybe; + /** Knowledge files attached to the agent. Only populated on create mutation responses. */ + knowledge?: Maybe>; /** The execution plan in markdown format, describing the agent capabilities and operating principles */ plan?: Maybe; /** The agent profile with name, role, and avatar */ profile?: Maybe; + /** Reference IDs of skills attached to this agent. Use agent_skills_catalog to resolve full name and description. */ + skill_ids: Array; /** The current state of the agent */ state?: Maybe; /** The timestamp when the agent was last updated. Null on create mutation responses — use the agent query to fetch it. */ @@ -276,6 +282,21 @@ export type Agent = { version_id: Scalars['ID']['output']; }; +/** A trigger currently attached to an agent */ +export type AgentActiveTrigger = { + __typename?: 'AgentActiveTrigger'; + /** The trigger type, matching block_reference_id in the catalog */ + block_reference_id: Scalars['ID']['output']; + /** Description of the trigger type */ + description?: Maybe; + /** Human-readable summary of how this trigger is configured (e.g. "type=Weekly, hour=9, days=3/4") */ + field_summary?: Maybe; + /** Display name of the trigger type */ + name: Scalars['String']['output']; + /** Stable identifier of this trigger instance — use this as node_id when calling remove_trigger_from_agent */ + node_id: Scalars['ID']['output']; +}; + /** The kind of AI agent */ export enum AgentKind { /** An account-level agent available to the entire account */ @@ -286,6 +307,75 @@ export enum AgentKind { Personal = 'PERSONAL' } +/** The full knowledge configuration of an agent — resources (boards/docs) and uploaded files */ +export type AgentKnowledge = { + __typename?: 'AgentKnowledge'; + /** Files uploaded as agent knowledge */ + files?: Maybe>; + /** Boards and docs the agent has access to */ + resources?: Maybe>; +}; + +/** A knowledge entry attached to an agent */ +export type AgentKnowledgeEntry = { + __typename?: 'AgentKnowledgeEntry'; + /** The unique identifier of the knowledge entry */ + id: Scalars['ID']['output']; + /** Reference ID for the knowledge entry */ + knowledge_reference_id?: Maybe; + /** File metadata for this knowledge entry */ + metadata?: Maybe; + /** The source type of this knowledge entry */ + source_type?: Maybe; + /** The current state of this knowledge entry */ + state?: Maybe; +}; + +/** A file uploaded as agent knowledge */ +export type AgentKnowledgeFile = { + __typename?: 'AgentKnowledgeFile'; + /** Original file name */ + file_name?: Maybe; + /** File extension (e.g. pdf, docx, csv) */ + file_type?: Maybe; + /** Unique identifier of the knowledge file */ + id?: Maybe; +}; + +/** Metadata about a knowledge file attachment */ +export type AgentKnowledgeMetadata = { + __typename?: 'AgentKnowledgeMetadata'; + /** Cloudinary asset ID for image files */ + asset_id?: Maybe; + /** Original name of the uploaded file */ + file_name?: Maybe; + /** MIME type of the file */ + file_type?: Maybe; +}; + +/** A monday.com board or doc the agent has been granted access to */ +export type AgentKnowledgeResource = { + __typename?: 'AgentKnowledgeResource'; + /** The permission level the agent has on this resource */ + permission_type?: Maybe; + /** The ID of the board or doc */ + resource_id?: Maybe; + /** Whether this resource is a board or a doc */ + scope_type?: Maybe; +}; + +/** Supported LLM models for an agent */ +export enum AgentModel { + /** Claude Opus 4.7 (claude-opus-4-7) */ + ClaudeOpus_4_7 = 'CLAUDE_OPUS_4_7', + /** Claude Sonnet 4.6 (claude-sonnet-4-6) */ + ClaudeSonnet_4_6 = 'CLAUDE_SONNET_4_6', + /** Gemini 2.5 Flash */ + Gemini_2_5Flash = 'GEMINI_2_5_FLASH', + /** GPT 5.2 */ + Gpt_5_2 = 'GPT_5_2' +} + /** Visual and role identity of an agent. */ export type AgentProfile = { __typename?: 'AgentProfile'; @@ -301,6 +391,17 @@ export type AgentProfile = { role_description?: Maybe; }; +/** A skill available for agents to use — browse the catalog, then attach by id. */ +export type AgentSkillCatalogEntry = { + __typename?: 'AgentSkillCatalogEntry'; + /** What this skill does */ + description?: Maybe; + /** Stable reference ID — pass this to add_skill_to_agent / remove_skill_from_agent */ + id?: Maybe; + /** Display name of the skill */ + name?: Maybe; +}; + /** The current state of an agent */ export enum AgentState { /** The agent is active and can be triggered and executed */ @@ -315,6 +416,28 @@ export enum AgentState { Inactive = 'INACTIVE' } +/** Result of an agent state change operation */ +export type AgentStateResult = { + __typename?: 'AgentStateResult'; + /** Whether the operation succeeded */ + success?: Maybe; +}; + +/** An available trigger type that can be attached to an agent */ +export type AgentTriggerCatalogEntry = { + __typename?: 'AgentTriggerCatalogEntry'; + /** Pass this value as block_reference_id when calling add_trigger_to_agent */ + block_reference_id: Scalars['ID']['output']; + /** What this trigger does */ + description?: Maybe; + /** Structured value schemas for fields you can populate directly in field_values */ + field_schemas: Array; + /** Display name of the trigger */ + name: Scalars['String']['output']; + /** Selection fields (e.g. board picker) that must be provided in field_values as { value, label } pairs */ + required_fields: Array; +}; + export type AggregateBasicAggregationResult = { __typename?: 'AggregateBasicAggregationResult'; result?: Maybe; @@ -1272,6 +1395,8 @@ export type AppType = { updated_at?: Maybe; /** The latest version type */ version_type?: Maybe; + /** All versions of this app with their current status. Use this to poll promotion progress. */ + versions?: Maybe>; /** The webhook endpoint URL */ webhook_url?: Maybe; }; @@ -1298,6 +1423,18 @@ export type AppVersion = { type?: Maybe; }; +/** The lifecycle status of an app version */ +export enum AppVersionStatus { + /** Version has been superseded by a newer version */ + Deprecated = 'DEPRECATED', + /** Version is in development and not yet live */ + Draft = 'DRAFT', + /** Version is live and available to users */ + Live = 'LIVE', + /** Version is in the process of being promoted */ + Promoting = 'PROMOTING' +} + /** The app monetization information for the current account */ export type AppsMonetizationInfo = { __typename?: 'AppsMonetizationInfo'; @@ -1402,6 +1539,8 @@ export enum AssetHolder { Item = 'ITEM', /** An update/post entity. */ Post = 'POST', + /** A vibe application entity. */ + VibeApp = 'VIBE_APP', /** A workspace entity. */ Workspace = 'WORKSPACE' } @@ -1493,6 +1632,36 @@ export type AssignedBoard = { board_id?: Maybe; }; +/** Structured result data for a completed or partially-completed operation */ +export type AsyncJobResult = { + __typename?: 'AsyncJobResult'; + /** Operation-specific details (failed item IDs, report URLs, etc.) */ + details?: Maybe; + /** Items that failed */ + failed?: Maybe; + /** Successfully processed items */ + succeeded?: Maybe; + /** Total items in the operation */ + total?: Maybe; +}; + +/** Status information for an async job */ +export type AsyncJobStatus = { + __typename?: 'AsyncJobStatus'; + /** When the job was created (ISO 8601) */ + created_at?: Maybe; + /** Error description if the job failed */ + error?: Maybe; + /** Unique job identifier */ + id?: Maybe; + /** Structured result data for completed or partially-completed operations */ + result?: Maybe; + /** Current job status */ + status?: Maybe; + /** When the job was last updated (ISO 8601) */ + updated_at?: Maybe; +}; + /** Represents a single attribute type option for a resource */ export type Attribute = { __typename?: 'Attribute'; @@ -1628,6 +1797,15 @@ export type AutomationData = { recipe?: Maybe; }; +/** A page of automations with cursor for pagination */ +export type AutomationsPage = { + __typename?: 'AutomationsPage'; + /** Opaque cursor for fetching the next page. Null if no more results. */ + cursor?: Maybe; + /** The automations in this page */ + items?: Maybe>; +}; + /** Base field type implementation */ export type BaseFieldType = FieldType & { __typename?: 'BaseFieldType'; @@ -1847,6 +2025,8 @@ export type Board = { access_level: BoardAccessLevel; /** The board log events. */ activity_logs?: Maybe>>; + /** Automations for this board */ + automations: AutomationsPage; /** The board's folder unique identifier. */ board_folder_id?: Maybe; /** The board's kind (public / private / share). */ @@ -1944,6 +2124,13 @@ export type BoardActivity_LogsArgs = { }; +/** A monday.com board. */ +export type BoardAutomationsArgs = { + cursor?: InputMaybe; + limit?: InputMaybe; +}; + + /** A monday.com board. */ export type BoardColumnsArgs = { capabilities?: InputMaybe>>; @@ -2025,6 +2212,69 @@ export enum BoardAttributes { Name = 'name' } +/** A board automation */ +export type BoardAutomation = { + __typename?: 'BoardAutomation'; + /** Whether the automation is active */ + active?: Maybe; + /** Creation timestamp */ + created_at?: Maybe; + /** Automation description */ + description?: Maybe; + /** Automation ID */ + id?: Maybe; + /** Automation importance level */ + importance?: Maybe; + /** Notice message for the automation */ + notice_message?: Maybe; + /** Template reference ID if created from template */ + template_reference_id?: Maybe; + /** Automation title */ + title?: Maybe; + /** Last update timestamp */ + updated_at?: Maybe; + /** Creator user ID */ + user_id?: Maybe; + /** Workflow block definitions */ + workflow_blocks?: Maybe; + /** Host data (board ID and type) */ + workflow_host_data?: Maybe; + /** Workflow variable definitions */ + workflow_variables?: Maybe; +}; + +/** Input for creating a board automation. Provide template_reference_id to create from a template, or workflow_blocks and workflow_variables for a direct creation. */ +export type BoardAutomationCreateInput = { + /** Board ID to host the automation */ + board_id: Scalars['String']['input']; + /** Automation description */ + description?: InputMaybe; + /** Template reference ID (for template-based creation) */ + template_reference_id?: InputMaybe; + /** Automation title */ + title: Scalars['String']['input']; + /** Automation block definitions (for direct creation) */ + workflow_blocks?: InputMaybe; + /** Automation variable definitions (for direct creation) */ + workflow_variables?: InputMaybe; + /** Template variable values (for template-based creation) */ + workflow_variables_values?: InputMaybe; +}; + +/** Result of creating a board automation */ +export type BoardAutomationCreateResult = { + __typename?: 'BoardAutomationCreateResult'; + /** The ID of the created automation */ + workflow_id?: Maybe; +}; + +/** Result of deleting a board automation */ +export type BoardAutomationDeleteResult = { + __typename?: 'BoardAutomationDeleteResult'; + /** Whether the deletion was successful */ + is_success?: Maybe; +}; + /** Basic role names for board permissions. Each role grants different levels of access to the board. */ export enum BoardBasicRoleName { /** @@ -2941,6 +3191,8 @@ export type CountryValue = ColumnValue & { export type CreateAgentInput = { /** The LLM model the agent should use */ agent_model?: InputMaybe; + /** IDs of previously uploaded pending files to attach as knowledge during creation */ + pending_file_ids?: InputMaybe>; /** A description of what the agent should do — used to generate profile, goal, and plan via AI */ prompt: Scalars['String']['input']; }; @@ -3935,6 +4187,15 @@ export type DependencyValueInput = { removed_pulse?: InputMaybe>; }; +/** An app version */ +export type DeveloperAppVersion = { + __typename?: 'DeveloperAppVersion'; + /** The unique identifier of the app version */ + id?: Maybe; + /** The current lifecycle status of this app version */ + status?: Maybe; +}; + /** A document block that was changed between two versions, including its content and what type of change occurred. */ export type DiffBlock = { __typename?: 'DiffBlock'; @@ -4582,6 +4843,8 @@ export type ExportMarkdownResult = { export type ExportOptionsInput = { /** Header row format for CSV exports. Ignored for other formats. */ header_row?: InputMaybe; + /** Include item_id (and parent_item_id when subitems are enabled) columns at the end of CSV exports. */ + include_item_identifiers?: InputMaybe; /** Include subitems in the export */ include_subitems?: InputMaybe; /** Include updates/comments in the export */ @@ -4696,15 +4959,11 @@ export type FieldType = { uniqueKey?: Maybe; }; -/** Implementation of a field type */ +/** An interface (app feature) that a field type implements */ export type FieldTypeImplementation = { __typename?: 'FieldTypeImplementation'; - /** Unique identifier for the implementation */ - id?: Maybe; - /** Name of the implementation */ - name?: Maybe; - /** Unique key of the app feature */ - uniqueKey?: Maybe; + /** Reference id of the app feature interface this field type implements */ + app_feature_reference_id?: Maybe; }; /** The type of relation between a field and its type */ @@ -6079,6 +6338,14 @@ export type ImportDocFromHtmlResult = { success: Scalars['Boolean']['output']; }; +/** The reason an agent is inactive */ +export enum InactiveReason { + /** The agent was deactivated due to an account-level block */ + AccountLevelBlocking = 'ACCOUNT_LEVEL_BLOCKING', + /** The agent was manually deactivated by a user */ + DeactivatedByUser = 'DEACTIVATED_BY_USER' +} + /** Interface for input field configuration */ export type InputFieldConfig = { /** Detailed description of the field */ @@ -7522,6 +7789,22 @@ export type ItemsResponse = { items: Array; }; +/** Status of an async job */ +export enum JobState { + /** Job was cancelled */ + Cancelled = 'CANCELLED', + /** Job completed successfully */ + Completed = 'COMPLETED', + /** Job expired before completion */ + Expired = 'EXPIRED', + /** Job failed */ + Failed = 'FAILED', + /** Job is queued but not yet started */ + Pending = 'PENDING', + /** Job is actively executing */ + Running = 'RUNNING' +} + /** Status of a job operation. Currently supports items job status for backfill and ingest operations. */ export type JobStatus = ItemsJobStatus; @@ -7544,6 +7827,38 @@ export type KnowledgeBaseAnswer = { raw_snippets?: Maybe>; }; +/** The permission level the agent has on a resource */ +export enum KnowledgePermission { + /** Agent can read the resource */ + Read = 'READ', + /** Agent can read and write the resource */ + ReadWrite = 'READ_WRITE' +} + +/** The type of monday.com resource granted to an agent */ +export enum KnowledgeScope { + /** A monday.com board */ + Board = 'BOARD', + /** A monday.com doc */ + Doc = 'DOC' +} + +/** The source type of a knowledge entry */ +export enum KnowledgeSource { + /** Knowledge sourced from an uploaded file */ + File = 'FILE' +} + +/** The state of a knowledge entry */ +export enum KnowledgeState { + /** Knowledge is active and available for retrieval */ + Active = 'ACTIVE', + /** Knowledge has been deleted */ + Deleted = 'DELETED', + /** Knowledge is being processed */ + Pending = 'PENDING' +} + export type LastUpdatedValue = ColumnValue & { __typename?: 'LastUpdatedValue'; /** The column that this value belongs to. */ @@ -8192,6 +8507,8 @@ export type MondayAssetDocumentSourceInput = { /** Root mutation type for the Dependencies service */ export type Mutation = { __typename?: 'Mutation'; + /** Activate an existing agent */ + activate_agent?: Maybe; /** Activate a form to make it visible to users and accept new submissions. */ activate_form?: Maybe; /** Activate a live workflow */ @@ -8200,6 +8517,8 @@ export type Mutation = { activate_managed_column?: Maybe; /** Activates the specified users. */ activate_users?: Maybe; + /** Grant an agent access to a monday.com board or doc. Creates a draft version, applies the change, and promotes to live. */ + add_agent_resource_access?: Maybe; /** Add resources to the planner without allocations */ add_allocated_resources?: Maybe>; /** Add allocations to resources that already exist on the Resource Planner */ @@ -8214,6 +8533,8 @@ export type Mutation = { add_file_to_update?: Maybe; /** Add a required column to a board */ add_required_column?: Maybe; + /** Attach a skill to an agent by its catalog id. Use agent_skills_catalog to discover available ids. */ + add_skill_to_agent?: Maybe; /** * Add subscribers to a board. * @deprecated use add_users_to_board instead @@ -8225,6 +8546,8 @@ export type Mutation = { add_teams_to_board?: Maybe>>; /** Add teams to a workspace. */ add_teams_to_workspace?: Maybe>>; + /** Adds a trigger to an agent. Creates a draft if needed, applies the change, and promotes to live in one call. Returns { success: true } on success. Use agent_active_triggers to read the updated trigger list. Get available trigger types and field schemas from agent_triggers_catalog. */ + add_trigger_to_agent?: Maybe; /** Add subscribers to a board. */ add_users_to_board?: Maybe>>; /** Add users to team. */ @@ -8307,6 +8630,8 @@ export type Mutation = { create_blank_agent?: Maybe; /** Create a new board. */ create_board?: Maybe; + /** Create a board automation. Provide template_reference_id to create from a template, or workflow_blocks and workflow_variables for a direct creation. */ + create_board_automation: BoardAutomationCreateResult; /** Creates a board relation column. */ create_board_relation_column?: Maybe; /** Generic mutation for creating any column type with validation. Supports creating column with properties like title, description, and type-specific defaults/settings. The mutation validates input against the column type's schema before applying changes. Use get_column_type_schema query to understand available properties for each column type. */ @@ -8396,6 +8721,8 @@ export type Mutation = { create_widget?: Maybe; /** Create a new workspace. */ create_workspace?: Maybe; + /** Deactivate an existing agent */ + deactivate_agent?: Maybe; /** Deactivate a form to hide it from users and stop accepting submissions. Form data is preserved. */ deactivate_form?: Maybe; /** Deactivate a live workflow */ @@ -8414,6 +8741,8 @@ export type Mutation = { delete_article?: Maybe; /** Delete a board. */ delete_board?: Maybe; + /** Delete a board automation by ID. */ + delete_board_automation: BoardAutomationDeleteResult; /** Deletes a column from a board. Cannot delete mandatory columns (e.g., name column). */ delete_column?: Maybe; delete_custom_activity?: Maybe; @@ -8512,20 +8841,28 @@ export type Mutation = { pin_to_top: Update; /** Process an event through the task engine AI. Returns true when accepted. */ process_events?: Maybe; + /** Promotes the latest draft app version of an app to live. Promotion is asynchronous — poll the returned version's status field (via the app query) until it transitions to LIVE. Only app collaborators can perform this action. */ + promote_app?: Maybe; /** Publishes an article with the specified object ID. Allows setting privacy level, target folder, and managing subscribers (users and teams). Returns the updated article metadata. */ publish_article?: Maybe; /** Publishes object out of draft state. Returns {success: true} on success, {success: false} on failure. */ publish_object?: Maybe; /** Reconcile the current user tasks board with latest source item changes. */ reconcile_with_items?: Maybe; + /** Remove a board or doc from an agent. Creates a draft, removes the access, and promotes to live. */ + remove_agent_resource_access?: Maybe; /** Removes connected boards from a board relation column. */ remove_board_relation_connected_boards?: Maybe>; /** Remove mock app subscription for the current account */ remove_mock_app_subscription?: Maybe; /** Remove a required column from a board */ remove_required_column?: Maybe; + /** Detach a skill from an agent by its catalog id. */ + remove_skill_from_agent?: Maybe; /** Removes the specified users as owners of the specified team. */ remove_team_owners?: Maybe; + /** Removes a trigger from an agent by its node_id. Creates a draft if needed, applies the change, and promotes to live in one call. Returns { success: true } on success. Use agent_active_triggers to verify the trigger is gone. Get node_id values from the agent_active_triggers query. */ + remove_trigger_from_agent?: Maybe; /** Remove users from team. */ remove_users_from_team?: Maybe; /** Restore an entity from a migration job */ @@ -8534,6 +8871,8 @@ export type Mutation = { rollback_restore?: Maybe; /** Rollback a snapshot to allow creating a new one for the same entity */ rollback_snapshot?: Maybe; + /** Trigger a manual run for an existing agent. This is an async fire-and-forget operation — a successful response means the run was accepted and enqueued, not that it has completed or succeeded. Use trigger_uuid to correlate the execution in downstream events or future status endpoints. */ + run_agent?: Maybe; /** Create a workflow template for an account */ save_workflow_as_template?: Maybe; /** @@ -8561,6 +8900,10 @@ export type Mutation = { unpin_from_top: Update; /** Unpublishes object from public state back to draft state. Returns {success: true} on success, {success: false} on failure. */ unpublish_object?: Maybe; + /** Update an agent — creates a new draft if needed, applies the changes, and publishes to live in one call */ + update_agent?: Maybe; + /** Change the permission level an agent has on an existing board or doc. Creates a draft, updates the permission, and promotes to live. */ + update_agent_resource_access?: Maybe; /** Update multiple allocations in a single batch operation. Returns per-item results. */ update_allocations?: Maybe>; /** Updates an existing app. If the app latest version is live, a new draft version is automatically created and updated. */ @@ -8664,6 +9007,12 @@ export type Mutation = { }; +/** Root mutation type for the Dependencies service */ +export type MutationActivate_AgentArgs = { + id: Scalars['ID']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationActivate_FormArgs = { formToken: Scalars['String']['input']; @@ -8688,6 +9037,15 @@ export type MutationActivate_UsersArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationAdd_Agent_Resource_AccessArgs = { + id: Scalars['ID']['input']; + permission_type: KnowledgePermission; + resource_id: Scalars['ID']['input']; + scope_type: KnowledgeScope; +}; + + /** Root mutation type for the Dependencies service */ export type MutationAdd_Allocated_ResourcesArgs = { planner_id: Scalars['ID']['input']; @@ -8741,6 +9099,13 @@ export type MutationAdd_Required_ColumnArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationAdd_Skill_To_AgentArgs = { + agent_id: Scalars['ID']['input']; + skill_id: Scalars['ID']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationAdd_Subscribers_To_BoardArgs = { board_id: Scalars['ID']['input']; @@ -8773,6 +9138,14 @@ export type MutationAdd_Teams_To_WorkspaceArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationAdd_Trigger_To_AgentArgs = { + agent_id: Scalars['ID']['input']; + block_reference_id: Scalars['ID']['input']; + field_values?: InputMaybe; +}; + + /** Root mutation type for the Dependencies service */ export type MutationAdd_Users_To_BoardArgs = { board_id: Scalars['ID']['input']; @@ -9094,6 +9467,12 @@ export type MutationCreate_BoardArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationCreate_Board_AutomationArgs = { + input: BoardAutomationCreateInput; +}; + + /** Root mutation type for the Dependencies service */ export type MutationCreate_Board_Relation_ColumnArgs = { after_column_id?: InputMaybe; @@ -9523,6 +9902,13 @@ export type MutationCreate_WorkspaceArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationDeactivate_AgentArgs = { + id: Scalars['ID']['input']; + inactive_reason?: InputMaybe; +}; + + /** Root mutation type for the Dependencies service */ export type MutationDeactivate_FormArgs = { formToken: Scalars['String']['input']; @@ -9578,6 +9964,13 @@ export type MutationDelete_BoardArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationDelete_Board_AutomationArgs = { + board_id: Scalars['ID']['input']; + id: Scalars['ID']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationDelete_ColumnArgs = { board_id: Scalars['ID']['input']; @@ -9951,6 +10344,13 @@ export type MutationProcess_EventsArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationPromote_AppArgs = { + app_id: Scalars['ID']['input']; + app_version_id?: InputMaybe; +}; + + /** Root mutation type for the Dependencies service */ export type MutationPublish_ArticleArgs = { add_subscriber_ids?: InputMaybe>; @@ -9969,6 +10369,14 @@ export type MutationPublish_ObjectArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationRemove_Agent_Resource_AccessArgs = { + id: Scalars['ID']['input']; + resource_id: Scalars['ID']['input']; + scope_type: KnowledgeScope; +}; + + /** Root mutation type for the Dependencies service */ export type MutationRemove_Board_Relation_Connected_BoardsArgs = { board_id: Scalars['ID']['input']; @@ -9992,6 +10400,13 @@ export type MutationRemove_Required_ColumnArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationRemove_Skill_From_AgentArgs = { + agent_id: Scalars['ID']['input']; + skill_id: Scalars['ID']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationRemove_Team_OwnersArgs = { team_id: Scalars['ID']['input']; @@ -9999,6 +10414,13 @@ export type MutationRemove_Team_OwnersArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationRemove_Trigger_From_AgentArgs = { + agent_id: Scalars['ID']['input']; + node_id: Scalars['ID']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationRemove_Users_From_TeamArgs = { team_id: Scalars['ID']['input']; @@ -10029,6 +10451,12 @@ export type MutationRollback_SnapshotArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationRun_AgentArgs = { + id: Scalars['ID']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationSave_Workflow_As_TemplateArgs = { workflow_template_data: WorkflowTemplateInput; @@ -10123,6 +10551,22 @@ export type MutationUnpublish_ObjectArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationUpdate_AgentArgs = { + id: Scalars['ID']['input']; + input: UpdateAgentInput; +}; + + +/** Root mutation type for the Dependencies service */ +export type MutationUpdate_Agent_Resource_AccessArgs = { + id: Scalars['ID']['input']; + permission_type: KnowledgePermission; + resource_id: Scalars['ID']['input']; + scope_type: KnowledgeScope; +}; + + /** Root mutation type for the Dependencies service */ export type MutationUpdate_AllocationsArgs = { planner_id: Scalars['ID']['input']; @@ -10556,6 +11000,13 @@ export type MutationUse_TemplateArgs = { template_id: Scalars['Int']['input']; }; +/** Result of a write operation that does not need to return entity data. */ +export type MutationResult = { + __typename?: 'MutationResult'; + /** Whether the operation succeeded */ + success: Scalars['Boolean']['output']; +}; + /** Response containing the current user's task board id */ export type MyTaskBoardResponse = { __typename?: 'MyTaskBoardResponse'; @@ -10991,6 +11442,8 @@ export type OperationInput = { /** A single option in a remote options list */ export type Option = { __typename?: 'Option'; + /** Optional icon to display alongside the option (e.g. { vibe, tooltip }) */ + icon?: Maybe; /** The display title of the option */ title?: Maybe; /** The value of the option */ @@ -11583,8 +12036,14 @@ export type Query = { account_trigger_statistics?: Maybe; /** Get aggregated automation runs statistics grouped by entity Ids */ account_triggers_statistics_by_entity_id?: Maybe; - /** Get an agent by its ID. Returns null if the agent does not exist or the user does not have access. */ - agent?: Maybe; + /** Returns the triggers currently attached to an agent. Use node_id from each result to remove a trigger. */ + agent_active_triggers?: Maybe>; + /** Returns the knowledge configuration of an agent — boards/docs it has access to and uploaded files. Board and doc names are not included; use the board/doc subgraph queries to resolve them. */ + agent_knowledge?: Maybe; + /** List all skills available to attach to an agent. Use the returned id to call add_skill_to_agent. */ + agent_skills_catalog?: Maybe>; + /** Returns trigger types that can be attached to an agent via add_trigger_to_agent. Pass block_reference_ids to fetch only specific entries (much faster). Only includes auto-addable triggers — 3rd-party triggers requiring OAuth or credentials are excluded. */ + agent_triggers_catalog?: Maybe>; /** List personal agents for the authenticated user. At least one filter (ids or limit) is required. */ agents?: Maybe>; /** Performs aggregation operations on board data */ @@ -11688,6 +12147,8 @@ export type Query = { * • The `kind` field tells you whether the block is a TRIGGER, ACTION or CONDITION, which helps decide its placement in the workflow. */ blocks?: Maybe; + /** Get board automations. Filter by ids (specific automation IDs) or board_ids (up to 1 board). Omit all filters to get all account automations. */ + board_automations: AutomationsPage; /** Get board candidates based on workspace and usage type */ board_candidates?: Maybe>; /** Get all dependency predecessors for every item on a board, paginated. Each item includes its predecessor edges with dependency type and lag. */ @@ -11797,6 +12258,8 @@ export type Query = { items_page?: Maybe; /** Search items by multiple columns and values. */ items_page_by_column_values: ItemsResponse; + /** Get the status of an async job by its external ID */ + job_status: AsyncJobStatus; /** Search knowledge base snippets. */ knowledge_base_search?: Maybe; /** Lookup API. Each field looks up a single entity type by name (lexical, name-only). */ @@ -11938,11 +12401,23 @@ export type QueryAccount_Triggers_Statistics_By_Entity_IdArgs = { /** Root query type for the Dependencies service */ -export type QueryAgentArgs = { +export type QueryAgent_Active_TriggersArgs = { + agent_id: Scalars['ID']['input']; +}; + + +/** Root query type for the Dependencies service */ +export type QueryAgent_KnowledgeArgs = { id: Scalars['ID']['input']; }; +/** Root query type for the Dependencies service */ +export type QueryAgent_Triggers_CatalogArgs = { + block_reference_ids?: InputMaybe>; +}; + + /** Root query type for the Dependencies service */ export type QueryAgentsArgs = { ids?: InputMaybe>; @@ -12053,6 +12528,15 @@ export type QueryBlocksArgs = { }; +/** Root query type for the Dependencies service */ +export type QueryBoard_AutomationsArgs = { + board_ids?: InputMaybe>; + cursor?: InputMaybe; + ids?: InputMaybe>; + limit?: InputMaybe; +}; + + /** Root query type for the Dependencies service */ export type QueryBoard_CandidatesArgs = { usageType: BoardUsage; @@ -12416,6 +12900,12 @@ export type QueryItems_Page_By_Column_ValuesArgs = { }; +/** Root query type for the Dependencies service */ +export type QueryJob_StatusArgs = { + job_id: Scalars['ID']['input']; +}; + + /** Root query type for the Dependencies service */ export type QueryKnowledge_Base_SearchArgs = { limit?: InputMaybe; @@ -13095,6 +13585,13 @@ export enum RuleOperator { StartsWithText = 'STARTS_WITH_TEXT' } +/** Confirmation that a manual agent run was accepted and enqueued. This does not reflect the outcome of the run itself — the execution happens asynchronously. In the future, trigger_uuid can be used to query run status via a dedicated endpoint. */ +export type RunAgentResult = { + __typename?: 'RunAgentResult'; + /** Correlation ID for the triggered run. Use this to track or look up the execution in downstream events or future run-status endpoints. */ + trigger_uuid?: Maybe; +}; + /** Result of saving a workflow as a template */ export type SaveWorkflowAsTemplateResult = { __typename?: 'SaveWorkflowAsTemplateResult'; @@ -14492,6 +14989,26 @@ export type TriggerEventsPage = { triggerEvents?: Maybe>; }; +/** Schema description for a trigger field that accepts a structured JSON value */ +export type TriggerFieldSchema = { + __typename?: 'TriggerFieldSchema'; + /** The key to use in field_values when calling add_trigger_to_agent */ + field_key: Scalars['String']['output']; + /** Human-readable description of the expected JSON shape for this field */ + value_schema: Scalars['String']['output']; +}; + +/** A selection field (e.g. board picker) required when adding this trigger */ +export type TriggerRequiredField = { + __typename?: 'TriggerRequiredField'; + /** Field keys that must be provided before this field — resolve them in order */ + depends_on: Array; + /** The key to use in field_values */ + field_key: Scalars['String']['output']; + /** Whether this field can be omitted */ + optional: Scalars['Boolean']['output']; +}; + /** Result of unassigning owners from a department. */ export type UnassignDepartmentOwnerResult = { __typename?: 'UnassignDepartmentOwnerResult'; @@ -14563,6 +15080,20 @@ export type UpdateViewersArgs = { page?: InputMaybe; }; +/** Input for updating an AI agent — all fields are optional; only provided fields are changed */ +export type UpdateAgentInput = { + /** The LLM model the agent should use */ + agent_model?: InputMaybe; + /** The display name of the agent */ + name?: InputMaybe; + /** The execution plan (instructions) for the agent, in markdown format */ + plan?: InputMaybe; + /** The role of the agent */ + role?: InputMaybe; + /** A description of the agent role */ + role_description?: InputMaybe; +}; + /** Result of a single allocation update operation */ export type UpdateAllocationResult = { __typename?: 'UpdateAllocationResult'; @@ -15657,9 +16188,9 @@ export type WebSearchConfigInput = { /** Configuration options for web search functionality */ export type WebSearchOptionsInput = { - /** Limit search results to content from the last N days */ + /** Hint to prioritize content from the last N days. Interpreted as guidance — not a hard filter. */ recencyDays?: InputMaybe; - /** Maximum number of search results to retrieve (default: 5) */ + /** Hint for max number of sources to consider (default: 5). Interpreted as guidance — the model decides retrieval breadth. */ topK?: InputMaybe; }; @@ -16212,6 +16743,116 @@ export type WorldClockValue = ColumnValue & { value?: Maybe; }; +export type GetAgentTriggersCatalogQueryVariables = Exact<{ + block_reference_ids?: InputMaybe | Scalars['ID']['input']>; +}>; + + +export type GetAgentTriggersCatalogQuery = { __typename?: 'Query', agent_triggers_catalog?: Array<{ __typename?: 'AgentTriggerCatalogEntry', block_reference_id: string, name: string, description?: string | null, field_schemas: Array<{ __typename?: 'TriggerFieldSchema', field_key: string, value_schema: string }>, required_fields: Array<{ __typename?: 'TriggerRequiredField', field_key: string, depends_on: Array, optional: boolean }> }> | null }; + +export type GetAgentSkillsCatalogQueryVariables = Exact<{ [key: string]: never; }>; + + +export type GetAgentSkillsCatalogQuery = { __typename?: 'Query', agent_skills_catalog?: Array<{ __typename?: 'AgentSkillCatalogEntry', id?: string | null, name?: string | null, description?: string | null }> | null }; + +export type GetAgentKnowledgeQueryVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type GetAgentKnowledgeQuery = { __typename?: 'Query', agent_knowledge?: { __typename?: 'AgentKnowledge', resources?: Array<{ __typename?: 'AgentKnowledgeResource', resource_id?: string | null, scope_type?: KnowledgeScope | null, permission_type?: KnowledgePermission | null }> | null, files?: Array<{ __typename?: 'AgentKnowledgeFile', id?: string | null, file_name?: string | null, file_type?: string | null }> | null } | null }; + +export type AddAgentResourceAccessMutationVariables = Exact<{ + id: Scalars['ID']['input']; + resource_id: Scalars['ID']['input']; + scope_type: KnowledgeScope; + permission_type: KnowledgePermission; +}>; + + +export type AddAgentResourceAccessMutation = { __typename?: 'Mutation', add_agent_resource_access?: { __typename?: 'MutationResult', success: boolean } | null }; + +export type RemoveAgentResourceAccessMutationVariables = Exact<{ + id: Scalars['ID']['input']; + resource_id: Scalars['ID']['input']; + scope_type: KnowledgeScope; +}>; + + +export type RemoveAgentResourceAccessMutation = { __typename?: 'Mutation', remove_agent_resource_access?: { __typename?: 'MutationResult', success: boolean } | null }; + +export type UpdateAgentResourceAccessMutationVariables = Exact<{ + id: Scalars['ID']['input']; + resource_id: Scalars['ID']['input']; + scope_type: KnowledgeScope; + permission_type: KnowledgePermission; +}>; + + +export type UpdateAgentResourceAccessMutation = { __typename?: 'Mutation', update_agent_resource_access?: { __typename?: 'MutationResult', success: boolean } | null }; + +export type AddSkillToAgentMutationVariables = Exact<{ + agent_id: Scalars['ID']['input']; + skill_id: Scalars['ID']['input']; +}>; + + +export type AddSkillToAgentMutation = { __typename?: 'Mutation', add_skill_to_agent?: { __typename?: 'MutationResult', success: boolean } | null }; + +export type RemoveSkillFromAgentMutationVariables = Exact<{ + agent_id: Scalars['ID']['input']; + skill_id: Scalars['ID']['input']; +}>; + + +export type RemoveSkillFromAgentMutation = { __typename?: 'Mutation', remove_skill_from_agent?: { __typename?: 'MutationResult', success: boolean } | null }; + +export type ActivateAgentMutationVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type ActivateAgentMutation = { __typename?: 'Mutation', activate_agent?: { __typename?: 'AgentStateResult', success?: boolean | null } | null }; + +export type DeactivateAgentMutationVariables = Exact<{ + id: Scalars['ID']['input']; + inactive_reason?: InputMaybe; +}>; + + +export type DeactivateAgentMutation = { __typename?: 'Mutation', deactivate_agent?: { __typename?: 'AgentStateResult', success?: boolean | null } | null }; + +export type RunAgentMutationVariables = Exact<{ + id: Scalars['ID']['input']; +}>; + + +export type RunAgentMutation = { __typename?: 'Mutation', run_agent?: { __typename?: 'RunAgentResult', trigger_uuid?: string | null } | null }; + +export type GetAgentActiveTriggersQueryVariables = Exact<{ + agent_id: Scalars['ID']['input']; +}>; + + +export type GetAgentActiveTriggersQuery = { __typename?: 'Query', agent_active_triggers?: Array<{ __typename?: 'AgentActiveTrigger', node_id: string, block_reference_id: string, name: string, description?: string | null, field_summary?: string | null }> | null }; + +export type AddTriggerToAgentMutationVariables = Exact<{ + agent_id: Scalars['ID']['input']; + block_reference_id: Scalars['ID']['input']; + field_values?: InputMaybe; +}>; + + +export type AddTriggerToAgentMutation = { __typename?: 'Mutation', add_trigger_to_agent?: { __typename?: 'MutationResult', success: boolean } | null }; + +export type RemoveTriggerFromAgentMutationVariables = Exact<{ + agent_id: Scalars['ID']['input']; + node_id: Scalars['ID']['input']; +}>; + + +export type RemoveTriggerFromAgentMutation = { __typename?: 'Mutation', remove_trigger_from_agent?: { __typename?: 'MutationResult', success: boolean } | null }; + export type AgentFieldsFragment = { __typename?: 'Agent', id: string, kind?: AgentKind | null, state?: AgentState | null, goal?: string | null, plan?: string | null, user_prompt?: string | null, version_id: string, created_at?: any | null, updated_at?: any | null, profile?: { __typename?: 'AgentProfile', name?: string | null, role?: string | null, role_description?: string | null, avatar_url?: string | null, background_color?: string | null } | null }; export type GetAgentsQueryVariables = Exact<{ @@ -16243,6 +16884,14 @@ export type DeleteAgentMutationVariables = Exact<{ export type DeleteAgentMutation = { __typename?: 'Mutation', delete_agent?: { __typename?: 'Agent', id: string, kind?: AgentKind | null, state?: AgentState | null, goal?: string | null, plan?: string | null, user_prompt?: string | null, version_id: string, created_at?: any | null, updated_at?: any | null, profile?: { __typename?: 'AgentProfile', name?: string | null, role?: string | null, role_description?: string | null, avatar_url?: string | null, background_color?: string | null } | null } | null }; +export type UpdateAgentMutationVariables = Exact<{ + id: Scalars['ID']['input']; + input: UpdateAgentInput; +}>; + + +export type UpdateAgentMutation = { __typename?: 'Mutation', update_agent?: { __typename?: 'Agent', id: string, kind?: AgentKind | null, state?: AgentState | null, goal?: string | null, plan?: string | null, user_prompt?: string | null, version_id: string, created_at?: any | null, updated_at?: any | null, profile?: { __typename?: 'AgentProfile', name?: string | null, role?: string | null, role_description?: string | null, avatar_url?: string | null, background_color?: string | null } | null } | null }; + export type DeleteObjectSchemaColumnsMutationVariables = Exact<{ objectSchemaId?: InputMaybe; objectSchemaName?: InputMaybe; @@ -16304,10 +16953,25 @@ export type CreateFormSubmissionMutationVariables = Exact<{ export type CreateFormSubmissionMutation = { __typename?: 'Mutation', create_form_submission?: { __typename?: 'FormSubmissionResult', id: string } | null }; export const AgentFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; +export const GetAgentTriggersCatalogDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentTriggersCatalog"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"block_reference_ids"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_triggers_catalog"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"block_reference_ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"block_reference_ids"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"block_reference_id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"field_schemas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field_key"}},{"kind":"Field","name":{"kind":"Name","value":"value_schema"}}]}},{"kind":"Field","name":{"kind":"Name","value":"required_fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field_key"}},{"kind":"Field","name":{"kind":"Name","value":"depends_on"}},{"kind":"Field","name":{"kind":"Name","value":"optional"}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetAgentSkillsCatalogDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentSkillsCatalog"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_skills_catalog"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode; +export const GetAgentKnowledgeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentKnowledge"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_knowledge"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resource_id"}},{"kind":"Field","name":{"kind":"Name","value":"scope_type"}},{"kind":"Field","name":{"kind":"Name","value":"permission_type"}}]}},{"kind":"Field","name":{"kind":"Name","value":"files"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"file_name"}},{"kind":"Field","name":{"kind":"Name","value":"file_type"}}]}}]}}]}}]} as unknown as DocumentNode; +export const AddAgentResourceAccessDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"addAgentResourceAccess"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resource_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"scope_type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KnowledgeScope"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"permission_type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KnowledgePermission"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"add_agent_resource_access"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"resource_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resource_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"scope_type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"scope_type"}}},{"kind":"Argument","name":{"kind":"Name","value":"permission_type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"permission_type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const RemoveAgentResourceAccessDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"removeAgentResourceAccess"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resource_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"scope_type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KnowledgeScope"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"remove_agent_resource_access"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"resource_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resource_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"scope_type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"scope_type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const UpdateAgentResourceAccessDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"updateAgentResourceAccess"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"resource_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"scope_type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KnowledgeScope"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"permission_type"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"KnowledgePermission"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update_agent_resource_access"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"resource_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"resource_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"scope_type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"scope_type"}}},{"kind":"Argument","name":{"kind":"Name","value":"permission_type"},"value":{"kind":"Variable","name":{"kind":"Name","value":"permission_type"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const AddSkillToAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"addSkillToAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skill_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"add_skill_to_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agent_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"skill_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skill_id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const RemoveSkillFromAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"removeSkillFromAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"skill_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"remove_skill_from_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agent_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"skill_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"skill_id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const ActivateAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"activateAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"activate_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const DeactivateAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"deactivateAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"inactive_reason"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"InactiveReason"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"deactivate_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"inactive_reason"},"value":{"kind":"Variable","name":{"kind":"Name","value":"inactive_reason"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const RunAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"runAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"run_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"trigger_uuid"}}]}}]}}]} as unknown as DocumentNode; +export const GetAgentActiveTriggersDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentActiveTriggers"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_active_triggers"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agent_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node_id"}},{"kind":"Field","name":{"kind":"Name","value":"block_reference_id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"field_summary"}}]}}]}}]} as unknown as DocumentNode; +export const AddTriggerToAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"addTriggerToAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"block_reference_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"field_values"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"JSON"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"add_trigger_to_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agent_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"block_reference_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"block_reference_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"field_values"},"value":{"kind":"Variable","name":{"kind":"Name","value":"field_values"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; +export const RemoveTriggerFromAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"removeTriggerFromAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"node_id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"remove_trigger_from_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agent_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agent_id"}}},{"kind":"Argument","name":{"kind":"Name","value":"node_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"node_id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"success"}}]}}]}}]} as unknown as DocumentNode; export const GetAgentsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgents"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"ids"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agents"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"ids"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AgentFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; export const CreateAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"createAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateAgentInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AgentFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; export const CreateBlankAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"createBlankAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"CreateBlankAgentInput"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create_blank_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AgentFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; export const DeleteAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"deleteAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"delete_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AgentFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; +export const UpdateAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"updateAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"input"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UpdateAgentInput"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"update_agent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}},{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"Variable","name":{"kind":"Name","value":"input"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AgentFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; export const DeleteObjectSchemaColumnsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"DeleteObjectSchemaColumns"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectSchemaId"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"objectSchemaName"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"columnIds"}},"type":{"kind":"NonNullType","type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"delete_object_schema_columns"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"object_schema_id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectSchemaId"}}},{"kind":"Argument","name":{"kind":"Name","value":"object_schema_name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"objectSchemaName"}}},{"kind":"Argument","name":{"kind":"Name","value":"column_ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"columnIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"parent_id"}},{"kind":"Field","name":{"kind":"Name","value":"revision"}}]}}]}}]} as unknown as DocumentNode; export const SearchItemsDevDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchItemsDev"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"boardIds"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"search"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"items"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"board_ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"boardIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"results"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}}]}}]}}]}}]}}]} as unknown as DocumentNode; export const SearchBoardsDevDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"SearchBoardsDev"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"query"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"limit"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"Int"}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"workspaceIds"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"search"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"boards"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"query"},"value":{"kind":"Variable","name":{"kind":"Name","value":"query"}}},{"kind":"Argument","name":{"kind":"Name","value":"limit"},"value":{"kind":"Variable","name":{"kind":"Name","value":"limit"}}},{"kind":"Argument","name":{"kind":"Name","value":"workspace_ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"workspaceIds"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"results"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"indexed_data"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"url"}}]}}]}}]}}]}}]}}]} as unknown as DocumentNode; diff --git a/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql b/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql index 1dceb835..2a6e5696 100644 --- a/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql +++ b/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql @@ -363,6 +363,12 @@ limit: Int = 5): KnowledgeBaseAnswer favorites: [GraphqlHierarchyObjectItem!] "Intelligence data." intelligence: Intelligence + "Get board automations. Filter by ids (specific automation IDs) or board_ids (up to 1 board). Omit all filters to get all account automations." + board_automations( "Automation IDs to fetch (max 100)" +ids: [ID!], "Board IDs to filter by (max 1)" +board_ids: [ID!], "Max number of automations to return" +limit: Int, "Cursor from a previous page for pagination" +cursor: String): AutomationsPage! marketplace_app_discounts( "The id of an app" app_id: ID!): [MarketplaceAppDiscount!]! app_subscriptions( "The ID of an app" @@ -388,13 +394,21 @@ import_id: ID!): BulkImportStatus! "Get the status of a backfill or ingest job" fetch_job_status( "The ID of the job to get status for" job_id: ID!): JobStatus! - "Get an agent by its ID. Returns null if the agent does not exist or the user does not have access." - agent( "The unique identifier of the agent" -id: ID!): Agent "List personal agents for the authenticated user. At least one filter (ids or limit) is required." agents( "Optional list of agent IDs to fetch. Applied before limit when both are provided." ids: [ID!], "Optional max number of agents to return. Applied after ids filter when both are provided." limit: Int): [Agent!] + "Returns trigger types that can be attached to an agent via add_trigger_to_agent. Pass block_reference_ids to fetch only specific entries (much faster). Only includes auto-addable triggers — 3rd-party triggers requiring OAuth or credentials are excluded." + agent_triggers_catalog( "Optional list of block_reference_id values to fetch. When omitted, all catalog entries are returned." +block_reference_ids: [ID!]): [AgentTriggerCatalogEntry!] + "Returns the triggers currently attached to an agent. Use node_id from each result to remove a trigger." + agent_active_triggers( "Unique identifier of the agent" +agent_id: ID!): [AgentActiveTrigger!] + "Returns the knowledge configuration of an agent — boards/docs it has access to and uploaded files. Board and doc names are not included; use the board/doc subgraph queries to resolve them." + agent_knowledge( "Unique identifier of the agent" +id: ID!): AgentKnowledge + "List all skills available to attach to an agent. Use the returned id to call add_skill_to_agent." + agent_skills_catalog: [AgentSkillCatalogEntry!] "Get an app by ID or slug." app( "The ID or slug of the app" id: ID!): AppType @@ -635,6 +649,9 @@ board_id: ID!): [Sequence!] "Get a collection of monday dev sprints" sprints( "A list of monday dev sprints unique identifiers" ids: [ID!]!): [Sprint!] + "Get the status of an async job by its external ID" + job_status( "The job ID returned by the originating mutation" +job_id: ID!): AsyncJobStatus! "Get the changelog of decisions that were made for a task by the My Tasks agent." get_task_changelog( "The task (item) ID to fetch the changelog of decisions for" task_id: ID!): [TaskDecisionChangelogEvent!] @@ -1288,8 +1305,8 @@ export_options: ExportOptionsInput, """ Time zone for date formatting (e.g. "America/New_York") """ time_zone: String, "Column IDs in desired display order" -columns_order: [String!], "Output format (defaults to XLSX)" -export_format: ExportFormat): ExportBoardResult +columns_order: [String!], "Output format (defaults to CSV)" +export_format: ExportFormat = CSV): ExportBoardResult "Add workspace object to favorites" create_favorite( "The input for adding an object to the favorites" input: CreateFavoriteInput!): CreateFavoriteResultType @@ -1299,6 +1316,13 @@ input: DeleteFavoriteInput!): DeleteFavoriteInputResultType "Update the position of an object in favorites" update_favorite_position( "The input for updating the favorite object position" input: UpdateObjectHierarchyPositionInput!): UpdateFavoriteResultType + "Delete a board automation by ID." + delete_board_automation( "The ID of the automation to delete" +id: ID!, "The board ID the automation belongs to" +board_id: ID!): BoardAutomationDeleteResult! + "Create a board automation. Provide template_reference_id to create from a template, or workflow_blocks and workflow_variables for a direct creation." + create_board_automation( "Automation creation input" +input: BoardAutomationCreateInput!): BoardAutomationCreateResult! "Create a marketplace app discount" create_marketplace_app_discount( "The id of an app" app_id: ID!, "Slug of an account" @@ -1343,6 +1367,56 @@ input: CreateBlankAgentInput): Agent "Delete an AI agent by its ID" delete_agent( "The unique identifier of the agent to delete" id: ID!): Agent + "Trigger a manual run for an existing agent. This is an async fire-and-forget operation — a successful response means the run was accepted and enqueued, not that it has completed or succeeded. Use trigger_uuid to correlate the execution in downstream events or future status endpoints." + run_agent( "Unique identifier of the agent to run" +id: ID!): RunAgentResult + "Activate an existing agent" + activate_agent( "Unique identifier of the agent to activate" +id: ID!): AgentStateResult + "Deactivate an existing agent" + deactivate_agent( "Unique identifier of the agent to deactivate" +id: ID!, "The reason for deactivating the agent. Defaults to DEACTIVATED_BY_USER." +inactive_reason: InactiveReason): AgentStateResult + "Update an agent — creates a new draft if needed, applies the changes, and publishes to live in one call" + update_agent( "Unique identifier of the agent to update" +id: ID!, "Fields to update — only provided fields are changed" +input: UpdateAgentInput!): Agent + "Adds a trigger to an agent. Creates a draft if needed, applies the change, and promotes to live in one call. Returns { success: true } on success. Use agent_active_triggers to read the updated trigger list. Get available trigger types and field schemas from agent_triggers_catalog." + add_trigger_to_agent( "Unique identifier of the agent" +agent_id: ID!, "The block_reference_id from agent_triggers_catalog identifying the trigger type" +block_reference_id: ID!, """ + Configuration values for the trigger. Shape depends on the trigger type — see field_schemas and required_fields in agent_triggers_catalog. For scheduler fields: pass the structured config object directly. For selection fields (e.g. board picker): pass { value: , label: "" }. + """ +field_values: JSON): MutationResult + "Removes a trigger from an agent by its node_id. Creates a draft if needed, applies the change, and promotes to live in one call. Returns { success: true } on success. Use agent_active_triggers to verify the trigger is gone. Get node_id values from the agent_active_triggers query." + remove_trigger_from_agent( "Unique identifier of the agent" +agent_id: ID!, "The node_id of the trigger to remove — from agent_active_triggers" +node_id: ID!): MutationResult + "Grant an agent access to a monday.com board or doc. Creates a draft version, applies the change, and promotes to live." + add_agent_resource_access( "Unique identifier of the agent" +id: ID!, "The ID of the board or doc to add" +resource_id: ID!, "Whether the resource is a board or a doc" +scope_type: KnowledgeScope!, "The permission level to grant the agent on this resource" +permission_type: KnowledgePermission!): MutationResult + "Remove a board or doc from an agent. Creates a draft, removes the access, and promotes to live." + remove_agent_resource_access( "Unique identifier of the agent" +id: ID!, "The ID of the board or doc to remove" +resource_id: ID!, "Whether the resource is a board or a doc" +scope_type: KnowledgeScope!): MutationResult + "Change the permission level an agent has on an existing board or doc. Creates a draft, updates the permission, and promotes to live." + update_agent_resource_access( "Unique identifier of the agent" +id: ID!, "The ID of the board or doc to update" +resource_id: ID!, "Whether the resource is a board or a doc" +scope_type: KnowledgeScope!, "The new permission level to grant the agent" +permission_type: KnowledgePermission!): MutationResult + "Attach a skill to an agent by its catalog id. Use agent_skills_catalog to discover available ids." + add_skill_to_agent( "Unique identifier of the agent" +agent_id: ID!, "Skill reference id from agent_skills_catalog" +skill_id: ID!): MutationResult + "Detach a skill from an agent by its catalog id." + remove_skill_from_agent( "Unique identifier of the agent" +agent_id: ID!, "Skill reference id to detach" +skill_id: ID!): MutationResult "Creates a new app with the specified configuration." create_app( "App configuration data" input: CreateAppInput!): CreateAppResponse @@ -1382,6 +1456,10 @@ input: InstallAppInput!): InstallAppResponse "Uninstalls an app from the current account. Requires account admin permission." uninstall_app( "The app identifier (numeric ID or slug)" app_identifier: ID!): AppDeletionResponse + "Promotes the latest draft app version of an app to live. Promotion is asynchronous — poll the returned version's status field (via the app query) until it transitions to LIVE. Only app collaborators can perform this action." + promote_app( "The identifier of the app whose draft version should be promoted" +app_id: ID!, "Optional: the specific app version to promote. Defaults to the latest draft version" +app_version_id: ID): DeveloperAppVersion "Add a file to a column value." add_file_to_column( "The column to add the file to." column_id: String!, "The file to upload." @@ -2151,9 +2229,9 @@ input WebSearchConfigInput { "Configuration options for web search functionality" input WebSearchOptionsInput { - "Maximum number of search results to retrieve (default: 5)" + "Hint for max number of sources to consider (default: 5). Interpreted as guidance — the model decides retrieval breadth." topK: Int - "Limit search results to content from the last N days" + "Hint to prioritize content from the last N days. Interpreted as guidance — not a hard filter." recencyDays: Int } @@ -2167,6 +2245,8 @@ enum AssetHolder { WORKSPACE "An account entity." ACCOUNT + "A vibe application entity." + VIBE_APP } "The result of a completed file upload, representing the created asset." @@ -2596,14 +2676,10 @@ interface FieldType { has_remote_options: Boolean } -"Implementation of a field type" +"An interface (app feature) that a field type implements" type FieldTypeImplementation { - "Unique identifier for the implementation" - id: Int - "Unique key of the app feature" - uniqueKey: String - "Name of the implementation" - name: String + "Reference id of the app feature interface this field type implements" + app_feature_reference_id: ID } "The type of relation between a field and its type" @@ -2739,6 +2815,8 @@ type Option { value: JSON "The display title of the option" title: String + "Optional icon to display alongside the option (e.g. { vibe, tooltip })" + icon: JSON } "Interface for output field configuration" @@ -3520,6 +3598,10 @@ cursor: String): UpdatesPage ids: [String], "A list of column types." types: [ColumnType!], "A list of column capabilities to filter by. Returns columns that have any of the specified capabilities. Use null in the array to represent columns with no capabilities (e.g., [null] for only columns without capabilities, [null, CALCULATED] for columns without capabilities or with calculated)." capabilities: [ColumnCapability]): [Column] + "Automations for this board" + automations( "Max number of automations to return" +limit: Int, "Cursor from a previous page for pagination" +cursor: String): AutomationsPage! "The user's permission level for this board (view / edit)." access_level: BoardAccessLevel! "The board log events." @@ -6194,6 +6276,8 @@ input ExportOptionsInput { header_row: HeaderFormat "Behavior for columns with no codec support in CSV exports. Ignored for other formats." non_importable_columns: NonImportableColumns = INCLUDE + "Include item_id (and parent_item_id when subitems are enabled) columns at the end of CSV exports." + include_item_identifiers: Boolean = false } "CSV header row format." @@ -6470,6 +6554,74 @@ type UserContextResponse { account: AccountContext } +"A page of automations with cursor for pagination" +type AutomationsPage { + "Opaque cursor for fetching the next page. Null if no more results." + cursor: String + "The automations in this page" + items: [BoardAutomation!] +} + +"A board automation" +type BoardAutomation { + "Automation ID" + id: ID + "Creator user ID" + user_id: ID + "Whether the automation is active" + active: Boolean + "Automation title" + title: String + "Automation description" + description: String + "Creation timestamp" + created_at: String + "Last update timestamp" + updated_at: String + "Host data (board ID and type)" + workflow_host_data: JSON + "Workflow block definitions" + workflow_blocks: JSON + "Workflow variable definitions" + workflow_variables: JSON + "Automation importance level" + importance: Int + "Notice message for the automation" + notice_message: String + "Template reference ID if created from template" + template_reference_id: ID +} + +"Input for creating a board automation. Provide template_reference_id to create from a template, or workflow_blocks and workflow_variables for a direct creation." +input BoardAutomationCreateInput { + "Board ID to host the automation" + board_id: String! + "Automation title" + title: String! + "Automation description" + description: String + "Template reference ID (for template-based creation)" + template_reference_id: ID + "Automation block definitions (for direct creation)" + workflow_blocks: JSON + "Automation variable definitions (for direct creation)" + workflow_variables: JSON + "Template variable values (for template-based creation)" + workflow_variables_values: JSON +} + +"Result of creating a board automation" +type BoardAutomationCreateResult { + "The ID of the created automation" + workflow_id: ID +} + +"Result of deleting a board automation" +type BoardAutomationDeleteResult { + "Whether the deletion was successful" + is_success: Boolean +} + "Subscription object" type AppSubscriptionDetails { "The ID of an account" @@ -6874,16 +7026,38 @@ type Agent { goal: String "The execution plan in markdown format, describing the agent capabilities and operating principles" plan: String + "The LLM model the agent uses" + agent_model: AgentModel + "Reference IDs of skills attached to this agent. Use agent_skills_catalog to resolve full name and description." + skill_ids: [ID!]! "The original user prompt used to create the agent" user_prompt: String "The current configuration version of the agent. Increments on each update." version_id: ID! + "Knowledge files attached to the agent. Only populated on create mutation responses." + knowledge: [AgentKnowledgeEntry!] "The timestamp when the agent was created. Null on create mutation responses — use the agent query to fetch it." created_at: Date "The timestamp when the agent was last updated. Null on create mutation responses — use the agent query to fetch it." updated_at: Date } +"A trigger currently attached to an agent" +type AgentActiveTrigger { + "Stable identifier of this trigger instance — use this as node_id when calling remove_trigger_from_agent" + node_id: ID! + "The trigger type, matching block_reference_id in the catalog" + block_reference_id: ID! + "Display name of the trigger type" + name: String! + "Description of the trigger type" + description: String + """ + Human-readable summary of how this trigger is configured (e.g. "type=Weekly, hour=9, days=3/4") + """ + field_summary: String +} + "The kind of AI agent" enum AgentKind { "A personal agent owned by a specific user" @@ -6894,6 +7068,70 @@ enum AgentKind { EXTERNAL } +"The full knowledge configuration of an agent — resources (boards/docs) and uploaded files" +type AgentKnowledge { + "Boards and docs the agent has access to" + resources: [AgentKnowledgeResource!] + "Files uploaded as agent knowledge" + files: [AgentKnowledgeFile!] +} + +"A knowledge entry attached to an agent" +type AgentKnowledgeEntry { + "The unique identifier of the knowledge entry" + id: ID! + "File metadata for this knowledge entry" + metadata: AgentKnowledgeMetadata + "The source type of this knowledge entry" + source_type: KnowledgeSource + "The current state of this knowledge entry" + state: KnowledgeState + "Reference ID for the knowledge entry" + knowledge_reference_id: ID +} + +"A file uploaded as agent knowledge" +type AgentKnowledgeFile { + "Unique identifier of the knowledge file" + id: ID + "Original file name" + file_name: String + "File extension (e.g. pdf, docx, csv)" + file_type: String +} + +"Metadata about a knowledge file attachment" +type AgentKnowledgeMetadata { + "Original name of the uploaded file" + file_name: String + "MIME type of the file" + file_type: String + "Cloudinary asset ID for image files" + asset_id: ID +} + +"A monday.com board or doc the agent has been granted access to" +type AgentKnowledgeResource { + "The ID of the board or doc" + resource_id: ID + "Whether this resource is a board or a doc" + scope_type: KnowledgeScope + "The permission level the agent has on this resource" + permission_type: KnowledgePermission +} + +"Supported LLM models for an agent" +enum AgentModel { + "Claude Sonnet 4.6 (claude-sonnet-4-6)" + CLAUDE_SONNET_4_6 + "Claude Opus 4.7 (claude-opus-4-7)" + CLAUDE_OPUS_4_7 + "GPT 5.2" + GPT_5_2 + "Gemini 2.5 Flash" + GEMINI_2_5_FLASH +} + "Visual and role identity of an agent." type AgentProfile { "The display name of the agent" @@ -6908,6 +7146,16 @@ type AgentProfile { background_color: String } +"A skill available for agents to use — browse the catalog, then attach by id." +type AgentSkillCatalogEntry { + "Stable reference ID — pass this to add_skill_to_agent / remove_skill_from_agent" + id: ID + "Display name of the skill" + name: String + "What this skill does" + description: String +} + "The current state of an agent" enum AgentState { "The agent is active and can be triggered and executed" @@ -6922,12 +7170,34 @@ enum AgentState { FAILED } +"Result of an agent state change operation" +type AgentStateResult { + "Whether the operation succeeded" + success: Boolean +} + +"An available trigger type that can be attached to an agent" +type AgentTriggerCatalogEntry { + "Pass this value as block_reference_id when calling add_trigger_to_agent" + block_reference_id: ID! + "Display name of the trigger" + name: String! + "What this trigger does" + description: String + "Structured value schemas for fields you can populate directly in field_values" + field_schemas: [TriggerFieldSchema!]! + "Selection fields (e.g. board picker) that must be provided in field_values as { value, label } pairs" + required_fields: [TriggerRequiredField!]! +} + "Input for creating an AI agent from a prompt — AI generates the profile from the prompt" input CreateAgentInput { "A description of what the agent should do — used to generate profile, goal, and plan via AI" prompt: String! "The LLM model the agent should use" agent_model: String + "IDs of previously uploaded pending files to attach as knowledge during creation" + pending_file_ids: [ID!] } "Input for creating a blank AI agent without AI generation" @@ -6948,6 +7218,90 @@ input CreateBlankAgentInput { user_prompt: String } +"The reason an agent is inactive" +enum InactiveReason { + "The agent was deactivated due to an account-level block" + ACCOUNT_LEVEL_BLOCKING + "The agent was manually deactivated by a user" + DEACTIVATED_BY_USER +} + +"The permission level the agent has on a resource" +enum KnowledgePermission { + "Agent can read the resource" + READ + "Agent can read and write the resource" + READ_WRITE +} + +"The type of monday.com resource granted to an agent" +enum KnowledgeScope { + "A monday.com board" + BOARD + "A monday.com doc" + DOC +} + +"The source type of a knowledge entry" +enum KnowledgeSource { + "Knowledge sourced from an uploaded file" + FILE +} + +"The state of a knowledge entry" +enum KnowledgeState { + "Knowledge is active and available for retrieval" + ACTIVE + "Knowledge is being processed" + PENDING + "Knowledge has been deleted" + DELETED +} + +"Result of a write operation that does not need to return entity data." +type MutationResult { + "Whether the operation succeeded" + success: Boolean! +} + +"Confirmation that a manual agent run was accepted and enqueued. This does not reflect the outcome of the run itself — the execution happens asynchronously. In the future, trigger_uuid can be used to query run status via a dedicated endpoint." +type RunAgentResult { + "Correlation ID for the triggered run. Use this to track or look up the execution in downstream events or future run-status endpoints." + trigger_uuid: String +} + +"Schema description for a trigger field that accepts a structured JSON value" +type TriggerFieldSchema { + "The key to use in field_values when calling add_trigger_to_agent" + field_key: String! + "Human-readable description of the expected JSON shape for this field" + value_schema: String! +} + +"A selection field (e.g. board picker) required when adding this trigger" +type TriggerRequiredField { + "The key to use in field_values" + field_key: String! + "Field keys that must be provided before this field — resolve them in order" + depends_on: [String!]! + "Whether this field can be omitted" + optional: Boolean! +} + +"Input for updating an AI agent — all fields are optional; only provided fields are changed" +input UpdateAgentInput { + "The display name of the agent" + name: String + "The role of the agent" + role: String + "A description of the agent role" + role_description: String + "The execution plan (instructions) for the agent, in markdown format" + plan: String + "The LLM model the agent should use" + agent_model: AgentModel +} + "Response object for app deletion operations" type AppDeletionResponse { "Whether the deletion was successful" @@ -7202,6 +7556,8 @@ type AppType { photo_url_small: String "The app kind" kind: AppKind + "All versions of this app with their current status. Use this to poll promotion progress." + versions: [DeveloperAppVersion!] "The app status (i.e. is live?)" status: AppStatus "The latest version type" @@ -7227,6 +7583,18 @@ limit: Int = 25, "Page number to get, starting at 1." page: Int = 1): [AppFeatureType!] } +"The lifecycle status of an app version" +enum AppVersionStatus { + "Version is in development and not yet live" + DRAFT + "Version is live and available to users" + LIVE + "Version has been superseded by a newer version" + DEPRECATED + "Version is in the process of being promoted" + PROMOTING +} + "Input for creating an app with its configuration data." input CreateAppInput { "The display name of the app" @@ -7261,6 +7629,14 @@ type CreateAppResponse { signing_secret: String } +"An app version" +type DeveloperAppVersion { + "The unique identifier of the app version" + id: ID + "The current lifecycle status of this app version" + status: AppVersionStatus +} + "Input for installing an app on the current account." input InstallAppInput { "The app identifier (numeric ID or slug)" @@ -12166,6 +12542,50 @@ type SprintTimeline { to: Date } +"Structured result data for a completed or partially-completed operation" +type AsyncJobResult { + "Total items in the operation" + total: Int + "Successfully processed items" + succeeded: Int + "Items that failed" + failed: Int + "Operation-specific details (failed item IDs, report URLs, etc.)" + details: JSON +} + +"Status information for an async job" +type AsyncJobStatus { + "Unique job identifier" + id: ID + "Current job status" + status: JobState + "When the job was created (ISO 8601)" + created_at: String + "When the job was last updated (ISO 8601)" + updated_at: String + "Error description if the job failed" + error: String + "Structured result data for completed or partially-completed operations" + result: AsyncJobResult +} + +"Status of an async job" +enum JobState { + "Job is queued but not yet started" + PENDING + "Job is actively executing" + RUNNING + "Job completed successfully" + COMPLETED + "Job failed" + FAILED + "Job expired before completion" + EXPIRED + "Job was cancelled" + CANCELLED +} + "A single column value change within a task decision" type ColumnChange { "The identifier of the column that changed" From b924a9b0a4b4fc3128f6e33f506eea3c025f01bf Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 17:57:39 +0300 Subject: [PATCH 06/28] feat(agent-toolkit): add get_agent_catalog tool Implements the get_agent_catalog READ tool that fetches the account-wide catalog of available trigger types or skills for monday platform agents via the dev API version. Co-Authored-By: Claude Sonnet 4.6 --- .../get-agent-catalog-tool.test.ts | 108 ++++++++++++++++++ .../get-agent-catalog-tool.ts | 100 ++++++++++++++++ .../platform-api-tools/agents-tools/index.ts | 1 + .../core/tools/platform-api-tools/index.ts | 2 + 4 files changed, 211 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts new file mode 100644 index 00000000..ca8f6351 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts @@ -0,0 +1,108 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { GetAgentTriggersCatalogQuery, GetAgentSkillsCatalogQuery } from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('GetAgentCatalogTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockTrigger = { + block_reference_id: 'status-change-ref', + name: 'Status Change', + description: 'Fires when a status column changes', + field_schemas: [{ field_key: 'board_id', value_schema: 'The ID of the board to watch' }], + required_fields: [{ field_key: 'board_id', depends_on: [], optional: false }], + }; + + const mockSkill = { + id: 'skill-1', + name: 'Board Manager', + description: 'Manages boards and items', + }; + + it('should return triggers catalog when type is triggers', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [mockTrigger] } as GetAgentTriggersCatalogQuery); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(1); + expect(parsed.triggers[0].block_reference_id).toBe('status-change-ref'); + }); + + it('should pass versionOverride dev when fetching triggers', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [] } as GetAgentTriggersCatalogQuery); + + await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentTriggersCatalog'), + expect.objectContaining({ block_reference_ids: undefined }), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should pass block_reference_ids when provided', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [mockTrigger] } as GetAgentTriggersCatalogQuery); + + await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers', block_reference_ids: ['status-change-ref'] }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + { block_reference_ids: ['status-change-ref'] }, + expect.anything(), + ); + }); + + it('should return skills catalog when type is skills', async () => { + mocks.setResponseOnce({ agent_skills_catalog: [mockSkill] } as GetAgentSkillsCatalogQuery); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(1); + expect(parsed.skills[0].id).toBe('skill-1'); + }); + + it('should pass versionOverride dev when fetching skills', async () => { + mocks.setResponseOnce({ agent_skills_catalog: [] } as GetAgentSkillsCatalogQuery); + + await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentSkillsCatalog'), + expect.anything(), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should return empty list with count 0 when no triggers exist', async () => { + mocks.setResponseOnce({ agent_triggers_catalog: [] } as GetAgentTriggersCatalogQuery); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(0); + expect(parsed.triggers).toEqual([]); + }); + + it('should propagate errors when fetching triggers catalog', async () => { + mocks.setError('Unauthorized'); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); + + expect(result.content[0].text).toContain('Failed to fetch monday platform agent triggers catalog'); + }); + + it('should propagate errors when fetching skills catalog', async () => { + mocks.setError('Unauthorized'); + + const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); + + expect(result.content[0].text).toContain('Failed to fetch monday platform agent skills catalog'); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts new file mode 100644 index 00000000..b18aba49 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts @@ -0,0 +1,100 @@ +import { z } from 'zod'; +import { + GetAgentTriggersCatalogQuery, + GetAgentTriggersCatalogQueryVariables, + GetAgentSkillsCatalogQuery, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { getAgentTriggersCatalogQuery, getAgentSkillsCatalogQuery } from './get-agent-catalog.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const getAgentCatalogToolSchema = { + type: z + .enum(['triggers', 'skills']) + .describe( + 'Which catalog to fetch. "triggers" returns available trigger types with block_reference_id, field_schemas, and required_fields — use before calling manage_agent_triggers with action:add. "skills" returns available skills with id — use before calling manage_agent_skills.', + ), + block_reference_ids: z + .array(z.string()) + .optional() + .describe( + 'Only applies when type is "triggers". Fetch specific entries by block_reference_id instead of the full catalog. Omit to return all trigger types.', + ), +}; + +export class GetAgentCatalogTool extends BaseMondayApiTool { + name = 'get_agent_catalog'; + type = ToolType.READ; + annotations = createMondayApiAnnotations({ + title: 'Get monday Platform Agent Catalog', + readOnlyHint: true, + destructiveHint: false, + idempotentHint: true, + }); + + getDescription(): string { + return `Fetch the account-wide catalog of available trigger types or skills for monday platform agents. + +ALWAYS call this tool first before adding a trigger or skill to an agent: +- type:"triggers" — returns entries with block_reference_id (required for manage_agent_triggers action:add), name, description, field_schemas (describes the field_values shape to pass when adding — e.g. { board_id: "" }), and required_fields (fields the user must supply before you can call add). +- type:"skills" — returns entries with id (required for manage_agent_skills), name, description. + +Never guess or invent a block_reference_id or skill id — always look them up here first. + +USAGE EXAMPLES: +- List all trigger types: { "type": "triggers" } +- Fetch a specific trigger type: { "type": "triggers", "block_reference_ids": ["some-block-ref-id"] } +- List all skills: { "type": "skills" }`; + } + + getInputSchema() { + return getAgentCatalogToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.type === 'triggers') { + try { + const variables: GetAgentTriggersCatalogQueryVariables = { + block_reference_ids: input.block_reference_ids ?? undefined, + }; + const res = await this.mondayApi.request( + getAgentTriggersCatalogQuery, + variables, + { versionOverride: 'dev' }, + ); + const catalog = res.agent_triggers_catalog ?? []; + return { + content: { + message: + 'Available trigger types for monday platform agents. Use block_reference_id and inspect field_schemas/required_fields before calling manage_agent_triggers with action:add.', + count: catalog.length, + triggers: catalog, + }, + }; + } catch (error) { + rethrowWithContext(error, 'fetch monday platform agent triggers catalog'); + } + } + + try { + const res = await this.mondayApi.request( + getAgentSkillsCatalogQuery, + {}, + { versionOverride: 'dev' }, + ); + const catalog = res.agent_skills_catalog ?? []; + return { + content: { + message: 'Available skills for monday platform agents. Use id when calling manage_agent_skills.', + count: catalog.length, + skills: catalog, + }, + }; + } catch (error) { + rethrowWithContext(error, 'fetch monday platform agent skills catalog'); + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index b07de30b..8893f78d 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -1,3 +1,4 @@ export * from './get-agent/get-agent-tool'; export * from './create-agent/create-agent-tool'; export * from './delete-agent/delete-agent-tool'; +export * from './get-agent-catalog/get-agent-catalog-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 7c121fcb..2dafef41 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -68,6 +68,7 @@ import { FetchFileContentTool } from './fetch-file-content-tool/fetch-file-conte import { GetAgentTool } from './agents-tools/get-agent/get-agent-tool'; import { CreateAgentTool } from './agents-tools/create-agent/create-agent-tool'; import { DeleteAgentTool } from './agents-tools/delete-agent/delete-agent-tool'; +import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -141,6 +142,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ GetAgentTool, CreateAgentTool, DeleteAgentTool, + GetAgentCatalogTool, ]; export * from './all-monday-api-tool'; From da245b0128cc26c08f73613cfeff0fd42f0cc7cb Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:01:12 +0300 Subject: [PATCH 07/28] fix(agent-toolkit): clean up get_agent_catalog variable assignment and test assertion Co-Authored-By: Claude Sonnet 4.6 --- .../get-agent-catalog/get-agent-catalog-tool.test.ts | 2 +- .../agents-tools/get-agent-catalog/get-agent-catalog-tool.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts index ca8f6351..b0673c3a 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts @@ -53,7 +53,7 @@ describe('GetAgentCatalogTool', () => { expect(mocks.getMockRequest()).toHaveBeenCalledWith( expect.anything(), - { block_reference_ids: ['status-change-ref'] }, + expect.objectContaining({ block_reference_ids: ['status-change-ref'] }), expect.anything(), ); }); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts index b18aba49..0ce39cb1 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts @@ -58,7 +58,7 @@ USAGE EXAMPLES: if (input.type === 'triggers') { try { const variables: GetAgentTriggersCatalogQueryVariables = { - block_reference_ids: input.block_reference_ids ?? undefined, + block_reference_ids: input.block_reference_ids, }; const res = await this.mondayApi.request( getAgentTriggersCatalogQuery, From ca5cd0db9e1c7b48629fb3ce3e0926f0ace1cb02 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:04:28 +0300 Subject: [PATCH 08/28] feat(agent-toolkit): add manage_agent_triggers tool Implements list/add/remove actions for agent triggers, using the dev API versionOverride. All 10 tests pass. Co-Authored-By: Claude Sonnet 4.6 --- .../platform-api-tools/agents-tools/index.ts | 1 + .../manage-agent-triggers-tool.test.ts | 138 +++++++++++++++ .../manage-agent-triggers-tool.ts | 159 ++++++++++++++++++ .../core/tools/platform-api-tools/index.ts | 2 + 4 files changed, 300 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index 8893f78d..ca4530d0 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -2,3 +2,4 @@ export * from './get-agent/get-agent-tool'; export * from './create-agent/create-agent-tool'; export * from './delete-agent/delete-agent-tool'; export * from './get-agent-catalog/get-agent-catalog-tool'; +export * from './manage-agent-triggers/manage-agent-triggers-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts new file mode 100644 index 00000000..dfab569f --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts @@ -0,0 +1,138 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + GetAgentActiveTriggersQuery, + AddTriggerToAgentMutation, + RemoveTriggerFromAgentMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentTriggersTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockActiveTrigger = { + node_id: 'node-abc', + block_reference_id: 'status-change-ref', + name: 'Status Change', + description: 'Fires when a status column changes', + field_summary: 'board_id=42', + }; + + it('should list active triggers for an agent', async () => { + mocks.setResponseOnce({ agent_active_triggers: [mockActiveTrigger] } as GetAgentActiveTriggersQuery); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.count).toBe(1); + expect(parsed.triggers[0].node_id).toBe('node-abc'); + }); + + it('should pass agent_id and versionOverride dev when listing', async () => { + mocks.setResponseOnce({ agent_active_triggers: [] } as GetAgentActiveTriggersQuery); + + await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('getAgentActiveTriggers'), + { agent_id: '7' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should add a trigger to an agent', async () => { + mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + field_values: { board_id: '42' }, + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass block_reference_id and field_values when adding trigger', async () => { + mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); + + await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + field_values: { board_id: '42' }, + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('addTriggerToAgent'), + { agent_id: '7', block_reference_id: 'status-change-ref', field_values: { board_id: '42' } }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should add a trigger without field_values when omitted', async () => { + mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); + + await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ field_values: undefined }), + expect.anything(), + ); + }); + + it('should remove a trigger from an agent', async () => { + mocks.setResponseOnce({ remove_trigger_from_agent: { success: true } } as RemoveTriggerFromAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { + action: 'remove', + agent_id: '7', + node_id: 'node-abc', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass node_id and versionOverride dev when removing', async () => { + mocks.setResponseOnce({ remove_trigger_from_agent: { success: true } } as RemoveTriggerFromAgentMutation); + + await callToolByNameRawAsync('manage_agent_triggers', { action: 'remove', agent_id: '7', node_id: 'node-abc' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('removeTriggerFromAgent'), + { agent_id: '7', node_id: 'node-abc' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should reject add action without block_reference_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'add', agent_id: '7' }); + + expect(result.content[0].text).toContain('block_reference_id is required'); + }); + + it('should reject remove action without node_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'remove', agent_id: '7' }); + + expect(result.content[0].text).toContain('node_id is required'); + }); + + it('should propagate errors with operation context', async () => { + mocks.setError('Not found'); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '999' }); + + expect(result.content[0].text).toContain('Failed to list active triggers'); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts new file mode 100644 index 00000000..a5371c3c --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts @@ -0,0 +1,159 @@ +import { z } from 'zod'; +import { + GetAgentActiveTriggersQuery, + GetAgentActiveTriggersQueryVariables, + AddTriggerToAgentMutation, + AddTriggerToAgentMutationVariables, + RemoveTriggerFromAgentMutation, + RemoveTriggerFromAgentMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { + getAgentActiveTriggersQuery, + addTriggerToAgentMutation, + removeTriggerFromAgentMutation, +} from './manage-agent-triggers.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentTriggersToolSchema = { + action: z + .enum(['list', 'add', 'remove']) + .describe( + '"list" — returns all triggers currently attached to the agent (includes node_id needed for remove). "add" — attaches a new trigger by block_reference_id. "remove" — detaches a trigger by node_id.', + ), + agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), + block_reference_id: z + .string() + .trim() + .min(1) + .optional() + .describe( + 'Required for action:add. The block_reference_id from get_agent_catalog (type:triggers) identifying the trigger type to attach. Never guess this value — look it up in the catalog first.', + ), + field_values: z + .record(z.unknown()) + .optional() + .describe( + 'Required for action:add when the trigger type has required_fields. A key/value object whose shape is described by field_schemas in the get_agent_catalog response. Example: { "board_id": "12345" }. For scheduler fields pass the structured config directly; for selection fields (e.g. board picker) pass { "value": "", "label": "" }.', + ), + node_id: z + .string() + .trim() + .min(1) + .optional() + .describe( + 'Required for action:remove. The node_id of the trigger instance to remove — get it from action:list. Each trigger instance has a unique node_id even if the same trigger type is attached multiple times.', + ), +}; + +export class ManageAgentTriggersTool extends BaseMondayApiTool { + name = 'manage_agent_triggers'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent Triggers', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `List, add, or remove triggers on a monday platform agent. + +Triggers define when an agent runs automatically — for example, when a board status changes, when a date arrives, or on a schedule. + +WORKFLOW FOR ADD: +1. Call get_agent_catalog with type:"triggers" to find the right trigger type by name/description. Note its block_reference_id and inspect field_schemas (describes what field_values to pass when adding — e.g. { board_id: "" }) and required_fields (fields you must collect from the user — e.g. which board, which column). +2. Collect any required field values from the user. +3. Call this tool with action:"add", the block_reference_id, and the assembled field_values. + +WORKFLOW FOR REMOVE: +1. Call this tool with action:"list" to see active triggers by name and field_summary. Match the trigger the user described, note its node_id. +2. Call this tool with action:"remove" and that node_id. + +USAGE EXAMPLES: +- List triggers: { "action": "list", "agent_id": "7" } +- Add trigger: { "action": "add", "agent_id": "7", "block_reference_id": "status-change-ref", "field_values": { "board_id": "42" } } +- Remove trigger: { "action": "remove", "agent_id": "7", "node_id": "node-abc" }`; + } + + getInputSchema() { + return manageAgentTriggersToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'list') { + try { + const variables: GetAgentActiveTriggersQueryVariables = { agent_id: input.agent_id }; + const res = await this.mondayApi.request( + getAgentActiveTriggersQuery, + variables, + { versionOverride: 'dev' }, + ); + const triggers = res.agent_active_triggers ?? []; + return { + content: { + message: 'Active triggers on this agent. Use node_id with action:remove to detach a trigger.', + count: triggers.length, + triggers, + }, + }; + } catch (error) { + rethrowWithContext(error, 'list active triggers for monday platform agent'); + } + } + + if (input.action === 'add') { + if (!input.block_reference_id) { + throw new Error('block_reference_id is required for action:add. Call get_agent_catalog with type:triggers first.'); + } + try { + const variables: AddTriggerToAgentMutationVariables = { + agent_id: input.agent_id, + block_reference_id: input.block_reference_id, + field_values: input.field_values, + }; + const res = await this.mondayApi.request( + addTriggerToAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Trigger added to agent. Call manage_agent_triggers with action:list to verify.', + success: res.add_trigger_to_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'add trigger to monday platform agent'); + } + } + + if (!input.node_id) { + throw new Error( + 'node_id is required for action:remove. Call manage_agent_triggers with action:list first to get node_id values.', + ); + } + try { + const variables: RemoveTriggerFromAgentMutationVariables = { + agent_id: input.agent_id, + node_id: input.node_id, + }; + const res = await this.mondayApi.request( + removeTriggerFromAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Trigger removed from agent.', + success: res.remove_trigger_from_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'remove trigger from monday platform agent'); + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 2dafef41..111fab52 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -69,6 +69,7 @@ import { GetAgentTool } from './agents-tools/get-agent/get-agent-tool'; import { CreateAgentTool } from './agents-tools/create-agent/create-agent-tool'; import { DeleteAgentTool } from './agents-tools/delete-agent/delete-agent-tool'; import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; +import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -143,6 +144,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ CreateAgentTool, DeleteAgentTool, GetAgentCatalogTool, + ManageAgentTriggersTool, ]; export * from './all-monday-api-tool'; From 9897389f7b661e62386f91cf7940486250be0760 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:08:36 +0300 Subject: [PATCH 09/28] test(agent-toolkit): add error propagation tests for add and remove trigger actions Co-Authored-By: Claude Sonnet 4.6 --- .../manage-agent-triggers-tool.test.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts index dfab569f..a7e29607 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts @@ -135,4 +135,28 @@ describe('ManageAgentTriggersTool', () => { expect(result.content[0].text).toContain('Failed to list active triggers'); }); + + it('should propagate errors with operation context for add', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { + action: 'add', + agent_id: '7', + block_reference_id: 'status-change-ref', + }); + + expect(result.content[0].text).toContain('Failed to add trigger'); + }); + + it('should propagate errors with operation context for remove', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_triggers', { + action: 'remove', + agent_id: '7', + node_id: 'node-abc', + }); + + expect(result.content[0].text).toContain('Failed to remove trigger'); + }); }); From 45b51322aaf8f107678d50122542770b4db83ed0 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:11:48 +0300 Subject: [PATCH 10/28] feat(agent-toolkit): add manage_agent_skills tool Implements the manage_agent_skills tool supporting add/remove actions, with full test coverage for happy paths, request shape verification, and error propagation. Co-Authored-By: Claude Sonnet 4.6 --- .../platform-api-tools/agents-tools/index.ts | 1 + .../manage-agent-skills-tool.test.ts | 97 +++++++++++++++++ .../manage-agent-skills-tool.ts | 103 ++++++++++++++++++ .../core/tools/platform-api-tools/index.ts | 2 + 4 files changed, 203 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index ca4530d0..d9e455e5 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -3,3 +3,4 @@ export * from './create-agent/create-agent-tool'; export * from './delete-agent/delete-agent-tool'; export * from './get-agent-catalog/get-agent-catalog-tool'; export * from './manage-agent-triggers/manage-agent-triggers-tool'; +export * from './manage-agent-skills/manage-agent-skills-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts new file mode 100644 index 00000000..d9daaf19 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts @@ -0,0 +1,97 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + AddSkillToAgentMutation, + RemoveSkillFromAgentMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentSkillsTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + it('should add a skill to an agent', async () => { + mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should remove a skill from an agent', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'remove', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should pass correct variables and versionOverride when adding skill', async () => { + mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); + + await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('addSkillToAgent'), + { agent_id: '7', skill_id: 'skill-abc-123' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should pass correct variables and versionOverride when removing skill', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + + await callToolByNameRawAsync('manage_agent_skills', { + action: 'remove', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('removeSkillFromAgent'), + { agent_id: '7', skill_id: 'skill-abc-123' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should propagate errors with operation context for add', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + + expect(result.content[0].text).toContain('Failed to add skill'); + }); + + it('should propagate errors with operation context for remove', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'remove', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + + expect(result.content[0].text).toContain('Failed to remove skill'); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts new file mode 100644 index 00000000..eb788c25 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts @@ -0,0 +1,103 @@ +import { z } from 'zod'; +import { + AddSkillToAgentMutation, + AddSkillToAgentMutationVariables, + RemoveSkillFromAgentMutation, + RemoveSkillFromAgentMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { + addSkillToAgentMutation, + removeSkillFromAgentMutation, +} from './manage-agent-skills.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentSkillsToolSchema = { + action: z + .enum(['add', 'remove']) + .describe('"add" — attaches a skill; "remove" — detaches a skill'), + agent_id: z.string().describe('Unique identifier of the agent'), + skill_id: z + .string() + .describe( + 'The skill ID from get_agent_catalog (type:skills). Never guess — look it up.', + ), +}; + +export class ManageAgentSkillsTool extends BaseMondayApiTool { + name = 'manage_agent_skills'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent Skills', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Add or remove a skill from a monday platform agent. + +Skills extend what an agent can do — for example, sending emails, searching the web, or querying databases. Each skill has a unique ID assigned by the platform. + +IMPORTANT: Always call get_agent_catalog with type:"skills" first to discover available skills and resolve the correct skill_id. Never guess or invent a skill ID. + +WORKFLOW: +1. Call get_agent_catalog with type:"skills" to list available skills and find the one the user wants by name/description. Note its id. +2. Call this tool with action:"add" or action:"remove" and the resolved skill_id. + +USAGE EXAMPLES: +- Add skill: { "action": "add", "agent_id": "7", "skill_id": "skill-abc-123" } +- Remove skill: { "action": "remove", "agent_id": "7", "skill_id": "skill-abc-123" }`; + } + + getInputSchema() { + return manageAgentSkillsToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'add') { + try { + const variables: AddSkillToAgentMutationVariables = { + agent_id: input.agent_id, + skill_id: input.skill_id, + }; + const res = await this.mondayApi.request( + addSkillToAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Skill added to agent.', + success: res.add_skill_to_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'add skill to monday platform agent'); + } + } + + try { + const variables: RemoveSkillFromAgentMutationVariables = { + agent_id: input.agent_id, + skill_id: input.skill_id, + }; + const res = await this.mondayApi.request( + removeSkillFromAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Skill removed from agent.', + success: res.remove_skill_from_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'remove skill from monday platform agent'); + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 111fab52..d25f674e 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -70,6 +70,7 @@ import { CreateAgentTool } from './agents-tools/create-agent/create-agent-tool'; import { DeleteAgentTool } from './agents-tools/delete-agent/delete-agent-tool'; import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; +import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -145,6 +146,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteAgentTool, GetAgentCatalogTool, ManageAgentTriggersTool, + ManageAgentSkillsTool, ]; export * from './all-monday-api-tool'; From caec9a8151e7b27a1856955df06d75aa78eb081c Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:14:33 +0300 Subject: [PATCH 11/28] fix(agent-toolkit): improve manage_agent_skills control flow and add null response tests Use explicit if/else branching in executeInternal and add tests verifying the ?? false fallback when the API returns null for add_skill_to_agent or remove_skill_from_agent. Co-Authored-By: Claude Sonnet 4.6 --- .../manage-agent-skills-tool.test.ts | 20 ++++++++++ .../manage-agent-skills-tool.ts | 40 +++++++++---------- 2 files changed, 40 insertions(+), 20 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts index d9daaf19..aa502459 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts @@ -94,4 +94,24 @@ describe('ManageAgentSkillsTool', () => { expect(result.content[0].text).toContain('Failed to remove skill'); }); + + it('should return success:false when add_skill_to_agent is null', async () => { + mocks.setResponseOnce({ add_skill_to_agent: null } as AddSkillToAgentMutation); + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + expect(parseToolResult(result).success).toBe(false); + }); + + it('should return success:false when remove_skill_from_agent is null', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: null } as RemoveSkillFromAgentMutation); + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'remove', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + expect(parseToolResult(result).success).toBe(false); + }); }); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts index eb788c25..54ac816e 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts @@ -78,26 +78,26 @@ USAGE EXAMPLES: } catch (error) { rethrowWithContext(error, 'add skill to monday platform agent'); } - } - - try { - const variables: RemoveSkillFromAgentMutationVariables = { - agent_id: input.agent_id, - skill_id: input.skill_id, - }; - const res = await this.mondayApi.request( - removeSkillFromAgentMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: 'Skill removed from agent.', - success: res.remove_skill_from_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'remove skill from monday platform agent'); + } else { + try { + const variables: RemoveSkillFromAgentMutationVariables = { + agent_id: input.agent_id, + skill_id: input.skill_id, + }; + const res = await this.mondayApi.request( + removeSkillFromAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Skill removed from agent.', + success: res.remove_skill_from_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'remove skill from monday platform agent'); + } } } } From 8de165d935bcf46ab8bc3634a6384b7802aea239 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:18:16 +0300 Subject: [PATCH 12/28] feat(agent-toolkit): add update_agent tool Implements the update_agent WRITE tool that patches an existing monday platform agent's profile or execution plan, including only the provided fields in the mutation input. Co-Authored-By: Claude Sonnet 4.6 --- .../platform-api-tools/agents-tools/index.ts | 1 + .../update-agent/update-agent-tool.test.ts | 97 +++++++++++++++++++ .../update-agent/update-agent-tool.ts | 77 +++++++++++++++ .../core/tools/platform-api-tools/index.ts | 2 + 4 files changed, 177 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index d9e455e5..eef646c2 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -4,3 +4,4 @@ export * from './delete-agent/delete-agent-tool'; export * from './get-agent-catalog/get-agent-catalog-tool'; export * from './manage-agent-triggers/manage-agent-triggers-tool'; export * from './manage-agent-skills/manage-agent-skills-tool'; +export * from './update-agent/update-agent-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts new file mode 100644 index 00000000..b271613c --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts @@ -0,0 +1,97 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { UpdateAgentMutation } from 'src/monday-graphql/generated/graphql.dev/graphql'; + +const mockAgent = { + id: '7', + kind: null, + state: null, + goal: null, + plan: null, + user_prompt: null, + version_id: 'v1', + created_at: null, + updated_at: null, + profile: { + name: 'Updated Agent', + role: 'Test Role', + role_description: 'A test agent', + avatar_url: null, + background_color: null, + }, +}; + +describe('UpdateAgentTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + it('should update agent name — happy path', async () => { + mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); + + const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'Updated Agent' }); + const parsed = parseToolResult(result); + + expect(parsed.id).toBe('7'); + }); + + it('should update multiple fields — happy path', async () => { + mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); + + const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'X', plan: 'step 1' }); + + expect(mocks.getMockRequest()).toHaveBeenCalled(); + expect(result).toBeDefined(); + }); + + it('should only include provided fields in input object', async () => { + mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); + + await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ input: { name: 'X' } }), + expect.anything(), + ); + }); + + it('should not include omitted fields in input object', async () => { + mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); + + await callToolByNameRawAsync('update_agent', { id: '7', role: 'Bot' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ input: { role: 'Bot' } }), + expect.anything(), + ); + + const callArgs = mocks.getMockRequest().mock.calls[0]; + const variables = callArgs[1] as { input: Record }; + expect(variables.input).not.toHaveProperty('name'); + }); + + it('should pass versionOverride dev', async () => { + mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); + + await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should propagate API errors with context', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + + expect(result.content[0].text).toContain('Failed to update monday platform agent'); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts new file mode 100644 index 00000000..3b224176 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts @@ -0,0 +1,77 @@ +import { z } from 'zod'; +import { + AgentModel, + UpdateAgentMutation, + UpdateAgentMutationVariables, + UpdateAgentInput, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { updateAgentMutation } from './update-agent.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const updateAgentToolSchema = { + id: z.string().trim().min(1).describe('Unique identifier of the agent to update'), + name: z.string().trim().min(1).optional().describe('New display name for the agent'), + role: z.string().trim().min(1).optional().describe('Short role title (e.g. "Customer Success Bot")'), + role_description: z + .string() + .trim() + .min(1) + .optional() + .describe("Detailed description of the agent's role"), + plan: z.string().trim().min(1).optional().describe('Step-by-step execution plan in markdown'), + agent_model: z + .string() + .trim() + .min(1) + .optional() + .describe('AI model identifier — only set if user explicitly named a model'), +}; + +export class UpdateAgentTool extends BaseMondayApiTool { + name = 'update_agent'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Update monday Platform Agent', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Update an existing monday platform agent's profile or execution plan. + +Only the fields you provide are changed — omit any field to leave it unchanged. + +IMPORTANT — agent_model: Do not set agent_model unless the user has explicitly named a specific model. The platform selects a sensible default; setting an incorrect model degrades the agent's performance. + +USAGE EXAMPLE: +- Update name only: { "id": "7", "name": "New Name" } +- Update plan: { "id": "7", "plan": "1. Check board status\\n2. Send notification" }`; + } + + getInputSchema() { + return updateAgentToolSchema; + } + + protected async executeInternal(input: ToolInputType): Promise> { + try { + const agentInput: UpdateAgentInput = {}; + if (input.name !== undefined) agentInput.name = input.name; + if (input.role !== undefined) agentInput.role = input.role; + if (input.role_description !== undefined) agentInput.role_description = input.role_description; + if (input.plan !== undefined) agentInput.plan = input.plan; + if (input.agent_model !== undefined) agentInput.agent_model = input.agent_model as AgentModel; + + const variables: UpdateAgentMutationVariables = { id: input.id, input: agentInput }; + const res = await this.mondayApi.request(updateAgentMutation, variables, { + versionOverride: 'dev', + }); + + return { content: res.update_agent ?? {} }; + } catch (error) { + rethrowWithContext(error, 'update monday platform agent'); + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index d25f674e..1edcdadc 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -71,6 +71,7 @@ import { DeleteAgentTool } from './agents-tools/delete-agent/delete-agent-tool'; import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; +import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -147,6 +148,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ GetAgentCatalogTool, ManageAgentTriggersTool, ManageAgentSkillsTool, + UpdateAgentTool, ]; export * from './all-monday-api-tool'; From 5deefcb609d4a1abf7fee0ba7c3c94072a0cb909 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:21:08 +0300 Subject: [PATCH 13/28] fix(agent-toolkit): improve update_agent null safety and test coverage - Throw explicit error when update_agent returns no data instead of falling back to {} - Strengthen agent_model describe string to match create_agent's STRONGLY DISCOURAGED wording - Add profile.name assertion to happy-path test to confirm response forwarding Co-Authored-By: Claude Sonnet 4.6 --- .../agents-tools/update-agent/update-agent-tool.test.ts | 3 +++ .../agents-tools/update-agent/update-agent-tool.ts | 7 +++++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts index b271613c..632e26c1 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts @@ -36,6 +36,9 @@ describe('UpdateAgentTool', () => { const parsed = parseToolResult(result); expect(parsed.id).toBe('7'); + // also assert something from the profile to confirm response forwarding + expect(parsed.profile).toBeDefined(); + expect(parsed.profile.name).toBe('Updated Agent'); }); it('should update multiple fields — happy path', async () => { diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts index 3b224176..ea98dac3 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts @@ -26,7 +26,7 @@ export const updateAgentToolSchema = { .trim() .min(1) .optional() - .describe('AI model identifier — only set if user explicitly named a model'), + .describe('AI model identifier. STRONGLY DISCOURAGED — omit this field. Only set when the user explicitly names a monday-supported model. Do not invent or guess model identifiers — use the exact string the user provided.'), }; export class UpdateAgentTool extends BaseMondayApiTool { @@ -69,7 +69,10 @@ USAGE EXAMPLE: versionOverride: 'dev', }); - return { content: res.update_agent ?? {} }; + if (!res.update_agent) { + throw new Error('update_agent returned no data — the agent may not exist'); + } + return { content: res.update_agent }; } catch (error) { rethrowWithContext(error, 'update monday platform agent'); } From 836573bd4b48604e7bdbe8023b1029297b8ad91e Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:24:04 +0300 Subject: [PATCH 14/28] feat(agent-toolkit): add manage_agent_state tool Adds manage_agent_state tool supporting activate, deactivate, and run actions for monday platform agents. Includes 11 unit tests covering happy paths, error propagation, versionOverride, default inactive_reason, and null fallbacks. Co-Authored-By: Claude Sonnet 4.6 --- .../platform-api-tools/agents-tools/index.ts | 1 + .../manage-agent-state-tool.test.ts | 160 ++++++++++++++++++ .../manage-agent-state-tool.ts | 119 +++++++++++++ .../core/tools/platform-api-tools/index.ts | 2 + 4 files changed, 282 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index eef646c2..579f7af7 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -5,3 +5,4 @@ export * from './get-agent-catalog/get-agent-catalog-tool'; export * from './manage-agent-triggers/manage-agent-triggers-tool'; export * from './manage-agent-skills/manage-agent-skills-tool'; export * from './update-agent/update-agent-tool'; +export * from './manage-agent-state/manage-agent-state-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts new file mode 100644 index 00000000..de9f7576 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts @@ -0,0 +1,160 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + ActivateAgentMutation, + DeactivateAgentMutation, + RunAgentMutation, + InactiveReason, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentStateTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + // Happy path tests + it('should activate an agent successfully', async () => { + mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'activate', + agent_id: '7', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should deactivate an agent successfully', async () => { + mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'deactivate', + agent_id: '7', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + it('should enqueue an agent run and return trigger_uuid', async () => { + mocks.setResponseOnce({ run_agent: { trigger_uuid: 'uuid-123' } } as RunAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'run', + agent_id: '7', + }); + const parsed = parseToolResult(result); + + expect(parsed.trigger_uuid).toBe('uuid-123'); + }); + + // versionOverride dev + it('should pass versionOverride:dev for activate', async () => { + mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { + action: 'activate', + agent_id: '7', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('activateAgent'), + { id: '7' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + // Default inactive_reason + it('should default inactive_reason to DeactivatedByUser when not provided', async () => { + mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { + action: 'deactivate', + agent_id: '7', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('deactivateAgent'), + expect.objectContaining({ inactive_reason: InactiveReason.DeactivatedByUser }), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + // Explicit inactive_reason + it('should accept explicit inactive_reason ACCOUNT_LEVEL_BLOCKING', async () => { + mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); + + await callToolByNameRawAsync('manage_agent_state', { + action: 'deactivate', + agent_id: '7', + inactive_reason: 'ACCOUNT_LEVEL_BLOCKING', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('deactivateAgent'), + expect.objectContaining({ inactive_reason: 'ACCOUNT_LEVEL_BLOCKING' }), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + // Error propagation + it('should propagate errors with context for activate', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'activate', + agent_id: '7', + }); + + expect(result.content[0].text).toContain('Failed to activate'); + }); + + it('should propagate errors with context for deactivate', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'deactivate', + agent_id: '7', + }); + + expect(result.content[0].text).toContain('Failed to deactivate'); + }); + + it('should propagate errors with context for run', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'run', + agent_id: '7', + }); + + expect(result.content[0].text).toContain('Failed to run'); + }); + + // success:false fallback + it('should return success:false when activate_agent is null', async () => { + mocks.setResponseOnce({ activate_agent: null } as ActivateAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'activate', + agent_id: '7', + }); + + expect(parseToolResult(result).success).toBe(false); + }); + + it('should return success:false when deactivate_agent is null', async () => { + mocks.setResponseOnce({ deactivate_agent: null } as DeactivateAgentMutation); + + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'deactivate', + agent_id: '7', + }); + + expect(parseToolResult(result).success).toBe(false); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts new file mode 100644 index 00000000..a64797a0 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts @@ -0,0 +1,119 @@ +import { z } from 'zod'; +import { + ActivateAgentMutation, + ActivateAgentMutationVariables, + DeactivateAgentMutation, + DeactivateAgentMutationVariables, + RunAgentMutation, + RunAgentMutationVariables, + InactiveReason, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { + activateAgentMutation, + deactivateAgentMutation, + runAgentMutation, +} from './manage-agent-state.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentStateToolSchema = { + action: z.enum(['activate', 'deactivate', 'run']).describe( + '"activate" — transitions the agent to ACTIVE state. "deactivate" — transitions the agent to INACTIVE. "run" — manually enqueues a run of the agent.', + ), + agent_id: z.string().trim().min(1).describe('Unique identifier of the agent.'), + inactive_reason: z + .enum(['DEACTIVATED_BY_USER', 'ACCOUNT_LEVEL_BLOCKING']) + .optional() + .describe( + 'Only for action:deactivate. Reason for deactivation. Defaults to "DEACTIVATED_BY_USER" if omitted.', + ), +}; + +export class ManageAgentStateTool extends BaseMondayApiTool { + name = 'manage_agent_state'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent State', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Activate, deactivate, or manually trigger a run for a monday platform agent. + +- activate: Transitions the agent to ACTIVE state so it can receive and respond to triggers. +- deactivate: Transitions the agent to INACTIVE. Use inactive_reason:"DEACTIVATED_BY_USER" (default) for user-initiated deactivation. +- run: Manually enqueues a run of the agent (fire-and-forget). Returns a trigger_uuid for downstream correlation. Success means the run was enqueued — not that it completed. + +USAGE EXAMPLES: +- Activate: { "action": "activate", "agent_id": "7" } +- Deactivate: { "action": "deactivate", "agent_id": "7" } +- Run: { "action": "run", "agent_id": "7" }`; + } + + getInputSchema() { + return manageAgentStateToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'activate') { + try { + const variables: ActivateAgentMutationVariables = { id: input.agent_id }; + const res = await this.mondayApi.request( + activateAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Agent activated.', + success: res.activate_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'activate monday platform agent'); + } + } else if (input.action === 'deactivate') { + try { + const variables: DeactivateAgentMutationVariables = { + id: input.agent_id, + inactive_reason: (input.inactive_reason as InactiveReason) ?? InactiveReason.DeactivatedByUser, + }; + const res = await this.mondayApi.request( + deactivateAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Agent deactivated.', + success: res.deactivate_agent?.success ?? false, + }, + }; + } catch (error) { + rethrowWithContext(error, 'deactivate monday platform agent'); + } + } else { + try { + const variables: RunAgentMutationVariables = { id: input.agent_id }; + const res = await this.mondayApi.request( + runAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { + content: { + message: 'Agent run enqueued.', + trigger_uuid: res.run_agent?.trigger_uuid, + }, + }; + } catch (error) { + rethrowWithContext(error, 'run monday platform agent'); + } + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 1edcdadc..4399c836 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -72,6 +72,7 @@ import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent- import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; +import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -149,6 +150,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ ManageAgentTriggersTool, ManageAgentSkillsTool, UpdateAgentTool, + ManageAgentStateTool, ]; export * from './all-monday-api-tool'; From 79a00f3f0d43fb021857ffa582279a1bb398c9ac Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:27:43 +0300 Subject: [PATCH 15/28] fix(agent-toolkit): improve manage_agent_state control flow, null safety, and test coverage Restructure try/catch blocks so return statements are outside the try, add explicit null check for run_agent response, and add test coverage for null run_agent case. Co-Authored-By: Claude Sonnet 4.6 --- .../manage-agent-state-tool.test.ts | 9 ++++ .../manage-agent-state-tool.ts | 54 ++++++++++--------- 2 files changed, 38 insertions(+), 25 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts index de9f7576..8ef501fb 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts @@ -157,4 +157,13 @@ describe('ManageAgentStateTool', () => { expect(parseToolResult(result).success).toBe(false); }); + + it('should handle null run_agent response', async () => { + mocks.setResponseOnce({ run_agent: null } as RunAgentMutation); + const result = await callToolByNameRawAsync('manage_agent_state', { + action: 'run', + agent_id: '7', + }); + expect(result.content[0].text).toContain('run_agent returned no data'); + }); }); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts index a64797a0..0706c370 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts @@ -61,59 +61,63 @@ USAGE EXAMPLES: input: ToolInputType, ): Promise> { if (input.action === 'activate') { + let activateRes: ActivateAgentMutation; try { - const variables: ActivateAgentMutationVariables = { id: input.agent_id }; - const res = await this.mondayApi.request( + activateRes = await this.mondayApi.request( activateAgentMutation, - variables, + { id: input.agent_id } satisfies ActivateAgentMutationVariables, { versionOverride: 'dev' }, ); - return { - content: { - message: 'Agent activated.', - success: res.activate_agent?.success ?? false, - }, - }; } catch (error) { rethrowWithContext(error, 'activate monday platform agent'); } + return { + content: { + message: 'Agent activated.', + success: activateRes!.activate_agent?.success ?? false, + }, + }; } else if (input.action === 'deactivate') { + let deactivateRes: DeactivateAgentMutation; try { const variables: DeactivateAgentMutationVariables = { id: input.agent_id, inactive_reason: (input.inactive_reason as InactiveReason) ?? InactiveReason.DeactivatedByUser, }; - const res = await this.mondayApi.request( + deactivateRes = await this.mondayApi.request( deactivateAgentMutation, variables, { versionOverride: 'dev' }, ); - return { - content: { - message: 'Agent deactivated.', - success: res.deactivate_agent?.success ?? false, - }, - }; } catch (error) { rethrowWithContext(error, 'deactivate monday platform agent'); } + return { + content: { + message: 'Agent deactivated.', + success: deactivateRes!.deactivate_agent?.success ?? false, + }, + }; } else { + let runRes: RunAgentMutation; try { - const variables: RunAgentMutationVariables = { id: input.agent_id }; - const res = await this.mondayApi.request( + runRes = await this.mondayApi.request( runAgentMutation, - variables, + { id: input.agent_id } satisfies RunAgentMutationVariables, { versionOverride: 'dev' }, ); - return { - content: { - message: 'Agent run enqueued.', - trigger_uuid: res.run_agent?.trigger_uuid, - }, - }; } catch (error) { rethrowWithContext(error, 'run monday platform agent'); } + if (!runRes!.run_agent) { + throw new Error('run_agent returned no data — the agent run may not have been enqueued'); + } + return { + content: { + message: 'Agent run enqueued.', + trigger_uuid: runRes.run_agent.trigger_uuid, + }, + }; } } } From 4d64cfc1b8fd9e78961545fb2e45ed78622bab99 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 18:58:57 +0300 Subject: [PATCH 16/28] feat(agent-toolkit): add manage_agent_knowledge tool Implements list/add/update/remove actions for managing a monday platform agent's access to boards and docs, following the restructured try/catch pattern from manage-agent-state-tool. Co-Authored-By: Claude Sonnet 4.6 --- .../platform-api-tools/agents-tools/index.ts | 1 + .../manage-agent-knowledge-tool.test.ts | 187 ++++++++++++++++++ .../manage-agent-knowledge-tool.ts | 180 +++++++++++++++++ .../core/tools/platform-api-tools/index.ts | 2 + 4 files changed, 370 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index 579f7af7..7fdcf4d9 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -6,3 +6,4 @@ export * from './manage-agent-triggers/manage-agent-triggers-tool'; export * from './manage-agent-skills/manage-agent-skills-tool'; export * from './update-agent/update-agent-tool'; export * from './manage-agent-state/manage-agent-state-tool'; +export * from './manage-agent-knowledge/manage-agent-knowledge-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts new file mode 100644 index 00000000..1e1427c1 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts @@ -0,0 +1,187 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { + GetAgentKnowledgeQuery, + AddAgentResourceAccessMutation, + RemoveAgentResourceAccessMutation, + UpdateAgentResourceAccessMutation, +} from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('ManageAgentKnowledgeTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockKnowledge = { + resources: [{ resource_id: '42', scope_type: 'BOARD', permission_type: 'READ' }], + files: [], + }; + + // 1. Happy path list + it('should list agent knowledge resources', async () => { + mocks.setResponseOnce({ agent_knowledge: mockKnowledge } as GetAgentKnowledgeQuery); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); + const parsed = parseToolResult(result); + + expect(parsed.knowledge.resources[0].resource_id).toBe('42'); + }); + + // 2. Happy path add + it('should add resource access to agent', async () => { + mocks.setResponseOnce({ add_agent_resource_access: { success: true } } as AddAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + // 3. Happy path update + it('should update resource access permission', async () => { + mocks.setResponseOnce({ update_agent_resource_access: { success: true } } as UpdateAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'update', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ_WRITE', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + // 4. Happy path remove + it('should remove resource access from agent', async () => { + mocks.setResponseOnce({ remove_agent_resource_access: { success: true } } as RemoveAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'remove', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + }); + const parsed = parseToolResult(result); + + expect(parsed.success).toBe(true); + }); + + // 5. list passes versionOverride dev + it('should pass versionOverride:dev when listing', async () => { + mocks.setResponseOnce({ agent_knowledge: mockKnowledge } as GetAgentKnowledgeQuery); + + await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + // 6. add maps agent_id to id + it('should map agent_id to id in add variables', async () => { + mocks.setResponseOnce({ add_agent_resource_access: { success: true } } as AddAgentResourceAccessMutation); + + await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ id: '7', resource_id: '42', scope_type: 'BOARD', permission_type: 'READ' }), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + // 7. Validation error — add missing resource_id + it('should reject add action without resource_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + scope_type: 'BOARD', + permission_type: 'READ', + }); + + expect(result.content[0].text).toContain('resource_id, scope_type, and permission_type are required'); + }); + + // 8. Validation error — remove missing scope_type + it('should reject remove action without scope_type', async () => { + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'remove', + agent_id: '7', + resource_id: '42', + }); + + expect(result.content[0].text).toContain('resource_id and scope_type are required'); + }); + + // 9. API error propagation — list + it('should propagate errors with context for list', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); + + expect(result.content[0].text).toContain('Failed to list agent knowledge'); + }); + + // 10. API error propagation — add + it('should propagate errors with context for add', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ', + }); + + expect(result.content[0].text).toContain('Failed to add agent resource access'); + }); + + // 11. success:false fallback — add + it('should return success:false when add_agent_resource_access is null', async () => { + mocks.setResponseOnce({ add_agent_resource_access: null } as AddAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'add', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ', + }); + + expect(parseToolResult(result).success).toBe(false); + }); + + // 12. success:false fallback — remove + it('should return success:false when remove_agent_resource_access is null', async () => { + mocks.setResponseOnce({ remove_agent_resource_access: null } as RemoveAgentResourceAccessMutation); + + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'remove', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + }); + + expect(parseToolResult(result).success).toBe(false); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts new file mode 100644 index 00000000..5e43b7fd --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts @@ -0,0 +1,180 @@ +import { z } from 'zod'; +import { + GetAgentKnowledgeQuery, + GetAgentKnowledgeQueryVariables, + AddAgentResourceAccessMutation, + AddAgentResourceAccessMutationVariables, + RemoveAgentResourceAccessMutation, + RemoveAgentResourceAccessMutationVariables, + UpdateAgentResourceAccessMutation, + UpdateAgentResourceAccessMutationVariables, + KnowledgeScope, + KnowledgePermission, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { + getAgentKnowledgeQuery, + addAgentResourceAccessMutation, + removeAgentResourceAccessMutation, + updateAgentResourceAccessMutation, +} from './manage-agent-knowledge.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const manageAgentKnowledgeToolSchema = { + action: z.enum(['list', 'add', 'update', 'remove']).describe( + '"list" — returns all resources the agent currently has access to. "add" — grants access to a board or doc. "update" — changes the permission level on an existing resource. "remove" — revokes the agent\'s access to a board or doc.', + ), + agent_id: z.string().trim().min(1).describe('Unique identifier of the agent.'), + resource_id: z + .string() + .trim() + .min(1) + .optional() + .describe('Required for action:add, action:update, action:remove. The ID of the board or doc to grant/update/revoke access to.'), + scope_type: z + .enum(['BOARD', 'DOC']) + .optional() + .describe('Required for action:add, action:update, action:remove. The type of resource: "BOARD" or "DOC".'), + permission_type: z + .enum(['READ', 'READ_WRITE']) + .optional() + .describe( + 'Required for action:add and action:update. The permission level: "READ" (agent can read the resource) or "READ_WRITE" (agent can read and write the resource).', + ), +}; + +export class ManageAgentKnowledgeTool extends BaseMondayApiTool { + name = 'manage_agent_knowledge'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Manage monday Platform Agent Knowledge', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `List, grant, update, or revoke a monday platform agent's access to boards and docs. + +An agent's "knowledge" is the set of monday.com boards and docs it can read from or write to during a run. + +- list: Returns all resources the agent currently has access to, including permission level and resource type. +- add: Grants the agent access to a board or doc with the specified permission level. +- update: Changes the permission level on a resource the agent already has access to. +- remove: Revokes the agent's access to a board or doc entirely. + +IMPORTANT: Call with action:"list" first to see the current resource access before adding, updating, or removing. + +Permission types: +- READ: Agent can read data from the resource. +- READ_WRITE: Agent can read and write data to the resource. + +USAGE EXAMPLES: +- List: { "action": "list", "agent_id": "7" } +- Add board access: { "action": "add", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD", "permission_type": "READ" } +- Update to read-write: { "action": "update", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD", "permission_type": "READ_WRITE" } +- Remove access: { "action": "remove", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD" }`; + } + + getInputSchema() { + return manageAgentKnowledgeToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + if (input.action === 'list') { + let res: GetAgentKnowledgeQuery; + try { + res = await this.mondayApi.request( + getAgentKnowledgeQuery, + { id: input.agent_id } satisfies GetAgentKnowledgeQueryVariables, + { versionOverride: 'dev' }, + ); + } catch (error) { + rethrowWithContext(error, 'list agent knowledge for monday platform agent'); + } + return { + content: { + message: 'Current agent resource access.', + knowledge: res!.agent_knowledge, + }, + }; + } else if (input.action === 'add') { + if (!input.resource_id || !input.scope_type || !input.permission_type) { + throw new Error('resource_id, scope_type, and permission_type are required for action:add'); + } + let res: AddAgentResourceAccessMutation; + try { + res = await this.mondayApi.request( + addAgentResourceAccessMutation, + { + id: input.agent_id, + resource_id: input.resource_id, + scope_type: input.scope_type as KnowledgeScope, + permission_type: input.permission_type as KnowledgePermission, + } satisfies AddAgentResourceAccessMutationVariables, + { versionOverride: 'dev' }, + ); + } catch (error) { + rethrowWithContext(error, 'add agent resource access for monday platform agent'); + } + return { + content: { + message: 'Resource access granted to agent.', + success: res!.add_agent_resource_access?.success ?? false, + }, + }; + } else if (input.action === 'update') { + if (!input.resource_id || !input.scope_type || !input.permission_type) { + throw new Error('resource_id, scope_type, and permission_type are required for action:update'); + } + let res: UpdateAgentResourceAccessMutation; + try { + res = await this.mondayApi.request( + updateAgentResourceAccessMutation, + { + id: input.agent_id, + resource_id: input.resource_id, + scope_type: input.scope_type as KnowledgeScope, + permission_type: input.permission_type as KnowledgePermission, + } satisfies UpdateAgentResourceAccessMutationVariables, + { versionOverride: 'dev' }, + ); + } catch (error) { + rethrowWithContext(error, 'update agent resource access for monday platform agent'); + } + return { + content: { + message: 'Resource access updated.', + success: res!.update_agent_resource_access?.success ?? false, + }, + }; + } else { + if (!input.resource_id || !input.scope_type) { + throw new Error('resource_id and scope_type are required for action:remove'); + } + let res: RemoveAgentResourceAccessMutation; + try { + res = await this.mondayApi.request( + removeAgentResourceAccessMutation, + { + id: input.agent_id, + resource_id: input.resource_id, + scope_type: input.scope_type as KnowledgeScope, + } satisfies RemoveAgentResourceAccessMutationVariables, + { versionOverride: 'dev' }, + ); + } catch (error) { + rethrowWithContext(error, 'remove agent resource access for monday platform agent'); + } + return { + content: { + message: 'Resource access removed from agent.', + success: res!.remove_agent_resource_access?.success ?? false, + }, + }; + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 4399c836..4846b1e5 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -73,6 +73,7 @@ import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/ma import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; +import { ManageAgentKnowledgeTool } from './agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -151,6 +152,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ ManageAgentSkillsTool, UpdateAgentTool, ManageAgentStateTool, + ManageAgentKnowledgeTool, ]; export * from './all-monday-api-tool'; From 30363fc1446586af668ba4f03565f88ca5ca6a32 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 19:01:55 +0300 Subject: [PATCH 17/28] fix(agent-toolkit): fix update validation message and improve manage_agent_knowledge test coverage Co-Authored-By: Claude Sonnet 4.6 --- .../manage-agent-knowledge-tool.test.ts | 23 +++++++++++++++++++ .../manage-agent-knowledge-tool.ts | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts index 1e1427c1..c6b2dc96 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts @@ -184,4 +184,27 @@ describe('ManageAgentKnowledgeTool', () => { expect(parseToolResult(result).success).toBe(false); }); + + it('should reject update action with missing permission_type', async () => { + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'update', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + // permission_type omitted + }); + expect(result.content[0].text).toContain('resource_id, scope_type, and permission_type are required for action:update'); + }); + + it('should return success:false when update_agent_resource_access is null', async () => { + mocks.setResponseOnce({ update_agent_resource_access: null } as UpdateAgentResourceAccessMutation); + const result = await callToolByNameRawAsync('manage_agent_knowledge', { + action: 'update', + agent_id: '7', + resource_id: '42', + scope_type: 'BOARD', + permission_type: 'READ_WRITE', + }); + expect(parseToolResult(result).success).toBe(false); + }); }); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts index 5e43b7fd..4a116476 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts @@ -98,7 +98,7 @@ USAGE EXAMPLES: return { content: { message: 'Current agent resource access.', - knowledge: res!.agent_knowledge, + knowledge: res!.agent_knowledge ?? { resources: [], files: [] }, }, }; } else if (input.action === 'add') { From d23006e11cc826a1640b58d8edf23ec4c0a6e625 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 19:04:58 +0300 Subject: [PATCH 18/28] fix(agent-toolkit): remove semicolons from tool descriptions to pass safety checks Co-Authored-By: Claude Sonnet 4.6 --- .../manage-agent-skills/manage-agent-skills-tool.ts | 2 +- .../manage-agent-triggers/manage-agent-triggers-tool.ts | 2 +- .../agents-tools/update-agent/update-agent-tool.ts | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts index 54ac816e..664cdb86 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts @@ -16,7 +16,7 @@ import { rethrowWithContext } from '../../../../../utils'; export const manageAgentSkillsToolSchema = { action: z .enum(['add', 'remove']) - .describe('"add" — attaches a skill; "remove" — detaches a skill'), + .describe('"add" attaches a skill. "remove" detaches a skill.'), agent_id: z.string().describe('Unique identifier of the agent'), skill_id: z .string() diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts index a5371c3c..cb28f406 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts @@ -35,7 +35,7 @@ export const manageAgentTriggersToolSchema = { .record(z.unknown()) .optional() .describe( - 'Required for action:add when the trigger type has required_fields. A key/value object whose shape is described by field_schemas in the get_agent_catalog response. Example: { "board_id": "12345" }. For scheduler fields pass the structured config directly; for selection fields (e.g. board picker) pass { "value": "", "label": "" }.', + 'Required for action:add when the trigger type has required_fields. A key/value object whose shape is described by field_schemas in the get_agent_catalog response. Example: { "board_id": "12345" }. For scheduler fields pass the structured config directly. For selection fields (e.g. board picker) pass { "value": "", "label": "" }.', ), node_id: z .string() diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts index ea98dac3..bb507d64 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts @@ -44,7 +44,7 @@ export class UpdateAgentTool extends BaseMondayApiTool Date: Wed, 13 May 2026 19:05:06 +0300 Subject: [PATCH 19/28] chore(agent-toolkit): bump version to 5.11.0 Co-Authored-By: Claude Sonnet 4.6 --- packages/agent-toolkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json index f0db11ca..5116733f 100644 --- a/packages/agent-toolkit/package.json +++ b/packages/agent-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@mondaydotcomorg/agent-toolkit", - "version": "5.10.3", + "version": "5.11.0", "description": "monday.com agent toolkit", From 4fd9a27b999504cd1a16b997e57abd7c781433a6 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 19:08:07 +0300 Subject: [PATCH 20/28] refactor(agent-toolkit): move returns inside try blocks and add skills list note Move return statements inside try blocks (using const) for all branches in manage-agent-state-tool.ts and manage-agent-knowledge-tool.ts, eliminating non-null assertions. Add a note to manage_agent_skills description that there is no list action because the platform does not yet expose that query. Co-Authored-By: Claude Sonnet 4.6 --- .../manage-agent-knowledge-tool.ts | 60 +++++++++---------- .../manage-agent-skills-tool.ts | 4 +- .../manage-agent-state-tool.ts | 60 +++++++++---------- 3 files changed, 59 insertions(+), 65 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts index 4a116476..1acb2a48 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts @@ -85,29 +85,27 @@ USAGE EXAMPLES: input: ToolInputType, ): Promise> { if (input.action === 'list') { - let res: GetAgentKnowledgeQuery; try { - res = await this.mondayApi.request( + const res = await this.mondayApi.request( getAgentKnowledgeQuery, { id: input.agent_id } satisfies GetAgentKnowledgeQueryVariables, { versionOverride: 'dev' }, ); + return { + content: { + message: 'Current agent resource access.', + knowledge: res.agent_knowledge ?? { resources: [], files: [] }, + }, + }; } catch (error) { rethrowWithContext(error, 'list agent knowledge for monday platform agent'); } - return { - content: { - message: 'Current agent resource access.', - knowledge: res!.agent_knowledge ?? { resources: [], files: [] }, - }, - }; } else if (input.action === 'add') { if (!input.resource_id || !input.scope_type || !input.permission_type) { throw new Error('resource_id, scope_type, and permission_type are required for action:add'); } - let res: AddAgentResourceAccessMutation; try { - res = await this.mondayApi.request( + const res = await this.mondayApi.request( addAgentResourceAccessMutation, { id: input.agent_id, @@ -117,22 +115,21 @@ USAGE EXAMPLES: } satisfies AddAgentResourceAccessMutationVariables, { versionOverride: 'dev' }, ); + return { + content: { + message: 'Resource access granted to agent.', + success: res.add_agent_resource_access?.success ?? false, + }, + }; } catch (error) { rethrowWithContext(error, 'add agent resource access for monday platform agent'); } - return { - content: { - message: 'Resource access granted to agent.', - success: res!.add_agent_resource_access?.success ?? false, - }, - }; } else if (input.action === 'update') { if (!input.resource_id || !input.scope_type || !input.permission_type) { throw new Error('resource_id, scope_type, and permission_type are required for action:update'); } - let res: UpdateAgentResourceAccessMutation; try { - res = await this.mondayApi.request( + const res = await this.mondayApi.request( updateAgentResourceAccessMutation, { id: input.agent_id, @@ -142,22 +139,21 @@ USAGE EXAMPLES: } satisfies UpdateAgentResourceAccessMutationVariables, { versionOverride: 'dev' }, ); + return { + content: { + message: 'Resource access updated.', + success: res.update_agent_resource_access?.success ?? false, + }, + }; } catch (error) { rethrowWithContext(error, 'update agent resource access for monday platform agent'); } - return { - content: { - message: 'Resource access updated.', - success: res!.update_agent_resource_access?.success ?? false, - }, - }; } else { if (!input.resource_id || !input.scope_type) { throw new Error('resource_id and scope_type are required for action:remove'); } - let res: RemoveAgentResourceAccessMutation; try { - res = await this.mondayApi.request( + const res = await this.mondayApi.request( removeAgentResourceAccessMutation, { id: input.agent_id, @@ -166,15 +162,15 @@ USAGE EXAMPLES: } satisfies RemoveAgentResourceAccessMutationVariables, { versionOverride: 'dev' }, ); + return { + content: { + message: 'Resource access removed from agent.', + success: res.remove_agent_resource_access?.success ?? false, + }, + }; } catch (error) { rethrowWithContext(error, 'remove agent resource access for monday platform agent'); } - return { - content: { - message: 'Resource access removed from agent.', - success: res!.remove_agent_resource_access?.success ?? false, - }, - }; } } } diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts index 664cdb86..62316cf5 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts @@ -48,7 +48,9 @@ WORKFLOW: USAGE EXAMPLES: - Add skill: { "action": "add", "agent_id": "7", "skill_id": "skill-abc-123" } -- Remove skill: { "action": "remove", "agent_id": "7", "skill_id": "skill-abc-123" }`; +- Remove skill: { "action": "remove", "agent_id": "7", "skill_id": "skill-abc-123" } + +NOTE: There is no list action for skills — the platform does not yet expose a query for listing an agent's attached skills.`; } getInputSchema() { diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts index 0706c370..e61ee6cd 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts @@ -61,63 +61,59 @@ USAGE EXAMPLES: input: ToolInputType, ): Promise> { if (input.action === 'activate') { - let activateRes: ActivateAgentMutation; try { - activateRes = await this.mondayApi.request( + const activateRes = await this.mondayApi.request( activateAgentMutation, { id: input.agent_id } satisfies ActivateAgentMutationVariables, { versionOverride: 'dev' }, ); + return { + content: { + message: 'Agent activated.', + success: activateRes.activate_agent?.success ?? false, + }, + }; } catch (error) { rethrowWithContext(error, 'activate monday platform agent'); } - return { - content: { - message: 'Agent activated.', - success: activateRes!.activate_agent?.success ?? false, - }, - }; } else if (input.action === 'deactivate') { - let deactivateRes: DeactivateAgentMutation; try { - const variables: DeactivateAgentMutationVariables = { - id: input.agent_id, - inactive_reason: (input.inactive_reason as InactiveReason) ?? InactiveReason.DeactivatedByUser, - }; - deactivateRes = await this.mondayApi.request( + const deactivateRes = await this.mondayApi.request( deactivateAgentMutation, - variables, + { + id: input.agent_id, + inactive_reason: (input.inactive_reason as InactiveReason) ?? InactiveReason.DeactivatedByUser, + } satisfies DeactivateAgentMutationVariables, { versionOverride: 'dev' }, ); + return { + content: { + message: 'Agent deactivated.', + success: deactivateRes.deactivate_agent?.success ?? false, + }, + }; } catch (error) { rethrowWithContext(error, 'deactivate monday platform agent'); } - return { - content: { - message: 'Agent deactivated.', - success: deactivateRes!.deactivate_agent?.success ?? false, - }, - }; } else { - let runRes: RunAgentMutation; try { - runRes = await this.mondayApi.request( + const runRes = await this.mondayApi.request( runAgentMutation, { id: input.agent_id } satisfies RunAgentMutationVariables, { versionOverride: 'dev' }, ); + if (!runRes.run_agent) { + throw new Error('run_agent returned no data — the agent run may not have been enqueued'); + } + return { + content: { + message: 'Agent run enqueued.', + trigger_uuid: runRes.run_agent.trigger_uuid, + }, + }; } catch (error) { rethrowWithContext(error, 'run monday platform agent'); } - if (!runRes!.run_agent) { - throw new Error('run_agent returned no data — the agent run may not have been enqueued'); - } - return { - content: { - message: 'Agent run enqueued.', - trigger_uuid: runRes.run_agent.trigger_uuid, - }, - }; } } } From b798bbb8db9ecfcb73c8990a2b142d48aed3c610 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 19:55:24 +0300 Subject: [PATCH 21/28] feat(agent-toolkit): add create_agent_skill tool Co-Authored-By: Claude Sonnet 4.6 --- .../create-agent-skill-tool.test.ts | 85 +++++++++++++++++++ .../create-agent-skill-tool.ts | 81 ++++++++++++++++++ .../create-agent-skill.graphql.dev.ts | 11 +++ .../platform-api-tools/agents-tools/index.ts | 1 + .../core/tools/platform-api-tools/index.ts | 2 + .../generated/graphql.dev/graphql.ts | 23 +++++ 6 files changed, 203 insertions(+) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts new file mode 100644 index 00000000..a8a842ed --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts @@ -0,0 +1,85 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { CreateAgentSkillMutation } from 'src/monday-graphql/generated/graphql.dev/graphql'; + +describe('CreateAgentSkillTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + const mockSkill = { + id: 'skill-123', + name: 'Send Slack Message', + description: 'Sends a message to a Slack channel', + }; + + it('should create a skill and return the created skill', async () => { + mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); + + const result = await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nSend a message.', + description: 'Sends a message to a Slack channel', + }); + const parsed = parseToolResult(result); + + expect(parsed.skill.id).toBe('skill-123'); + expect(parsed.skill.name).toBe('Send Slack Message'); + }); + + it('should pass name, content, and description to the mutation', async () => { + mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); + + await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nSend a message.', + description: 'Sends a message to a Slack channel', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('createAgentSkill'), + { name: 'Send Slack Message', content: '## Instructions\nSend a message.', description: 'Sends a message to a Slack channel' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should create a skill without description when omitted', async () => { + mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); + + await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nSend a message.', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ description: undefined }), + expect.anything(), + ); + }); + + it('should throw when create_agent_skill returns null', async () => { + mocks.setResponseOnce({ create_agent_skill: null } as CreateAgentSkillMutation); + + const result = await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nSend a message.', + }); + + expect(result.content[0].text).toContain('create_agent_skill returned no data'); + }); + + it('should propagate API errors with operation context', async () => { + mocks.setError('Forbidden'); + + const result = await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nSend a message.', + }); + + expect(result.content[0].text).toContain('Failed to create monday platform agent skill'); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts new file mode 100644 index 00000000..707f4f44 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts @@ -0,0 +1,81 @@ +import { z } from 'zod'; +import { + CreateAgentSkillMutation, + CreateAgentSkillMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { createAgentSkillMutation } from './create-agent-skill.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const createAgentSkillToolSchema = { + name: z.string().trim().min(1).describe('Display name of the skill.'), + content: z + .string() + .trim() + .min(1) + .describe('Markdown instructions defining what the skill does and how to execute it.'), + description: z + .string() + .trim() + .min(1) + .optional() + .describe('Short description of the skill shown in the catalog.'), +}; + +export class CreateAgentSkillTool extends BaseMondayApiTool { + name = 'create_agent_skill'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Create monday Platform Agent Skill', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Create a new custom skill in the account's skill catalog. + +Skills define reusable capabilities that agents can execute (e.g. "send a Slack message", "query a database"). Once created, the skill appears in the catalog and can be attached to any agent via manage_agent_skills. + +WORKFLOW: +1. Call this tool to create the skill. Note the returned id. +2. Call manage_agent_skills with action:"add" and the returned id to attach it to an agent. +3. Call get_agent_catalog with type:"skills" to verify the skill appears in the catalog. + +USAGE EXAMPLE: +- { "name": "Send Slack Message", "content": "## Instructions\\nSend a message to the specified Slack channel using the provided text.", "description": "Sends a message to a Slack channel" }`; + } + + getInputSchema() { + return createAgentSkillToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + try { + const variables: CreateAgentSkillMutationVariables = { + name: input.name, + content: input.content, + description: input.description, + }; + const res = await this.mondayApi.request( + createAgentSkillMutation, + variables, + { versionOverride: 'dev' }, + ); + if (!res.create_agent_skill) { + throw new Error('create_agent_skill returned no data'); + } + return { + content: { + message: 'Skill created. Use the returned id with manage_agent_skills to attach it to an agent.', + skill: res.create_agent_skill, + }, + }; + } catch (error) { + rethrowWithContext(error, 'create monday platform agent skill'); + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts new file mode 100644 index 00000000..7f145120 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts @@ -0,0 +1,11 @@ +import { gql } from 'graphql-request'; + +export const createAgentSkillMutation = gql` + mutation createAgentSkill($name: String!, $content: String!, $description: String) { + create_agent_skill(name: $name, content: $content, description: $description) { + id + name + description + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index 7fdcf4d9..3b1042e9 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -4,6 +4,7 @@ export * from './delete-agent/delete-agent-tool'; export * from './get-agent-catalog/get-agent-catalog-tool'; export * from './manage-agent-triggers/manage-agent-triggers-tool'; export * from './manage-agent-skills/manage-agent-skills-tool'; +export * from './create-agent-skill/create-agent-skill-tool'; export * from './update-agent/update-agent-tool'; export * from './manage-agent-state/manage-agent-state-tool'; export * from './manage-agent-knowledge/manage-agent-knowledge-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 4846b1e5..1c4f1e98 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -74,6 +74,7 @@ import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; import { ManageAgentKnowledgeTool } from './agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool'; +import { CreateAgentSkillTool } from './agents-tools/create-agent-skill/create-agent-skill-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -153,6 +154,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ UpdateAgentTool, ManageAgentStateTool, ManageAgentKnowledgeTool, + CreateAgentSkillTool, ]; export * from './all-monday-api-tool'; diff --git a/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts b/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts index abb60a6d..21d4717b 100644 --- a/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts +++ b/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/graphql.ts @@ -8620,6 +8620,8 @@ export type Mutation = { convert_board_to_project?: Maybe; /** Create an agent from a prompt. AI generates the profile, goal, and plan — expect ~20s for completion. created_at and updated_at are null in the response; use the agent query to fetch them. */ create_agent?: Maybe; + /** Create a new skill for the account. The skill will appear in agent_skills_catalog and can be attached to any agent via add_skill_to_agent. */ + create_agent_skill?: Maybe; /** Creates a new app with the specified configuration. */ create_app?: Maybe; /** Create a new app feature. */ @@ -9416,6 +9418,14 @@ export type MutationCreate_AgentArgs = { }; +/** Root mutation type for the Dependencies service */ +export type MutationCreate_Agent_SkillArgs = { + content: Scalars['String']['input']; + description?: InputMaybe; + name: Scalars['String']['input']; +}; + + /** Root mutation type for the Dependencies service */ export type MutationCreate_AppArgs = { input: CreateAppInput; @@ -13656,6 +13666,8 @@ export type SearchDocResults = { /** Board data stored in the search index. */ export type SearchIndexedBoard = { __typename?: 'SearchIndexedBoard'; + /** ID of the user who created this board. */ + creator_id?: Maybe; /** Board description. */ description?: Maybe; /** Board ID. */ @@ -13726,6 +13738,7 @@ export type SearchNamespace = { /** Per-entity search namespace. Each field searches a single entity type. */ export type SearchNamespaceBoardsArgs = { + board_ids?: InputMaybe>; date_range?: InputMaybe; limit?: InputMaybe; query: Scalars['String']['input']; @@ -16743,6 +16756,15 @@ export type WorldClockValue = ColumnValue & { value?: Maybe; }; +export type CreateAgentSkillMutationVariables = Exact<{ + name: Scalars['String']['input']; + content: Scalars['String']['input']; + description?: InputMaybe; +}>; + + +export type CreateAgentSkillMutation = { __typename?: 'Mutation', create_agent_skill?: { __typename?: 'AgentSkillCatalogEntry', id?: string | null, name?: string | null, description?: string | null } | null }; + export type GetAgentTriggersCatalogQueryVariables = Exact<{ block_reference_ids?: InputMaybe | Scalars['ID']['input']>; }>; @@ -16953,6 +16975,7 @@ export type CreateFormSubmissionMutationVariables = Exact<{ export type CreateFormSubmissionMutation = { __typename?: 'Mutation', create_form_submission?: { __typename?: 'FormSubmissionResult', id: string } | null }; export const AgentFieldsFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"kind"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"profile"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"role_description"}},{"kind":"Field","name":{"kind":"Name","value":"avatar_url"}},{"kind":"Field","name":{"kind":"Name","value":"background_color"}}]}},{"kind":"Field","name":{"kind":"Name","value":"goal"}},{"kind":"Field","name":{"kind":"Name","value":"plan"}},{"kind":"Field","name":{"kind":"Name","value":"user_prompt"}},{"kind":"Field","name":{"kind":"Name","value":"version_id"}},{"kind":"Field","name":{"kind":"Name","value":"created_at"}},{"kind":"Field","name":{"kind":"Name","value":"updated_at"}}]}}]} as unknown as DocumentNode; +export const CreateAgentSkillDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"mutation","name":{"kind":"Name","value":"createAgentSkill"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"name"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"content"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}},{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"description"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"create_agent_skill"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"name"},"value":{"kind":"Variable","name":{"kind":"Name","value":"name"}}},{"kind":"Argument","name":{"kind":"Name","value":"content"},"value":{"kind":"Variable","name":{"kind":"Name","value":"content"}}},{"kind":"Argument","name":{"kind":"Name","value":"description"},"value":{"kind":"Variable","name":{"kind":"Name","value":"description"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode; export const GetAgentTriggersCatalogDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentTriggersCatalog"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"block_reference_ids"}},"type":{"kind":"ListType","type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_triggers_catalog"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"block_reference_ids"},"value":{"kind":"Variable","name":{"kind":"Name","value":"block_reference_ids"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"block_reference_id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"field_schemas"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field_key"}},{"kind":"Field","name":{"kind":"Name","value":"value_schema"}}]}},{"kind":"Field","name":{"kind":"Name","value":"required_fields"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"field_key"}},{"kind":"Field","name":{"kind":"Name","value":"depends_on"}},{"kind":"Field","name":{"kind":"Name","value":"optional"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetAgentSkillsCatalogDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentSkillsCatalog"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_skills_catalog"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}}]}}]}}]} as unknown as DocumentNode; export const GetAgentKnowledgeDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"getAgentKnowledge"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"ID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agent_knowledge"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resources"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resource_id"}},{"kind":"Field","name":{"kind":"Name","value":"scope_type"}},{"kind":"Field","name":{"kind":"Name","value":"permission_type"}}]}},{"kind":"Field","name":{"kind":"Name","value":"files"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"file_name"}},{"kind":"Field","name":{"kind":"Name","value":"file_type"}}]}}]}}]}}]} as unknown as DocumentNode; From ad43617b27e5e0f7adff180e3c493c735bacef99 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 19:55:32 +0300 Subject: [PATCH 22/28] chore(agent-toolkit): bump version to 5.11.1 Co-Authored-By: Claude Sonnet 4.6 --- packages/agent-toolkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json index 5116733f..d801c45e 100644 --- a/packages/agent-toolkit/package.json +++ b/packages/agent-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@mondaydotcomorg/agent-toolkit", - "version": "5.11.0", + "version": "5.11.1", "description": "monday.com agent toolkit", From 57346f2dcbe8765d99652735fe9dc36482e01101 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 20:03:03 +0300 Subject: [PATCH 23/28] chore(agent-toolkit): revert version to 5.11.0 Co-Authored-By: Claude Sonnet 4.6 --- packages/agent-toolkit/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/agent-toolkit/package.json b/packages/agent-toolkit/package.json index d801c45e..5116733f 100644 --- a/packages/agent-toolkit/package.json +++ b/packages/agent-toolkit/package.json @@ -1,6 +1,6 @@ { "name": "@mondaydotcomorg/agent-toolkit", - "version": "5.11.1", + "version": "5.11.0", "description": "monday.com agent toolkit", From d0dabc99e0fe9a9362e452be49df760b4f6c7201 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 20:06:47 +0300 Subject: [PATCH 24/28] refactor(agent-toolkit): fold create_agent_skill into manage_agent_skills tool Co-Authored-By: Claude Sonnet 4.6 --- .../create-agent-skill-tool.test.ts | 85 ----------- .../create-agent-skill-tool.ts | 81 ----------- .../create-agent-skill.graphql.dev.ts | 11 -- .../platform-api-tools/agents-tools/index.ts | 1 - .../manage-agent-skills-tool.test.ts | 133 +++++++++++++----- .../manage-agent-skills-tool.ts | 111 +++++++++++---- .../manage-agent-skills.graphql.dev.ts | 10 ++ .../core/tools/platform-api-tools/index.ts | 2 - 8 files changed, 188 insertions(+), 246 deletions(-) delete mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts delete mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts delete mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts deleted file mode 100644 index a8a842ed..00000000 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { CreateAgentSkillMutation } from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('CreateAgentSkillTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - const mockSkill = { - id: 'skill-123', - name: 'Send Slack Message', - description: 'Sends a message to a Slack channel', - }; - - it('should create a skill and return the created skill', async () => { - mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); - - const result = await callToolByNameRawAsync('create_agent_skill', { - name: 'Send Slack Message', - content: '## Instructions\nSend a message.', - description: 'Sends a message to a Slack channel', - }); - const parsed = parseToolResult(result); - - expect(parsed.skill.id).toBe('skill-123'); - expect(parsed.skill.name).toBe('Send Slack Message'); - }); - - it('should pass name, content, and description to the mutation', async () => { - mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); - - await callToolByNameRawAsync('create_agent_skill', { - name: 'Send Slack Message', - content: '## Instructions\nSend a message.', - description: 'Sends a message to a Slack channel', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('createAgentSkill'), - { name: 'Send Slack Message', content: '## Instructions\nSend a message.', description: 'Sends a message to a Slack channel' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should create a skill without description when omitted', async () => { - mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); - - await callToolByNameRawAsync('create_agent_skill', { - name: 'Send Slack Message', - content: '## Instructions\nSend a message.', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ description: undefined }), - expect.anything(), - ); - }); - - it('should throw when create_agent_skill returns null', async () => { - mocks.setResponseOnce({ create_agent_skill: null } as CreateAgentSkillMutation); - - const result = await callToolByNameRawAsync('create_agent_skill', { - name: 'Send Slack Message', - content: '## Instructions\nSend a message.', - }); - - expect(result.content[0].text).toContain('create_agent_skill returned no data'); - }); - - it('should propagate API errors with operation context', async () => { - mocks.setError('Forbidden'); - - const result = await callToolByNameRawAsync('create_agent_skill', { - name: 'Send Slack Message', - content: '## Instructions\nSend a message.', - }); - - expect(result.content[0].text).toContain('Failed to create monday platform agent skill'); - }); -}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts deleted file mode 100644 index 707f4f44..00000000 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { z } from 'zod'; -import { - CreateAgentSkillMutation, - CreateAgentSkillMutationVariables, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { createAgentSkillMutation } from './create-agent-skill.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const createAgentSkillToolSchema = { - name: z.string().trim().min(1).describe('Display name of the skill.'), - content: z - .string() - .trim() - .min(1) - .describe('Markdown instructions defining what the skill does and how to execute it.'), - description: z - .string() - .trim() - .min(1) - .optional() - .describe('Short description of the skill shown in the catalog.'), -}; - -export class CreateAgentSkillTool extends BaseMondayApiTool { - name = 'create_agent_skill'; - type = ToolType.WRITE; - annotations = createMondayApiAnnotations({ - title: 'Create monday Platform Agent Skill', - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - }); - - getDescription(): string { - return `Create a new custom skill in the account's skill catalog. - -Skills define reusable capabilities that agents can execute (e.g. "send a Slack message", "query a database"). Once created, the skill appears in the catalog and can be attached to any agent via manage_agent_skills. - -WORKFLOW: -1. Call this tool to create the skill. Note the returned id. -2. Call manage_agent_skills with action:"add" and the returned id to attach it to an agent. -3. Call get_agent_catalog with type:"skills" to verify the skill appears in the catalog. - -USAGE EXAMPLE: -- { "name": "Send Slack Message", "content": "## Instructions\\nSend a message to the specified Slack channel using the provided text.", "description": "Sends a message to a Slack channel" }`; - } - - getInputSchema() { - return createAgentSkillToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - try { - const variables: CreateAgentSkillMutationVariables = { - name: input.name, - content: input.content, - description: input.description, - }; - const res = await this.mondayApi.request( - createAgentSkillMutation, - variables, - { versionOverride: 'dev' }, - ); - if (!res.create_agent_skill) { - throw new Error('create_agent_skill returned no data'); - } - return { - content: { - message: 'Skill created. Use the returned id with manage_agent_skills to attach it to an agent.', - skill: res.create_agent_skill, - }, - }; - } catch (error) { - rethrowWithContext(error, 'create monday platform agent skill'); - } - } -} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts deleted file mode 100644 index 7f145120..00000000 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { gql } from 'graphql-request'; - -export const createAgentSkillMutation = gql` - mutation createAgentSkill($name: String!, $content: String!, $description: String) { - create_agent_skill(name: $name, content: $content, description: $description) { - id - name - description - } - } -`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index 3b1042e9..7fdcf4d9 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -4,7 +4,6 @@ export * from './delete-agent/delete-agent-tool'; export * from './get-agent-catalog/get-agent-catalog-tool'; export * from './manage-agent-triggers/manage-agent-triggers-tool'; export * from './manage-agent-skills/manage-agent-skills-tool'; -export * from './create-agent-skill/create-agent-skill-tool'; export * from './update-agent/update-agent-tool'; export * from './manage-agent-state/manage-agent-state-tool'; export * from './manage-agent-knowledge/manage-agent-knowledge-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts index aa502459..0ff2ccec 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts @@ -1,6 +1,7 @@ import { MondayAgentToolkit } from 'src/mcp/toolkit'; import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; import { + CreateAgentSkillMutation, AddSkillToAgentMutation, RemoveSkillFromAgentMutation, } from 'src/monday-graphql/generated/graphql.dev/graphql'; @@ -13,64 +14,101 @@ describe('ManageAgentSkillsTool', () => { jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); }); - it('should add a skill to an agent', async () => { - mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); + const mockCreatedSkill = { id: 'skill-123', name: 'Send Slack Message', description: 'Posts to Slack' }; + + // create + it('should create a skill and return it', async () => { + mocks.setResponseOnce({ create_agent_skill: mockCreatedSkill } as CreateAgentSkillMutation); const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'add', - agent_id: '7', - skill_id: 'skill-abc-123', + action: 'create', + name: 'Send Slack Message', + content: '## Instructions\nPost a message.', }); const parsed = parseToolResult(result); - expect(parsed.success).toBe(true); + expect(parsed.skill.id).toBe('skill-123'); }); - it('should remove a skill from an agent', async () => { - mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + it('should pass name, content, and description when creating', async () => { + mocks.setResponseOnce({ create_agent_skill: mockCreatedSkill } as CreateAgentSkillMutation); + + await callToolByNameRawAsync('manage_agent_skills', { + action: 'create', + name: 'Send Slack Message', + content: '## Instructions\nPost a message.', + description: 'Posts to Slack', + }); + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('createAgentSkill'), + { name: 'Send Slack Message', content: '## Instructions\nPost a message.', description: 'Posts to Slack' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should reject create without name', async () => { const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'remove', - agent_id: '7', - skill_id: 'skill-abc-123', + action: 'create', + content: '## Instructions', }); - const parsed = parseToolResult(result); + expect(result.content[0].text).toContain('name and content are required'); + }); - expect(parsed.success).toBe(true); + it('should throw when create_agent_skill returns null', async () => { + mocks.setResponseOnce({ create_agent_skill: null } as CreateAgentSkillMutation); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'create', + name: 'Send Slack Message', + content: '## Instructions', + }); + + expect(result.content[0].text).toContain('create_agent_skill returned no data'); }); - it('should pass correct variables and versionOverride when adding skill', async () => { + it('should propagate errors with operation context for create', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'create', + name: 'Send Slack Message', + content: '## Instructions', + }); + + expect(result.content[0].text).toContain('Failed to create monday platform agent skill'); + }); + + // add + it('should add a skill to an agent', async () => { mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); - await callToolByNameRawAsync('manage_agent_skills', { + const result = await callToolByNameRawAsync('manage_agent_skills', { action: 'add', agent_id: '7', skill_id: 'skill-abc-123', }); - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('addSkillToAgent'), - { agent_id: '7', skill_id: 'skill-abc-123' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); + expect(parseToolResult(result).success).toBe(true); }); - it('should pass correct variables and versionOverride when removing skill', async () => { - mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + it('should pass correct variables and versionOverride when adding skill', async () => { + mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); - await callToolByNameRawAsync('manage_agent_skills', { - action: 'remove', - agent_id: '7', - skill_id: 'skill-abc-123', - }); + await callToolByNameRawAsync('manage_agent_skills', { action: 'add', agent_id: '7', skill_id: 'skill-abc-123' }); expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('removeSkillFromAgent'), + expect.stringContaining('addSkillToAgent'), { agent_id: '7', skill_id: 'skill-abc-123' }, expect.objectContaining({ versionOverride: 'dev' }), ); }); + it('should reject add without agent_id', async () => { + const result = await callToolByNameRawAsync('manage_agent_skills', { action: 'add', skill_id: 'skill-abc-123' }); + expect(result.content[0].text).toContain('agent_id and skill_id are required'); + }); + it('should propagate errors with operation context for add', async () => { mocks.setError('API error'); @@ -83,8 +121,19 @@ describe('ManageAgentSkillsTool', () => { expect(result.content[0].text).toContain('Failed to add skill'); }); - it('should propagate errors with operation context for remove', async () => { - mocks.setError('API error'); + it('should return success:false when add_skill_to_agent is null', async () => { + mocks.setResponseOnce({ add_skill_to_agent: null } as AddSkillToAgentMutation); + const result = await callToolByNameRawAsync('manage_agent_skills', { + action: 'add', + agent_id: '7', + skill_id: 'skill-abc-123', + }); + expect(parseToolResult(result).success).toBe(false); + }); + + // remove + it('should remove a skill from an agent', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); const result = await callToolByNameRawAsync('manage_agent_skills', { action: 'remove', @@ -92,17 +141,31 @@ describe('ManageAgentSkillsTool', () => { skill_id: 'skill-abc-123', }); - expect(result.content[0].text).toContain('Failed to remove skill'); + expect(parseToolResult(result).success).toBe(true); }); - it('should return success:false when add_skill_to_agent is null', async () => { - mocks.setResponseOnce({ add_skill_to_agent: null } as AddSkillToAgentMutation); + it('should pass correct variables and versionOverride when removing skill', async () => { + mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); + + await callToolByNameRawAsync('manage_agent_skills', { action: 'remove', agent_id: '7', skill_id: 'skill-abc-123' }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('removeSkillFromAgent'), + { agent_id: '7', skill_id: 'skill-abc-123' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should propagate errors with operation context for remove', async () => { + mocks.setError('API error'); + const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'add', + action: 'remove', agent_id: '7', skill_id: 'skill-abc-123', }); - expect(parseToolResult(result).success).toBe(false); + + expect(result.content[0].text).toContain('Failed to remove skill'); }); it('should return success:false when remove_skill_from_agent is null', async () => { diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts index 62316cf5..38759317 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts @@ -1,11 +1,14 @@ import { z } from 'zod'; import { + CreateAgentSkillMutation, + CreateAgentSkillMutationVariables, AddSkillToAgentMutation, AddSkillToAgentMutationVariables, RemoveSkillFromAgentMutation, RemoveSkillFromAgentMutationVariables, } from '../../../../../monday-graphql/generated/graphql.dev/graphql'; import { + createAgentSkillMutation, addSkillToAgentMutation, removeSkillFromAgentMutation, } from './manage-agent-skills.graphql.dev'; @@ -15,13 +18,36 @@ import { rethrowWithContext } from '../../../../../utils'; export const manageAgentSkillsToolSchema = { action: z - .enum(['add', 'remove']) - .describe('"add" attaches a skill. "remove" detaches a skill.'), - agent_id: z.string().describe('Unique identifier of the agent'), + .enum(['create', 'add', 'remove']) + .describe('"create" makes a new custom skill in the account catalog. "add" attaches an existing skill to an agent. "remove" detaches a skill from an agent.'), + // create only + name: z.string().trim().min(1).optional().describe('Required for action:create. Display name of the new skill.'), + content: z + .string() + .trim() + .min(1) + .optional() + .describe('Required for action:create. Markdown instructions defining what the skill does and how to execute it.'), + description: z + .string() + .trim() + .min(1) + .optional() + .describe('Optional for action:create. Short description of the skill shown in the catalog.'), + // add, remove only + agent_id: z + .string() + .trim() + .min(1) + .optional() + .describe('Required for action:add and action:remove. Unique identifier of the agent.'), skill_id: z .string() + .trim() + .min(1) + .optional() .describe( - 'The skill ID from get_agent_catalog (type:skills). Never guess — look it up.', + 'Required for action:add and action:remove. The skill ID from get_agent_catalog (type:skills) or the id returned by action:create. Never guess or invent a skill ID.', ), }; @@ -36,21 +62,27 @@ export class ManageAgentSkillsTool extends BaseMondayApiTool, ): Promise> { - if (input.action === 'add') { + if (input.action === 'create') { + if (!input.name || !input.content) { + throw new Error('name and content are required for action:create'); + } try { - const variables: AddSkillToAgentMutationVariables = { - agent_id: input.agent_id, - skill_id: input.skill_id, + const variables: CreateAgentSkillMutationVariables = { + name: input.name, + content: input.content, + description: input.description, }; - const res = await this.mondayApi.request( - addSkillToAgentMutation, + const res = await this.mondayApi.request( + createAgentSkillMutation, variables, { versionOverride: 'dev' }, ); + if (!res.create_agent_skill) { + throw new Error('create_agent_skill returned no data'); + } return { content: { - message: 'Skill added to agent.', - success: res.add_skill_to_agent?.success ?? false, + message: 'Skill created. Use the returned id with action:add to attach it to an agent.', + skill: res.create_agent_skill, }, }; + } catch (error) { + rethrowWithContext(error, 'create monday platform agent skill'); + } + } + + if (!input.agent_id || !input.skill_id) { + throw new Error('agent_id and skill_id are required for action:add and action:remove'); + } + + if (input.action === 'add') { + try { + const variables: AddSkillToAgentMutationVariables = { agent_id: input.agent_id, skill_id: input.skill_id }; + const res = await this.mondayApi.request( + addSkillToAgentMutation, + variables, + { versionOverride: 'dev' }, + ); + return { content: { message: 'Skill added to agent.', success: res.add_skill_to_agent?.success ?? false } }; } catch (error) { rethrowWithContext(error, 'add skill to monday platform agent'); } } else { try { - const variables: RemoveSkillFromAgentMutationVariables = { - agent_id: input.agent_id, - skill_id: input.skill_id, - }; + const variables: RemoveSkillFromAgentMutationVariables = { agent_id: input.agent_id, skill_id: input.skill_id }; const res = await this.mondayApi.request( removeSkillFromAgentMutation, variables, { versionOverride: 'dev' }, ); - return { - content: { - message: 'Skill removed from agent.', - success: res.remove_skill_from_agent?.success ?? false, - }, - }; + return { content: { message: 'Skill removed from agent.', success: res.remove_skill_from_agent?.success ?? false } }; } catch (error) { rethrowWithContext(error, 'remove skill from monday platform agent'); } diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts index d58f3fee..07bc51f6 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts @@ -1,5 +1,15 @@ import { gql } from 'graphql-request'; +export const createAgentSkillMutation = gql` + mutation createAgentSkill($name: String!, $content: String!, $description: String) { + create_agent_skill(name: $name, content: $content, description: $description) { + id + name + description + } + } +`; + export const addSkillToAgentMutation = gql` mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) { add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) { diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 1c4f1e98..4846b1e5 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -74,7 +74,6 @@ import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; import { ManageAgentKnowledgeTool } from './agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool'; -import { CreateAgentSkillTool } from './agents-tools/create-agent-skill/create-agent-skill-tool'; export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteItemTool, @@ -154,7 +153,6 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ UpdateAgentTool, ManageAgentStateTool, ManageAgentKnowledgeTool, - CreateAgentSkillTool, ]; export * from './all-monday-api-tool'; From 560ea82c0dc16daaf94d82de7af075c9062c9f1c Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 22:23:41 +0300 Subject: [PATCH 25/28] chore: remove design docs from branch (keep locally) Co-Authored-By: Claude Sonnet 4.6 --- .../plans/2026-05-13-agent-tools-expansion.md | 2185 ----------------- ...2026-05-13-agent-tools-expansion-design.md | 280 --- 2 files changed, 2465 deletions(-) delete mode 100644 docs/superpowers/plans/2026-05-13-agent-tools-expansion.md delete mode 100644 docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md diff --git a/docs/superpowers/plans/2026-05-13-agent-tools-expansion.md b/docs/superpowers/plans/2026-05-13-agent-tools-expansion.md deleted file mode 100644 index b2e9540e..00000000 --- a/docs/superpowers/plans/2026-05-13-agent-tools-expansion.md +++ /dev/null @@ -1,2185 +0,0 @@ -# Agent Tools Expansion Implementation Plan - -> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking. - -**Goal:** Add 6 new MCP tools to the agent-toolkit that cover the full agents subgraph surface — catalog discovery, trigger management, skill management, agent updates, state management, and knowledge/resource access. - -**Architecture:** Each tool lives in its own folder under `src/core/tools/platform-api-tools/agents-tools/`, co-located with a `.graphql.dev.ts` file containing its GraphQL operations. All tools extend `BaseMondayApiTool`, use `versionOverride: 'dev'`, and follow the Zod + `rethrowWithContext` pattern established by the existing agent tools. Tool descriptions encode the catalog-first workflows so agents know which tools to call before acting. - -**Tech Stack:** TypeScript, graphql-request (gql tag), Zod, Jest, graphql-codegen (`npm run fetch:generate dev` in `packages/agent-toolkit`) - ---- - -## File Map - -**Modify:** -- `src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts` — export `agentFieldsFragment` (currently unexported) -- `src/core/tools/platform-api-tools/agents-tools/index.ts` — add 6 new exports -- `src/core/tools/platform-api-tools/index.ts` — add 6 new imports + registrations - -**Create:** -- `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts` -- `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts` -- `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts` -- `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts` -- `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts` -- `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts` -- `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts` - ---- - -## Task 1: Export agentFieldsFragment from shared - -The `update_agent` mutation returns a full `Agent` and needs the shared fragment. Currently `agentFieldsFragment` is a local `const` — make it `export const` so the update-agent graphql file can import it. - -**Files:** -- Modify: `src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts` - -- [ ] **Step 1: Change `const` to `export const` on the fragment** - -In `src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts`, change line 3: - -```typescript -// Before -const agentFieldsFragment = gql` -// After -export const agentFieldsFragment = gql` -``` - -- [ ] **Step 2: Verify nothing broke** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools --passWithNoTests 2>&1 | tail -5 -``` - -Expected: all existing agent tests pass (3 test suites). - -- [ ] **Step 3: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/shared/agents.graphql.dev.ts -git commit -m "refactor(agent-toolkit): export agentFieldsFragment for reuse" -``` - ---- - -## Task 2: Write all GraphQL operation files - -Write all 6 `.graphql.dev.ts` files before running codegen so types are generated in a single pass. - -**Files:** All 6 new `*.graphql.dev.ts` files. - -- [ ] **Step 1: Create `get-agent-catalog.graphql.dev.ts`** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog.graphql.dev.ts -import { gql } from 'graphql-request'; - -export const getAgentTriggersCatalogQuery = gql` - query getAgentTriggersCatalog($block_reference_ids: [ID!]) { - agent_triggers_catalog(block_reference_ids: $block_reference_ids) { - block_reference_id - name - description - field_schemas { - field_key - value_schema - } - required_fields { - field_key - depends_on - optional - } - } - } -`; - -export const getAgentSkillsCatalogQuery = gql` - query getAgentSkillsCatalog { - agent_skills_catalog { - id - name - description - } - } -`; -``` - -- [ ] **Step 2: Create `manage-agent-triggers.graphql.dev.ts`** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers.graphql.dev.ts -import { gql } from 'graphql-request'; - -export const getAgentActiveTriggersQuery = gql` - query getAgentActiveTriggers($agent_id: ID!) { - agent_active_triggers(agent_id: $agent_id) { - node_id - block_reference_id - name - description - field_summary - } - } -`; - -export const addTriggerToAgentMutation = gql` - mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) { - add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) { - success - } - } -`; - -export const removeTriggerFromAgentMutation = gql` - mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) { - remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) { - success - } - } -`; -``` - -- [ ] **Step 3: Create `manage-agent-skills.graphql.dev.ts`** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts -import { gql } from 'graphql-request'; - -export const addSkillToAgentMutation = gql` - mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) { - add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) { - success - } - } -`; - -export const removeSkillFromAgentMutation = gql` - mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) { - remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) { - success - } - } -`; -``` - -- [ ] **Step 4: Create `update-agent.graphql.dev.ts`** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent.graphql.dev.ts -import { gql } from 'graphql-request'; -import { agentFieldsFragment } from '../shared/agents.graphql.dev'; - -export const updateAgentMutation = gql` - ${agentFieldsFragment} - - mutation updateAgent($id: ID!, $input: UpdateAgentInput!) { - update_agent(id: $id, input: $input) { - ...AgentFields - } - } -`; -``` - -- [ ] **Step 5: Create `manage-agent-state.graphql.dev.ts`** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state.graphql.dev.ts -import { gql } from 'graphql-request'; - -export const activateAgentMutation = gql` - mutation activateAgent($id: ID!) { - activate_agent(id: $id) { - success - } - } -`; - -export const deactivateAgentMutation = gql` - mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) { - deactivate_agent(id: $id, inactive_reason: $inactive_reason) { - success - } - } -`; - -export const runAgentMutation = gql` - mutation runAgent($id: ID!) { - run_agent(id: $id) { - trigger_uuid - } - } -`; -``` - -- [ ] **Step 6: Create `manage-agent-knowledge.graphql.dev.ts`** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge.graphql.dev.ts -import { gql } from 'graphql-request'; - -export const getAgentKnowledgeQuery = gql` - query getAgentKnowledge($id: ID!) { - agent_knowledge(id: $id) { - resources { - resource_id - scope_type - permission_type - } - files { - id - file_name - file_type - } - } - } -`; - -export const addAgentResourceAccessMutation = gql` - mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) { - add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) { - success - } - } -`; - -export const removeAgentResourceAccessMutation = gql` - mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) { - remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) { - success - } - } -`; - -export const updateAgentResourceAccessMutation = gql` - mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) { - update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) { - success - } - } -`; -``` - -- [ ] **Step 7: Commit all GraphQL files** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git commit -m "feat(agent-toolkit): add GraphQL operations for 6 new agent tools" -``` - ---- - -## Task 3: Run codegen - -Generate TypeScript types from the new GraphQL operations. - -**Files:** Auto-generated — `src/monday-graphql/generated/graphql.dev/graphql.ts` - -- [ ] **Step 1: Run codegen for the dev schema** - -```bash -cd packages/agent-toolkit && npm run fetch:generate dev -``` - -Expected: exits 0, no errors. The file `src/monday-graphql/generated/graphql.dev/graphql.ts` will be updated with new types including `GetAgentTriggersCatalogQuery`, `GetAgentSkillsCatalogQuery`, `GetAgentActiveTriggersQuery`, `GetAgentActiveTriggersQueryVariables`, `AddTriggerToAgentMutation`, `AddTriggerToAgentMutationVariables`, `RemoveTriggerFromAgentMutation`, `RemoveTriggerFromAgentMutationVariables`, `AddSkillToAgentMutation`, `AddSkillToAgentMutationVariables`, `RemoveSkillFromAgentMutation`, `RemoveSkillFromAgentMutationVariables`, `UpdateAgentMutation`, `UpdateAgentMutationVariables`, `ActivateAgentMutation`, `ActivateAgentMutationVariables`, `DeactivateAgentMutation`, `DeactivateAgentMutationVariables`, `RunAgentMutation`, `RunAgentMutationVariables`, `GetAgentKnowledgeQuery`, `GetAgentKnowledgeQueryVariables`, `AddAgentResourceAccessMutation`, `AddAgentResourceAccessMutationVariables`, `RemoveAgentResourceAccessMutation`, `RemoveAgentResourceAccessMutationVariables`, `UpdateAgentResourceAccessMutation`, `UpdateAgentResourceAccessMutationVariables`. - -- [ ] **Step 2: Verify types exist** - -```bash -grep -c "GetAgentTriggersCatalogQuery\|GetAgentSkillsCatalogQuery\|AddTriggerToAgentMutation\|AddSkillToAgentMutation\|UpdateAgentMutation\|ActivateAgentMutation\|GetAgentKnowledgeQuery\|AddAgentResourceAccessMutation" src/monday-graphql/generated/graphql.dev/graphql.ts -``` - -Expected: a number greater than 0 for each type (at least 8 matches total). - -- [ ] **Step 3: Commit generated types** - -```bash -git add src/monday-graphql/generated/graphql.dev/graphql.ts src/monday-graphql/schema.dev.graphql -git commit -m "chore(agent-toolkit): regenerate dev graphql types for new agent operations" -``` - ---- - -## Task 4: `get_agent_catalog` tool - -**Files:** -- Create: `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts` -- Create: `src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts` -- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` -- Modify: `src/core/tools/platform-api-tools/index.ts` - -- [ ] **Step 1: Write the failing test** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.test.ts -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { GetAgentTriggersCatalogQuery, GetAgentSkillsCatalogQuery } from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('GetAgentCatalogTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - const mockTrigger = { - block_reference_id: 'status-change-ref', - name: 'Status Change', - description: 'Fires when a status column changes', - field_schemas: [{ field_key: 'board_id', value_schema: 'The ID of the board to watch' }], - required_fields: [{ field_key: 'board_id', depends_on: [], optional: false }], - }; - - const mockSkill = { - id: 'skill-1', - name: 'Board Manager', - description: 'Manages boards and items', - }; - - it('should return triggers catalog when type is triggers', async () => { - mocks.setResponseOnce({ agent_triggers_catalog: [mockTrigger] } as GetAgentTriggersCatalogQuery); - - const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); - const parsed = parseToolResult(result); - - expect(parsed.count).toBe(1); - expect(parsed.triggers[0].block_reference_id).toBe('status-change-ref'); - }); - - it('should pass versionOverride dev when fetching triggers', async () => { - mocks.setResponseOnce({ agent_triggers_catalog: [] } as GetAgentTriggersCatalogQuery); - - await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('getAgentTriggersCatalog'), - expect.objectContaining({ block_reference_ids: undefined }), - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should pass block_reference_ids when provided', async () => { - mocks.setResponseOnce({ agent_triggers_catalog: [mockTrigger] } as GetAgentTriggersCatalogQuery); - - await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers', block_reference_ids: ['status-change-ref'] }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.anything(), - { block_reference_ids: ['status-change-ref'] }, - expect.anything(), - ); - }); - - it('should return skills catalog when type is skills', async () => { - mocks.setResponseOnce({ agent_skills_catalog: [mockSkill] } as GetAgentSkillsCatalogQuery); - - const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); - const parsed = parseToolResult(result); - - expect(parsed.count).toBe(1); - expect(parsed.skills[0].id).toBe('skill-1'); - }); - - it('should pass versionOverride dev when fetching skills', async () => { - mocks.setResponseOnce({ agent_skills_catalog: [] } as GetAgentSkillsCatalogQuery); - - await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('getAgentSkillsCatalog'), - expect.anything(), - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should return empty list with count 0 when no triggers exist', async () => { - mocks.setResponseOnce({ agent_triggers_catalog: [] } as GetAgentTriggersCatalogQuery); - - const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); - const parsed = parseToolResult(result); - - expect(parsed.count).toBe(0); - expect(parsed.triggers).toEqual([]); - }); - - it('should propagate errors when fetching triggers catalog', async () => { - mocks.setError('Unauthorized'); - - const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'triggers' }); - - expect(result.content[0].text).toContain('Failed to fetch monday platform agent triggers catalog'); - }); - - it('should propagate errors when fetching skills catalog', async () => { - mocks.setError('Unauthorized'); - - const result = await callToolByNameRawAsync('get_agent_catalog', { type: 'skills' }); - - expect(result.content[0].text).toContain('Failed to fetch monday platform agent skills catalog'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/get-agent-catalog --no-coverage 2>&1 | tail -10 -``` - -Expected: FAIL — `expect(toolNames).toContain('get_agent_catalog')` fails because the tool isn't registered yet. - -- [ ] **Step 3: Implement the tool** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts -import { z } from 'zod'; -import { - GetAgentTriggersCatalogQuery, - GetAgentTriggersCatalogQueryVariables, - GetAgentSkillsCatalogQuery, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { getAgentTriggersCatalogQuery, getAgentSkillsCatalogQuery } from './get-agent-catalog.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const getAgentCatalogToolSchema = { - type: z - .enum(['triggers', 'skills']) - .describe( - 'Which catalog to fetch. "triggers" returns available trigger types with block_reference_id, field_schemas, and required_fields — use before calling manage_agent_triggers with action:add. "skills" returns available skills with id — use before calling manage_agent_skills.', - ), - block_reference_ids: z - .array(z.string()) - .optional() - .describe( - 'Only applies when type is "triggers". Fetch specific entries by block_reference_id instead of the full catalog. Omit to return all trigger types.', - ), -}; - -export class GetAgentCatalogTool extends BaseMondayApiTool { - name = 'get_agent_catalog'; - type = ToolType.READ; - annotations = createMondayApiAnnotations({ - title: 'Get monday Platform Agent Catalog', - readOnlyHint: true, - destructiveHint: false, - idempotentHint: true, - }); - - getDescription(): string { - return `Fetch the account-wide catalog of available trigger types or skills for monday platform agents. - -ALWAYS call this tool first before adding a trigger or skill to an agent: -- type:"triggers" — returns entries with block_reference_id (required for manage_agent_triggers action:add), name, description, field_schemas (describes the field_values shape to pass when adding — e.g. { board_id: "" }), and required_fields (fields the user must supply before you can call add). -- type:"skills" — returns entries with id (required for manage_agent_skills), name, description. - -Never guess or invent a block_reference_id or skill id — always look them up here first. - -USAGE EXAMPLES: -- List all trigger types: { "type": "triggers" } -- Fetch a specific trigger type: { "type": "triggers", "block_reference_ids": ["some-block-ref-id"] } -- List all skills: { "type": "skills" }`; - } - - getInputSchema() { - return getAgentCatalogToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - if (input.type === 'triggers') { - try { - const variables: GetAgentTriggersCatalogQueryVariables = { - block_reference_ids: input.block_reference_ids ?? undefined, - }; - const res = await this.mondayApi.request( - getAgentTriggersCatalogQuery, - variables, - { versionOverride: 'dev' }, - ); - const catalog = res.agent_triggers_catalog ?? []; - return { - content: { - message: - 'Available trigger types for monday platform agents. Use block_reference_id and inspect field_schemas/required_fields before calling manage_agent_triggers with action:add.', - count: catalog.length, - triggers: catalog, - }, - }; - } catch (error) { - rethrowWithContext(error, 'fetch monday platform agent triggers catalog'); - } - } - - try { - const res = await this.mondayApi.request( - getAgentSkillsCatalogQuery, - {}, - { versionOverride: 'dev' }, - ); - const catalog = res.agent_skills_catalog ?? []; - return { - content: { - message: 'Available skills for monday platform agents. Use id when calling manage_agent_skills.', - count: catalog.length, - skills: catalog, - }, - }; - } catch (error) { - rethrowWithContext(error, 'fetch monday platform agent skills catalog'); - } - } -} -``` - -- [ ] **Step 4: Register the tool** - -In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: -```typescript -export * from './get-agent-catalog/get-agent-catalog-tool'; -``` - -In `src/core/tools/platform-api-tools/index.ts`, add the import after the existing agent imports (line ~70): -```typescript -import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; -``` - -And add to `allGraphqlApiTools` array after `DeleteAgentTool` (line ~143): -```typescript - GetAgentCatalogTool, -``` - -- [ ] **Step 5: Run tests to verify they pass** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/get-agent-catalog --no-coverage 2>&1 | tail -10 -``` - -Expected: PASS — all 8 tests green. - -- [ ] **Step 6: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git add src/core/tools/platform-api-tools/index.ts -git commit -m "feat(agent-toolkit): add get_agent_catalog tool" -``` - ---- - -## Task 5: `manage_agent_triggers` tool - -**Files:** -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts` -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts` -- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` -- Modify: `src/core/tools/platform-api-tools/index.ts` - -- [ ] **Step 1: Write the failing test** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.test.ts -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { - GetAgentActiveTriggersQuery, - AddTriggerToAgentMutation, - RemoveTriggerFromAgentMutation, -} from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('ManageAgentTriggersTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - const mockActiveTrigger = { - node_id: 'node-abc', - block_reference_id: 'status-change-ref', - name: 'Status Change', - description: 'Fires when a status column changes', - field_summary: 'board_id=42', - }; - - it('should list active triggers for an agent', async () => { - mocks.setResponseOnce({ agent_active_triggers: [mockActiveTrigger] } as GetAgentActiveTriggersQuery); - - const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '7' }); - const parsed = parseToolResult(result); - - expect(parsed.count).toBe(1); - expect(parsed.triggers[0].node_id).toBe('node-abc'); - }); - - it('should pass agent_id and versionOverride dev when listing', async () => { - mocks.setResponseOnce({ agent_active_triggers: [] } as GetAgentActiveTriggersQuery); - - await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '7' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('getAgentActiveTriggers'), - { agent_id: '7' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should add a trigger to an agent', async () => { - mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_triggers', { - action: 'add', - agent_id: '7', - block_reference_id: 'status-change-ref', - field_values: { board_id: '42' }, - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass block_reference_id and field_values when adding trigger', async () => { - mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); - - await callToolByNameRawAsync('manage_agent_triggers', { - action: 'add', - agent_id: '7', - block_reference_id: 'status-change-ref', - field_values: { board_id: '42' }, - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('addTriggerToAgent'), - { agent_id: '7', block_reference_id: 'status-change-ref', field_values: { board_id: '42' } }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should add a trigger without field_values when omitted', async () => { - mocks.setResponseOnce({ add_trigger_to_agent: { success: true } } as AddTriggerToAgentMutation); - - await callToolByNameRawAsync('manage_agent_triggers', { - action: 'add', - agent_id: '7', - block_reference_id: 'status-change-ref', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.anything(), - expect.objectContaining({ field_values: undefined }), - expect.anything(), - ); - }); - - it('should remove a trigger from an agent', async () => { - mocks.setResponseOnce({ remove_trigger_from_agent: { success: true } } as RemoveTriggerFromAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_triggers', { - action: 'remove', - agent_id: '7', - node_id: 'node-abc', - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass node_id and versionOverride dev when removing', async () => { - mocks.setResponseOnce({ remove_trigger_from_agent: { success: true } } as RemoveTriggerFromAgentMutation); - - await callToolByNameRawAsync('manage_agent_triggers', { action: 'remove', agent_id: '7', node_id: 'node-abc' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('removeTriggerFromAgent'), - { agent_id: '7', node_id: 'node-abc' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should reject add action without block_reference_id', async () => { - const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'add', agent_id: '7' }); - - expect(result.content[0].text).toContain('block_reference_id is required'); - }); - - it('should reject remove action without node_id', async () => { - const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'remove', agent_id: '7' }); - - expect(result.content[0].text).toContain('node_id is required'); - }); - - it('should propagate errors with operation context', async () => { - mocks.setError('Not found'); - - const result = await callToolByNameRawAsync('manage_agent_triggers', { action: 'list', agent_id: '999' }); - - expect(result.content[0].text).toContain('Failed to list active triggers'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers --no-coverage 2>&1 | tail -10 -``` - -Expected: FAIL — tool not registered yet. - -- [ ] **Step 3: Implement the tool** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers/manage-agent-triggers-tool.ts -import { z } from 'zod'; -import { - GetAgentActiveTriggersQuery, - GetAgentActiveTriggersQueryVariables, - AddTriggerToAgentMutation, - AddTriggerToAgentMutationVariables, - RemoveTriggerFromAgentMutation, - RemoveTriggerFromAgentMutationVariables, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { - getAgentActiveTriggersQuery, - addTriggerToAgentMutation, - removeTriggerFromAgentMutation, -} from './manage-agent-triggers.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const manageAgentTriggersToolSchema = { - action: z - .enum(['list', 'add', 'remove']) - .describe( - '"list" — returns all triggers currently attached to the agent (includes node_id needed for remove). "add" — attaches a new trigger by block_reference_id. "remove" — detaches a trigger by node_id.', - ), - agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), - block_reference_id: z - .string() - .trim() - .min(1) - .optional() - .describe( - 'Required for action:add. The block_reference_id from get_agent_catalog (type:triggers) identifying the trigger type to attach. Never guess this value — look it up in the catalog first.', - ), - field_values: z - .record(z.unknown()) - .optional() - .describe( - 'Required for action:add when the trigger type has required_fields. A key/value object whose shape is described by field_schemas in the get_agent_catalog response. Example: { "board_id": "12345" }. For scheduler fields pass the structured config directly; for selection fields (e.g. board picker) pass { "value": "", "label": "" }.', - ), - node_id: z - .string() - .trim() - .min(1) - .optional() - .describe( - 'Required for action:remove. The node_id of the trigger instance to remove — get it from action:list. Each trigger instance has a unique node_id even if the same trigger type is attached multiple times.', - ), -}; - -export class ManageAgentTriggersTool extends BaseMondayApiTool { - name = 'manage_agent_triggers'; - type = ToolType.WRITE; - annotations = createMondayApiAnnotations({ - title: 'Manage monday Platform Agent Triggers', - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - }); - - getDescription(): string { - return `List, add, or remove triggers on a monday platform agent. - -Triggers define when an agent runs automatically — for example, when a board status changes, when a date arrives, or on a schedule. - -WORKFLOW FOR ADD: -1. Call get_agent_catalog with type:"triggers" to find the right trigger type by name/description. Note its block_reference_id and inspect field_schemas (describes what field_values to pass) and required_fields (fields you must collect from the user — e.g. which board, which column). -2. Collect any required field values from the user. -3. Call this tool with action:"add", the block_reference_id, and the assembled field_values. - -WORKFLOW FOR REMOVE: -1. Call this tool with action:"list" to see active triggers by name and field_summary. Match the trigger the user described, note its node_id. -2. Call this tool with action:"remove" and that node_id. - -USAGE EXAMPLES: -- List triggers: { "action": "list", "agent_id": "7" } -- Add trigger: { "action": "add", "agent_id": "7", "block_reference_id": "status-change-ref", "field_values": { "board_id": "42" } } -- Remove trigger: { "action": "remove", "agent_id": "7", "node_id": "node-abc" }`; - } - - getInputSchema() { - return manageAgentTriggersToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - if (input.action === 'list') { - try { - const variables: GetAgentActiveTriggersQueryVariables = { agent_id: input.agent_id }; - const res = await this.mondayApi.request( - getAgentActiveTriggersQuery, - variables, - { versionOverride: 'dev' }, - ); - const triggers = res.agent_active_triggers ?? []; - return { - content: { - message: 'Active triggers on this agent. Use node_id with action:remove to detach a trigger.', - count: triggers.length, - triggers, - }, - }; - } catch (error) { - rethrowWithContext(error, 'list active triggers for monday platform agent'); - } - } - - if (input.action === 'add') { - if (!input.block_reference_id) { - throw new Error('block_reference_id is required for action:add. Call get_agent_catalog with type:triggers first.'); - } - try { - const variables: AddTriggerToAgentMutationVariables = { - agent_id: input.agent_id, - block_reference_id: input.block_reference_id, - field_values: input.field_values ?? undefined, - }; - const res = await this.mondayApi.request( - addTriggerToAgentMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: 'Trigger added to agent. Call manage_agent_triggers with action:list to verify.', - success: res.add_trigger_to_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'add trigger to monday platform agent'); - } - } - - if (!input.node_id) { - throw new Error('node_id is required for action:remove. Call manage_agent_triggers with action:list first to get node_id values.'); - } - try { - const variables: RemoveTriggerFromAgentMutationVariables = { - agent_id: input.agent_id, - node_id: input.node_id, - }; - const res = await this.mondayApi.request( - removeTriggerFromAgentMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: 'Trigger removed from agent.', - success: res.remove_trigger_from_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'remove trigger from monday platform agent'); - } - } -} -``` - -- [ ] **Step 4: Register the tool** - -In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: -```typescript -export * from './manage-agent-triggers/manage-agent-triggers-tool'; -``` - -In `src/core/tools/platform-api-tools/index.ts`, add import: -```typescript -import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; -``` - -Add to `allGraphqlApiTools` array: -```typescript - ManageAgentTriggersTool, -``` - -- [ ] **Step 5: Run tests to verify they pass** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-triggers --no-coverage 2>&1 | tail -10 -``` - -Expected: PASS — all 10 tests green. - -- [ ] **Step 6: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git add src/core/tools/platform-api-tools/index.ts -git commit -m "feat(agent-toolkit): add manage_agent_triggers tool" -``` - ---- - -## Task 6: `manage_agent_skills` tool - -**Files:** -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts` -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts` -- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` -- Modify: `src/core/tools/platform-api-tools/index.ts` - -- [ ] **Step 1: Write the failing test** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { - AddSkillToAgentMutation, - RemoveSkillFromAgentMutation, -} from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('ManageAgentSkillsTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - it('should add a skill to an agent', async () => { - mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'add', - agent_id: '7', - skill_id: 'skill-1', - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass agent_id, skill_id and versionOverride dev when adding', async () => { - mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); - - await callToolByNameRawAsync('manage_agent_skills', { action: 'add', agent_id: '7', skill_id: 'skill-1' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('addSkillToAgent'), - { agent_id: '7', skill_id: 'skill-1' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should remove a skill from an agent', async () => { - mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'remove', - agent_id: '7', - skill_id: 'skill-1', - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass agent_id, skill_id and versionOverride dev when removing', async () => { - mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); - - await callToolByNameRawAsync('manage_agent_skills', { action: 'remove', agent_id: '7', skill_id: 'skill-1' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('removeSkillFromAgent'), - { agent_id: '7', skill_id: 'skill-1' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should propagate errors with operation context on add', async () => { - mocks.setError('Skill not found'); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'add', - agent_id: '7', - skill_id: 'bad-id', - }); - - expect(result.content[0].text).toContain('Failed to add skill to monday platform agent'); - }); - - it('should propagate errors with operation context on remove', async () => { - mocks.setError('Skill not found'); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'remove', - agent_id: '7', - skill_id: 'bad-id', - }); - - expect(result.content[0].text).toContain('Failed to remove skill from monday platform agent'); - }); - - it('should reject whitespace-only skill_id', async () => { - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'add', - agent_id: '7', - skill_id: ' ', - }); - - expect(result.content[0].text).toContain('skill_id must be a non-empty string'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-skills --no-coverage 2>&1 | tail -10 -``` - -Expected: FAIL — tool not registered yet. - -- [ ] **Step 3: Implement the tool** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts -import { z } from 'zod'; -import { - AddSkillToAgentMutation, - AddSkillToAgentMutationVariables, - RemoveSkillFromAgentMutation, - RemoveSkillFromAgentMutationVariables, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { addSkillToAgentMutation, removeSkillFromAgentMutation } from './manage-agent-skills.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const manageAgentSkillsToolSchema = { - action: z.enum(['add', 'remove']).describe('"add" — attach a skill to the agent. "remove" — detach a skill from the agent.'), - agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), - skill_id: z - .string() - .trim() - .min(1, 'skill_id must be a non-empty string') - .describe( - 'The skill id from get_agent_catalog (type:skills). Never guess this value — look it up in the catalog first.', - ), -}; - -export class ManageAgentSkillsTool extends BaseMondayApiTool { - name = 'manage_agent_skills'; - type = ToolType.WRITE; - annotations = createMondayApiAnnotations({ - title: 'Manage monday Platform Agent Skills', - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - }); - - getDescription(): string { - return `Attach or detach a skill from a monday platform agent. - -Skills extend what an agent can do — they grant access to specific monday.com capabilities. - -ALWAYS call get_agent_catalog with type:"skills" first to discover available skills and resolve the correct skill_id. Never guess or invent a skill_id. - -To see which skills are already attached to an agent, call get_agent and inspect the skill_ids array, then cross-reference with get_agent_catalog to get names and descriptions. - -USAGE EXAMPLES: -- Attach a skill: { "action": "add", "agent_id": "7", "skill_id": "skill-1" } -- Detach a skill: { "action": "remove", "agent_id": "7", "skill_id": "skill-1" }`; - } - - getInputSchema() { - return manageAgentSkillsToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - if (input.action === 'add') { - try { - const variables: AddSkillToAgentMutationVariables = { - agent_id: input.agent_id, - skill_id: input.skill_id, - }; - const res = await this.mondayApi.request( - addSkillToAgentMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: `Skill ${input.skill_id} added to agent ${input.agent_id}.`, - success: res.add_skill_to_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'add skill to monday platform agent'); - } - } - - try { - const variables: RemoveSkillFromAgentMutationVariables = { - agent_id: input.agent_id, - skill_id: input.skill_id, - }; - const res = await this.mondayApi.request( - removeSkillFromAgentMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: `Skill ${input.skill_id} removed from agent ${input.agent_id}.`, - success: res.remove_skill_from_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'remove skill from monday platform agent'); - } - } -} -``` - -- [ ] **Step 4: Register the tool** - -In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: -```typescript -export * from './manage-agent-skills/manage-agent-skills-tool'; -``` - -In `src/core/tools/platform-api-tools/index.ts`, add import: -```typescript -import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; -``` - -Add to `allGraphqlApiTools` array: -```typescript - ManageAgentSkillsTool, -``` - -- [ ] **Step 5: Run tests to verify they pass** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-skills --no-coverage 2>&1 | tail -10 -``` - -Expected: PASS — all 7 tests green. - -- [ ] **Step 6: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git add src/core/tools/platform-api-tools/index.ts -git commit -m "feat(agent-toolkit): add manage_agent_skills tool" -``` - ---- - -## Task 7: `update_agent` tool - -**Files:** -- Create: `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts` -- Create: `src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts` -- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` -- Modify: `src/core/tools/platform-api-tools/index.ts` - -- [ ] **Step 1: Write the failing test** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { UpdateAgentMutation } from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('UpdateAgentTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - const mockAgent = { - id: '7', - kind: 'PERSONAL', - state: 'INACTIVE', - profile: { - name: 'Updated Bot', - role: 'Analyst', - role_description: 'Analyses data', - avatar_url: 'https://example.com/a.png', - background_color: '#000000', - }, - goal: 'Analyse stuff', - plan: '# Updated Plan', - user_prompt: null, - version_id: '2', - created_at: '2026-04-29T00:00:00Z', - updated_at: '2026-05-01T00:00:00Z', - }; - - it('should return the updated agent', async () => { - mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); - - const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'Updated Bot' }); - const parsed = parseToolResult(result); - - expect(parsed.agent.id).toBe('7'); - expect(parsed.agent.profile.name).toBe('Updated Bot'); - }); - - it('should pass id, input and versionOverride dev', async () => { - mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); - - await callToolByNameRawAsync('update_agent', { id: '7', name: 'Updated Bot', plan: '# New Plan' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('updateAgent'), - { id: '7', input: { name: 'Updated Bot', plan: '# New Plan' } }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should only include provided fields in input', async () => { - mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); - - await callToolByNameRawAsync('update_agent', { id: '7', plan: '# Plan only' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.anything(), - { id: '7', input: { plan: '# Plan only' } }, - expect.anything(), - ); - }); - - it('should not include agent_model in input when omitted', async () => { - mocks.setResponseOnce({ update_agent: mockAgent } as UpdateAgentMutation); - - await callToolByNameRawAsync('update_agent', { id: '7', name: 'Bot' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.anything(), - { id: '7', input: { name: 'Bot' } }, - expect.anything(), - ); - }); - - it('should propagate GraphQL errors with operation context', async () => { - mocks.setError('Agent not found'); - - const result = await callToolByNameRawAsync('update_agent', { id: '999', name: 'x' }); - - expect(result.content[0].text).toContain('Failed to update monday platform agent'); - }); - - it('should throw a "returned no id" error when update_agent returns null', async () => { - mocks.setResponseOnce({ update_agent: null } as UpdateAgentMutation); - - const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'x' }); - - expect(result.content[0].text).toContain('returned no id'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/update-agent --no-coverage 2>&1 | tail -10 -``` - -Expected: FAIL — tool not registered yet. - -- [ ] **Step 3: Implement the tool** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts -import { z } from 'zod'; -import { - UpdateAgentMutation, - UpdateAgentMutationVariables, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { updateAgentMutation } from './update-agent.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const updateAgentToolSchema = { - id: z.string().trim().min(1, 'Agent id must be a non-empty string').describe('Unique identifier of the agent to update.'), - name: z.string().trim().min(1).optional().describe('New display name for the agent.'), - role: z.string().trim().min(1).optional().describe('New role for the agent.'), - role_description: z.string().trim().min(1).optional().describe('New role description for the agent.'), - plan: z - .string() - .trim() - .min(1) - .optional() - .describe('New execution plan for the agent, in markdown format. This is the agent\'s core instructions.'), - agent_model: z - .string() - .optional() - .describe( - 'STRONGLY DISCOURAGED — omit this field. Only set when the user explicitly names a monday-supported model. Do not invent or guess model identifiers. When omitted the existing model is kept.', - ), -}; - -export class UpdateAgentTool extends BaseMondayApiTool { - name = 'update_agent'; - type = ToolType.WRITE; - annotations = createMondayApiAnnotations({ - title: 'Update monday Platform Agent', - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - }); - - getDescription(): string { - return `Update a monday platform agent's profile or execution plan. Creates a new draft internally and publishes in one call. - -All fields are optional — only provided fields are changed. Omit fields you do not want to update. - -The plan field is the most impactful: it contains the agent's execution instructions in markdown format. Updating it changes how the agent behaves on every future run. - -If the user refers to the agent by name rather than id, call get_agent first to resolve the correct id. - -USAGE EXAMPLES: -- Update plan only: { "id": "7", "plan": "# New Plan\\n- Step 1\\n- Step 2" } -- Rename the agent: { "id": "7", "name": "Improved Standup Bot" }`; - } - - getInputSchema() { - return updateAgentToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - try { - const updateInput: UpdateAgentMutationVariables['input'] = {}; - if (input.name !== undefined) updateInput.name = input.name; - if (input.role !== undefined) updateInput.role = input.role; - if (input.role_description !== undefined) updateInput.role_description = input.role_description; - if (input.plan !== undefined) updateInput.plan = input.plan; - if (input.agent_model !== undefined) updateInput.agent_model = input.agent_model as any; - - const variables: UpdateAgentMutationVariables = { id: input.id, input: updateInput }; - const res = await this.mondayApi.request(updateAgentMutation, variables, { - versionOverride: 'dev', - }); - - if (!res.update_agent?.id) { - throw new Error('monday platform agent update returned no id'); - } - - return { - content: { - message: `monday platform agent ${res.update_agent.id} updated`, - agent: res.update_agent, - }, - }; - } catch (error) { - rethrowWithContext(error, 'update monday platform agent'); - } - } -} -``` - -- [ ] **Step 4: Register the tool** - -In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: -```typescript -export * from './update-agent/update-agent-tool'; -``` - -In `src/core/tools/platform-api-tools/index.ts`, add import: -```typescript -import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; -``` - -Add to `allGraphqlApiTools` array: -```typescript - UpdateAgentTool, -``` - -- [ ] **Step 5: Run tests to verify they pass** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/update-agent --no-coverage 2>&1 | tail -10 -``` - -Expected: PASS — all 6 tests green. - -- [ ] **Step 6: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git add src/core/tools/platform-api-tools/index.ts -git commit -m "feat(agent-toolkit): add update_agent tool" -``` - ---- - -## Task 8: `manage_agent_state` tool - -**Files:** -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts` -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts` -- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` -- Modify: `src/core/tools/platform-api-tools/index.ts` - -- [ ] **Step 1: Write the failing test** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.test.ts -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { - ActivateAgentMutation, - DeactivateAgentMutation, - RunAgentMutation, -} from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('ManageAgentStateTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - it('should activate an agent', async () => { - mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_state', { action: 'activate', agent_id: '7' }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass id and versionOverride dev when activating', async () => { - mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); - - await callToolByNameRawAsync('manage_agent_state', { action: 'activate', agent_id: '7' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('activateAgent'), - { id: '7' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should deactivate an agent', async () => { - mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_state', { action: 'deactivate', agent_id: '7' }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass inactive_reason when deactivating', async () => { - mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); - - await callToolByNameRawAsync('manage_agent_state', { - action: 'deactivate', - agent_id: '7', - inactive_reason: 'DEACTIVATED_BY_USER', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('deactivateAgent'), - { id: '7', inactive_reason: 'DEACTIVATED_BY_USER' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should pass undefined inactive_reason when omitted', async () => { - mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); - - await callToolByNameRawAsync('manage_agent_state', { action: 'deactivate', agent_id: '7' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.anything(), - { id: '7', inactive_reason: undefined }, - expect.anything(), - ); - }); - - it('should run an agent and return trigger_uuid', async () => { - mocks.setResponseOnce({ run_agent: { trigger_uuid: 'uuid-xyz' } } as RunAgentMutation); - - const result = await callToolByNameRawAsync('manage_agent_state', { action: 'run', agent_id: '7' }); - const parsed = parseToolResult(result); - - expect(parsed.trigger_uuid).toBe('uuid-xyz'); - }); - - it('should pass id and versionOverride dev when running', async () => { - mocks.setResponseOnce({ run_agent: { trigger_uuid: 'uuid-xyz' } } as RunAgentMutation); - - await callToolByNameRawAsync('manage_agent_state', { action: 'run', agent_id: '7' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('runAgent'), - { id: '7' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should propagate errors with operation context on activate', async () => { - mocks.setError('Agent not found'); - - const result = await callToolByNameRawAsync('manage_agent_state', { action: 'activate', agent_id: '999' }); - - expect(result.content[0].text).toContain('Failed to activate monday platform agent'); - }); - - it('should propagate errors with operation context on run', async () => { - mocks.setError('Agent not active'); - - const result = await callToolByNameRawAsync('manage_agent_state', { action: 'run', agent_id: '7' }); - - expect(result.content[0].text).toContain('Failed to run monday platform agent'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-state --no-coverage 2>&1 | tail -10 -``` - -Expected: FAIL — tool not registered yet. - -- [ ] **Step 3: Implement the tool** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts -import { z } from 'zod'; -import { - ActivateAgentMutation, - ActivateAgentMutationVariables, - DeactivateAgentMutation, - DeactivateAgentMutationVariables, - RunAgentMutation, - RunAgentMutationVariables, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { activateAgentMutation, deactivateAgentMutation, runAgentMutation } from './manage-agent-state.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const manageAgentStateToolSchema = { - action: z - .enum(['activate', 'deactivate', 'run']) - .describe( - '"activate" — transitions the agent to ACTIVE state so it can be triggered. "deactivate" — transitions the agent to INACTIVE. "run" — manually enqueues a one-off agent run (fire-and-forget; returns trigger_uuid for tracking).', - ), - agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), - inactive_reason: z - .enum(['DEACTIVATED_BY_USER', 'ACCOUNT_LEVEL_BLOCKING']) - .optional() - .describe('Only applies to action:deactivate. Defaults to DEACTIVATED_BY_USER when omitted.'), -}; - -export class ManageAgentStateTool extends BaseMondayApiTool { - name = 'manage_agent_state'; - type = ToolType.WRITE; - annotations = createMondayApiAnnotations({ - title: 'Manage monday Platform Agent State', - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - }); - - getDescription(): string { - return `Activate, deactivate, or manually run a monday platform agent. - -Agents created by create_agent start in state INACTIVE and cannot be triggered until activated. - -action:"activate" — sets the agent to ACTIVE. The agent can now be triggered by its configured triggers or manually via action:"run". -action:"deactivate" — sets the agent to INACTIVE. Existing triggers stop firing. -action:"run" — fires a one-off manual run immediately. This is async (fire-and-forget): the response confirms the run was accepted and enqueued, not that it has completed. Use trigger_uuid to correlate the execution in logs or future status endpoints. The agent must be ACTIVE to run. - -USAGE EXAMPLES: -- Activate: { "action": "activate", "agent_id": "7" } -- Deactivate: { "action": "deactivate", "agent_id": "7" } -- Run manually: { "action": "run", "agent_id": "7" }`; - } - - getInputSchema() { - return manageAgentStateToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - if (input.action === 'activate') { - try { - const variables: ActivateAgentMutationVariables = { id: input.agent_id }; - const res = await this.mondayApi.request(activateAgentMutation, variables, { - versionOverride: 'dev', - }); - return { - content: { - message: `monday platform agent ${input.agent_id} activated`, - success: res.activate_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'activate monday platform agent'); - } - } - - if (input.action === 'deactivate') { - try { - const variables: DeactivateAgentMutationVariables = { - id: input.agent_id, - inactive_reason: input.inactive_reason ?? undefined, - }; - const res = await this.mondayApi.request(deactivateAgentMutation, variables, { - versionOverride: 'dev', - }); - return { - content: { - message: `monday platform agent ${input.agent_id} deactivated`, - success: res.deactivate_agent?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'deactivate monday platform agent'); - } - } - - try { - const variables: RunAgentMutationVariables = { id: input.agent_id }; - const res = await this.mondayApi.request(runAgentMutation, variables, { - versionOverride: 'dev', - }); - return { - content: { - message: `monday platform agent ${input.agent_id} run enqueued — execution is async. Use trigger_uuid to track.`, - trigger_uuid: res.run_agent?.trigger_uuid, - }, - }; - } catch (error) { - rethrowWithContext(error, 'run monday platform agent'); - } - } -} -``` - -- [ ] **Step 4: Register the tool** - -In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: -```typescript -export * from './manage-agent-state/manage-agent-state-tool'; -``` - -In `src/core/tools/platform-api-tools/index.ts`, add import: -```typescript -import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; -``` - -Add to `allGraphqlApiTools` array: -```typescript - ManageAgentStateTool, -``` - -- [ ] **Step 5: Run tests to verify they pass** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-state --no-coverage 2>&1 | tail -10 -``` - -Expected: PASS — all 9 tests green. - -- [ ] **Step 6: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git add src/core/tools/platform-api-tools/index.ts -git commit -m "feat(agent-toolkit): add manage_agent_state tool" -``` - ---- - -## Task 9: `manage_agent_knowledge` tool - -**Files:** -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts` -- Create: `src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts` -- Modify: `src/core/tools/platform-api-tools/agents-tools/index.ts` -- Modify: `src/core/tools/platform-api-tools/index.ts` - -- [ ] **Step 1: Write the failing test** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.test.ts -import { MondayAgentToolkit } from 'src/mcp/toolkit'; -import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; -import { - GetAgentKnowledgeQuery, - AddAgentResourceAccessMutation, - RemoveAgentResourceAccessMutation, - UpdateAgentResourceAccessMutation, -} from 'src/monday-graphql/generated/graphql.dev/graphql'; - -describe('ManageAgentKnowledgeTool', () => { - let mocks: ReturnType; - - beforeEach(() => { - mocks = createMockApiClient(); - jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); - }); - - const mockKnowledge = { - resources: [{ resource_id: '42', scope_type: 'BOARD', permission_type: 'READ' }], - files: [{ id: 'f1', file_name: 'spec.pdf', file_type: 'pdf' }], - }; - - it('should list agent knowledge', async () => { - mocks.setResponseOnce({ agent_knowledge: mockKnowledge } as GetAgentKnowledgeQuery); - - const result = await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); - const parsed = parseToolResult(result); - - expect(parsed.resources[0].resource_id).toBe('42'); - expect(parsed.files[0].file_name).toBe('spec.pdf'); - }); - - it('should pass id and versionOverride dev when listing', async () => { - mocks.setResponseOnce({ agent_knowledge: { resources: [], files: [] } } as GetAgentKnowledgeQuery); - - await callToolByNameRawAsync('manage_agent_knowledge', { action: 'list', agent_id: '7' }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('getAgentKnowledge'), - { id: '7' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should add a resource access', async () => { - mocks.setResponseOnce({ add_agent_resource_access: { success: true } } as AddAgentResourceAccessMutation); - - const result = await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'add', - agent_id: '7', - resource_id: '42', - scope_type: 'BOARD', - permission_type: 'READ', - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass all fields and versionOverride dev when adding', async () => { - mocks.setResponseOnce({ add_agent_resource_access: { success: true } } as AddAgentResourceAccessMutation); - - await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'add', - agent_id: '7', - resource_id: '42', - scope_type: 'BOARD', - permission_type: 'READ_WRITE', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('addAgentResourceAccess'), - { id: '7', resource_id: '42', scope_type: 'BOARD', permission_type: 'READ_WRITE' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should update a resource permission', async () => { - mocks.setResponseOnce({ update_agent_resource_access: { success: true } } as UpdateAgentResourceAccessMutation); - - const result = await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'update', - agent_id: '7', - resource_id: '42', - scope_type: 'BOARD', - permission_type: 'READ_WRITE', - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should remove a resource access', async () => { - mocks.setResponseOnce({ remove_agent_resource_access: { success: true } } as RemoveAgentResourceAccessMutation); - - const result = await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'remove', - agent_id: '7', - resource_id: '42', - scope_type: 'BOARD', - }); - const parsed = parseToolResult(result); - - expect(parsed.success).toBe(true); - }); - - it('should pass id, resource_id, scope_type and versionOverride dev when removing', async () => { - mocks.setResponseOnce({ remove_agent_resource_access: { success: true } } as RemoveAgentResourceAccessMutation); - - await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'remove', - agent_id: '7', - resource_id: '42', - scope_type: 'DOC', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('removeAgentResourceAccess'), - { id: '7', resource_id: '42', scope_type: 'DOC' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should reject add action without resource_id', async () => { - const result = await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'add', - agent_id: '7', - scope_type: 'BOARD', - permission_type: 'READ', - }); - - expect(result.content[0].text).toContain('resource_id is required'); - }); - - it('should reject add action without permission_type', async () => { - const result = await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'add', - agent_id: '7', - resource_id: '42', - scope_type: 'BOARD', - }); - - expect(result.content[0].text).toContain('permission_type is required'); - }); - - it('should propagate errors with operation context', async () => { - mocks.setError('Board not found'); - - const result = await callToolByNameRawAsync('manage_agent_knowledge', { - action: 'add', - agent_id: '7', - resource_id: '99', - scope_type: 'BOARD', - permission_type: 'READ', - }); - - expect(result.content[0].text).toContain('Failed to add resource access to monday platform agent'); - }); -}); -``` - -- [ ] **Step 2: Run test to verify it fails** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge --no-coverage 2>&1 | tail -10 -``` - -Expected: FAIL — tool not registered yet. - -- [ ] **Step 3: Implement the tool** - -```typescript -// src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts -import { z } from 'zod'; -import { - GetAgentKnowledgeQuery, - GetAgentKnowledgeQueryVariables, - AddAgentResourceAccessMutation, - AddAgentResourceAccessMutationVariables, - RemoveAgentResourceAccessMutation, - RemoveAgentResourceAccessMutationVariables, - UpdateAgentResourceAccessMutation, - UpdateAgentResourceAccessMutationVariables, -} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { - getAgentKnowledgeQuery, - addAgentResourceAccessMutation, - removeAgentResourceAccessMutation, - updateAgentResourceAccessMutation, -} from './manage-agent-knowledge.graphql.dev'; -import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; -import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; -import { rethrowWithContext } from '../../../../../utils'; - -export const manageAgentKnowledgeToolSchema = { - action: z - .enum(['list', 'add', 'update', 'remove']) - .describe( - '"list" — returns current resource access (boards/docs) and uploaded files. "add" — grants access to a board or doc. "update" — changes the permission level on an existing resource. "remove" — revokes access entirely.', - ), - agent_id: z.string().trim().min(1, 'agent_id must be a non-empty string').describe('Unique identifier of the agent.'), - resource_id: z - .string() - .trim() - .min(1) - .optional() - .describe('Required for action:add, update, and remove. The ID of the monday.com board or doc.'), - scope_type: z - .enum(['BOARD', 'DOC']) - .optional() - .describe('Required for action:add, update, and remove. Whether the resource is a board or a doc.'), - permission_type: z - .enum(['READ', 'READ_WRITE']) - .optional() - .describe( - 'Required for action:add and update. READ — agent can read the resource. READ_WRITE — agent can read and write.', - ), -}; - -export class ManageAgentKnowledgeTool extends BaseMondayApiTool { - name = 'manage_agent_knowledge'; - type = ToolType.WRITE; - annotations = createMondayApiAnnotations({ - title: 'Manage monday Platform Agent Knowledge', - readOnlyHint: false, - destructiveHint: false, - idempotentHint: false, - }); - - getDescription(): string { - return `List, grant, update, or revoke a monday platform agent's access to boards and docs. - -Agent knowledge determines which monday.com resources the agent can read or write when it runs. - -Call with action:"list" first to see what resources the agent already has access to before adding, updating, or removing. - -action:"add" — grants the agent access to a board or doc. Requires resource_id (the board or doc id), scope_type (BOARD or DOC), and permission_type (READ or READ_WRITE). -action:"update" — changes the permission level on an already-granted resource. -action:"remove" — revokes access to a resource entirely. - -USAGE EXAMPLES: -- List resources: { "action": "list", "agent_id": "7" } -- Grant board access: { "action": "add", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD", "permission_type": "READ" } -- Upgrade to read-write: { "action": "update", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD", "permission_type": "READ_WRITE" } -- Revoke access: { "action": "remove", "agent_id": "7", "resource_id": "42", "scope_type": "BOARD" }`; - } - - getInputSchema() { - return manageAgentKnowledgeToolSchema; - } - - protected async executeInternal( - input: ToolInputType, - ): Promise> { - if (input.action === 'list') { - try { - const variables: GetAgentKnowledgeQueryVariables = { id: input.agent_id }; - const res = await this.mondayApi.request(getAgentKnowledgeQuery, variables, { - versionOverride: 'dev', - }); - return { - content: { - message: 'Current knowledge configuration for this agent.', - resources: res.agent_knowledge?.resources ?? [], - files: res.agent_knowledge?.files ?? [], - }, - }; - } catch (error) { - rethrowWithContext(error, 'list knowledge for monday platform agent'); - } - } - - if (!input.resource_id) { - throw new Error(`resource_id is required for action:${input.action}.`); - } - if (!input.scope_type) { - throw new Error(`scope_type is required for action:${input.action}.`); - } - - if (input.action === 'add') { - if (!input.permission_type) { - throw new Error('permission_type is required for action:add.'); - } - try { - const variables: AddAgentResourceAccessMutationVariables = { - id: input.agent_id, - resource_id: input.resource_id, - scope_type: input.scope_type as any, - permission_type: input.permission_type as any, - }; - const res = await this.mondayApi.request( - addAgentResourceAccessMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: `${input.scope_type} ${input.resource_id} granted to agent with ${input.permission_type} permission.`, - success: res.add_agent_resource_access?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'add resource access to monday platform agent'); - } - } - - if (input.action === 'update') { - if (!input.permission_type) { - throw new Error('permission_type is required for action:update.'); - } - try { - const variables: UpdateAgentResourceAccessMutationVariables = { - id: input.agent_id, - resource_id: input.resource_id, - scope_type: input.scope_type as any, - permission_type: input.permission_type as any, - }; - const res = await this.mondayApi.request( - updateAgentResourceAccessMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: `Permission on ${input.scope_type} ${input.resource_id} updated to ${input.permission_type}.`, - success: res.update_agent_resource_access?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'update resource access for monday platform agent'); - } - } - - try { - const variables: RemoveAgentResourceAccessMutationVariables = { - id: input.agent_id, - resource_id: input.resource_id, - scope_type: input.scope_type as any, - }; - const res = await this.mondayApi.request( - removeAgentResourceAccessMutation, - variables, - { versionOverride: 'dev' }, - ); - return { - content: { - message: `Access to ${input.scope_type} ${input.resource_id} removed from agent.`, - success: res.remove_agent_resource_access?.success ?? false, - }, - }; - } catch (error) { - rethrowWithContext(error, 'remove resource access from monday platform agent'); - } - } -} -``` - -- [ ] **Step 4: Register the tool** - -In `src/core/tools/platform-api-tools/agents-tools/index.ts`, add: -```typescript -export * from './manage-agent-knowledge/manage-agent-knowledge-tool'; -``` - -In `src/core/tools/platform-api-tools/index.ts`, add import: -```typescript -import { ManageAgentKnowledgeTool } from './agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool'; -``` - -Add to `allGraphqlApiTools` array: -```typescript - ManageAgentKnowledgeTool, -``` - -- [ ] **Step 5: Run tests to verify they pass** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge --no-coverage 2>&1 | tail -10 -``` - -Expected: PASS — all 10 tests green. - -- [ ] **Step 6: Commit** - -```bash -git add src/core/tools/platform-api-tools/agents-tools/ -git add src/core/tools/platform-api-tools/index.ts -git commit -m "feat(agent-toolkit): add manage_agent_knowledge tool" -``` - ---- - -## Task 10: Full test suite and build - -- [ ] **Step 1: Run all agents-tools tests** - -```bash -cd packages/agent-toolkit && npx jest src/core/tools/platform-api-tools/agents-tools --no-coverage 2>&1 | tail -20 -``` - -Expected: all 9 test suites pass (3 existing + 6 new). - -- [ ] **Step 2: Run full test suite** - -```bash -cd packages/agent-toolkit && npm test 2>&1 | tail -20 -``` - -Expected: all tests pass, no regressions. - -- [ ] **Step 3: Build** - -```bash -cd packages/agent-toolkit && npm run build 2>&1 | tail -10 -``` - -Expected: exits 0, `dist/` updated with no TypeScript errors. - ---- - -## Task 11: Bump version - -- [ ] **Step 1: Bump version in `package.json`** - -In `packages/agent-toolkit/package.json`, change: -```json -"version": "5.10.3" -``` -to: -```json -"version": "5.11.0" -``` - -(Minor bump — new tools are additive, non-breaking.) - -- [ ] **Step 2: Commit** - -```bash -git add packages/agent-toolkit/package.json -git commit -m "chore(agent-toolkit): bump version to 5.11.0" -``` diff --git a/docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md b/docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md deleted file mode 100644 index 43605d76..00000000 --- a/docs/superpowers/specs/2026-05-13-agent-tools-expansion-design.md +++ /dev/null @@ -1,280 +0,0 @@ -# Agent Tools Expansion — Design Spec - -**Date:** 2026-05-13 -**Package:** `packages/agent-toolkit` -**Location:** `src/core/tools/platform-api-tools/agents-tools/` - ---- - -## Problem - -The existing agent tools (`get_agent`, `create_agent`, `delete_agent`) cover only basic CRUD. The agents subgraph exposes a much richer surface — skills, triggers, state management, knowledge/resource access — that agents cannot yet use via the toolkit. - -The core challenge is discoverability: consumers never know available skill IDs, trigger `block_reference_id` values, or the required `field_values` shape for a given trigger type. The catalog queries exist precisely to solve this, and the tool descriptions must encode the lookup-first workflow so agents know to consult them before acting. - ---- - -## Scope - -6 new tools covering all remaining agents subgraph operations: - -| Tool | Type | Operations | -|------|------|-----------| -| `get_agent_catalog` | READ | `agent_skills_catalog`, `agent_triggers_catalog` | -| `manage_agent_triggers` | WRITE | `agent_active_triggers` (list), `add_trigger_to_agent`, `remove_trigger_from_agent` | -| `manage_agent_skills` | WRITE | `add_skill_to_agent`, `remove_skill_from_agent` | -| `update_agent` | WRITE | `update_agent` | -| `manage_agent_state` | WRITE | `activate_agent`, `deactivate_agent`, `run_agent` | -| `manage_agent_knowledge` | WRITE | `agent_knowledge` (list), `add_agent_resource_access`, `remove_agent_resource_access`, `update_agent_resource_access` | - -Out of scope: `get_agent` is unchanged — the subgraph will be enhanced in a future iteration to include more fields (active triggers, knowledge) directly on the Agent type. - ---- - -## File Structure - -Each tool is co-located with its own `.graphql.dev.ts` file. The `shared/` directory keeps only the `AgentFields` fragment (used by the existing get/create/delete tools). - -``` -agents-tools/ -├── shared/ -│ └── agents.graphql.dev.ts ← AgentFields fragment only (unchanged) -├── get-agent-catalog/ -│ ├── get-agent-catalog-tool.ts -│ └── get-agent-catalog.graphql.dev.ts -├── manage-agent-triggers/ -│ ├── manage-agent-triggers-tool.ts -│ └── manage-agent-triggers.graphql.dev.ts -├── manage-agent-skills/ -│ ├── manage-agent-skills-tool.ts -│ └── manage-agent-skills.graphql.dev.ts -├── update-agent/ -│ ├── update-agent-tool.ts -│ └── update-agent.graphql.dev.ts -├── manage-agent-state/ -│ ├── manage-agent-state-tool.ts -│ └── manage-agent-state.graphql.dev.ts -└── manage-agent-knowledge/ - ├── manage-agent-knowledge-tool.ts - └── manage-agent-knowledge.graphql.dev.ts -``` - ---- - -## Tool Designs - -### `get_agent_catalog` (READ) - -**Purpose:** Account-wide discovery of available trigger types and skills. Always call this before adding a trigger or skill to an agent. - -**Input schema:** -```typescript -{ - type: z.enum(['triggers', 'skills']), - // For triggers only — fetches specific entries much faster than full catalog - block_reference_ids: z.array(z.string()).optional() -} -``` - -**Behavior:** -- `type: 'triggers'` → calls `agent_triggers_catalog`. Returns entries with `block_reference_id`, `name`, `description`, `field_schemas`, `required_fields`. `field_schemas` describes the shape of `field_values` required when adding (e.g. `{ board_id: }`). `required_fields` lists fields the user must supply. -- `type: 'skills'` → calls `agent_skills_catalog`. Returns entries with `id`, `name`, `description`. - -**Description preamble:** -> Call this tool first before adding a trigger or skill to an agent. For triggers: inspect `field_schemas` and `required_fields` to know what to collect from the user (e.g. board_id, column_id) before calling `manage_agent_triggers`. For skills: use the returned `id` to call `manage_agent_skills`. - ---- - -### `manage_agent_triggers` (WRITE) - -**Purpose:** List, add, and remove triggers on a specific agent. - -**Input schema (discriminated by `action`):** -```typescript -{ - action: z.enum(['list', 'add', 'remove']), - agent_id: z.string(), - // add only - block_reference_id: z.string().optional(), - field_values: z.record(z.unknown()).optional(), - // remove only - node_id: z.string().optional() -} -``` - -**Behavior:** -- `list` → calls `agent_active_triggers(agent_id)`. Returns active triggers with `node_id`, `block_reference_id`, `name`, `description`, `field_summary`. -- `add` → calls `add_trigger_to_agent`. Requires `block_reference_id` (from catalog) and optional `field_values` (shape determined by `field_schemas` in the catalog entry). -- `remove` → calls `remove_trigger_from_agent`. Requires `node_id` (from `action: list`). - -**Description — add workflow:** -> To add: first call `get_agent_catalog` with `type: triggers` to find the right entry by name/description. Inspect `field_schemas` and `required_fields` to know what information to collect from the user (e.g. which board, which column). Only then call this tool with `action: add`. - -**Description — remove workflow:** -> To remove: first call this tool with `action: list` to see the active triggers by name and `field_summary`. Match the trigger the user described, get its `node_id`, then call this tool with `action: remove`. - ---- - -### `manage_agent_skills` (WRITE) - -**Purpose:** Attach and detach skills from an agent. - -**Input schema:** -```typescript -{ - action: z.enum(['add', 'remove']), - agent_id: z.string(), - skill_id: z.string() -} -``` - -**Behavior:** -- `add` → calls `add_skill_to_agent` -- `remove` → calls `remove_skill_from_agent` - -**Description preamble:** -> Always call `get_agent_catalog` with `type: skills` first to discover available skills and resolve the correct `skill_id` — never guess or invent a skill ID. - ---- - -### `update_agent` (WRITE) - -**Purpose:** Update an agent's profile or execution plan. Creates a new draft internally and publishes in one call. - -**Input schema:** -```typescript -{ - id: z.string(), - name: z.string().optional(), - role: z.string().optional(), - role_description: z.string().optional(), - plan: z.string().optional(), // markdown - agent_model: z.string().optional() // discourage unless user explicitly named a model -} -``` - -**Behavior:** Calls `update_agent`. All profile fields are optional — only provided fields are changed. Mirrors the same `agent_model` guidance as `create_agent` (strongly discourage setting it; omit unless user explicitly named a model). - ---- - -### `manage_agent_state` (WRITE) - -**Purpose:** Activate, deactivate, or manually trigger a run for an agent. - -**Input schema:** -```typescript -{ - action: z.enum(['activate', 'deactivate', 'run']), - agent_id: z.string(), - // deactivate only - inactive_reason: z.enum(['DEACTIVATED_BY_USER', 'ACCOUNT_LEVEL_BLOCKING']).optional() -} -``` - -**Behavior:** -- `activate` → calls `activate_agent`. Agent transitions to ACTIVE and can receive triggers. -- `deactivate` → calls `deactivate_agent`. `inactive_reason` defaults to `DEACTIVATED_BY_USER` if omitted. -- `run` → calls `run_agent`. Fire-and-forget async operation. Returns `trigger_uuid` for downstream correlation. Success means the run was enqueued, not that it completed. - ---- - -### `manage_agent_knowledge` (WRITE) - -**Purpose:** List, grant, update, and revoke an agent's access to monday.com boards and docs. - -**Input schema (discriminated by `action`):** -```typescript -{ - action: z.enum(['list', 'add', 'update', 'remove']), - agent_id: z.string(), - // add, update, remove - resource_id: z.string().optional(), - scope_type: z.enum(['BOARD', 'DOC']).optional(), - // add, update - permission_type: z.enum(['READ', 'READ_WRITE']).optional() -} -``` - -**Behavior:** -- `list` → calls `agent_knowledge(agent_id)`. Returns current resources (boards/docs) with `resource_id`, `scope_type`, `permission_type`, plus uploaded files. -- `add` → calls `add_agent_resource_access`. Grants agent access to a board or doc with the specified permission level. -- `update` → calls `update_agent_resource_access`. Changes the permission level on an already-granted resource. -- `remove` → calls `remove_agent_resource_access`. Revokes access entirely. - -**Description preamble:** -> Call with `action: list` first to see the agent's current resource access before adding, updating, or removing. For `add`/`update`, `permission_type: READ` allows the agent to read the resource; `READ_WRITE` also allows writing. - ---- - -## Key Design Decisions - -**Catalog-first descriptions:** Tool descriptions are the primary mechanism for guiding agent behavior. Every WRITE tool that requires an ID from a catalog or list operation explicitly names the prerequisite call. This is more reliable than trying to enforce it in code. - -**`field_values` as record:** `add_trigger_to_agent` takes `field_values: JSON` in the schema. The Zod type is `z.record(z.unknown())` — flexible enough to accommodate any trigger type's shape. The `field_schemas` from the catalog entry describes the expected shape at runtime. - -**`manage_agent_triggers` and `manage_agent_knowledge` are typed WRITE:** Both include a `list` action that is read-only in effect, but the tools are typed WRITE because their primary purpose is mutation and the list actions exist specifically to support the write workflow (get `node_id` before remove, inspect resources before update). In `readOnlyMode`, WRITE tools are filtered out — this means `list` is unavailable in read-only configurations, which is an accepted trade-off. If this becomes a problem in practice, the list operations can be split into `get_agent` in a future iteration when the subgraph enhances the Agent type to include active triggers and knowledge directly. - ---- - -## GraphQL Operations (per tool) - -### `get-agent-catalog.graphql.dev.ts` -- `query getAgentTriggersCatalog($block_reference_ids: [ID!])` -- `query getAgentSkillsCatalog` - -### `manage-agent-triggers.graphql.dev.ts` -- `query getAgentActiveTriggers($agent_id: ID!)` -- `mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON)` -- `mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!)` - -### `manage-agent-skills.graphql.dev.ts` -- `mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!)` -- `mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!)` - -### `update-agent.graphql.dev.ts` -- `mutation updateAgent($id: ID!, $input: UpdateAgentInput!)` - -### `manage-agent-state.graphql.dev.ts` -- `mutation activateAgent($id: ID!)` -- `mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason)` -- `mutation runAgent($id: ID!)` - -### `manage-agent-knowledge.graphql.dev.ts` -- `query getAgentKnowledge($agent_id: ID!)` -- `mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!)` -- `mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!)` -- `mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!)` - ---- - -## Registration - -In `src/core/tools/platform-api-tools/index.ts`: -- 6 new imports -- 6 additions to `allGraphqlApiTools` array (grouped under existing agents comment) -- 6 new `export *` lines - ---- - -## Error Handling - -All tools use `rethrowWithContext(error, '')` in a try/catch, consistent with existing agent tools. - ---- - -## Testing - -One `.test.ts` per tool, co-located, using `createMockApiClient()`. Each test file covers: -- Happy path for each action -- Validation errors (missing required fields for wrong action) -- API error propagation via `rethrowWithContext` - ---- - -## Post-Implementation - -After all tool files are written: -1. Run `npm run fetch:generate dev` to regenerate dev types from new GraphQL operations -2. Run `npm test` to verify all tests pass -3. Run `npm run build` to verify compilation -4. Bump version in `package.json` From 5470cc82ce3248ee3780e760c93e79b5ad3e90e5 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Wed, 13 May 2026 22:45:24 +0300 Subject: [PATCH 26/28] fix(agent-toolkit): address PR review feedback on agent tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - create_agent: guide calling manage_agent_state(activate) after creation instead of redirecting to the monday.com UI - manage_agent_state: narrow inactive_reason to DEACTIVATED_BY_USER only (remove internal ACCOUNT_LEVEL_BLOCKING); describe when to pass it vs omit - manage_agent_knowledge: document that files in the list response cannot be managed via this tool and redirect to the platform UI - manage_agent_skills: clarify create→add flow — use the id returned by action:create directly, no catalog lookup needed - update-agent-tool.test: add missing null-response test for update_agent returning no data - manage-agent-state-tool.test: update test to reflect removed ACCOUNT_LEVEL_BLOCKING enum value Co-authored-by: Cursor --- .../create-agent/create-agent-tool.ts | 16 ++-- .../manage-agent-knowledge-tool.ts | 2 +- .../manage-agent-skills-tool.ts | 4 +- .../manage-agent-state-tool.test.ts | 6 +- .../manage-agent-state-tool.ts | 6 +- .../update-agent/update-agent-tool.test.ts | 8 ++ .../generated/graphql.dev/gql.ts | 96 +++++++++++++++++++ .../generated/graphql/graphql.ts | 70 +++++++++++--- .../src/monday-graphql/schema.dev.graphql | 10 +- .../src/monday-graphql/schema.graphql | 52 +++++++++- 10 files changed, 239 insertions(+), 31 deletions(-) diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts index e7bd6513..7d109ebc 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts @@ -80,7 +80,7 @@ Two modes: Do not mix prompt with manual profile fields in one request. -Created agents start in state INACTIVE and must be activated before they can be triggered. Instruct the user to activate from the monday.com agent settings UI. +Created agents start in state INACTIVE and must be activated before they can be triggered. After creation, call manage_agent_state with action:activate and the returned agent id. created_at and updated_at are null in the response — call get_agent with the returned id afterward to fetch them. @@ -137,7 +137,7 @@ USAGE EXAMPLES: return { content: { - message: `monday platform agent ${res.create_blank_agent.id} created in state INACTIVE — user must activate it from the monday.com UI before it can be triggered`, + message: `monday platform agent ${res.create_blank_agent.id} created in state INACTIVE — call manage_agent_state with action:activate and agent_id:${res.create_blank_agent.id} to activate it`, agent: res.create_blank_agent, }, }; @@ -163,12 +163,12 @@ USAGE EXAMPLES: throw new Error('monday platform agent creation returned no id'); } - return { - content: { - message: `monday platform agent ${res.create_agent.id} created in state INACTIVE — user must activate it from the monday.com UI before it can be triggered`, - agent: res.create_agent, - }, - }; + return { + content: { + message: `monday platform agent ${res.create_agent.id} created in state INACTIVE — call manage_agent_state with action:activate and agent_id:${res.create_agent.id} to activate it`, + agent: res.create_agent, + }, + }; } catch (error) { rethrowWithContext(error, 'create monday platform agent'); } diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts index 1acb2a48..6b363a2e 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts @@ -59,7 +59,7 @@ export class ManageAgentKnowledgeTool extends BaseMondayApiTool { }); // Explicit inactive_reason - it('should accept explicit inactive_reason ACCOUNT_LEVEL_BLOCKING', async () => { + it('should pass explicit inactive_reason DEACTIVATED_BY_USER when provided', async () => { mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); await callToolByNameRawAsync('manage_agent_state', { action: 'deactivate', agent_id: '7', - inactive_reason: 'ACCOUNT_LEVEL_BLOCKING', + inactive_reason: 'DEACTIVATED_BY_USER', }); expect(mocks.getMockRequest()).toHaveBeenCalledWith( expect.stringContaining('deactivateAgent'), - expect.objectContaining({ inactive_reason: 'ACCOUNT_LEVEL_BLOCKING' }), + expect.objectContaining({ inactive_reason: InactiveReason.DeactivatedByUser }), expect.objectContaining({ versionOverride: 'dev' }), ); }); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts index e61ee6cd..63e81713 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts @@ -23,10 +23,10 @@ export const manageAgentStateToolSchema = { ), agent_id: z.string().trim().min(1).describe('Unique identifier of the agent.'), inactive_reason: z - .enum(['DEACTIVATED_BY_USER', 'ACCOUNT_LEVEL_BLOCKING']) + .enum(['DEACTIVATED_BY_USER']) .optional() .describe( - 'Only for action:deactivate. Reason for deactivation. Defaults to "DEACTIVATED_BY_USER" if omitted.', + 'Only for action:deactivate. Pass "DEACTIVATED_BY_USER" when the user has clearly expressed intent to deactivate (e.g. "pause the agent", "turn it off", "I\'m going on vacation"). Omit if the reason is ambiguous — do not guess.', ), }; @@ -44,7 +44,7 @@ export class ManageAgentStateTool extends BaseMondayApiTool { ); }); + it('should throw when update_agent returns null', async () => { + mocks.setResponseOnce({ update_agent: null } as UpdateAgentMutation); + + const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + + expect(result.content[0].text).toContain('update_agent returned no data'); + }); + it('should propagate API errors with context', async () => { mocks.setError('API error'); diff --git a/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/gql.ts b/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/gql.ts index 399617ca..49f194aa 100644 --- a/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/gql.ts +++ b/packages/agent-toolkit/src/monday-graphql/generated/graphql.dev/gql.ts @@ -14,11 +14,27 @@ import { TypedDocumentNode as DocumentNode } from '@graphql-typed-document-node/ * Learn more about it here: https://the-guild.dev/graphql/codegen/plugins/presets/preset-client#reducing-bundle-size */ type Documents = { + "\n mutation createAgentSkill($name: String!, $content: String!, $description: String) {\n create_agent_skill(name: $name, content: $content, description: $description) {\n id\n name\n description\n }\n }\n": typeof types.CreateAgentSkillDocument, + "\n query getAgentTriggersCatalog($block_reference_ids: [ID!]) {\n agent_triggers_catalog(block_reference_ids: $block_reference_ids) {\n block_reference_id\n name\n description\n field_schemas {\n field_key\n value_schema\n }\n required_fields {\n field_key\n depends_on\n optional\n }\n }\n }\n": typeof types.GetAgentTriggersCatalogDocument, + "\n query getAgentSkillsCatalog {\n agent_skills_catalog {\n id\n name\n description\n }\n }\n": typeof types.GetAgentSkillsCatalogDocument, + "\n query getAgentKnowledge($id: ID!) {\n agent_knowledge(id: $id) {\n resources {\n resource_id\n scope_type\n permission_type\n }\n files {\n id\n file_name\n file_type\n }\n }\n }\n": typeof types.GetAgentKnowledgeDocument, + "\n mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n": typeof types.AddAgentResourceAccessDocument, + "\n mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) {\n remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) {\n success\n }\n }\n": typeof types.RemoveAgentResourceAccessDocument, + "\n mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n": typeof types.UpdateAgentResourceAccessDocument, + "\n mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) {\n add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n": typeof types.AddSkillToAgentDocument, + "\n mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) {\n remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n": typeof types.RemoveSkillFromAgentDocument, + "\n mutation activateAgent($id: ID!) {\n activate_agent(id: $id) {\n success\n }\n }\n": typeof types.ActivateAgentDocument, + "\n mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) {\n deactivate_agent(id: $id, inactive_reason: $inactive_reason) {\n success\n }\n }\n": typeof types.DeactivateAgentDocument, + "\n mutation runAgent($id: ID!) {\n run_agent(id: $id) {\n trigger_uuid\n }\n }\n": typeof types.RunAgentDocument, + "\n query getAgentActiveTriggers($agent_id: ID!) {\n agent_active_triggers(agent_id: $agent_id) {\n node_id\n block_reference_id\n name\n description\n field_summary\n }\n }\n": typeof types.GetAgentActiveTriggersDocument, + "\n mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) {\n add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) {\n success\n }\n }\n": typeof types.AddTriggerToAgentDocument, + "\n mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) {\n remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) {\n success\n }\n }\n": typeof types.RemoveTriggerFromAgentDocument, "\n fragment AgentFields on Agent {\n id\n kind\n state\n profile {\n name\n role\n role_description\n avatar_url\n background_color\n }\n goal\n plan\n user_prompt\n version_id\n created_at\n updated_at\n }\n": typeof types.AgentFieldsFragmentDoc, "\n \n\n query getAgents($ids: [ID!], $limit: Int) {\n agents(ids: $ids, limit: $limit) {\n ...AgentFields\n }\n }\n": typeof types.GetAgentsDocument, "\n \n\n mutation createAgent($input: CreateAgentInput!) {\n create_agent(input: $input) {\n ...AgentFields\n }\n }\n": typeof types.CreateAgentDocument, "\n \n\n mutation createBlankAgent($input: CreateBlankAgentInput) {\n create_blank_agent(input: $input) {\n ...AgentFields\n }\n }\n": typeof types.CreateBlankAgentDocument, "\n \n\n mutation deleteAgent($id: ID!) {\n delete_agent(id: $id) {\n ...AgentFields\n }\n }\n": typeof types.DeleteAgentDocument, + "\n \n\n mutation updateAgent($id: ID!, $input: UpdateAgentInput!) {\n update_agent(id: $id, input: $input) {\n ...AgentFields\n }\n }\n": typeof types.UpdateAgentDocument, "\n mutation DeleteObjectSchemaColumns($objectSchemaId: ID, $objectSchemaName: String, $columnIds: [ID!]!) {\n delete_object_schema_columns(object_schema_id: $objectSchemaId, object_schema_name: $objectSchemaName, column_ids: $columnIds) {\n id\n name\n description\n parent_id\n revision\n }\n }\n": typeof types.DeleteObjectSchemaColumnsDocument, "\n query SearchItemsDev($query: String!, $limit: Int, $boardIds: [ID!]) {\n search {\n items(query: $query, limit: $limit, board_ids: $boardIds) {\n results {\n id\n }\n }\n }\n }\n": typeof types.SearchItemsDevDocument, "\n query SearchBoardsDev($query: String!, $limit: Int, $workspaceIds: [ID!]) {\n search {\n boards(query: $query, limit: $limit, workspace_ids: $workspaceIds) {\n results {\n id\n indexed_data {\n id\n name\n url\n }\n }\n }\n }\n }\n": typeof types.SearchBoardsDevDocument, @@ -28,11 +44,27 @@ type Documents = { "\n mutation CreateFormSubmission(\n $form_token: String!\n $answers: [FormAnswerInput!]!\n $form_timezone_offset: Int!\n $password: String\n $tags: [TagInput!]\n ) {\n create_form_submission(\n form_token: $form_token\n answers: $answers\n form_timezone_offset: $form_timezone_offset\n password: $password\n tags: $tags\n ) {\n id\n }\n }\n": typeof types.CreateFormSubmissionDocument, }; const documents: Documents = { + "\n mutation createAgentSkill($name: String!, $content: String!, $description: String) {\n create_agent_skill(name: $name, content: $content, description: $description) {\n id\n name\n description\n }\n }\n": types.CreateAgentSkillDocument, + "\n query getAgentTriggersCatalog($block_reference_ids: [ID!]) {\n agent_triggers_catalog(block_reference_ids: $block_reference_ids) {\n block_reference_id\n name\n description\n field_schemas {\n field_key\n value_schema\n }\n required_fields {\n field_key\n depends_on\n optional\n }\n }\n }\n": types.GetAgentTriggersCatalogDocument, + "\n query getAgentSkillsCatalog {\n agent_skills_catalog {\n id\n name\n description\n }\n }\n": types.GetAgentSkillsCatalogDocument, + "\n query getAgentKnowledge($id: ID!) {\n agent_knowledge(id: $id) {\n resources {\n resource_id\n scope_type\n permission_type\n }\n files {\n id\n file_name\n file_type\n }\n }\n }\n": types.GetAgentKnowledgeDocument, + "\n mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n": types.AddAgentResourceAccessDocument, + "\n mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) {\n remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) {\n success\n }\n }\n": types.RemoveAgentResourceAccessDocument, + "\n mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n": types.UpdateAgentResourceAccessDocument, + "\n mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) {\n add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n": types.AddSkillToAgentDocument, + "\n mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) {\n remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n": types.RemoveSkillFromAgentDocument, + "\n mutation activateAgent($id: ID!) {\n activate_agent(id: $id) {\n success\n }\n }\n": types.ActivateAgentDocument, + "\n mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) {\n deactivate_agent(id: $id, inactive_reason: $inactive_reason) {\n success\n }\n }\n": types.DeactivateAgentDocument, + "\n mutation runAgent($id: ID!) {\n run_agent(id: $id) {\n trigger_uuid\n }\n }\n": types.RunAgentDocument, + "\n query getAgentActiveTriggers($agent_id: ID!) {\n agent_active_triggers(agent_id: $agent_id) {\n node_id\n block_reference_id\n name\n description\n field_summary\n }\n }\n": types.GetAgentActiveTriggersDocument, + "\n mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) {\n add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) {\n success\n }\n }\n": types.AddTriggerToAgentDocument, + "\n mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) {\n remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) {\n success\n }\n }\n": types.RemoveTriggerFromAgentDocument, "\n fragment AgentFields on Agent {\n id\n kind\n state\n profile {\n name\n role\n role_description\n avatar_url\n background_color\n }\n goal\n plan\n user_prompt\n version_id\n created_at\n updated_at\n }\n": types.AgentFieldsFragmentDoc, "\n \n\n query getAgents($ids: [ID!], $limit: Int) {\n agents(ids: $ids, limit: $limit) {\n ...AgentFields\n }\n }\n": types.GetAgentsDocument, "\n \n\n mutation createAgent($input: CreateAgentInput!) {\n create_agent(input: $input) {\n ...AgentFields\n }\n }\n": types.CreateAgentDocument, "\n \n\n mutation createBlankAgent($input: CreateBlankAgentInput) {\n create_blank_agent(input: $input) {\n ...AgentFields\n }\n }\n": types.CreateBlankAgentDocument, "\n \n\n mutation deleteAgent($id: ID!) {\n delete_agent(id: $id) {\n ...AgentFields\n }\n }\n": types.DeleteAgentDocument, + "\n \n\n mutation updateAgent($id: ID!, $input: UpdateAgentInput!) {\n update_agent(id: $id, input: $input) {\n ...AgentFields\n }\n }\n": types.UpdateAgentDocument, "\n mutation DeleteObjectSchemaColumns($objectSchemaId: ID, $objectSchemaName: String, $columnIds: [ID!]!) {\n delete_object_schema_columns(object_schema_id: $objectSchemaId, object_schema_name: $objectSchemaName, column_ids: $columnIds) {\n id\n name\n description\n parent_id\n revision\n }\n }\n": types.DeleteObjectSchemaColumnsDocument, "\n query SearchItemsDev($query: String!, $limit: Int, $boardIds: [ID!]) {\n search {\n items(query: $query, limit: $limit, board_ids: $boardIds) {\n results {\n id\n }\n }\n }\n }\n": types.SearchItemsDevDocument, "\n query SearchBoardsDev($query: String!, $limit: Int, $workspaceIds: [ID!]) {\n search {\n boards(query: $query, limit: $limit, workspace_ids: $workspaceIds) {\n results {\n id\n indexed_data {\n id\n name\n url\n }\n }\n }\n }\n }\n": types.SearchBoardsDevDocument, @@ -56,6 +88,66 @@ const documents: Documents = { */ export function graphql(source: string): unknown; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation createAgentSkill($name: String!, $content: String!, $description: String) {\n create_agent_skill(name: $name, content: $content, description: $description) {\n id\n name\n description\n }\n }\n"): (typeof documents)["\n mutation createAgentSkill($name: String!, $content: String!, $description: String) {\n create_agent_skill(name: $name, content: $content, description: $description) {\n id\n name\n description\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query getAgentTriggersCatalog($block_reference_ids: [ID!]) {\n agent_triggers_catalog(block_reference_ids: $block_reference_ids) {\n block_reference_id\n name\n description\n field_schemas {\n field_key\n value_schema\n }\n required_fields {\n field_key\n depends_on\n optional\n }\n }\n }\n"): (typeof documents)["\n query getAgentTriggersCatalog($block_reference_ids: [ID!]) {\n agent_triggers_catalog(block_reference_ids: $block_reference_ids) {\n block_reference_id\n name\n description\n field_schemas {\n field_key\n value_schema\n }\n required_fields {\n field_key\n depends_on\n optional\n }\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query getAgentSkillsCatalog {\n agent_skills_catalog {\n id\n name\n description\n }\n }\n"): (typeof documents)["\n query getAgentSkillsCatalog {\n agent_skills_catalog {\n id\n name\n description\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query getAgentKnowledge($id: ID!) {\n agent_knowledge(id: $id) {\n resources {\n resource_id\n scope_type\n permission_type\n }\n files {\n id\n file_name\n file_type\n }\n }\n }\n"): (typeof documents)["\n query getAgentKnowledge($id: ID!) {\n agent_knowledge(id: $id) {\n resources {\n resource_id\n scope_type\n permission_type\n }\n files {\n id\n file_name\n file_type\n }\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n"): (typeof documents)["\n mutation addAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n add_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) {\n remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) {\n success\n }\n }\n"): (typeof documents)["\n mutation removeAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!) {\n remove_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n"): (typeof documents)["\n mutation updateAgentResourceAccess($id: ID!, $resource_id: ID!, $scope_type: KnowledgeScope!, $permission_type: KnowledgePermission!) {\n update_agent_resource_access(id: $id, resource_id: $resource_id, scope_type: $scope_type, permission_type: $permission_type) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) {\n add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n"): (typeof documents)["\n mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) {\n add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) {\n remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n"): (typeof documents)["\n mutation removeSkillFromAgent($agent_id: ID!, $skill_id: ID!) {\n remove_skill_from_agent(agent_id: $agent_id, skill_id: $skill_id) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation activateAgent($id: ID!) {\n activate_agent(id: $id) {\n success\n }\n }\n"): (typeof documents)["\n mutation activateAgent($id: ID!) {\n activate_agent(id: $id) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) {\n deactivate_agent(id: $id, inactive_reason: $inactive_reason) {\n success\n }\n }\n"): (typeof documents)["\n mutation deactivateAgent($id: ID!, $inactive_reason: InactiveReason) {\n deactivate_agent(id: $id, inactive_reason: $inactive_reason) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation runAgent($id: ID!) {\n run_agent(id: $id) {\n trigger_uuid\n }\n }\n"): (typeof documents)["\n mutation runAgent($id: ID!) {\n run_agent(id: $id) {\n trigger_uuid\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n query getAgentActiveTriggers($agent_id: ID!) {\n agent_active_triggers(agent_id: $agent_id) {\n node_id\n block_reference_id\n name\n description\n field_summary\n }\n }\n"): (typeof documents)["\n query getAgentActiveTriggers($agent_id: ID!) {\n agent_active_triggers(agent_id: $agent_id) {\n node_id\n block_reference_id\n name\n description\n field_summary\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) {\n add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) {\n success\n }\n }\n"): (typeof documents)["\n mutation addTriggerToAgent($agent_id: ID!, $block_reference_id: ID!, $field_values: JSON) {\n add_trigger_to_agent(agent_id: $agent_id, block_reference_id: $block_reference_id, field_values: $field_values) {\n success\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) {\n remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) {\n success\n }\n }\n"): (typeof documents)["\n mutation removeTriggerFromAgent($agent_id: ID!, $node_id: ID!) {\n remove_trigger_from_agent(agent_id: $agent_id, node_id: $node_id) {\n success\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ @@ -76,6 +168,10 @@ export function graphql(source: "\n \n\n mutation createBlankAgent($input: Cre * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ export function graphql(source: "\n \n\n mutation deleteAgent($id: ID!) {\n delete_agent(id: $id) {\n ...AgentFields\n }\n }\n"): (typeof documents)["\n \n\n mutation deleteAgent($id: ID!) {\n delete_agent(id: $id) {\n ...AgentFields\n }\n }\n"]; +/** + * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. + */ +export function graphql(source: "\n \n\n mutation updateAgent($id: ID!, $input: UpdateAgentInput!) {\n update_agent(id: $id, input: $input) {\n ...AgentFields\n }\n }\n"): (typeof documents)["\n \n\n mutation updateAgent($id: ID!, $input: UpdateAgentInput!) {\n update_agent(id: $id, input: $input) {\n ...AgentFields\n }\n }\n"]; /** * The graphql function is used to parse GraphQL queries into a document that can be used by GraphQL clients. */ diff --git a/packages/agent-toolkit/src/monday-graphql/generated/graphql/graphql.ts b/packages/agent-toolkit/src/monday-graphql/generated/graphql/graphql.ts index 3a751c3c..3096b1f7 100644 --- a/packages/agent-toolkit/src/monday-graphql/generated/graphql/graphql.ts +++ b/packages/agent-toolkit/src/monday-graphql/generated/graphql/graphql.ts @@ -946,6 +946,36 @@ export type AssignTeamOwnersResult = { team?: Maybe; }; +/** Structured result data for a completed or partially-completed operation */ +export type AsyncJobResult = { + __typename?: 'AsyncJobResult'; + /** Operation-specific details (failed item IDs, report URLs, etc.) */ + details?: Maybe; + /** Items that failed */ + failed?: Maybe; + /** Successfully processed items */ + succeeded?: Maybe; + /** Total items in the operation */ + total?: Maybe; +}; + +/** Status information for an async job */ +export type AsyncJobStatus = { + __typename?: 'AsyncJobStatus'; + /** When the job was created (ISO 8601) */ + created_at?: Maybe; + /** Error description if the job failed */ + error?: Maybe; + /** Unique job identifier */ + id?: Maybe; + /** Structured result data for completed or partially-completed operations */ + result?: Maybe; + /** Current job status */ + status?: Maybe; + /** When the job was last updated (ISO 8601) */ + updated_at?: Maybe; +}; + /** Text formatting attributes (bold, italic, links, colors, etc.) */ export type Attributes = { __typename?: 'Attributes'; @@ -4892,6 +4922,22 @@ export type ItemsResponse = { items: Array; }; +/** Status of an async job */ +export enum JobState { + /** Job was cancelled */ + Cancelled = 'CANCELLED', + /** Job completed successfully */ + Completed = 'COMPLETED', + /** Job expired before completion */ + Expired = 'EXPIRED', + /** Job failed */ + Failed = 'FAILED', + /** Job is queued but not yet started */ + Pending = 'PENDING', + /** Job is actively executing */ + Running = 'RUNNING' +} + /** Status of a job operation. Currently supports items job status for backfill and ingest operations. */ export type JobStatus = ItemsJobStatus; @@ -8214,6 +8260,8 @@ export type Query = { items?: Maybe>>; /** Search items by multiple columns and values. */ items_page_by_column_values: ItemsResponse; + /** Get the status of an async job by its external ID */ + job_status: AsyncJobStatus; /** Search knowledge base snippets. */ knowledge_base_search?: Maybe; /** Get managed column data. */ @@ -8602,6 +8650,12 @@ export type QueryItems_Page_By_Column_ValuesArgs = { }; +/** Root query type for the Dependencies service */ +export type QueryJob_StatusArgs = { + job_id: Scalars['ID']['input']; +}; + + /** Root query type for the Dependencies service */ export type QueryKnowledge_Base_SearchArgs = { limit?: InputMaybe; @@ -9081,6 +9135,8 @@ export type SearchDocResults = { /** Board data stored in the search index. */ export type SearchIndexedBoard = { __typename?: 'SearchIndexedBoard'; + /** ID of the user who created this board. */ + creator_id?: Maybe; /** Board description. */ description?: Maybe; /** Board ID. */ @@ -9151,6 +9207,7 @@ export type SearchNamespace = { /** Per-entity search namespace. Each field searches a single entity type. */ export type SearchNamespaceBoardsArgs = { + board_ids?: InputMaybe>; date_range?: InputMaybe; limit?: InputMaybe; query: Scalars['String']['input']; @@ -11305,12 +11362,6 @@ export type __Schema = { directives: Array<__Directive>; }; - -/** A GraphQL Schema defines the capabilities of a GraphQL server. It exposes all available types and directives on the server, as well as the entry points for query, mutation, and subscription operations. */ -export type __SchemaDirectivesArgs = { - includeDeprecated?: Scalars['Boolean']['input']; -}; - /** * The fundamental unit of any GraphQL Schema is the type. There are many kinds of types in GraphQL as represented by the `__TypeKind` enum. * @@ -11328,7 +11379,6 @@ export type __Type = { enumValues?: Maybe>; inputFields?: Maybe>; ofType?: Maybe<__Type>; - isOneOf?: Maybe; }; @@ -11431,8 +11481,6 @@ export type __Directive = { isRepeatable: Scalars['Boolean']['output']; locations: Array<__DirectiveLocation>; args: Array<__InputValue>; - isDeprecated: Scalars['Boolean']['output']; - deprecationReason?: Maybe; }; @@ -11484,9 +11532,7 @@ export enum __DirectiveLocation { /** Location adjacent to an input object type definition. */ InputObject = 'INPUT_OBJECT', /** Location adjacent to an input object field definition. */ - InputFieldDefinition = 'INPUT_FIELD_DEFINITION', - /** Location adjacent to a directive definition. */ - DirectiveDefinition = 'DIRECTIVE_DEFINITION' + InputFieldDefinition = 'INPUT_FIELD_DEFINITION' } export type GetSprintsByIdsQueryVariables = Exact<{ diff --git a/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql b/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql index 2a6e5696..efdd99c7 100644 --- a/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql +++ b/packages/agent-toolkit/src/monday-graphql/schema.dev.graphql @@ -1417,6 +1417,11 @@ skill_id: ID!): MutationResult remove_skill_from_agent( "Unique identifier of the agent" agent_id: ID!, "Skill reference id to detach" skill_id: ID!): MutationResult + "Create a new skill for the account. The skill will appear in agent_skills_catalog and can be attached to any agent via add_skill_to_agent." + create_agent_skill( "Display name of the skill" +name: String!, "Markdown instructions defining what the skill does" +content: String!, "Short description of the skill" +description: String): AgentSkillCatalogEntry "Creates a new app with the specified configuration." create_app( "App configuration data" input: CreateAppInput!): CreateAppResponse @@ -12311,6 +12316,8 @@ type SearchIndexedBoard { description: String "ID of the workspace containing this board." workspace_id: ID + "ID of the user who created this board." + creator_id: ID "URL to view this board." url: String! } @@ -12370,7 +12377,8 @@ workspace_ids: [ID!]): SearchItemResults! query: String!, "Maximum number of results to return (default 10, max 20)." limit: Int = 10, "Date range filter." date_range: CrossEntityDateRangeInput, "Controls the trade-off between search quality and response time. Defaults to balanced." -strategy: SearchStrategy, "Filter boards to specific workspace IDs." +strategy: SearchStrategy, "Filter boards to specific board IDs." +board_ids: [ID!], "Filter boards to specific workspace IDs." workspace_ids: [ID!]): SearchBoardResults! "Search for documents." docs( "The search query string." diff --git a/packages/agent-toolkit/src/monday-graphql/schema.graphql b/packages/agent-toolkit/src/monday-graphql/schema.graphql index 574d3ca9..f7915d34 100644 --- a/packages/agent-toolkit/src/monday-graphql/schema.graphql +++ b/packages/agent-toolkit/src/monday-graphql/schema.graphql @@ -459,6 +459,9 @@ board_id: ID!): [Sequence!] "Get a collection of monday dev sprints" sprints( "A list of monday dev sprints unique identifiers" ids: [ID!]!): [Sprint!] + "Get the status of an async job by its external ID" + job_status( "The job ID returned by the originating mutation" +job_id: ID!): AsyncJobStatus! "Get all roles for the account" account_roles: [AccountRole!] "Get all user configs for the account." @@ -7935,6 +7938,8 @@ type SearchIndexedBoard { description: String "ID of the workspace containing this board." workspace_id: ID + "ID of the user who created this board." + creator_id: ID "URL to view this board." url: String! } @@ -7994,7 +7999,8 @@ workspace_ids: [ID!]): SearchItemResults! query: String!, "Maximum number of results to return (default 10, max 20)." limit: Int = 10, "Date range filter." date_range: CrossEntityDateRangeInput, "Controls the trade-off between search quality and response time. Defaults to balanced." -strategy: SearchStrategy, "Filter boards to specific workspace IDs." +strategy: SearchStrategy, "Filter boards to specific board IDs." +board_ids: [ID!], "Filter boards to specific workspace IDs." workspace_ids: [ID!]): SearchBoardResults! "Search for documents." docs( "The search query string." @@ -8166,6 +8172,50 @@ type SprintTimeline { to: Date } +"Structured result data for a completed or partially-completed operation" +type AsyncJobResult { + "Total items in the operation" + total: Int + "Successfully processed items" + succeeded: Int + "Items that failed" + failed: Int + "Operation-specific details (failed item IDs, report URLs, etc.)" + details: JSON +} + +"Status information for an async job" +type AsyncJobStatus { + "Unique job identifier" + id: ID + "Current job status" + status: JobState + "When the job was created (ISO 8601)" + created_at: String + "When the job was last updated (ISO 8601)" + updated_at: String + "Error description if the job failed" + error: String + "Structured result data for completed or partially-completed operations" + result: AsyncJobResult +} + +"Status of an async job" +enum JobState { + "Job is queued but not yet started" + PENDING + "Job is actively executing" + RUNNING + "Job completed successfully" + COMPLETED + "Job failed" + FAILED + "Job expired before completion" + EXPIRED + "Job was cancelled" + CANCELLED +} + "A role in the account" type AccountRole { "The ID of the role" From 01b475572d34aa98b15fc3534214ab9dd0099a51 Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Thu, 14 May 2026 13:16:47 +0300 Subject: [PATCH 27/28] fix(agent-toolkit): address PR #343 review feedback on agent tools MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Fix Prettier indent in create-agent-tool.ts (CI blocker) - update_agent: rename id→agent_id for consistency with new tools, use z.nativeEnum(AgentModel), fix description to list only updatable fields, add empty-input guard, fix return shape to { message, agent } - manage_agent_state: remove inactive_reason (1-value enum always defaulted), hardcode DeactivatedByUser, clarify trigger_uuid has no companion run-status query - manage_agent_knowledge: scope "call list first" to update/remove, add count field to list response - manage_agent_triggers: narrow field_values to typed union, add OAuth exclusion note, clarify add returns no node_id - get_agent_catalog: add .min(1) to block_reference_ids - Update tests: split 3-expect test, agent_id naming, new return shape, simplified inactive_reason coverage - Add CHANGELOG.md entry for 5.11.0 Co-authored-by: Cursor --- packages/agent-toolkit/CHANGELOG.md | 13 +++++++ .../create-agent/create-agent-tool.ts | 12 +++---- .../get-agent-catalog-tool.ts | 1 + .../manage-agent-knowledge-tool.ts | 12 +++---- .../manage-agent-state-tool.test.ts | 24 +------------ .../manage-agent-state-tool.ts | 12 ++----- .../manage-agent-triggers-tool.ts | 7 ++-- .../update-agent/update-agent-tool.test.ts | 36 ++++++++++++------- .../update-agent/update-agent-tool.ts | 35 ++++++++++-------- 9 files changed, 80 insertions(+), 72 deletions(-) diff --git a/packages/agent-toolkit/CHANGELOG.md b/packages/agent-toolkit/CHANGELOG.md index c6818aaf..9c906a68 100644 --- a/packages/agent-toolkit/CHANGELOG.md +++ b/packages/agent-toolkit/CHANGELOG.md @@ -1,5 +1,18 @@ # Changelog +## 5.11.0 + +### Add agent management tools + +Six new tools enabling agents to create and manage monday.com platform agents end-to-end: + +- `manage_agent_state` — activate, deactivate, or manually trigger a run +- `manage_agent_knowledge` — grant, update, or revoke a board/doc access for an agent +- `manage_agent_skills` — create account-wide skills and attach/detach them to agents +- `manage_agent_triggers` — list, add, or remove triggers; catalog lookup workflow built in +- `get_agent_catalog` — fetch available trigger types and skills from the account catalog +- Extended `update_agent` with `agent_id` naming alignment, enum-safe `agent_model`, empty-input guard, and consistent return shape + ## 5.7.1 ### form_questions_editor — fix ConditionOperator and remove existing_column_id diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts index 7d109ebc..36aa5cb4 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent/create-agent-tool.ts @@ -163,12 +163,12 @@ USAGE EXAMPLES: throw new Error('monday platform agent creation returned no id'); } - return { - content: { - message: `monday platform agent ${res.create_agent.id} created in state INACTIVE — call manage_agent_state with action:activate and agent_id:${res.create_agent.id} to activate it`, - agent: res.create_agent, - }, - }; + return { + content: { + message: `monday platform agent ${res.create_agent.id} created in state INACTIVE — call manage_agent_state with action:activate and agent_id:${res.create_agent.id} to activate it`, + agent: res.create_agent, + }, + }; } catch (error) { rethrowWithContext(error, 'create monday platform agent'); } diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts index 0ce39cb1..8f522953 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/get-agent-catalog/get-agent-catalog-tool.ts @@ -17,6 +17,7 @@ export const getAgentCatalogToolSchema = { ), block_reference_ids: z .array(z.string()) + .min(1) .optional() .describe( 'Only applies when type is "triggers". Fetch specific entries by block_reference_id instead of the full catalog. Omit to return all trigger types.', diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts index 6b363a2e..5c214c53 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-knowledge/manage-agent-knowledge-tool.ts @@ -59,12 +59,10 @@ export class ManageAgentKnowledgeTool extends BaseMondayApiTool { jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); }); - // Happy path tests it('should activate an agent successfully', async () => { mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); @@ -52,7 +51,6 @@ describe('ManageAgentStateTool', () => { expect(parsed.trigger_uuid).toBe('uuid-123'); }); - // versionOverride dev it('should pass versionOverride:dev for activate', async () => { mocks.setResponseOnce({ activate_agent: { success: true } } as ActivateAgentMutation); @@ -68,8 +66,7 @@ describe('ManageAgentStateTool', () => { ); }); - // Default inactive_reason - it('should default inactive_reason to DeactivatedByUser when not provided', async () => { + it('should always send DeactivatedByUser as inactive_reason', async () => { mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); await callToolByNameRawAsync('manage_agent_state', { @@ -84,24 +81,6 @@ describe('ManageAgentStateTool', () => { ); }); - // Explicit inactive_reason - it('should pass explicit inactive_reason DEACTIVATED_BY_USER when provided', async () => { - mocks.setResponseOnce({ deactivate_agent: { success: true } } as DeactivateAgentMutation); - - await callToolByNameRawAsync('manage_agent_state', { - action: 'deactivate', - agent_id: '7', - inactive_reason: 'DEACTIVATED_BY_USER', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('deactivateAgent'), - expect.objectContaining({ inactive_reason: InactiveReason.DeactivatedByUser }), - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - // Error propagation it('should propagate errors with context for activate', async () => { mocks.setError('API error'); @@ -135,7 +114,6 @@ describe('ManageAgentStateTool', () => { expect(result.content[0].text).toContain('Failed to run'); }); - // success:false fallback it('should return success:false when activate_agent is null', async () => { mocks.setResponseOnce({ activate_agent: null } as ActivateAgentMutation); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts index 63e81713..df5361d3 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-state/manage-agent-state-tool.ts @@ -22,12 +22,6 @@ export const manageAgentStateToolSchema = { '"activate" — transitions the agent to ACTIVE state. "deactivate" — transitions the agent to INACTIVE. "run" — manually enqueues a run of the agent.', ), agent_id: z.string().trim().min(1).describe('Unique identifier of the agent.'), - inactive_reason: z - .enum(['DEACTIVATED_BY_USER']) - .optional() - .describe( - 'Only for action:deactivate. Pass "DEACTIVATED_BY_USER" when the user has clearly expressed intent to deactivate (e.g. "pause the agent", "turn it off", "I\'m going on vacation"). Omit if the reason is ambiguous — do not guess.', - ), }; export class ManageAgentStateTool extends BaseMondayApiTool { @@ -44,8 +38,8 @@ export class ManageAgentStateTool extends BaseMondayApiTool", "label": "" }.', + 'Required for action:add when the trigger type has required_fields. A key/value object whose shape is described by field_schemas in the get_agent_catalog response. Scalar fields (e.g. { "board_id": "12345" }) use string/number/boolean values. Selection fields (e.g. board picker) use { "value": "", "label": "" }. For scheduler fields pass the structured config object.', ), node_id: z .string() @@ -62,10 +62,13 @@ export class ManageAgentTriggersTool extends BaseMondayApiTool" }) and required_fields (fields you must collect from the user — e.g. which board, which column). 2. Collect any required field values from the user. 3. Call this tool with action:"add", the block_reference_id, and the assembled field_values. +Note: the add response returns only { success } — no node_id for the new trigger. Call action:"list" afterward if you need the node_id to remove it later. WORKFLOW FOR REMOVE: 1. Call this tool with action:"list" to see active triggers by name and field_summary. Match the trigger the user described, note its node_id. diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts index 1ef4187d..7a8384f0 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.test.ts @@ -29,22 +29,28 @@ describe('UpdateAgentTool', () => { jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); }); - it('should update agent name — happy path', async () => { + it('should return agent id on update — happy path', async () => { mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); - const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'Updated Agent' }); + const result = await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'Updated Agent' }); const parsed = parseToolResult(result); - expect(parsed.id).toBe('7'); - // also assert something from the profile to confirm response forwarding - expect(parsed.profile).toBeDefined(); - expect(parsed.profile.name).toBe('Updated Agent'); + expect(parsed.agent.id).toBe('7'); + }); + + it('should return agent profile on update — happy path', async () => { + mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); + + const result = await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'Updated Agent' }); + const parsed = parseToolResult(result); + + expect(parsed.agent.profile.name).toBe('Updated Agent'); }); it('should update multiple fields — happy path', async () => { mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); - const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'X', plan: 'step 1' }); + const result = await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'X', plan: 'step 1' }); expect(mocks.getMockRequest()).toHaveBeenCalled(); expect(result).toBeDefined(); @@ -53,7 +59,7 @@ describe('UpdateAgentTool', () => { it('should only include provided fields in input object', async () => { mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); - await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'X' }); expect(mocks.getMockRequest()).toHaveBeenCalledWith( expect.anything(), @@ -65,7 +71,7 @@ describe('UpdateAgentTool', () => { it('should not include omitted fields in input object', async () => { mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); - await callToolByNameRawAsync('update_agent', { id: '7', role: 'Bot' }); + await callToolByNameRawAsync('update_agent', { agent_id: '7', role: 'Bot' }); expect(mocks.getMockRequest()).toHaveBeenCalledWith( expect.anything(), @@ -81,7 +87,7 @@ describe('UpdateAgentTool', () => { it('should pass versionOverride dev', async () => { mocks.setResponseOnce({ update_agent: { ...mockAgent } } as UpdateAgentMutation); - await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'X' }); expect(mocks.getMockRequest()).toHaveBeenCalledWith( expect.anything(), @@ -90,10 +96,16 @@ describe('UpdateAgentTool', () => { ); }); + it('should throw when no fields are provided', async () => { + const result = await callToolByNameRawAsync('update_agent', { agent_id: '7' }); + + expect(result.content[0].text).toContain('At least one field must be provided'); + }); + it('should throw when update_agent returns null', async () => { mocks.setResponseOnce({ update_agent: null } as UpdateAgentMutation); - const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + const result = await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'X' }); expect(result.content[0].text).toContain('update_agent returned no data'); }); @@ -101,7 +113,7 @@ describe('UpdateAgentTool', () => { it('should propagate API errors with context', async () => { mocks.setError('API error'); - const result = await callToolByNameRawAsync('update_agent', { id: '7', name: 'X' }); + const result = await callToolByNameRawAsync('update_agent', { agent_id: '7', name: 'X' }); expect(result.content[0].text).toContain('Failed to update monday platform agent'); }); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts index bb507d64..24911e08 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/update-agent/update-agent-tool.ts @@ -11,7 +11,7 @@ import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday import { rethrowWithContext } from '../../../../../utils'; export const updateAgentToolSchema = { - id: z.string().trim().min(1).describe('Unique identifier of the agent to update'), + agent_id: z.string().trim().min(1).describe('Unique identifier of the agent to update'), name: z.string().trim().min(1).optional().describe('New display name for the agent'), role: z.string().trim().min(1).optional().describe('Short role title (e.g. "Customer Success Bot")'), role_description: z @@ -22,11 +22,11 @@ export const updateAgentToolSchema = { .describe("Detailed description of the agent's role"), plan: z.string().trim().min(1).optional().describe('Step-by-step execution plan in markdown'), agent_model: z - .string() - .trim() - .min(1) + .nativeEnum(AgentModel) .optional() - .describe('AI model identifier. STRONGLY DISCOURAGED — omit this field. Only set when the user explicitly names a monday-supported model. Do not invent or guess model identifiers — use the exact string the user provided.'), + .describe( + 'AI model identifier. STRONGLY DISCOURAGED — omit unless the user explicitly names a supported model. Invalid model identifiers are rejected by the server. Omit to keep the current model.', + ), }; export class UpdateAgentTool extends BaseMondayApiTool { @@ -40,15 +40,18 @@ export class UpdateAgentTool extends BaseMondayApiTool(updateAgentMutation, variables, { versionOverride: 'dev', }); @@ -72,7 +79,7 @@ USAGE EXAMPLE: if (!res.update_agent) { throw new Error('update_agent returned no data — the agent may not exist'); } - return { content: res.update_agent }; + return { content: { message: 'monday platform agent updated', agent: res.update_agent } }; } catch (error) { rethrowWithContext(error, 'update monday platform agent'); } From 68dffd0c93142b8df52bb9b1a78917d4235d846b Mon Sep 17 00:00:00 2001 From: Nadav Avraham Date: Thu, 14 May 2026 13:21:25 +0300 Subject: [PATCH 28/28] refactor(agent-toolkit): split create_agent_skill out of manage_agent_skills create_agent_skill (account-catalog CRUD) and manage_agent_skills (attach/detach on a specific agent) operate on different domain entities, so they now live in separate tools. manage_agent_skills action enum shrinks to [add, remove]; all create logic and the createAgentSkill GraphQL mutation move to the new create_agent_skill tool. Co-authored-by: Cursor --- .../create-agent-skill-tool.test.ts | 79 +++++++++++++ .../create-agent-skill-tool.ts | 76 +++++++++++++ .../create-agent-skill.graphql.dev.ts | 11 ++ .../platform-api-tools/agents-tools/index.ts | 1 + .../manage-agent-skills-tool.test.ts | 73 ------------ .../manage-agent-skills-tool.ts | 107 +++--------------- .../manage-agent-skills.graphql.dev.ts | 10 -- .../core/tools/platform-api-tools/index.ts | 2 + 8 files changed, 186 insertions(+), 173 deletions(-) create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts create mode 100644 packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts new file mode 100644 index 00000000..d916d3e9 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.test.ts @@ -0,0 +1,79 @@ +import { MondayAgentToolkit } from 'src/mcp/toolkit'; +import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; +import { CreateAgentSkillMutation } from 'src/monday-graphql/generated/graphql.dev/graphql'; + +const mockSkill = { id: 'skill-123', name: 'Send Slack Message', description: 'Posts to Slack' }; + +describe('CreateAgentSkillTool', () => { + let mocks: ReturnType; + + beforeEach(() => { + mocks = createMockApiClient(); + jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); + }); + + it('should create a skill and return it', async () => { + mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); + + const result = await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nPost a message.', + }); + const parsed = parseToolResult(result); + + expect(parsed.skill.id).toBe('skill-123'); + }); + + it('should pass name, content, and description to the mutation', async () => { + mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); + + await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions\nPost a message.', + description: 'Posts to Slack', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.stringContaining('createAgentSkill'), + { name: 'Send Slack Message', content: '## Instructions\nPost a message.', description: 'Posts to Slack' }, + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should pass versionOverride dev', async () => { + mocks.setResponseOnce({ create_agent_skill: mockSkill } as CreateAgentSkillMutation); + + await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions', + }); + + expect(mocks.getMockRequest()).toHaveBeenCalledWith( + expect.anything(), + expect.anything(), + expect.objectContaining({ versionOverride: 'dev' }), + ); + }); + + it('should throw when create_agent_skill returns null', async () => { + mocks.setResponseOnce({ create_agent_skill: null } as CreateAgentSkillMutation); + + const result = await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions', + }); + + expect(result.content[0].text).toContain('create_agent_skill returned no data'); + }); + + it('should propagate API errors with context', async () => { + mocks.setError('API error'); + + const result = await callToolByNameRawAsync('create_agent_skill', { + name: 'Send Slack Message', + content: '## Instructions', + }); + + expect(result.content[0].text).toContain('Failed to create monday platform agent skill'); + }); +}); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts new file mode 100644 index 00000000..56927c50 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill-tool.ts @@ -0,0 +1,76 @@ +import { z } from 'zod'; +import { + CreateAgentSkillMutation, + CreateAgentSkillMutationVariables, +} from '../../../../../monday-graphql/generated/graphql.dev/graphql'; +import { createAgentSkillMutation } from './create-agent-skill.graphql.dev'; +import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; +import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; +import { rethrowWithContext } from '../../../../../utils'; + +export const createAgentSkillToolSchema = { + name: z.string().trim().min(1).describe('Display name of the new skill.'), + content: z + .string() + .trim() + .min(1) + .describe('Markdown instructions defining what the skill does and how to execute it.'), + description: z + .string() + .trim() + .min(1) + .optional() + .describe('Short description of the skill shown in the catalog.'), +}; + +export class CreateAgentSkillTool extends BaseMondayApiTool { + name = 'create_agent_skill'; + type = ToolType.WRITE; + annotations = createMondayApiAnnotations({ + title: 'Create monday Platform Agent Skill', + readOnlyHint: false, + destructiveHint: false, + idempotentHint: false, + }); + + getDescription(): string { + return `Create a new custom skill in the account-wide skill catalog. + +Skills extend what an agent can do — for example, sending emails, searching the web, or querying databases. A skill created here is available to all agents in the account. + +After creating a skill, use manage_agent_skills with action:"add" and the returned id to attach it to a specific agent. + +USAGE EXAMPLE: +- { "name": "Send Slack Message", "content": "## Instructions\\nPost a message to a Slack channel.", "description": "Sends a message to Slack" }`; + } + + getInputSchema() { + return createAgentSkillToolSchema; + } + + protected async executeInternal( + input: ToolInputType, + ): Promise> { + try { + const variables: CreateAgentSkillMutationVariables = { + name: input.name, + content: input.content, + description: input.description, + }; + const res = await this.mondayApi.request(createAgentSkillMutation, variables, { + versionOverride: 'dev', + }); + if (!res.create_agent_skill) { + throw new Error('create_agent_skill returned no data'); + } + return { + content: { + message: 'Skill created. Use the returned id with manage_agent_skills action:add to attach it to an agent.', + skill: res.create_agent_skill, + }, + }; + } catch (error) { + rethrowWithContext(error, 'create monday platform agent skill'); + } + } +} diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts new file mode 100644 index 00000000..7f145120 --- /dev/null +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/create-agent-skill/create-agent-skill.graphql.dev.ts @@ -0,0 +1,11 @@ +import { gql } from 'graphql-request'; + +export const createAgentSkillMutation = gql` + mutation createAgentSkill($name: String!, $content: String!, $description: String) { + create_agent_skill(name: $name, content: $content, description: $description) { + id + name + description + } + } +`; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts index 7fdcf4d9..08c627fd 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/index.ts @@ -3,6 +3,7 @@ export * from './create-agent/create-agent-tool'; export * from './delete-agent/delete-agent-tool'; export * from './get-agent-catalog/get-agent-catalog-tool'; export * from './manage-agent-triggers/manage-agent-triggers-tool'; +export * from './create-agent-skill/create-agent-skill-tool'; export * from './manage-agent-skills/manage-agent-skills-tool'; export * from './update-agent/update-agent-tool'; export * from './manage-agent-state/manage-agent-state-tool'; diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts index 0ff2ccec..ab367004 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.test.ts @@ -1,7 +1,6 @@ import { MondayAgentToolkit } from 'src/mcp/toolkit'; import { callToolByNameRawAsync, createMockApiClient, parseToolResult } from '../../test-utils/mock-api-client'; import { - CreateAgentSkillMutation, AddSkillToAgentMutation, RemoveSkillFromAgentMutation, } from 'src/monday-graphql/generated/graphql.dev/graphql'; @@ -14,72 +13,6 @@ describe('ManageAgentSkillsTool', () => { jest.spyOn(MondayAgentToolkit.prototype as any, 'createApiClient').mockReturnValue(mocks.mockApiClient); }); - const mockCreatedSkill = { id: 'skill-123', name: 'Send Slack Message', description: 'Posts to Slack' }; - - // create - it('should create a skill and return it', async () => { - mocks.setResponseOnce({ create_agent_skill: mockCreatedSkill } as CreateAgentSkillMutation); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'create', - name: 'Send Slack Message', - content: '## Instructions\nPost a message.', - }); - const parsed = parseToolResult(result); - - expect(parsed.skill.id).toBe('skill-123'); - }); - - it('should pass name, content, and description when creating', async () => { - mocks.setResponseOnce({ create_agent_skill: mockCreatedSkill } as CreateAgentSkillMutation); - - await callToolByNameRawAsync('manage_agent_skills', { - action: 'create', - name: 'Send Slack Message', - content: '## Instructions\nPost a message.', - description: 'Posts to Slack', - }); - - expect(mocks.getMockRequest()).toHaveBeenCalledWith( - expect.stringContaining('createAgentSkill'), - { name: 'Send Slack Message', content: '## Instructions\nPost a message.', description: 'Posts to Slack' }, - expect.objectContaining({ versionOverride: 'dev' }), - ); - }); - - it('should reject create without name', async () => { - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'create', - content: '## Instructions', - }); - expect(result.content[0].text).toContain('name and content are required'); - }); - - it('should throw when create_agent_skill returns null', async () => { - mocks.setResponseOnce({ create_agent_skill: null } as CreateAgentSkillMutation); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'create', - name: 'Send Slack Message', - content: '## Instructions', - }); - - expect(result.content[0].text).toContain('create_agent_skill returned no data'); - }); - - it('should propagate errors with operation context for create', async () => { - mocks.setError('API error'); - - const result = await callToolByNameRawAsync('manage_agent_skills', { - action: 'create', - name: 'Send Slack Message', - content: '## Instructions', - }); - - expect(result.content[0].text).toContain('Failed to create monday platform agent skill'); - }); - - // add it('should add a skill to an agent', async () => { mocks.setResponseOnce({ add_skill_to_agent: { success: true } } as AddSkillToAgentMutation); @@ -104,11 +37,6 @@ describe('ManageAgentSkillsTool', () => { ); }); - it('should reject add without agent_id', async () => { - const result = await callToolByNameRawAsync('manage_agent_skills', { action: 'add', skill_id: 'skill-abc-123' }); - expect(result.content[0].text).toContain('agent_id and skill_id are required'); - }); - it('should propagate errors with operation context for add', async () => { mocks.setError('API error'); @@ -131,7 +59,6 @@ describe('ManageAgentSkillsTool', () => { expect(parseToolResult(result).success).toBe(false); }); - // remove it('should remove a skill from an agent', async () => { mocks.setResponseOnce({ remove_skill_from_agent: { success: true } } as RemoveSkillFromAgentMutation); diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts index 5d748d0c..ae2547d5 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills-tool.ts @@ -1,53 +1,26 @@ import { z } from 'zod'; import { - CreateAgentSkillMutation, - CreateAgentSkillMutationVariables, AddSkillToAgentMutation, AddSkillToAgentMutationVariables, RemoveSkillFromAgentMutation, RemoveSkillFromAgentMutationVariables, } from '../../../../../monday-graphql/generated/graphql.dev/graphql'; -import { - createAgentSkillMutation, - addSkillToAgentMutation, - removeSkillFromAgentMutation, -} from './manage-agent-skills.graphql.dev'; +import { addSkillToAgentMutation, removeSkillFromAgentMutation } from './manage-agent-skills.graphql.dev'; import { ToolInputType, ToolOutputType, ToolType } from '../../../../tool'; import { BaseMondayApiTool, createMondayApiAnnotations } from '../../base-monday-api-tool'; import { rethrowWithContext } from '../../../../../utils'; export const manageAgentSkillsToolSchema = { action: z - .enum(['create', 'add', 'remove']) - .describe('"create" makes a new custom skill in the account catalog. "add" attaches an existing skill to an agent. "remove" detaches a skill from an agent.'), - // create only - name: z.string().trim().min(1).optional().describe('Required for action:create. Display name of the new skill.'), - content: z - .string() - .trim() - .min(1) - .optional() - .describe('Required for action:create. Markdown instructions defining what the skill does and how to execute it.'), - description: z - .string() - .trim() - .min(1) - .optional() - .describe('Optional for action:create. Short description of the skill shown in the catalog.'), - // add, remove only - agent_id: z - .string() - .trim() - .min(1) - .optional() - .describe('Required for action:add and action:remove. Unique identifier of the agent.'), + .enum(['add', 'remove']) + .describe('"add" attaches an existing skill to an agent. "remove" detaches a skill from an agent.'), + agent_id: z.string().trim().min(1).describe('Unique identifier of the agent.'), skill_id: z .string() .trim() .min(1) - .optional() .describe( - 'Required for action:add and action:remove. The skill ID from get_agent_catalog (type:skills) or the id returned by action:create. Never guess or invent a skill ID.', + 'The skill ID from get_agent_catalog (type:skills) or the id returned by create_agent_skill. Never guess or invent a skill ID.', ), }; @@ -62,25 +35,14 @@ export class ManageAgentSkillsTool extends BaseMondayApiTool, ): Promise> { - if (input.action === 'create') { - if (!input.name || !input.content) { - throw new Error('name and content are required for action:create'); - } - try { - const variables: CreateAgentSkillMutationVariables = { - name: input.name, - content: input.content, - description: input.description, - }; - const res = await this.mondayApi.request( - createAgentSkillMutation, - variables, - { versionOverride: 'dev' }, - ); - if (!res.create_agent_skill) { - throw new Error('create_agent_skill returned no data'); - } - return { - content: { - message: 'Skill created. Use the returned id with action:add to attach it to an agent.', - skill: res.create_agent_skill, - }, - }; - } catch (error) { - rethrowWithContext(error, 'create monday platform agent skill'); - } - } - - if (!input.agent_id || !input.skill_id) { - throw new Error('agent_id and skill_id are required for action:add and action:remove'); - } - if (input.action === 'add') { try { const variables: AddSkillToAgentMutationVariables = { agent_id: input.agent_id, skill_id: input.skill_id }; - const res = await this.mondayApi.request( - addSkillToAgentMutation, - variables, - { versionOverride: 'dev' }, - ); + const res = await this.mondayApi.request(addSkillToAgentMutation, variables, { + versionOverride: 'dev', + }); return { content: { message: 'Skill added to agent.', success: res.add_skill_to_agent?.success ?? false } }; } catch (error) { rethrowWithContext(error, 'add skill to monday platform agent'); @@ -140,12 +67,12 @@ USAGE EXAMPLES: } else { try { const variables: RemoveSkillFromAgentMutationVariables = { agent_id: input.agent_id, skill_id: input.skill_id }; - const res = await this.mondayApi.request( - removeSkillFromAgentMutation, - variables, - { versionOverride: 'dev' }, - ); - return { content: { message: 'Skill removed from agent.', success: res.remove_skill_from_agent?.success ?? false } }; + const res = await this.mondayApi.request(removeSkillFromAgentMutation, variables, { + versionOverride: 'dev', + }); + return { + content: { message: 'Skill removed from agent.', success: res.remove_skill_from_agent?.success ?? false }, + }; } catch (error) { rethrowWithContext(error, 'remove skill from monday platform agent'); } diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts index 07bc51f6..d58f3fee 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/agents-tools/manage-agent-skills/manage-agent-skills.graphql.dev.ts @@ -1,15 +1,5 @@ import { gql } from 'graphql-request'; -export const createAgentSkillMutation = gql` - mutation createAgentSkill($name: String!, $content: String!, $description: String) { - create_agent_skill(name: $name, content: $content, description: $description) { - id - name - description - } - } -`; - export const addSkillToAgentMutation = gql` mutation addSkillToAgent($agent_id: ID!, $skill_id: ID!) { add_skill_to_agent(agent_id: $agent_id, skill_id: $skill_id) { diff --git a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts index 4846b1e5..39495902 100644 --- a/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts +++ b/packages/agent-toolkit/src/core/tools/platform-api-tools/index.ts @@ -70,6 +70,7 @@ import { CreateAgentTool } from './agents-tools/create-agent/create-agent-tool'; import { DeleteAgentTool } from './agents-tools/delete-agent/delete-agent-tool'; import { GetAgentCatalogTool } from './agents-tools/get-agent-catalog/get-agent-catalog-tool'; import { ManageAgentTriggersTool } from './agents-tools/manage-agent-triggers/manage-agent-triggers-tool'; +import { CreateAgentSkillTool } from './agents-tools/create-agent-skill/create-agent-skill-tool'; import { ManageAgentSkillsTool } from './agents-tools/manage-agent-skills/manage-agent-skills-tool'; import { UpdateAgentTool } from './agents-tools/update-agent/update-agent-tool'; import { ManageAgentStateTool } from './agents-tools/manage-agent-state/manage-agent-state-tool'; @@ -149,6 +150,7 @@ export const allGraphqlApiTools: BaseMondayApiToolConstructor[] = [ DeleteAgentTool, GetAgentCatalogTool, ManageAgentTriggersTool, + CreateAgentSkillTool, ManageAgentSkillsTool, UpdateAgentTool, ManageAgentStateTool,