@desplega.ai/agent-swarm 1.88.0 → 1.90.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +7 -0
- package/openapi.json +41 -1
- package/package.json +3 -2
- package/plugin/skills/composio/SKILL.md +173 -0
- package/plugin/skills/composio-gmail/SKILL.md +83 -0
- package/plugin/skills/composio-google-calendar/SKILL.md +81 -0
- package/plugin/skills/composio-google-docs/SKILL.md +71 -0
- package/src/be/db.ts +353 -2
- package/src/be/migrations/081_metrics.sql +39 -0
- package/src/be/migrations/082_user_audit_fields.sql +120 -0
- package/src/be/modelsdev-cache.json +3413 -1423
- package/src/be/seed-skills/index.ts +7 -0
- package/src/cli.tsx +18 -0
- package/src/commands/runner.ts +153 -22
- package/src/commands/x.ts +118 -0
- package/src/github/handlers.ts +40 -1
- package/src/heartbeat/heartbeat.ts +80 -12
- package/src/http/active-sessions.ts +32 -1
- package/src/http/auth.ts +36 -0
- package/src/http/core.ts +20 -16
- package/src/http/db-query.ts +20 -0
- package/src/http/index.ts +2 -0
- package/src/http/metrics.ts +447 -0
- package/src/http/operator-actor.ts +9 -0
- package/src/http/poll.ts +11 -1
- package/src/http/tasks.ts +6 -1
- package/src/http/workflows.ts +5 -1
- package/src/metrics/version.ts +26 -0
- package/src/prompts/base-prompt.ts +8 -0
- package/src/prompts/session-templates.ts +23 -0
- package/src/providers/opencode-adapter.ts +22 -6
- package/src/server.ts +10 -1
- package/src/tasks/worker-follow-up.ts +19 -1
- package/src/tests/base-prompt.test.ts +35 -0
- package/src/tests/budget-claim-gate.test.ts +26 -0
- package/src/tests/core-auth.test.ts +8 -1
- package/src/tests/events-http.test.ts +6 -2
- package/src/tests/github-handlers-cancel-config.test.ts +262 -0
- package/src/tests/heartbeat-supersede-resume.test.ts +91 -1
- package/src/tests/heartbeat.test.ts +84 -3
- package/src/tests/http-api-integration.test.ts +3 -1
- package/src/tests/metrics-http.test.ts +247 -0
- package/src/tests/opencode-adapter.test.ts +90 -30
- package/src/tests/runner-repo-autostash.test.ts +117 -0
- package/src/tests/runner-requester-profile.test.ts +25 -0
- package/src/tests/runner-skills-refresh.test.ts +1 -1
- package/src/tests/swarm-x-tool.test.ts +90 -0
- package/src/tests/system-default-skills.test.ts +3 -0
- package/src/tests/ui-logs-parser.test.ts +271 -0
- package/src/tests/user-token-rest-auth.test.ts +129 -0
- package/src/tests/workflow-async-v2.test.ts +23 -0
- package/src/tests/x-composio.test.ts +122 -0
- package/src/tools/create-metric.ts +191 -0
- package/src/tools/swarm-x.ts +116 -0
- package/src/tools/tool-config.ts +6 -0
- package/src/types.ts +120 -0
- package/src/utils/request-auth-context.ts +28 -0
- package/src/utils/skills-refresh.ts +2 -2
- package/src/workflows/engine.ts +24 -2
- package/src/workflows/executors/agent-task.ts +2 -0
- package/src/x/composio.ts +295 -0
- package/templates/skills/attio-interaction/SKILL.md +279 -0
- package/templates/skills/attio-interaction/config.json +14 -0
- package/templates/skills/attio-interaction/content.md +272 -0
package/README.md
CHANGED
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
<sub>Built by <a href="https://desplega.sh">desplega.sh</a> — by builders, for builders.</sub>
|
|
10
10
|
</p>
|
|
11
11
|
|
|
12
|
+
> [!TIP]
|
|
13
|
+
> **This repo evolves every single day.** [Watch now →](https://github.com/desplega-ai/agent-swarm/subscription)
|
|
14
|
+
|
|
12
15
|
<p align="center">
|
|
13
16
|
<video src="https://github.com/user-attachments/assets/e220712e-c54d-4f46-b059-bac04639d229" controls muted playsinline width="720"></video>
|
|
14
17
|
</p>
|
|
@@ -126,6 +129,8 @@ Check [our templates](https://templates.agent-swarm.dev) for a quick start.
|
|
|
126
129
|
- **Harness & LLM agnostic** — run with Claude Code, OpenAI Codex, pi-mono, Devin, Claude Managed Agents, raw LLMs, or opencode. [Harness config →](https://docs.agent-swarm.dev/docs/guides/harness-configuration) · [Add a new provider →](https://docs.agent-swarm.dev/docs/guides/harness-providers)
|
|
127
130
|
- **Follow-up continuity across all harnesses** — child tasks inherit a bounded prior-task context preamble built from the task chain, so continuity survives restarts and works the same across every provider. [Task lifecycle →](https://docs.agent-swarm.dev/docs/concepts/task-lifecycle)
|
|
128
131
|
- **Skills & MCP servers** — reusable procedural knowledge and per-agent MCP servers with scope cascade. [MCP tools →](https://docs.agent-swarm.dev/docs/reference/mcp-tools)
|
|
132
|
+
- **External tool-router access** — the `x` command and `swarm_x` MCP tool let humans and agents execute approved third-party routes such as Composio without baking bespoke MCP servers first. [CLI →](https://docs.agent-swarm.dev/docs/reference/cli) · [Composio →](https://docs.agent-swarm.dev/docs/integrations/composio)
|
|
133
|
+
- **Config-driven metrics dashboards** — define read-only SQL widgets, version them, and render them in the dashboard without shipping custom frontend code. [Metrics API →](https://docs.agent-swarm.dev/docs/api-reference/stats)
|
|
129
134
|
- **DB-backed pages** — agents publish HTML or JSON pages (reports, dashboards, action specs) via the `create_page` MCP tool with public / authed / password modes, version history, view counters, diff helpers, and PDF export. [MCP tools → Pages](https://docs.agent-swarm.dev/docs/reference/mcp-tools#pages-tools)
|
|
130
135
|
- **KV store** — Redis-like namespaced key/value store with auto-scoped context (Slack thread / PR / Linear issue / page). [MCP tools → KV](https://docs.agent-swarm.dev/docs/reference/mcp-tools#kv-tools)
|
|
131
136
|
- **Real-time dashboard** — monitor agents, tasks, and inter-agent chat. [app.agent-swarm.dev →](https://app.agent-swarm.dev)
|
|
@@ -194,6 +199,7 @@ Missing one? Ask the swarm to build it.
|
|
|
194
199
|
| **GitLab** | Same model as GitHub — webhooks on issues/MRs, `glab` preinstalled in workers | [Guide](https://docs.agent-swarm.dev/docs/guides/gitlab-integration) |
|
|
195
200
|
| **AgentMail** | Give each agent an inbox; emails become tasks or lead messages | [Guide](https://docs.agent-swarm.dev/docs/guides/agentmail-integration) |
|
|
196
201
|
| **Kapso (WhatsApp)** | Native inbound WhatsApp webhook routing; agents reply over WhatsApp with MCP tools or the `kapso-whatsapp` skill | [Guide](https://docs.agent-swarm.dev/docs/integrations/kapso) |
|
|
202
|
+
| **Composio** | Route approved third-party app operations through `agent-swarm x composio ...` or the `swarm_x` MCP tool | [Guide](https://docs.agent-swarm.dev/docs/integrations/composio) |
|
|
197
203
|
| **Linear** | Bidirectional ticket sync via OAuth + webhooks | [Guide](https://docs.agent-swarm.dev/docs/guides/linear-integration) |
|
|
198
204
|
| **Jira Cloud** | OAuth 3LO ticket sync — assignee/comment events create tasks; lifecycle posts comments back | [Guide](https://docs.agent-swarm.dev/docs/guides/jira-integration) |
|
|
199
205
|
| **Sentry** | Workers can triage Sentry issues with the `/investigate-sentry-issue` command | [Guide](https://docs.agent-swarm.dev/docs/guides/sentry-integration) |
|
|
@@ -223,6 +229,7 @@ bunx @desplega.ai/agent-swarm <command>
|
|
|
223
229
|
| `worker` | Run a worker agent |
|
|
224
230
|
| `lead` | Run a lead agent |
|
|
225
231
|
| `e2b` | Build E2B templates and launch/manage grouped API + lead + worker swarms |
|
|
232
|
+
| `x` | Execute approved external routes such as Composio |
|
|
226
233
|
| `docs` | Open documentation (`--open` to launch in browser) |
|
|
227
234
|
|
|
228
235
|
## Deployment
|
package/openapi.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"openapi": "3.1.0",
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Agent Swarm API",
|
|
5
|
-
"version": "1.
|
|
5
|
+
"version": "1.90.0",
|
|
6
6
|
"description": "Multi-agent orchestration API for Claude Code, Codex, and Gemini CLI. Enables task distribution, agent communication, and service discovery.\n\nMCP tools are documented separately in [MCP.md](./MCP.md)."
|
|
7
7
|
},
|
|
8
8
|
"servers": [
|
|
@@ -277,6 +277,46 @@
|
|
|
277
277
|
}
|
|
278
278
|
}
|
|
279
279
|
},
|
|
280
|
+
"/api/active-sessions/recover-orphaned-tasks": {
|
|
281
|
+
"post": {
|
|
282
|
+
"summary": "Recover orphaned in-progress tasks for an agent",
|
|
283
|
+
"tags": [
|
|
284
|
+
"Active Sessions"
|
|
285
|
+
],
|
|
286
|
+
"security": [
|
|
287
|
+
{
|
|
288
|
+
"bearerAuth": []
|
|
289
|
+
}
|
|
290
|
+
],
|
|
291
|
+
"requestBody": {
|
|
292
|
+
"content": {
|
|
293
|
+
"application/json": {
|
|
294
|
+
"schema": {
|
|
295
|
+
"type": "object",
|
|
296
|
+
"properties": {
|
|
297
|
+
"agentId": {
|
|
298
|
+
"type": "string",
|
|
299
|
+
"minLength": 1
|
|
300
|
+
},
|
|
301
|
+
"minAgeSeconds": {
|
|
302
|
+
"type": "integer",
|
|
303
|
+
"exclusiveMinimum": 0
|
|
304
|
+
}
|
|
305
|
+
},
|
|
306
|
+
"required": [
|
|
307
|
+
"agentId"
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
},
|
|
313
|
+
"responses": {
|
|
314
|
+
"200": {
|
|
315
|
+
"description": "Recovery result"
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
},
|
|
280
320
|
"/api/agents": {
|
|
281
321
|
"post": {
|
|
282
322
|
"summary": "Register or re-register an agent",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@desplega.ai/agent-swarm",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.90.0",
|
|
4
4
|
"description": "Multi-agent orchestration for Claude Code, Codex, Gemini CLI, and other AI coding assistants",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "desplega.sh <contact@desplega.sh>",
|
|
@@ -45,6 +45,7 @@
|
|
|
45
45
|
"tsc:check": "bun tsc --noEmit",
|
|
46
46
|
"check:db-boundary": "bash scripts/check-db-boundary.sh",
|
|
47
47
|
"check:api-key-boundary": "bash scripts/check-api-key-boundary.sh",
|
|
48
|
+
"check:audit-columns": "bash scripts/check-audit-columns.sh",
|
|
48
49
|
"prepare-release": "bun scripts/prepare-release.ts",
|
|
49
50
|
"sync-chart-version": "bun scripts/sync-chart-version.ts",
|
|
50
51
|
"check-chart-version": "bun scripts/sync-chart-version.ts --check-if-package-version-changed",
|
|
@@ -115,7 +116,7 @@
|
|
|
115
116
|
"@earendil-works/pi-ai": "^0.78.0",
|
|
116
117
|
"@earendil-works/pi-coding-agent": "^0.78.0",
|
|
117
118
|
"@modelcontextprotocol/sdk": "^1.25.1",
|
|
118
|
-
"@openai/codex-sdk": "^0.
|
|
119
|
+
"@openai/codex-sdk": "^0.136.0",
|
|
119
120
|
"@opencode-ai/sdk": "^1.15.13",
|
|
120
121
|
"@openfort/openfort-node": "^0.9.1",
|
|
121
122
|
"@opentelemetry/api": "^1.9.1",
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composio
|
|
3
|
+
description: Use Composio from Agent Swarm via the `agent-swarm x composio` CLI route or the `swarm_x` MCP tool. Trigger when a task needs connected third-party app tools such as Gmail, GitHub, Slack, Notion, or HubSpot through Composio Tool Router sessions, Connect Links, or connected accounts. This is the HUB skill — for Google apps see the sibling skills `composio-gmail`, `composio-google-calendar`, `composio-google-docs`.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Composio
|
|
7
|
+
|
|
8
|
+
Hub skill for Composio-managed third-party app access from the swarm.
|
|
9
|
+
The supported surface is the Agent Swarm `x` route:
|
|
10
|
+
|
|
11
|
+
- CLI: `agent-swarm x composio <METHOD> <path> [--body '<json>']`
|
|
12
|
+
- MCP: `swarm_x` with `target: "composio"`
|
|
13
|
+
|
|
14
|
+
`COMPOSIO_API_KEY` is deployment-scoped and injected by the CLI/API process — you
|
|
15
|
+
never pass or see it. All paths are **relative** Composio REST paths.
|
|
16
|
+
|
|
17
|
+
> **Per-app playbooks (verified slugs + argument shapes + gotchas):**
|
|
18
|
+
> [[composio-gmail]] · [[composio-google-calendar]] · [[composio-google-docs]].
|
|
19
|
+
> Read the sibling skill for the app you're touching — it lists the verified tool
|
|
20
|
+
> slugs so you don't have to `/search` blind.
|
|
21
|
+
|
|
22
|
+
## Core Model
|
|
23
|
+
|
|
24
|
+
- **`user_id`** is the app user whose connected accounts are used. We use the
|
|
25
|
+
person's **email** as `user_id` (e.g. `t@desplega.ai`). There is **no explicit
|
|
26
|
+
"create user" call** — a user is created implicitly the first time you reference
|
|
27
|
+
its `user_id` (e.g. when you create a Connect Link). Don't look for a
|
|
28
|
+
`POST /users` endpoint; it doesn't exist in this flow.
|
|
29
|
+
- **Auth config** (`ac_…`) = a project-level OAuth app config (one per toolkit,
|
|
30
|
+
set up in the Composio dashboard). A project can have several.
|
|
31
|
+
- **Connected account** (`ca_…`) = a specific user's authorized connection to a
|
|
32
|
+
toolkit. Persists across sessions under that `user_id`.
|
|
33
|
+
- **Connect Link** = the short-lived URL the user clicks to authorize OAuth.
|
|
34
|
+
- **Tool Router session** = a task/conversation runtime context that auto-resolves
|
|
35
|
+
the right connected account for a toolkit set. Reuse its `session_id`; create a
|
|
36
|
+
new one if the user, toolkit set, auth config, or pinned account changes.
|
|
37
|
+
|
|
38
|
+
## Two ways to call a tool — and when to use each
|
|
39
|
+
|
|
40
|
+
1. **Tool Router session** (`/tool_router/session…`) — best for multi-turn agent
|
|
41
|
+
work over a toolkit set. Auto-resolves connections, supports in-session
|
|
42
|
+
`/search`. **But** it can fail with `ToolRouterV2_NoActiveConnection` (code
|
|
43
|
+
4302) when stale/duplicate accounts shadow the good one (see Gotchas).
|
|
44
|
+
2. **Direct execute** (`POST /tools/execute/<TOOL_SLUG>`) — best for one-off reads,
|
|
45
|
+
verification, or when the session reports no active connection. Pin the account
|
|
46
|
+
explicitly with `connected_account_id`. **This is the reliable path** when a
|
|
47
|
+
user has exactly one good connection per toolkit.
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
agent-swarm x composio POST /tools/execute/GMAIL_FETCH_EMAILS \
|
|
51
|
+
--body '{"user_id":"t@desplega.ai","connected_account_id":"ca_xlWpkPocZSGr","arguments":{"max_results":3,"include_payload":false,"verbose":false}}'
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Recipe A — Register a user + send Connect Links (one per toolkit)
|
|
55
|
+
|
|
56
|
+
1. **List the project's auth configs** to get the `ac_…` ids:
|
|
57
|
+
```bash
|
|
58
|
+
agent-swarm x composio GET "/auth_configs" \
|
|
59
|
+
| jq -r '.items[] | "\(.toolkit.slug)\t\(.id)\t\(.name)"'
|
|
60
|
+
```
|
|
61
|
+
2. **Create one Connect Link per auth config** (flat payload — the user is created
|
|
62
|
+
implicitly here):
|
|
63
|
+
```bash
|
|
64
|
+
agent-swarm x composio POST /connected_accounts/link \
|
|
65
|
+
--body '{"auth_config_id":"ac_isRh2iU0Z0lM","user_id":"t@desplega.ai"}'
|
|
66
|
+
# → returns { redirect_url / connect_url: "https://connect.composio.dev/link/lk_…" }
|
|
67
|
+
```
|
|
68
|
+
- **Use `/connected_accounts/link`, NOT `POST /connected_accounts`.** The older
|
|
69
|
+
path now returns 400 for Composio-managed OAuth configs.
|
|
70
|
+
- **There is no single bundled URL** for multiple toolkits — Composio issues
|
|
71
|
+
**one link per toolkit**. Send all of them, labelled per app.
|
|
72
|
+
3. **Links expire ~10 minutes** after creation (link-start token TTL).
|
|
73
|
+
**Regenerate fresh links immediately before posting** to the user, and tell
|
|
74
|
+
them the expiry. Offer to regenerate on request.
|
|
75
|
+
4. The user clicks each link and authorizes. Connections then show as `ACTIVE`.
|
|
76
|
+
|
|
77
|
+
## Recipe B — Verify connections / check status
|
|
78
|
+
|
|
79
|
+
```bash
|
|
80
|
+
agent-swarm x composio GET "/connected_accounts?user_id=t@desplega.ai" \
|
|
81
|
+
| jq -r '.items[] | "\(.toolkit.slug)\t\(.id)\t\(.status)"'
|
|
82
|
+
```
|
|
83
|
+
Look for `status: ACTIVE`. Anything `INITIALIZING`/`FAILED`/`EXPIRED` is not
|
|
84
|
+
usable. Pin the `ca_…` of the ACTIVE account when calling tools directly.
|
|
85
|
+
|
|
86
|
+
## Recipe C — Link a Composio connection to a swarm user identity
|
|
87
|
+
|
|
88
|
+
"Add the composio connection to my user as identity" → `manage-user` with
|
|
89
|
+
`action: update` and the `identities` array.
|
|
90
|
+
|
|
91
|
+
> **CRITICAL: `identities` is declarative (the desired *full* set).** You MUST
|
|
92
|
+
> pass every existing externalId PLUS the new one, or the omitted ones get
|
|
93
|
+
> removed. First read the current identities (`resolve-user` / get the user),
|
|
94
|
+
> then write the full list back.
|
|
95
|
+
|
|
96
|
+
```jsonc
|
|
97
|
+
// manage-user action:update
|
|
98
|
+
{
|
|
99
|
+
"userId": "4dacc65cdab044a6805b2aa0342331b7",
|
|
100
|
+
"identities": [
|
|
101
|
+
{ "kind": "github", "externalId": "tarasyarema" },
|
|
102
|
+
{ "kind": "slack", "externalId": "U08NR6QD6CS" },
|
|
103
|
+
{ "kind": "linear", "externalId": "…" },
|
|
104
|
+
{ "kind": "kapso", "externalId": "…" },
|
|
105
|
+
{ "kind": "composio", "externalId": "t@desplega.ai" } // ← the new one
|
|
106
|
+
]
|
|
107
|
+
}
|
|
108
|
+
```
|
|
109
|
+
Confirm with `resolve-user(kind:composio, externalId:"t@desplega.ai")`.
|
|
110
|
+
|
|
111
|
+
## Workflow (Tool Router session path)
|
|
112
|
+
|
|
113
|
+
1. Create or reuse a Tool Router session for the user + toolkit set.
|
|
114
|
+
2. `/search` before executing — get the current slug, schema, plan, pitfalls,
|
|
115
|
+
and connection status. (The sibling skills list verified slugs so you can
|
|
116
|
+
often skip the search.)
|
|
117
|
+
3. If Composio reports no active connection, run `COMPOSIO_MANAGE_CONNECTIONS`
|
|
118
|
+
for the exact toolkit names, share the Connect Link, and pause for auth.
|
|
119
|
+
4. Retry only after the toolkit shows an ACTIVE connected account.
|
|
120
|
+
5. Prefer metadata-first reads (`include_payload:false`, `verbose:false`) unless
|
|
121
|
+
the user explicitly needs bodies/attachments/full records.
|
|
122
|
+
6. Paginate on `nextPageToken` / cursors.
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
# Create a Gmail-scoped session
|
|
126
|
+
agent-swarm x composio POST /tool_router/session \
|
|
127
|
+
--body '{"user_id":"t@desplega.ai","toolkits":{"enable":["gmail"]},"workbench":{"enable":false}}'
|
|
128
|
+
|
|
129
|
+
# Search for the right tool
|
|
130
|
+
agent-swarm x composio POST /tool_router/session/$SESSION_ID/search \
|
|
131
|
+
--body '{"queries":[{"use_case":"Check recent emails and return metadata only."}]}'
|
|
132
|
+
|
|
133
|
+
# Connect a toolkit if needed
|
|
134
|
+
agent-swarm x composio POST /tool_router/session/$SESSION_ID/execute \
|
|
135
|
+
--body '{"tool_slug":"COMPOSIO_MANAGE_CONNECTIONS","arguments":{"toolkits":["gmail"]}}'
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Discovering tools for any toolkit
|
|
139
|
+
|
|
140
|
+
The sibling skills cover the Google apps. For any other toolkit, list its tools:
|
|
141
|
+
```bash
|
|
142
|
+
agent-swarm x composio GET "/tools?toolkit_slug=<slug>&limit=100" \
|
|
143
|
+
| jq -r '.items[] | "\(.slug)\t\(.name)"'
|
|
144
|
+
```
|
|
145
|
+
Inspect a tool's arguments before calling:
|
|
146
|
+
```bash
|
|
147
|
+
agent-swarm x composio GET "/tools?toolkit_slug=<slug>&limit=200" \
|
|
148
|
+
| jq '.items[] | select(.slug=="<SLUG>") | {required:.input_parameters.required, props:(.input_parameters.properties|keys)}'
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
## Gotchas
|
|
152
|
+
|
|
153
|
+
- **`ToolRouterV2_NoActiveConnection` (4302) despite an ACTIVE account.** Cause:
|
|
154
|
+
stale `INITIALIZING` duplicate accounts (leftover from regenerated Connect
|
|
155
|
+
Links) shadow the good one; the session auto-resolves the wrong account and
|
|
156
|
+
in-session `/search` returns empty. **Fix:** use direct
|
|
157
|
+
`POST /tools/execute/<SLUG>` with the ACTIVE `connected_account_id` pinned
|
|
158
|
+
(Recipe B → the `ca_…`). Long-term fix is deleting the stale duplicates — but
|
|
159
|
+
**ask the user before deleting any connection.**
|
|
160
|
+
- **Calendar "from a year ago" trap** — `GOOGLECALENDAR_EVENTS_LIST` has **no
|
|
161
|
+
default `timeMin`**, so it returns old events. Always pass `timeMin` (now,
|
|
162
|
+
RFC3339), `singleEvents:true`, `orderBy:"startTime"`. See [[composio-google-calendar]].
|
|
163
|
+
|
|
164
|
+
## Guardrails
|
|
165
|
+
|
|
166
|
+
- Never invent tool slugs or argument shapes. Use the sibling skills, `/search`,
|
|
167
|
+
or `GET /tools?toolkit_slug=…`.
|
|
168
|
+
- Never pass absolute URLs as Composio paths — relative API paths only.
|
|
169
|
+
- Do not expose `COMPOSIO_API_KEY`; server-side code injects it.
|
|
170
|
+
- Do not fetch email bodies/attachments or run destructive/write tools unless the
|
|
171
|
+
task explicitly requires them.
|
|
172
|
+
- If multiple accounts exist for a toolkit, ask which to use or pin the specific
|
|
173
|
+
connected account per the task. **Ask before deleting any connection.**
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composio-gmail
|
|
3
|
+
description: Per-app playbook for driving Gmail through Composio (toolkit slug `gmail`). Verified GMAIL_* tool slugs and argument shapes for reading, searching, sending, drafts, labels, and threads. Use alongside the `composio` hub skill whenever a task reads or sends Gmail for a connected user. Covers the metadata-first reads, the GMAIL_SEND_EMAIL HTML flag, and reply-to-thread.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Composio · Gmail
|
|
7
|
+
|
|
8
|
+
Toolkit slug: **`gmail`**. Read the [[composio]] hub first for the call model
|
|
9
|
+
(`agent-swarm x composio …`, user_id, connected accounts, the 4302 gotcha).
|
|
10
|
+
Tool `arguments` go inside the request body; `user_id` defaults to `"me"` (the
|
|
11
|
+
authorized account) — you usually don't need to set it.
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Direct execute (reliable path — pin the ACTIVE ca_… from the hub Recipe B)
|
|
15
|
+
agent-swarm x composio POST /tools/execute/<SLUG> \
|
|
16
|
+
--body '{"user_id":"t@desplega.ai","connected_account_id":"ca_…","arguments":{ … }}'
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Headline tools
|
|
20
|
+
|
|
21
|
+
| Slug | What | Key args |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| `GMAIL_FETCH_EMAILS` | List/search emails | `query`, `max_results` (def **1** — set it!), `include_payload` (def true), `verbose` (def true), `ids_only`, `label_ids`, `page_token` |
|
|
24
|
+
| `GMAIL_FETCH_MESSAGE_BY_MESSAGE_ID` | Full single message | `message_id`, `include_payload` |
|
|
25
|
+
| `GMAIL_FETCH_MESSAGE_BY_THREAD_ID` | All messages in a thread | `thread_id` |
|
|
26
|
+
| `GMAIL_LIST_THREADS` | List threads | `query`, `max_results`, `page_token` |
|
|
27
|
+
| `GMAIL_SEND_EMAIL` | Send | `recipient_email`, `subject`, `body`, `is_html` (def false), `cc`, `bcc`, `extra_recipients`, `attachment` |
|
|
28
|
+
| `GMAIL_REPLY_TO_THREAD` | Reply in-thread | `thread_id`, `message_body`, `recipient_email` |
|
|
29
|
+
| `GMAIL_CREATE_EMAIL_DRAFT` / `GMAIL_SEND_DRAFT` | Draft then send | `body`, `subject`, `recipient_email` / `draft_id` |
|
|
30
|
+
| `GMAIL_GET_PROFILE` | Whose mailbox is this? | — |
|
|
31
|
+
| `GMAIL_LIST_LABELS` / `GMAIL_CREATE_LABEL` / `GMAIL_ADD_LABEL_TO_EMAIL` | Labels | `message_id`, `label_ids` (use LIST_LABELS for custom IDs) |
|
|
32
|
+
| `GMAIL_GET_CONTACTS` / `GMAIL_SEARCH_PEOPLE` | Contacts | `query` |
|
|
33
|
+
| `GMAIL_GET_ATTACHMENT` | Download attachment | `message_id`, `attachment_id` |
|
|
34
|
+
|
|
35
|
+
Full set: 63 tools — list with
|
|
36
|
+
`agent-swarm x composio GET "/tools?toolkit_slug=gmail&limit=100" | jq -r '.items[]|"\(.slug)\t\(.name)"'`.
|
|
37
|
+
Avoid the ones marked Deprecated (`GMAIL_LIST_MESSAGES`, `GMAIL_REMOVE_LABEL`).
|
|
38
|
+
|
|
39
|
+
## Read recipe (metadata-first)
|
|
40
|
+
|
|
41
|
+
```bash
|
|
42
|
+
agent-swarm x composio POST /tools/execute/GMAIL_FETCH_EMAILS \
|
|
43
|
+
--body '{"connected_account_id":"ca_…","arguments":{"max_results":5,"include_payload":false,"verbose":false}}'
|
|
44
|
+
```
|
|
45
|
+
- **Always set `max_results`** — the default is `1`.
|
|
46
|
+
- Use Gmail `query` syntax: `"is:unread"`, `"from:foo@bar.com newer_than:7d"`,
|
|
47
|
+
`"subject:invoice has:attachment"`.
|
|
48
|
+
- Keep `include_payload:false` + `verbose:false` unless the user needs full bodies
|
|
49
|
+
(token-heavy). Use `ids_only:true` for the cheapest listing.
|
|
50
|
+
|
|
51
|
+
## Send recipe
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
agent-swarm x composio POST /tools/execute/GMAIL_SEND_EMAIL \
|
|
55
|
+
--body '{"connected_account_id":"ca_…","arguments":{
|
|
56
|
+
"recipient_email":"someone@example.com",
|
|
57
|
+
"subject":"Hello",
|
|
58
|
+
"body":"<p>Hi there</p>",
|
|
59
|
+
"is_html":true,
|
|
60
|
+
"cc":["cc@example.com"]
|
|
61
|
+
}}'
|
|
62
|
+
```
|
|
63
|
+
- Set `is_html:true` when `body` contains HTML, otherwise it sends as literal text.
|
|
64
|
+
- `recipient_email` is the primary; add more via `extra_recipients` / `cc` / `bcc`.
|
|
65
|
+
- **Sending is a write action** — only do it when the task explicitly asks.
|
|
66
|
+
|
|
67
|
+
## Reply in a thread
|
|
68
|
+
|
|
69
|
+
```bash
|
|
70
|
+
agent-swarm x composio POST /tools/execute/GMAIL_REPLY_TO_THREAD \
|
|
71
|
+
--body '{"connected_account_id":"ca_…","arguments":{
|
|
72
|
+
"thread_id":"<thread_id>","recipient_email":"someone@example.com","message_body":"thanks!"
|
|
73
|
+
}}'
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Gotchas
|
|
77
|
+
|
|
78
|
+
- Default `max_results` is `1` — forgetting it makes "list my emails" return a
|
|
79
|
+
single message.
|
|
80
|
+
- Bodies/attachments are token-heavy and may contain secrets — default to
|
|
81
|
+
metadata; the secret-scrubber doesn't run on Composio tool output.
|
|
82
|
+
- If you get `ToolRouterV2_NoActiveConnection`, switch to direct execute with the
|
|
83
|
+
pinned `connected_account_id` (hub Gotchas).
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composio-google-calendar
|
|
3
|
+
description: Per-app playbook for driving Google Calendar through Composio (toolkit slug `googlecalendar`). Verified GOOGLECALENDAR_* tool slugs and argument shapes for listing, finding, creating, and updating events plus free/busy. Use alongside the `composio` hub skill. CRITICAL — covers the "events from a year ago" trap: GOOGLECALENDAR_EVENTS_LIST has no default timeMin, so you MUST pass timeMin/orderBy/singleEvents to get upcoming events.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Composio · Google Calendar
|
|
7
|
+
|
|
8
|
+
Toolkit slug: **`googlecalendar`**. Read the [[composio]] hub first for the call
|
|
9
|
+
model. `calendarId` defaults to `"primary"`. Times are **RFC3339**
|
|
10
|
+
(`2026-06-02T15:00:00Z` or with offset).
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
agent-swarm x composio POST /tools/execute/<SLUG> \
|
|
14
|
+
--body '{"user_id":"t@desplega.ai","connected_account_id":"ca_…","arguments":{ … }}'
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Headline tools
|
|
18
|
+
|
|
19
|
+
| Slug | What | Key args |
|
|
20
|
+
|---|---|---|
|
|
21
|
+
| `GOOGLECALENDAR_EVENTS_LIST` | List events on a calendar | `calendarId` (def `primary`), **`timeMin`**, `timeMax`, `singleEvents`, `orderBy`, `q`, `maxResults`, `timeZone`, `pageToken` |
|
|
22
|
+
| `GOOGLECALENDAR_EVENTS_LIST_ALL_CALENDARS` | List across all calendars | `timeMin`, `timeMax`, `singleEvents`, `orderBy` |
|
|
23
|
+
| `GOOGLECALENDAR_FIND_EVENT` | Search for an event | `query`, `timeMin`, `timeMax` |
|
|
24
|
+
| `GOOGLECALENDAR_EVENTS_GET` | One event by id | `calendar_id`, `event_id` |
|
|
25
|
+
| `GOOGLECALENDAR_CREATE_EVENT` | Create event | **`start_datetime`** (required), `end_datetime` / `event_duration_minutes` (def 30), `summary`, `description`, `location`, `attendees`, `timezone`, `calendar_id`, `send_updates`, `create_meeting_room` (def true) |
|
|
26
|
+
| `GOOGLECALENDAR_QUICK_ADD` | NL event ("lunch tmrw 1pm") | `calendar_id`, `text` |
|
|
27
|
+
| `GOOGLECALENDAR_UPDATE_EVENT` / `GOOGLECALENDAR_PATCH_EVENT` | Edit event | `calendar_id`, `event_id`, fields |
|
|
28
|
+
| `GOOGLECALENDAR_DELETE_EVENT` | Delete | `calendar_id`, `event_id` |
|
|
29
|
+
| `GOOGLECALENDAR_FIND_FREE_SLOTS` | Free slots | `items` (def `["primary"]`), `time_min`, `time_max`, `timezone` |
|
|
30
|
+
| `GOOGLECALENDAR_LIST_CALENDARS` | List the user's calendars | — |
|
|
31
|
+
| `GOOGLECALENDAR_GET_CURRENT_DATE_TIME` | Server "now" (use for timeMin) | `timezone` |
|
|
32
|
+
|
|
33
|
+
Full set: 48 tools — `agent-swarm x composio GET "/tools?toolkit_slug=googlecalendar&limit=100" | jq -r '.items[]|"\(.slug)\t\(.name)"'`.
|
|
34
|
+
|
|
35
|
+
## ⚠️ The "events from a year ago" trap
|
|
36
|
+
|
|
37
|
+
`GOOGLECALENDAR_EVENTS_LIST` has **no default `timeMin`**. Calling it with no time
|
|
38
|
+
window returns old/arbitrary events (this is exactly how "what's on my calendar?"
|
|
39
|
+
came back with stuff from a year ago). To get **upcoming** events you MUST set the
|
|
40
|
+
window and ordering explicitly:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
NOW=$(date -u +%Y-%m-%dT%H:%M:%SZ)
|
|
44
|
+
agent-swarm x composio POST /tools/execute/GOOGLECALENDAR_EVENTS_LIST \
|
|
45
|
+
--body "{\"connected_account_id\":\"ca_…\",\"arguments\":{
|
|
46
|
+
\"calendarId\":\"primary\",
|
|
47
|
+
\"timeMin\":\"$NOW\",
|
|
48
|
+
\"singleEvents\":true,
|
|
49
|
+
\"orderBy\":\"startTime\",
|
|
50
|
+
\"maxResults\":10
|
|
51
|
+
}}"
|
|
52
|
+
```
|
|
53
|
+
- `timeMin` = now (or the start of the window you care about).
|
|
54
|
+
- `singleEvents:true` expands recurring events into individual instances — required
|
|
55
|
+
for `orderBy:"startTime"` to be valid.
|
|
56
|
+
- Add `timeMax` to bound the window (e.g. next 7 days).
|
|
57
|
+
- For "today/this week" prefer computing `timeMin`/`timeMax` locally, or call
|
|
58
|
+
`GOOGLECALENDAR_GET_CURRENT_DATE_TIME` first to anchor to the server's clock.
|
|
59
|
+
|
|
60
|
+
## Create an event
|
|
61
|
+
|
|
62
|
+
```bash
|
|
63
|
+
agent-swarm x composio POST /tools/execute/GOOGLECALENDAR_CREATE_EVENT \
|
|
64
|
+
--body '{"connected_account_id":"ca_…","arguments":{
|
|
65
|
+
"summary":"Norrsken <> Desplega",
|
|
66
|
+
"start_datetime":"2026-06-05T15:00:00+02:00",
|
|
67
|
+
"event_duration_minutes":30,
|
|
68
|
+
"timezone":"Europe/Madrid",
|
|
69
|
+
"attendees":["someone@example.com"],
|
|
70
|
+
"send_updates":"all"
|
|
71
|
+
}}'
|
|
72
|
+
```
|
|
73
|
+
- Either `end_datetime` OR `event_duration_minutes` (default 30).
|
|
74
|
+
- `create_meeting_room` defaults true (adds Google Meet) — set false to skip.
|
|
75
|
+
- Create/update/delete are **write actions** — only on explicit request.
|
|
76
|
+
|
|
77
|
+
## Gotchas
|
|
78
|
+
|
|
79
|
+
- The year-ago trap above is the #1 issue. `timeMin` is not optional in practice.
|
|
80
|
+
- `orderBy:"startTime"` requires `singleEvents:true` or the API errors.
|
|
81
|
+
- Output uses the event's own timezone; pass `timeZone` to normalize display.
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: composio-google-docs
|
|
3
|
+
description: Per-app playbook for driving Google Docs through Composio (toolkit slug `googledocs`). Verified GOOGLEDOCS_* tool slugs and argument shapes for searching, reading plaintext, creating (incl. from markdown), and editing documents. Use alongside the `composio` hub skill whenever a task reads or writes Google Docs for a connected user.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Composio · Google Docs
|
|
7
|
+
|
|
8
|
+
Toolkit slug: **`googledocs`**. Read the [[composio]] hub first for the call model.
|
|
9
|
+
A document is identified by its `document_id` (the id in the Docs URL).
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
agent-swarm x composio POST /tools/execute/<SLUG> \
|
|
13
|
+
--body '{"user_id":"t@desplega.ai","connected_account_id":"ca_…","arguments":{ … }}'
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
## Headline tools
|
|
17
|
+
|
|
18
|
+
| Slug | What | Key args |
|
|
19
|
+
|---|---|---|
|
|
20
|
+
| `GOOGLEDOCS_SEARCH_DOCUMENTS` | Find docs (Drive search) | `query`, `max_results` (def 10), `order_by` (def `modifiedTime desc`), `modified_after`, `created_after`, `starred_only`, `shared_with_me`, `response_detail` (def `minimal`) |
|
|
21
|
+
| `GOOGLEDOCS_GET_DOCUMENT_PLAINTEXT` | Read doc as text | **`document_id`**, `include_tables` (def true), `include_headers`, `include_footers`, `include_footnotes`, `include_tabs_content` |
|
|
22
|
+
| `GOOGLEDOCS_GET_DOCUMENT_BY_ID` | Full structured doc JSON | `document_id` |
|
|
23
|
+
| `GOOGLEDOCS_CREATE_DOCUMENT` | Create blank/with text | `title`, `text` |
|
|
24
|
+
| `GOOGLEDOCS_CREATE_DOCUMENT_MARKDOWN` | Create from markdown | **`title`**, `markdown_text`, `image_assets` |
|
|
25
|
+
| `GOOGLEDOCS_UPDATE_DOCUMENT_MARKDOWN` | Replace body with markdown | `document_id`, `markdown_text` |
|
|
26
|
+
| `GOOGLEDOCS_INSERT_TEXT_ACTION` | Insert text at index | `document_id`, `text`, `index` |
|
|
27
|
+
| `GOOGLEDOCS_REPLACE_ALL_TEXT` | Find & replace | `document_id`, `find`, `replace` |
|
|
28
|
+
| `GOOGLEDOCS_COPY_DOCUMENT` | Duplicate a doc | `document_id`, `title` |
|
|
29
|
+
| `GOOGLEDOCS_EXPORT_DOCUMENT_AS_PDF` | Export to PDF | `document_id` |
|
|
30
|
+
|
|
31
|
+
Full set: 35 tools — `agent-swarm x composio GET "/tools?toolkit_slug=googledocs&limit=100" | jq -r '.items[]|"\(.slug)\t\(.name)"'`.
|
|
32
|
+
Prefer the `*_MARKDOWN` create/update tools for authoring; the granular
|
|
33
|
+
`INSERT_*`/`DELETE_*`/table tools are for surgical structural edits.
|
|
34
|
+
|
|
35
|
+
## Search recipe
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
agent-swarm x composio POST /tools/execute/GOOGLEDOCS_SEARCH_DOCUMENTS \
|
|
39
|
+
--body '{"connected_account_id":"ca_…","arguments":{"query":"workshop","max_results":5}}'
|
|
40
|
+
# → results under .data.files[] (id, name, modifiedTime …)
|
|
41
|
+
```
|
|
42
|
+
- Results are Drive file entries at **`.data.files[]`** — grab `.id` to read.
|
|
43
|
+
- `order_by` defaults to `modifiedTime desc` (most recent first).
|
|
44
|
+
- Use `modified_after` / `shared_with_me` to narrow.
|
|
45
|
+
|
|
46
|
+
## Read recipe
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
agent-swarm x composio POST /tools/execute/GOOGLEDOCS_GET_DOCUMENT_PLAINTEXT \
|
|
50
|
+
--body '{"connected_account_id":"ca_…","arguments":{"document_id":"<id>","include_tables":true}}'
|
|
51
|
+
```
|
|
52
|
+
Use `GET_DOCUMENT_PLAINTEXT` for reading content; only reach for
|
|
53
|
+
`GET_DOCUMENT_BY_ID` when you need the structured JSON (styles, indices) for an
|
|
54
|
+
edit.
|
|
55
|
+
|
|
56
|
+
## Create-from-markdown recipe
|
|
57
|
+
|
|
58
|
+
```bash
|
|
59
|
+
agent-swarm x composio POST /tools/execute/GOOGLEDOCS_CREATE_DOCUMENT_MARKDOWN \
|
|
60
|
+
--body '{"connected_account_id":"ca_…","arguments":{
|
|
61
|
+
"title":"Weekly updates","markdown_text":"# Heading\n\n- point one\n- point two"
|
|
62
|
+
}}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Gotchas
|
|
66
|
+
|
|
67
|
+
- Search returns Drive metadata, not document content — do a second
|
|
68
|
+
`GET_DOCUMENT_PLAINTEXT` call with the `.id` to read.
|
|
69
|
+
- Doc bodies can be long/token-heavy and may contain secrets — read only what you
|
|
70
|
+
need (`include_headers/footers/footnotes` default off for a reason).
|
|
71
|
+
- Create/update/replace are **write actions** — only on explicit request.
|