feat(agent-toolkit): agents subgraph tools expansion#343
Conversation
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…d test assertion Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Implements list/add/remove actions for agent triggers, using the dev API versionOverride. All 10 tests pass. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rigger actions Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
- 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…ety, 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 <noreply@anthropic.com>
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 <noreply@anthropic.com>
…agent_knowledge test coverage Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…safety checks Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…s 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 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…ills tool Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- 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 <cursoragent@cursor.com>
RanEldann
left a comment
There was a problem hiding this comment.
Strong addition overall — the 6 new tools follow established patterns in the toolkit, tests cover happy paths plus most error/null/validation cases, and the GraphQL operations are correctly wired. Auth model is fine: JWT-scoped, every mutation goes through authorizeAgentAction('edit', agentId), no security concerns from the toolkit perspective.
Three blocking issues
- Prettier will fail CI —
create-agent-tool.ts:166-171has an 8-space indent in a 6-space block. Looks like an editor mishap during the latest edits. .optional()+ manualthrowinstead ofz.discriminatedUnionacross all fourmanage_*tools. The repo already uses discriminated unions in 4 places (update-doc-tool.schema.ts,create-doc-tool.ts). The current pattern means LLMs see all action-conditional fields asoptionalin the JSON schema and only learn requirements via runtime errors.field_values: z.record(z.unknown())inmanage_agent_triggersprovides no schema guidance to the LLM. The description tells it to callget_agent_catalogand followfield_schemas, but the JSON schema is fully untyped — three different shape conventions hide behind one record.
Theme: description ↔ code drift
Several tool descriptions claim or imply behaviors the code doesn't deliver:
inactive_reason's "omit if ambiguous" is meaningless because the code defaults to the same value either way (it's also a 1-value enum, so the field is pure noise)update_agent's "profile or execution plan" overpromises —avatar_url,background_color,goal,user_promptaren't inUpdateAgentInputagent_model's "degrades the agent's performance" is wrong — invalid values are rejected by the server, not degradedmanage_agent_triggersdoesn't mention that the catalog excludes 3rd-party (OAuth) triggers — LLMs will look up Slack/Salesforce and be confused they're missingmanage_agent_knowledge's "call list first" is overstated — only needed forupdate/remove, notadd
Theme: cross-tool inconsistency
update_agentreturns{ content: agent }while siblings return{ content: { message, agent } }— LLM has to learn per-tool shapesagent_id(new tools) vsid(existingupdate/get/delete-agent) — same concept, two namescountfield on most list responses but missing from knowledgelist
Nits
- Missing CHANGELOG.md entry for 5.11.0 (the
agent-toolkit/CLAUDE.mdmandates this — though to be fair, CHANGELOG was already stale at 5.7.1) update-agent-tool.test.tshas 3expect()s in a singleit()— violates the "one assert per test" rule used elsewhererethrowWithContextstrings are verbose and inconsistent — 4 of them have double-"agent" ("list agent knowledge for monday platform agent", etc.). The"monday platform agent"suffix is wasted tokens in every error- Domain validation errors (e.g.
throw new Error('create_agent_skill returned no data')) get double-wrapped to"Failed to X: <inner>"because the throw is inside thetryblock trigger_uuidreturned bymanage_agent_state action:runhas no companion query yet — the description should say "store for future correlation; no run-status query exists yet"manage_agent_knowledge listreturns afilesarray the tool can't act on; the description has to apologize. Either drop from the GraphQL selection or split into a separate read tool
Recommendations
- Fix Prettier first (item 1) — that's CI.
- Convert the four
manage_*schemas toz.discriminatedUnion('action', [...]). This single change fixes findings 2, 4, 8, 13, plus removes the manual cross-field throws. - Fix the description honesty issues (medium-severity but cheap) — they directly affect tool-call success rate in production.
- Align
update_agent's return shape and renameid→agent_idfor consistency. - Optional but recommended: type
agent_modelasz.nativeEnum(AgentModel)so wrong values fail at zod time with a clear list of valid options, instead of producing a confusing GraphQL error.
Nice work overall — happy to clarify or drop any of the smaller items.
- 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 <cursoragent@cursor.com>
…_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 <cursoragent@cursor.com>
RanEldann
left a comment
There was a problem hiding this comment.
Nadav 👑 you're a king. Genuinely impressive turnaround — almost every finding addressed, several solved structurally (extracting create_agent_skill, dropping inactive_reason entirely), and descriptions are now honest about what each tool actually does. This is a major enhancement — agents can now manage the full agent lifecycle end-to-end with schemas they can actually act on. Approving 🎉
One thought on the discriminated-union pushback before we move on — I think the blocker is smaller than it looked, and the LLM ergonomics win is real:
The actual constraint is just Input extends ZodRawShape in BaseMondayApiTool plus 3–4 z.object(inputSchema) sites in toolkit.ts. ~15 lines, fully backwards-compatible:
// base-monday-api-tool.ts
export type ToolInputSchema = ZodRawShape | ZodTypeAny | undefined;
export abstract class BaseMondayApiTool<
Input extends ToolInputSchema,
Output extends Record<string, unknown> = never,
>// toolkit.ts — small helper
function buildZodSchema(input: any): ZodTypeAny | undefined {
if (!input) return undefined;
if (typeof input.safeParse === 'function') return input; // already a Zod schema
return z.object(input); // ZodRawShape — existing tools
}
// then replace the 4 z.object(inputSchema) sites with buildZodSchema(inputSchema)Then each manage_* schema becomes z.discriminatedUnion('action', [...]) with one z.object per variant. zodToJsonSchema produces oneOf with per-action required arrays — the LLM sees "for action=add, resource_id + scope_type + permission_type are required" in the schema itself instead of parsing it out of prose.
LLMs miss conditional prose ("Required for action:X") reasonably often. Discriminated oneOf cuts misuse-on-first-try meaningfully on real workloads. Bonus: drops the manual if (!input.x) throw blocks and TypeScript narrows the input type per case branch in executeInternal.
Fully backwards-compatible — every existing ZodRawShape tool keeps working unchanged. Not blocking, just smaller than the "follow-up" reply implied. Up to you whether to do it here or a separate PR 🙂
Great work 🚀
monday item
https://monday.monday.com/boards/10045819454/pulses/10045820228
Summary
@mondaydotcomorg/agent-toolkitcovering the full agents subgraph surfaceget_agent_catalog— discovers available trigger types and skills account-wide (READ)manage_agent_triggers— list, add, and remove triggers on an agent (WRITE)manage_agent_skills— create custom skills, attach and detach skills from an agent (WRITE)update_agent— update an agent's name, role, description, or execution plan (WRITE)manage_agent_state— activate, deactivate, or manually run an agent (WRITE)manage_agent_knowledge— list, grant, update, and revoke an agent's access to boards and docs (WRITE)5.11.0Design decisions
get_agent_catalogbefore adding triggers or skillsmanage_agent_triggersandmanage_agent_knowledgeinclude alistaction to support the lookup-before-mutate pattern (getnode_id/ inspect current state before remove/update)versionOverride: 'dev'— the agents subgraph is still on the dev API versionmanage_agent_skillsconsolidates skill creation (create_agent_skillmutation) alongside attach/detach in one tool since they're all skill management operationsshared/Test plan
npm testpasses (1013 tests across 55 suites)npm run buildcompiles cleanly🤖 Generated with Claude Code