diff --git a/.changeset/v2-tool-layer.md b/.changeset/v2-tool-layer.md new file mode 100644 index 0000000..5cb1d3b --- /dev/null +++ b/.changeset/v2-tool-layer.md @@ -0,0 +1,11 @@ +--- +'@taskade/mcp-server': minor +'@taskade/mcp-openapi-codegen': patch +--- + +Add a Taskade API **v2** tool layer alongside the existing v1 tools (additive — v1's +57 tools are unchanged). Exposes the highest-value capabilities v1 lacks: **agent chat** +(`promptAgent`, `listConversations`, `getConversation`) and **webhooks** +(`subscribeWebhook`, `unsubscribeWebhook`). The codegen gains an `exportName` option so +the second tool set (`setupToolsV2`) can be registered next to the first. v2 is beta; +the enabled set will grow as it stabilizes. diff --git a/packages/openapi-codegen/src/codegen.ts b/packages/openapi-codegen/src/codegen.ts index 3401442..c94140a 100644 --- a/packages/openapi-codegen/src/codegen.ts +++ b/packages/openapi-codegen/src/codegen.ts @@ -42,10 +42,17 @@ type CodegenOpts = { document: OpenAPIV3_1.Document | OpenAPIV3.Document | OpenAPIV2.Document; isActionsEnabled?: IsActionsEnabledOpt; actions?: Record; + /** + * Name of the generated setup function. Defaults to `setupTools`. Override it + * (e.g. `setupToolsV2`) so a second generated tool set can be imported alongside + * the first without an export-name collision. + */ + exportName?: string; }; export const codegen = async (opts: CodegenOpts) => { const { document, path: outputPath } = opts; + const exportName = opts.exportName ?? 'setupTools'; const tools = parseOpenApi(document.paths ?? {}); @@ -62,7 +69,7 @@ export const codegen = async (opts: CodegenOpts) => { ${runtime}\n - export const setupTools = (server: McpServer, opts: OpenAPIToolRuntimeConfigOpts) => { + export const ${exportName} = (server: McpServer, opts: OpenAPIToolRuntimeConfigOpts) => { const config = new OpenAPIToolRuntimeConfig(opts); diff --git a/packages/openapi-codegen/src/parser.test.ts b/packages/openapi-codegen/src/parser.test.ts index 6947930..b490c12 100644 --- a/packages/openapi-codegen/src/parser.test.ts +++ b/packages/openapi-codegen/src/parser.test.ts @@ -14,8 +14,14 @@ describe('deriveToolName', () => { expect(deriveToolName('get', '/bundles/{spaceId}/export/zip')).toBe('bundlesExportZip'); }); - it('falls back to the HTTP method for a root path', () => { + it('camelCases hyphen- and underscore-separated segments', () => { + expect(deriveToolName('post', '/list-conversations')).toBe('listConversations'); + expect(deriveToolName('get', '/user_profile')).toBe('userProfile'); + }); + + it('falls back to the HTTP method for a root or param-only path', () => { expect(deriveToolName('get', '/')).toBe('get'); + expect(deriveToolName('POST', '/{id}')).toBe('post'); }); }); @@ -39,4 +45,46 @@ describe('parseOpenApi name resolution', () => { expect(tools[0].name).toBe('promptAgent'); expect(tools[0].description).toBe('Prompt an agent'); }); + + it('falls back to an empty description when neither description nor summary is present', () => { + const tools = parseOpenApi({ + '/promptAgent': { post: { responses: {} } }, + } as never); + expect(tools).toHaveLength(1); + expect(tools[0].description).toBe(''); + }); + + it('keeps request-body params when the body schema is nullable (API v2 promptAgent)', () => { + const tools = parseOpenApi({ + '/promptAgent': { + post: { + summary: 'Prompt an agent', + requestBody: { + content: { + 'application/json': { + schema: { + type: 'object', + nullable: true, + properties: { + spaceId: { type: 'string' }, + agentId: { type: 'string' }, + prompt: { type: 'string' }, + }, + required: ['spaceId', 'agentId', 'prompt'], + }, + }, + }, + }, + responses: {}, + }, + }, + } as never); + expect(tools).toHaveLength(1); + expect(Object.keys(tools[0].inputSchema.properties ?? {})).toEqual([ + 'spaceId', + 'agentId', + 'prompt', + ]); + expect(tools[0].inputSchema.required).toEqual(['spaceId', 'agentId', 'prompt']); + }); }); diff --git a/packages/openapi-codegen/src/parser.ts b/packages/openapi-codegen/src/parser.ts index cf06211..b614938 100644 --- a/packages/openapi-codegen/src/parser.ts +++ b/packages/openapi-codegen/src/parser.ts @@ -26,7 +26,8 @@ export type ParsedTool = { * `operationId` — e.g. Taskade API v2's flat RPC routes (`POST /promptAgent`). Path * params (`{id}`) are dropped and remaining segments are camelCased * (`/media/{mediaId}/content` → `mediaContent`). Falls back to the HTTP method for a - * root path. Specs that DO provide `operationId` (e.g. Taskade v1) are unaffected. + * root or param-only path (`/`, `/{id}`). Specs that DO provide `operationId` (e.g. + * Taskade v1) are unaffected. */ export const deriveToolName = (method: string, path: string): string => { const words = path @@ -118,7 +119,15 @@ export const parseOpenApi = ( ), ); - if (bodySchema.type === 'object' && bodySchema.properties) { + // A request body marked `nullable: true` is rewritten by + // convertOpenApiSchemaToJsonSchema to `type: ['object', 'null']`, so a strict + // `=== 'object'` check would skip it and emit a parameterless tool (e.g. v2's + // promptAgent). Accept an object type whether scalar or in a nullable union. + const isObjectBody = Array.isArray(bodySchema.type) + ? bodySchema.type.includes('object') + : bodySchema.type === 'object'; + + if (isObjectBody && bodySchema.properties) { for (const [name, propSchema] of Object.entries(bodySchema.properties)) { inputSchema.properties![name] = propSchema; } diff --git a/packages/server/package.json b/packages/server/package.json index b902c44..a65a2f5 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -18,9 +18,11 @@ }, "scripts": { "fetch:openapi": "curl -fsSL -o taskade-public.yaml https://www.taskade.com/api/documentation/v1/yaml", + "fetch:openapi:v2": "curl -fsSL -o taskade-public.v2.json https://www.taskade.com/api/documentation/v2/json", "generate:taskade-mcp-tools": "tsx scripts/gen-taskade-mcp-tools.ts", + "generate:taskade-mcp-tools:v2": "tsx scripts/gen-taskade-mcp-tools-v2.ts", "build:cli": "tsx scripts/build-cli.ts", - "build": "run-s generate:taskade-mcp-tools build:cli && yarn --cwd=../../ lint:fix", + "build": "run-s generate:taskade-mcp-tools generate:taskade-mcp-tools:v2 build:cli && yarn --cwd=../../ lint:fix", "start:server": "tsx src/http.ts --watch" }, "devDependencies": { diff --git a/packages/server/scripts/gen-taskade-mcp-tools-v2.ts b/packages/server/scripts/gen-taskade-mcp-tools-v2.ts new file mode 100644 index 0000000..7d7758d --- /dev/null +++ b/packages/server/scripts/gen-taskade-mcp-tools-v2.ts @@ -0,0 +1,91 @@ +import { dereference } from '@readme/openapi-parser'; +import { codegen } from '@taskade/mcp-openapi-codegen'; +import fs from 'fs'; + +import { ENABLED_TASKADE_V2_ACTIONS, HUMANIZED_TASKADE_V2_ACTIONS } from '../src/constants.v2'; + +// Taskade API v2 is a flat RPC API whose operations omit `operationId`; the codegen +// derives tool names from the path (e.g. POST /promptAgent -> "promptAgent"). +const deriveName = (p: string) => p.replace(/^\//, '').split('/')[0]; + +// Why prune before dereferencing: the live v2 spec currently has a broken self-$ref +// inside components.schemas.Field (data.fillerConfig...sourceRef) that makes a full +// dereference throw. The enabled v2 tools don't reference Field, so we keep only the +// allow-listed paths + the component schemas transitively reachable from them. This +// is also what scopes the generated surface to the enabled tools. Remove once the +// upstream spec is fixed and the allow-list grows to need the rest. +const pruneToEnabled = (doc: any) => { + const enabled = new Set(ENABLED_TASKADE_V2_ACTIONS); + const paths: Record = {}; + const matched = new Set(); + for (const [p, ms] of Object.entries(doc.paths ?? {})) { + if (enabled.has(deriveName(p))) { + paths[p] = ms; + matched.add(deriveName(p)); + } + } + + // Fail loudly if an allow-listed action has no matching path (typo, renamed/removed + // upstream op). Without this the action is silently dropped and we ship fewer tools + // than ENABLED_TASKADE_V2_ACTIONS declares, with a green build. + const missing = [...enabled].filter((name) => !matched.has(name)); + if (missing.length > 0) { + throw new Error( + `v2 codegen: enabled action(s) have no matching path in taskade-public.v2.json: ${missing.join(', ')}`, + ); + } + + const allSchemas = doc.components?.schemas ?? {}; + const keep = new Set(); + const walk = (node: any): void => { + if (!node || typeof node !== 'object') { + return; + } + if (Array.isArray(node)) { + return node.forEach(walk); + } + for (const [k, v] of Object.entries(node)) { + if (k === '$ref' && typeof v === 'string') { + const m = v.match(/#\/components\/schemas\/(.+)$/); + if (m && !keep.has(m[1])) { + keep.add(m[1]); + walk(allSchemas[m[1]]); + } + } else { + walk(v); + } + } + }; + walk(paths); + + const schemas: Record = {}; + for (const name of keep) { + schemas[name] = allSchemas[name]; + } + return { ...doc, paths, components: { ...doc.components, schemas } }; +}; + +const raw = JSON.parse(fs.readFileSync('taskade-public.v2.json', 'utf8')); +let document; +try { + document = await dereference(pruneToEnabled(raw) as never); +} catch (error) { + // The live v2 spec has a known broken self-$ref in components.schemas.Field; pruneToEnabled + // sidesteps it only while the allow-list stays clear of schemas that reach Field. If this + // throws, an enabled tool likely now references the broken node — see the pruneToEnabled note. + throw new Error( + `v2 codegen: failed to dereference the pruned spec (likely the known upstream Field self-$ref reached by a newly enabled action): ${(error as Error).message}`, + ); +} + +const actions = Object.fromEntries( + Object.entries(HUMANIZED_TASKADE_V2_ACTIONS).map(([name, title]) => [name, { title }]), +); + +await codegen({ + path: 'src/tools.v2.generated.ts', + document: document as never, + isActionsEnabled: [...ENABLED_TASKADE_V2_ACTIONS], + actions, + exportName: 'setupToolsV2', +}); diff --git a/packages/server/src/constants.v2.ts b/packages/server/src/constants.v2.ts new file mode 100644 index 0000000..3c735e1 --- /dev/null +++ b/packages/server/src/constants.v2.ts @@ -0,0 +1,29 @@ +// Taskade Public API v2 (https://www.taskade.com/api/documentation/v2) tools. +// +// v2 is a flat RPC API (POST /operationName) and is currently beta. It is exposed +// as an ADDITIVE layer alongside the v1 tools (constants.ts) — v1 keeps the granular +// task-editing tools v2 does not yet have, and v2 adds capabilities v1 lacks (agent +// chat, webhooks). We start with the highest-value gaps and grow this list as v2 +// stabilizes. Names are derived from the path by the codegen (v2 omits operationId). + +export const ENABLED_TASKADE_V2_ACTIONS = [ + // Agent chat — the capability v1 cannot do at all + 'promptAgent', + 'listConversations', + 'getConversation', + // Real-time events + 'subscribeWebhook', + 'unsubscribeWebhook', +] as const; + +export type TaskadeV2Action = (typeof ENABLED_TASKADE_V2_ACTIONS)[number]; + +// Keyed to the allow-list so the two cannot drift: a missing, extra, or misspelled +// action here is a compile error rather than a silently untitled tool. +export const HUMANIZED_TASKADE_V2_ACTIONS: Record = { + promptAgent: 'Chat with an AI Agent', + listConversations: 'List Agent Conversations', + getConversation: 'Get Agent Conversation', + subscribeWebhook: 'Subscribe to a Webhook', + unsubscribeWebhook: 'Unsubscribe from a Webhook', +}; diff --git a/packages/server/src/server.ts b/packages/server/src/server.ts index 4f0bebb..1734216 100644 --- a/packages/server/src/server.ts +++ b/packages/server/src/server.ts @@ -2,6 +2,7 @@ import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; import fetch from 'node-fetch'; import { setupTools } from './tools.generated'; +import { setupToolsV2 } from './tools.v2.generated'; type TaskadeServerOpts = { accessToken: string; @@ -188,5 +189,29 @@ export class TaskadeMCPServer extends McpServer { }, }, }); + + // Taskade API v2 (beta) — additive layer for capabilities v1 lacks (agent chat, + // webhooks). Same bearer token; base URL is /api/v2. The v1 tools above are + // unaffected. + setupToolsV2(this, { + url: 'https://www.taskade.com/api/v2', + fetch, + headers: { + Authorization: `Bearer ${this.config.accessToken}`, + }, + normalizeResponse: { + promptAgent: (response) => { + return { + content: [ + { type: 'text', text: JSON.stringify(response) }, + { + type: 'text', + text: "This is the agent's reply. Relay it to the user; manage agents at https://www.taskade.com/agents.", + }, + ], + }; + }, + }, + }); } } diff --git a/packages/server/src/tools.v2.generated.ts b/packages/server/src/tools.v2.generated.ts new file mode 100644 index 0000000..59820a0 --- /dev/null +++ b/packages/server/src/tools.v2.generated.ts @@ -0,0 +1,309 @@ +/** + * This file is auto-generated by yarn generate:mcp-tools + * DO NOT EDIT THIS FILE MANUALLY + */ + +import { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js'; +import { CallToolResult } from '@modelcontextprotocol/sdk/types.js'; +import { z } from 'zod'; + +export type ToolCallOpenApiOperation = { + name: string; + path: string; + method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'; + input: Record; + pathParamKeys?: Array; + queryParamKeys?: Array; +}; + +export type ToolCallOpenApiRequestConfig = { + url: string; + headers: Record; + body?: string | null | undefined; + method: ToolCallOpenApiOperation['method']; +}; + +export type ExecuteToolCallOpenApiOperationCbPayload = ToolCallOpenApiRequestConfig & { + operation: ToolCallOpenApiOperation; +}; + +export type ExecuteToolCallOpenApiOperationCb = ( + payload: ExecuteToolCallOpenApiOperationCbPayload, +) => Promise; + +function toQueryParams(obj: Record): string { + const params = new URLSearchParams(); + + for (const key in obj) { + const value = obj[key]; + + if (value == null) { + continue; + } + + if (Array.isArray(value)) { + value.forEach((v) => params.append(key, String(v))); + } else if (typeof value === 'object') { + params.append(key, JSON.stringify(value)); + } else { + params.append(key, String(value)); + } + } + + const str = params.toString(); + + if (str === '') { + return ''; + } + + return `?${str}`; +} + +export const prepareToolCallOperation = ( + operation: ToolCallOpenApiOperation, +): ExecuteToolCallOpenApiOperationCbPayload => { + const queryParamKeys = new Set(operation.queryParamKeys ?? []); + const pathParamKeys = new Set(operation.pathParamKeys ?? []); + + const queryParams: Record = {}; + const pathParams: Record = {}; + const body: Record = {}; + const headers: HeadersInit = {}; + + for (const [key, value] of Object.entries(operation.input)) { + if (queryParamKeys.has(key)) { + queryParams[key] = value; + } else if (pathParamKeys.has(key)) { + pathParams[key] = value; + } else { + body[key] = value; + } + } + + let resolvedPath = operation.path; + + for (const paramKey of pathParamKeys) { + resolvedPath = resolvedPath.replace( + `{${paramKey}}`, + encodeURIComponent(pathParams[paramKey] ?? ''), + ); + } + + if (Object.keys(body).length > 0) { + headers['Accept'] = 'application/json'; + headers['Content-Type'] = 'application/json'; + } + + const url = `${resolvedPath}${toQueryParams(queryParams)}`; + + return { + url, + headers, + body: Object.keys(body).length > 0 ? JSON.stringify(body) : undefined, + method: operation.method, + operation, + }; +}; + +export type OpenAPIToolRuntimeConfigOpts = { + // basic configuration + url?: string; + fetch?: (...args: any[]) => Promise; + headers?: Record; + + // custom implementation of the tool call + executeToolCall?: ExecuteToolCallOpenApiOperationCb; + normalizeResponse?: Record CallToolResult>; +}; + +export class OpenAPIToolRuntimeConfig { + config: OpenAPIToolRuntimeConfigOpts; + + constructor(config: OpenAPIToolRuntimeConfigOpts) { + this.config = config; + } + + private async defaultExecuteToolCall(payload: ExecuteToolCallOpenApiOperationCbPayload) { + const response = await this.fetch(`${this.baseUrl}${payload.url}`, { + method: payload.method, + body: payload.body, + headers: { + ...payload.headers, + ...this.config.headers, + }, + }); + + return await response.json(); + } + + async executeToolCall(operation: ToolCallOpenApiOperation): Promise { + const payload = prepareToolCallOperation(operation); + + try { + const response = await (this.config.executeToolCall?.(payload) ?? + this.defaultExecuteToolCall(payload)); + return this.normaliseResponse(operation, response); + } catch (error) { + console.error('OPENAPI_TOOL_CALL_ERROR', error); + throw error; + } + } + + private normaliseResponse(operation: ToolCallOpenApiOperation, response: any): CallToolResult { + const normaliser = this.config.normalizeResponse?.[operation.name]; + + if (normaliser) { + return normaliser(response); + } + + return { + content: [ + { + type: 'text', + text: JSON.stringify(response), + }, + ], + }; + } + + get baseUrl() { + if (this.config.url) { + return this.config.url; + } + + throw new Error('"url" is not defined'); + } + + get fetch() { + const fetch = this.config.fetch ?? globalThis.fetch; + + if (!fetch) { + throw new Error('fetch is not defined'); + } + + return fetch.bind(fetch); + } +} + +export const setupToolsV2 = (server: McpServer, opts: OpenAPIToolRuntimeConfigOpts) => { + const config = new OpenAPIToolRuntimeConfig(opts); + + server.tool( + 'promptAgent', + 'Prompt an agent', + z.object({ + spaceId: z.string().describe('The space ID to prompt the agent for'), + agentId: z.string().describe('The agent ID to prompt'), + prompt: z.string().describe('The prompt to send to the agent'), + }).shape, + { + readOnlyHint: false, + destructiveHint: false, + title: 'Chat with an AI Agent', + }, + async (args) => { + return await config.executeToolCall({ + name: 'promptAgent', + path: '/promptAgent', + method: 'POST', + input: args, + pathParamKeys: [], + queryParamKeys: [], + }); + }, + ); + server.tool( + 'listConversations', + 'List agent conversations', + z.object({ + agentId: z.string().min(1), + limit: z.number().default(20), + page: z.number().default(1), + }).shape, + { + readOnlyHint: false, + destructiveHint: false, + title: 'List Agent Conversations', + }, + async (args) => { + return await config.executeToolCall({ + name: 'listConversations', + path: '/listConversations', + method: 'POST', + input: args, + pathParamKeys: [], + queryParamKeys: [], + }); + }, + ); + server.tool( + 'getConversation', + 'Get agent conversation by ID', + z.object({ agentId: z.string().min(1), convoId: z.string().min(1) }).shape, + { + readOnlyHint: false, + destructiveHint: false, + title: 'Get Agent Conversation', + }, + async (args) => { + return await config.executeToolCall({ + name: 'getConversation', + path: '/getConversation', + method: 'POST', + input: args, + pathParamKeys: [], + queryParamKeys: [], + }); + }, + ); + server.tool( + 'subscribeWebhook', + 'Subscribe to a webhook for a Taskade event', + z.object({ + targetUrl: z.string().url(), + triggerType: z.enum([ + 'task.due', + 'comment.created', + 'task.assigned', + 'project.created', + 'project.assigned', + 'project.joined', + ]), + }).shape, + { + readOnlyHint: false, + destructiveHint: false, + title: 'Subscribe to a Webhook', + }, + async (args) => { + return await config.executeToolCall({ + name: 'subscribeWebhook', + path: '/subscribeWebhook', + method: 'POST', + input: args, + pathParamKeys: [], + queryParamKeys: [], + }); + }, + ); + server.tool( + 'unsubscribeWebhook', + 'Remove a previously-created webhook subscription', + z.object({ hookId: z.string().min(1) }).shape, + { + readOnlyHint: false, + destructiveHint: false, + title: 'Unsubscribe from a Webhook', + }, + async (args) => { + return await config.executeToolCall({ + name: 'unsubscribeWebhook', + path: '/unsubscribeWebhook', + method: 'POST', + input: args, + pathParamKeys: [], + queryParamKeys: [], + }); + }, + ); +}; diff --git a/packages/server/taskade-public.v2.json b/packages/server/taskade-public.v2.json new file mode 100644 index 0000000..7c21210 --- /dev/null +++ b/packages/server/taskade-public.v2.json @@ -0,0 +1 @@ +{"openapi":"3.0.3","info":{"title":"Taskade Public API (v2)","description":"Taskade Action API (v2, Beta) — RPC-style operations (POST /listSpaces, /promptAgent, …) returning an ok-discriminated envelope ({ ok: true, items | item, … } on success; { ok: false, code, message } on error). Adds agent capabilities v1 lacks; tasks are read-only in v2 — use the REST API v1 for full task CRUD.","version":"2.0.0-beta"},"components":{"securitySchemes":{"oAuthAuthorizationCode":{"type":"oauth2","flows":{"authorizationCode":{"authorizationUrl":"https://www.taskade.com/oauth2/authorize","tokenUrl":"https://www.taskade.com/oauth2/token","scopes":{}}}},"personalAccessToken":{"type":"http","scheme":"bearer"}},"schemas":{"BundleInstallation":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the bundle installation."},"projectCount":{"type":"number","description":"Number of projects installed."},"flowCount":{"type":"number","description":"Number of automations installed."},"agentCount":{"type":"number","description":"Number of agents installed."},"templateCount":{"type":"number","description":"Number of templates installed."},"mediaCount":{"type":"number","description":"Number of media files installed."},"appCount":{"type":"number","description":"Number of apps installed."}},"required":["id","projectCount","flowCount","agentCount","templateCount","mediaCount","appCount"],"additionalProperties":false},"Project":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project. An alphanumeric string that is 16 characters long."},"name":{"type":"string","description":"The project’s name or title."}},"required":["id"],"additionalProperties":false},"ProjectShare":{"type":"object","properties":{"checkUrl":{"type":"string","format":"uri"},"editUrl":{"type":"string","format":"uri"},"viewUrl":{"type":"string","format":"uri"}},"required":["editUrl","viewUrl"],"additionalProperties":false,"description":"The share links of a project"},"ProjectTemplate":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id"],"additionalProperties":false},"Error":{"type":"object","properties":{"ok":{"type":"boolean","enum":[false]},"message":{"type":"string"},"code":{"type":"string"},"statusMessage":{"type":"string"}},"required":["ok","message","code","statusMessage"],"additionalProperties":false,"description":"Error description"},"Task":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"parentId":{"type":"string"},"completed":{"type":"boolean","default":false}},"required":["id"],"additionalProperties":false},"TaskNote":{"type":"object","properties":{"type":{"type":"string"},"value":{"type":"string"}},"required":["type","value"],"additionalProperties":false},"Date":{"type":"object","properties":{"date":{"type":"string","pattern":"^\\d{4}-\\d{2}-\\d{2}$","description":"ISO date format (YYYY-MM-DD), e.g. \"2021-12-31\""},"time":{"type":"string","pattern":"^(?:[0-1][0-9]|[2][0-3]):[0-5][0-9](?::[0-5][0-9])?$","nullable":true,"description":"Optional time component in 24-hour format (HH:MM:SS), e.g. \"15:30:45\". Can be null or omitted for date-only representations"},"timezone":{"type":"string","nullable":true,"description":"Optional timezone identifier (IANA timezone name), e.g. \"America/New_York\", \"Asia/Singapore\". Can be null or omitted for timezone-naive representations"}},"required":["date"],"additionalProperties":false},"SpaceAgent":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"space_id":{"type":"string"},"data":{"type":"object","properties":{"commands":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","minLength":1,"description":"Human-readable name of the command in title case. This should probably be a verb."},"description":{"type":"string","nullable":true,"description":"Short summary for discovery (e.g. progressive disclosure / skill listing). The full instruction stays in `prompt`."},"prompt":{"type":"string","minLength":1,"description":"Tell the agent what this command will do. It should be positioned as a direct instruction to the agent. At least 30 words."},"id":{"type":"string","minLength":1,"description":"ID based on the name in snake case."},"mode":{"type":"string","enum":["default","plan-and-execute-v1","plan-and-execute-v2"],"default":"default"}},"required":["name","prompt","id"],"additionalProperties":false}},"description":{"type":"string","description":"Role and purpose of agent, positioned as a direct instruction to the agent. Example: \"You are a doctor that helps save lives.\". At least 100 words."},"tone":{"type":"string","enum":["authoritative","clinical","cold","confident","cynical","emotional","empathetic","formal","friendly","humourous","informal","ironic","optimistic","pessimistic","playful","sarcastic","serious","sympathetic","tentative","warm","creative","inspiring","casual"]},"avatar":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["emoji"]},"data":{"type":"object","properties":{"value":{"type":"string","description":"Pick the most suitable emoji for this agent."}},"required":["value"],"additionalProperties":false}},"required":["type","data"],"additionalProperties":false}]},"knowledgeEnabled":{"type":"boolean"},"language":{"type":"string","description":"The language of the agent, e.g. en-US, zh-Hans"},"inputPlaceholder":{"type":"string","nullable":true}},"required":["commands"],"additionalProperties":false}},"required":["id","name","space_id","data"],"additionalProperties":false},"Media":{"type":"object","properties":{"id":{"type":"string"},"space_id":{"type":"string"},"kind":{"type":"string"}},"required":["id","space_id","kind"],"additionalProperties":false},"User":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"}},"required":["handle"],"additionalProperties":false},"Field":{"type":"object","properties":{"id":{"type":"string"},"data":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["boolean"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Note"]},"fillerConfig":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["string.translate"]},"sourceRef":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["field"]},"fieldPath":{"type":"string"}},"required":["type","fieldPath"],"additionalProperties":false}]},"targetLang":{"type":"string"}},"required":["type","sourceRef","targetLang"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["string.summarize"]},"sourceRef":{"$ref":"#/properties/data/anyOf/1/properties/fillerConfig/anyOf/0/properties/sourceRef"},"additionalInstructions":{"type":"string"}},"required":["type","sourceRef"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["string.extract"]},"sourceRef":{"$ref":"#/properties/data/anyOf/1/properties/fillerConfig/anyOf/0/properties/sourceRef"},"entity":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["email_address"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["first_name"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["last_name"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["phone_number"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["domain_name"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["link"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["date"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["time"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["year"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["custom"]},"instructions":{"type":"string"}},"required":["type","instructions"],"additionalProperties":false}]}},"required":["type","sourceRef","entity"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["string.custom"]},"instructions":{"type":"string"}},"required":["type","instructions"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Select.pick"]},"sourceRef":{"$ref":"#/properties/data/anyOf/1/properties/fillerConfig/anyOf/0/properties/sourceRef"},"permittedOptionIds":{"type":"array","items":{"type":"string"}},"additionalInstructions":{"type":"string"}},"required":["type","sourceRef","permittedOptionIds"],"additionalProperties":false}]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Timestamp"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["TimestampAt"]},"displayName":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["TimestampAuthor"]},"displayName":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"displayName":{"type":"string"},"description":{"type":"string"},"type":{"type":"string","enum":["Select"]},"options":{"type":"object","additionalProperties":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"rank":{"type":"string"},"description":{"type":"string"},"color":{"type":"string"}},"required":["id","name","rank"],"additionalProperties":false}},"defaultOption":{"type":"string"},"fillerConfig":{"$ref":"#/properties/data/anyOf/1/properties/fillerConfig"}},"required":["displayName","type","options"],"additionalProperties":false},{"type":"object","properties":{"displayName":{"type":"string","minLength":1},"type":{"type":"string","enum":["number"]},"render":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["text"]}},"required":["type"],"additionalProperties":false}]},"format":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["decimal"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["currency"]},"config":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["standard"]},"code":{"type":"string","minLength":1}},"required":["type","code"],"additionalProperties":false}]}},"required":["type","config"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["unit"]},"config":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["standard"]},"unit":{"type":"string","minLength":1}},"required":["type","unit"],"additionalProperties":false}]}},"required":["type","config"],"additionalProperties":false}]}},"required":["displayName","type","render","format"],"additionalProperties":false},{"type":"object","properties":{"displayName":{"type":"string","minLength":1},"type":{"type":"string","enum":["string"]},"description":{"type":"string"},"fillerConfig":{"$ref":"#/properties/data/anyOf/1/properties/fillerConfig"},"constraints":{"type":"object","properties":{"unique":{"type":"object","properties":{"type":{"type":"string","enum":["unique"]}},"required":["type"],"additionalProperties":false}},"additionalProperties":false}},"required":["displayName","type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Password"]},"title":{"type":"string"},"description":{"type":"string"},"hashAlgorithm":{"type":"string","enum":["bcrypt","argon2","scrypt","pbkdf2"],"default":"bcrypt"},"minLength":{"type":"integer","minimum":1,"default":8},"maxLength":{"type":"integer","minimum":1}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Assign"]},"title":{"type":"string"},"description":{"type":"string"}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["DateTime"]},"title":{"type":"string"},"description":{"type":"string"},"format":{"type":"object","properties":{"time":{"type":"boolean"},"zone":{"anyOf":[{"type":"boolean"},{"type":"string"}]}},"additionalProperties":false}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["DateRange"]},"title":{"type":"string"},"description":{"type":"string"},"format":{"type":"object","properties":{"time":{"type":"boolean"},"zone":{"anyOf":[{"type":"boolean"},{"type":"string"}]}},"additionalProperties":false}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["NodeText"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["NodeCompleted"]}},"required":["type"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["Unimplemented"]}},"required":["type"],"additionalProperties":false}]}},"required":["id","data"],"additionalProperties":false},"FieldValue":{"type":"object","properties":{"fieldId":{"type":"string"},"value":{}},"required":["fieldId"],"additionalProperties":false},"Block":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"completed":{"type":"boolean","default":false}},"required":["id"],"additionalProperties":false},"Convo":{"type":"object","properties":{"id":{"type":"string"},"space_agent_id":{"type":"string"},"status":{"type":"string","enum":["in_progress","idle","requires_review"]},"title":{"type":"string"},"data":{"type":"object","properties":{"llm":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["openai"]},"name":{"type":"string","enum":["gpt-3.5-turbo","gpt-4o","gpt-4-turbo","gpt-4o-mini","gpt-4.1","gpt-4.1-mini","gpt-4.1-nano","o3-mini:low","o3-mini:medium","o3-mini:high","o4-mini:low","o4-mini:medium","o4-mini:high","openai/gpt-4o","openai/gpt-4o-mini","openai/gpt-4.1","openai/gpt-4.1-mini","openai/gpt-4.1-nano","openai/gpt-5","openai/gpt-5:high","openai/gpt-5-mini","openai/gpt-5-mini:high","openai/gpt-5-nano","openai/gpt-5-nano:high","openai/gpt-5.1","openai/gpt-5.1:low","openai/gpt-5.1:medium","openai/gpt-5.1:high","openai/gpt-5.1-codex","openai/gpt-5.1-codex:low","openai/gpt-5.1-codex:medium","openai/gpt-5.1-codex:high","openai/gpt-5.1-codex-max","openai/gpt-5.1-codex-max:medium","openai/gpt-5.1-codex-max:high","openai/gpt-5.1-codex-max:xhigh","openai/gpt-5.2","openai/gpt-5.2:medium","openai/gpt-5.2:high","openai/gpt-5.2:xhigh","openai/gpt-5.2-codex","openai/gpt-5.2-codex:medium","openai/gpt-5.2-codex:high","openai/gpt-5.2-codex:xhigh","openai/gpt-5.3-codex","openai/gpt-5.3-codex:medium","openai/gpt-5.3-codex:high","openai/gpt-5.3-codex:xhigh","openai/gpt-5.3-chat","openai/gpt-5.4","openai/gpt-5.4:medium","openai/gpt-5.4:high","openai/gpt-5.4:xhigh","openai/gpt-5.4-pro","openai/gpt-5.4-pro:medium","openai/gpt-5.4-pro:high","openai/gpt-5.4-pro:xhigh","openai/gpt-5.4-mini","openai/gpt-5.4-nano","openai/gpt-5.5","openai/gpt-5.5:medium","openai/gpt-5.5:high","openai/gpt-5.5:xhigh","openai/gpt-5.5-pro","openai/gpt-5.5-pro:medium","openai/gpt-5.5-pro:high","openai/gpt-5.5-pro:xhigh"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["anthropic"]},"name":{"type":"string","enum":["anthropic/claude-4.0-sonnet","anthropic/claude-4.0-opus","anthropic/claude-sonnet-4.5","anthropic/claude-sonnet-4.5:thinking","anthropic/claude-haiku-4.5","anthropic/claude-haiku-4.5:thinking","anthropic/claude-opus-4.5","anthropic/claude-opus-4.5:thinking","anthropic/claude-opus-4.8","anthropic/claude-opus-4.8:thinking","anthropic/claude-fable-5","anthropic/claude-fable-5:thinking","anthropic/claude-opus-4.7","anthropic/claude-opus-4.7:thinking","anthropic/claude-opus-4.6","anthropic/claude-opus-4.6:thinking","anthropic/claude-sonnet-4.6","anthropic/claude-sonnet-4.6:thinking","anthropic/claude-3.5-sonnet","anthropic/claude-3.5-haiku","anthropic/claude-3.7-sonnet"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["google"]},"name":{"type":"string","enum":["google/gemini-2.5-pro","google/gemini-2.5-flash","google/gemini-2.5-flash-lite","google/gemini-3-pro-preview","google/gemini-3-flash-preview","google/gemini-3.1-pro-preview","google/gemini-3.1-flash-lite-preview","google/gemini-3.1-flash-lite","google/gemini-3.5-flash","google/gemma-4-31b-it","google/gemma-4-26b-a4b-it"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["alibaba"]},"name":{"type":"string","enum":["alibaba/qwen3.7-plus","alibaba/qwen3.6-plus","alibaba/qwen3.6-27b","alibaba/qwen-3.6-max-preview","alibaba/qwen3.7-max"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["minimax"]},"name":{"type":"string","enum":["minimax/minimax-m3","minimax/minimax-m2.7"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["zai"]},"name":{"type":"string","enum":["zai/glm-5.1","zai/glm-5.2"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["moonshotai"]},"name":{"type":"string","enum":["moonshotai/kimi-k2.6","moonshotai/kimi-k2.7-code"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["deepseek"]},"name":{"type":"string","enum":["deepseek/deepseek-v4-pro","deepseek/deepseek-v4-flash"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["xai"]},"name":{"type":"string","enum":["xai/grok-4.3","xai/grok-build-0.1"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["xiaomi"]},"name":{"type":"string","enum":["xiaomi/mimo-v2.5","xiaomi/mimo-v2.5-pro"]}},"required":["type","name"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["nvidia"]},"name":{"type":"string","enum":["nvidia/nemotron-3-ultra-550b-a55b"]}},"required":["type","name"],"additionalProperties":false}]},"endedAt":{"type":"number"}},"additionalProperties":false}},"required":["id","space_agent_id","status","data"],"additionalProperties":false}}},"paths":{"/listSpaces":{"post":{"summary":"List spaces","tags":["Workspace"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"filterBy":{"type":"object","properties":{"name":{"anyOf":[{"type":"object","properties":{"operator":{"type":"string","enum":["contains"]},"value":{"type":"string"}},"required":["operator","value"],"additionalProperties":false},{"type":"object","properties":{"operator":{"type":"string","enum":["equals"]},"value":{"type":"string"}},"required":["operator","value"],"additionalProperties":false}]}},"additionalProperties":false}},"additionalProperties":false,"nullable":true}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/listAgents":{"post":{"summary":"List agents","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","description":"The space ID to list agents for"},"filterBy":{"type":"object","properties":{"name":{"anyOf":[{"type":"object","properties":{"operator":{"type":"string","enum":["contains"]},"value":{"type":"string"}},"required":["operator","value"],"additionalProperties":false},{"type":"object","properties":{"operator":{"type":"string","enum":["equals"]},"value":{"type":"string"}},"required":["operator","value"],"additionalProperties":false}]}},"additionalProperties":false}},"required":["spaceId"],"additionalProperties":false,"nullable":true}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"},"tools":{"type":"object","additionalProperties":{"type":"string"}}},"required":["id","name","description","tools"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/promptAgent":{"post":{"summary":"Prompt an agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","description":"The space ID to prompt the agent for"},"agentId":{"type":"string","description":"The agent ID to prompt"},"prompt":{"type":"string","description":"The prompt to send to the agent"}},"required":["spaceId","agentId","prompt"],"additionalProperties":false,"nullable":true}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"summary":{"type":"string"}},"required":["ok","summary"],"additionalProperties":false}}}}}}},"/getAgent":{"post":{"summary":"Get agent by ID","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1}},"required":["agentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"allOf":[{"$ref":"#/components/schemas/SpaceAgent"}],"nullable":true}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/updateAgent":{"post":{"summary":"Update an agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"name":{"type":"string"},"data":{"$ref":"#/components/schemas/SpaceAgent/properties/data"}},"required":["agentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"allOf":[{"$ref":"#/components/schemas/SpaceAgent"}],"nullable":true}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/deleteAgent":{"post":{"summary":"Delete an agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1}},"required":["agentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"],"additionalProperties":false}}}}}}},"/createAgent":{"post":{"summary":"Create an agent in a team or workspace","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":"string","minLength":1},"name":{"type":"string"},"data":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["data"]},"data":{"$ref":"#/components/schemas/SpaceAgent/properties/data"}},"required":["type","data"],"additionalProperties":false},{"type":"object","properties":{"type":{"type":"string","enum":["template"]},"template":{"type":"object","properties":{"type":{"type":"string","enum":["Tasker","Researcher","Marketer","EmailWriter","Sales","CustomerSupport","ProjectManager","ContentCreator","Copywriter","LegalAdvisor","SeoSpecialist","ProductivityCoach","EngineeringExpert","Translator","Summarizer","ResumeBuilder","Storyteller","Tutor","BrandStrategist","SocialMediaSpecialist","BusinessStrategist","FinancialAnalyst","HumanResourcesManager","DataScientist","ITConsultant","FinancialAdvisor","HealthCoach","SustainabilityConsultant","UXDesigner","QualityAssuranceAnalyst","ProductManager","GrowthHacker","BusinessDevelopmentManager","PublicRelationsSpecialist","EventPlanner","DataAnalyst","Editor","CEO","InterviewCoach","TechSupportAdvisor","Doctor","BlogExpert","TweetOptimizer","EmailMarketer","CourseCreator","ScriptCreator","ScreenplayWriter","Proofreader","SalesColdEmailCoach","CodeExplainer","CreativeWritingCoach","AdvertisingCopywriter","VideoScriptWriter","ProjectArchitect","AICouncil","Negotiator","VCAssociate","Books","StartupMentor","SmallBusiness","WebDevelopment","PromptEngineer","ArticleWriter","WorkflowAgent","StrategyAgent","ViralAgent","SOPOnboardingAgent","PressReleaseAgent"]},"avatar":{"$ref":"#/components/schemas/SpaceAgent/properties/data/properties/avatar"}},"required":["type"],"additionalProperties":false}},"required":["type","template"],"additionalProperties":false}]}},"required":["folderId","name","data"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/SpaceAgent"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/listConversations":{"post":{"summary":"List agent conversations","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"limit":{"type":"number","default":20},"page":{"type":"number","default":1}},"required":["agentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"$ref":"#/components/schemas/Convo"}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/getConversation":{"post":{"summary":"Get agent conversation by ID","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"convoId":{"type":"string","minLength":1}},"required":["agentId","convoId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/Convo"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/addKnowledgeProject":{"post":{"summary":"Add a project as knowledge source to an agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"projectId":{"type":"string","minLength":1}},"required":["agentId","projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/SpaceAgent"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/removeKnowledgeProject":{"post":{"summary":"Remove a project from agent knowledge sources","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"projectId":{"type":"string","minLength":1}},"required":["agentId","projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"],"additionalProperties":false}}}}}}},"/addKnowledgeMedia":{"post":{"summary":"Add media as knowledge source to an agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"mediaId":{"type":"string","minLength":1}},"required":["agentId","mediaId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/SpaceAgent"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/removeKnowledgeMedia":{"post":{"summary":"Remove media from agent knowledge sources","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"mediaId":{"type":"string","minLength":1}},"required":["agentId","mediaId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"],"additionalProperties":false}}}}}}},"/enablePublicAgentAccess":{"post":{"summary":"Enable public access for an agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1}},"required":["agentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"publicUrl":{"type":"string","format":"uri"}},"required":["ok","publicUrl"],"additionalProperties":false}}}}}}},"/getPublicAgent":{"post":{"summary":"Get public agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1}},"required":["agentId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"data":{"type":"object","properties":{"avatar":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["custom"]},"data":{"type":"object","properties":{"file":{"type":"object","properties":{"ownerID":{"type":"string"},"ownerType":{"type":"string","minLength":1,"nullable":true},"id":{"type":"string"},"namespace":{"type":"string"},"extension":{"type":"string"},"s3KeyOriginal":{"type":"string"},"userID":{"type":"number","nullable":true},"spaceID":{"type":"string","minLength":1,"nullable":true},"documentID":{"type":"string","minLength":1,"nullable":true},"nodeID":{"type":"string","minLength":1,"nullable":true},"size":{"type":"number"},"mimetype":{"type":"string"},"metadata":{"type":"object","properties":{},"additionalProperties":true},"type":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"}},"required":["ownerID","id","namespace","extension","s3KeyOriginal","size","mimetype"],"additionalProperties":true}},"required":["file"],"additionalProperties":false}},"required":["type","data"],"additionalProperties":false},{"$ref":"#/components/schemas/SpaceAgent/properties/data/properties/avatar/anyOf/0"}]},"conversationStarters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"prompt":{"type":"string"}},"required":["id","text"],"additionalProperties":false}}},"additionalProperties":false},"preferences":{"type":"object","properties":{"mode":{"type":"string","enum":["template","chatbot"]},"canCopyKnowledge":{"type":"boolean"},"hideBranding":{"type":"boolean"},"theme":{"type":"string","enum":["light","dark","auto"]},"autoEndChats":{"type":"boolean"},"meta":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"image":{"allOf":[{"$ref":"#/properties/item/properties/data/properties/avatar/anyOf/0/properties/data/properties/file"}],"nullable":true}},"additionalProperties":false}},"additionalProperties":false}},"required":["id","name","data","preferences"],"additionalProperties":false},"publicUrl":{"type":"string","format":"uri"}},"required":["ok","item","publicUrl"],"additionalProperties":false}}}}}}},"/updatePublicAgent":{"post":{"summary":"Update public agent","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"agentId":{"type":"string","minLength":1},"preferences":{"type":"object","properties":{"mode":{"type":"string","enum":["template","chatbot"]},"canCopyKnowledge":{"type":"boolean"},"hideBranding":{"type":"boolean"},"theme":{"type":"string","enum":["light","dark","auto"]},"autoEndChats":{"type":"boolean"},"meta":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"image":{"type":"object","properties":{"ownerID":{"type":"string"},"ownerType":{"type":"string","minLength":1,"nullable":true},"id":{"type":"string"},"namespace":{"type":"string"},"extension":{"type":"string"},"s3KeyOriginal":{"type":"string"},"userID":{"type":"number","nullable":true},"spaceID":{"type":"string","minLength":1,"nullable":true},"documentID":{"type":"string","minLength":1,"nullable":true},"nodeID":{"type":"string","minLength":1,"nullable":true},"size":{"type":"number"},"mimetype":{"type":"string"},"metadata":{"type":"object","properties":{},"additionalProperties":true},"type":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"}},"required":["ownerID","id","namespace","extension","s3KeyOriginal","size","mimetype"],"additionalProperties":true,"nullable":true}},"additionalProperties":false}},"additionalProperties":false}},"required":["agentId","preferences"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"data":{"type":"object","properties":{"avatar":{"anyOf":[{"type":"object","properties":{"type":{"type":"string","enum":["custom"]},"data":{"type":"object","properties":{"file":{"type":"object","properties":{"ownerID":{"type":"string"},"ownerType":{"type":"string","minLength":1,"nullable":true},"id":{"type":"string"},"namespace":{"type":"string"},"extension":{"type":"string"},"s3KeyOriginal":{"type":"string"},"userID":{"type":"number","nullable":true},"spaceID":{"type":"string","minLength":1,"nullable":true},"documentID":{"type":"string","minLength":1,"nullable":true},"nodeID":{"type":"string","minLength":1,"nullable":true},"size":{"type":"number"},"mimetype":{"type":"string"},"metadata":{"type":"object","properties":{},"additionalProperties":true},"type":{"type":"string"},"name":{"type":"string"},"description":{"type":"string"}},"required":["ownerID","id","namespace","extension","s3KeyOriginal","size","mimetype"],"additionalProperties":true}},"required":["file"],"additionalProperties":false}},"required":["type","data"],"additionalProperties":false},{"$ref":"#/components/schemas/SpaceAgent/properties/data/properties/avatar/anyOf/0"}]},"conversationStarters":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","minLength":1},"text":{"type":"string","minLength":1},"prompt":{"type":"string"}},"required":["id","text"],"additionalProperties":false}}},"additionalProperties":false},"preferences":{"type":"object","properties":{"mode":{"type":"string","enum":["template","chatbot"]},"canCopyKnowledge":{"type":"boolean"},"hideBranding":{"type":"boolean"},"theme":{"type":"string","enum":["light","dark","auto"]},"autoEndChats":{"type":"boolean"},"meta":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"image":{"allOf":[{"$ref":"#/properties/item/properties/data/properties/avatar/anyOf/0/properties/data/properties/file"}],"nullable":true}},"additionalProperties":false}},"additionalProperties":false}},"required":["id","name","data","preferences"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/generateAgent":{"post":{"summary":"Generate agent based on input text prompts","tags":["Agent"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":"string","minLength":1},"text":{"type":"string"}},"required":["folderId","text"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/SpaceAgent"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/listProjects":{"post":{"summary":"List projects in a workspace","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","minLength":1,"description":"The workspace/space ID to list projects for"}},"required":["spaceId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/getProject":{"post":{"summary":"Get a project by ID","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to retrieve"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/createProject":{"post":{"summary":"Create a project in a workspace","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","minLength":1,"description":"The workspace/space ID to create the project in"},"contentType":{"type":"string","enum":["text/markdown"]},"content":{"type":"string","description":"Markdown content for the project"}},"required":["spaceId","contentType","content"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/listTasks":{"post":{"summary":"List tasks in a project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to list tasks for"},"limit":{"type":"number","default":100},"after":{"type":"string","description":"Cursor: task ID to get tasks after (do not combine with before)"},"before":{"type":"string","description":"Cursor: task ID to get tasks before (do not combine with after)"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"parentId":{"type":"string"},"completed":{"type":"boolean"}},"required":["id","text","completed"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/completeProject":{"post":{"summary":"Mark a project as completed (archived)","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to mark as completed"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/restoreProject":{"post":{"summary":"Restore a completed (archived) project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to restore"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/copyProject":{"post":{"summary":"Copy a project to a workspace","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The source project ID to copy"},"destinationSpaceId":{"type":"string","minLength":1,"description":"The destination workspace/space ID"},"projectTitle":{"type":"string","minLength":1,"description":"Optional title for the copied project"}},"required":["projectId","destinationSpaceId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/createProjectFromTemplate":{"post":{"summary":"Create a project from a custom template","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","minLength":1,"description":"The destination workspace/space ID"},"templateId":{"type":"string","minLength":1,"description":"The template project ID to create from"}},"required":["spaceId","templateId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"id":{"type":"string","description":"Unique identifier for the project"},"name":{"type":"string","description":"The project's name or title"}},"required":["id"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/listFields":{"post":{"summary":"Get all custom fields for a project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to get fields for"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"data":{"$ref":"#/components/schemas/Field/properties/data"}},"required":["id","data"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/listProjectMembers":{"post":{"summary":"Get members of a project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to get members for"},"limit":{"type":"number","default":20},"page":{"type":"number","default":1}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"handle":{"type":"string"},"displayName":{"type":"string"}},"required":["handle"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/getShareLink":{"post":{"summary":"Get share link for a project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to get share link for"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"checkUrl":{"type":"string","format":"uri"},"editUrl":{"type":"string","format":"uri"},"viewUrl":{"type":"string","format":"uri"}},"required":["editUrl","viewUrl"],"additionalProperties":false,"nullable":true}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/enableShareLink":{"post":{"summary":"Enable share link for a project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to enable share link for"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"checkUrl":{"type":"string","format":"uri"},"editUrl":{"type":"string","format":"uri"},"viewUrl":{"type":"string","format":"uri"}},"required":["editUrl","viewUrl"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/listBlocks":{"post":{"summary":"List top-level blocks in a project","tags":["Project"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"projectId":{"type":"string","minLength":1,"description":"The project ID to list blocks for"},"limit":{"type":"number","default":100},"after":{"type":"string","description":"Cursor: block ID to get blocks after (do not combine with before)"},"before":{"type":"string","description":"Cursor: block ID to get blocks before (do not combine with after)"}},"required":["projectId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"text":{"type":"string"},"completed":{"type":"boolean"}},"required":["id","completed"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/listFolders":{"post":{"summary":"List folders in a workspace","tags":["Workspace"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","minLength":1}},"required":["spaceId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/listMedia":{"post":{"summary":"List media in a folder","tags":["Media"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":"string","minLength":1},"limit":{"type":"number","default":100},"page":{"type":"number","default":1}},"required":["folderId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/Media"}],"nullable":true}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/listTemplates":{"post":{"summary":"List project templates in a folder","tags":["Workspace"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"folderId":{"type":"string","minLength":1},"limit":{"type":"number","default":20},"page":{"type":"number","default":1}},"required":["folderId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/ProjectTemplate"}],"nullable":true}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/importBundleZip":{"post":{"summary":"Import a ZIP/.tsk bundle into a workspace. Send the file as the raw request body with Content-Type: application/zip, application/octet-stream, or application/x-tsk. Pass workspaceId as a query parameter. Maximum file size: 50 MB.","tags":["Bundle"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"workspaceId","required":true,"description":"The target workspace ID to import the bundle into."}],"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/BundleInstallation"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/exportBundle":{"post":{"summary":"Export a space as a JSON bundle","tags":["Bundle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"spaceId":{"type":"string","minLength":1,"description":"The space (subspace / app) ID to export."}},"required":["spaceId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"version":{"type":"string","enum":["1"],"description":"Bundle format version."},"items":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"}},"required":["type"],"additionalProperties":true},"description":"Map of bundle items keyed by ID. Each item has a `type` field: space-bundle-flow-item, space-bundle-project-item, space-bundle-agent-item, space-bundle-template-item, space-bundle-media-item, space-bundle-app-item."}},"required":["version","items"],"additionalProperties":false,"description":"SpaceBundleData v1 — Workspace DNA bundle."}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/importBundle":{"post":{"summary":"Import a JSON bundle into a workspace","tags":["Bundle"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workspaceId":{"type":"string","minLength":1,"description":"The target workspace ID to import the bundle into."},"bundleData":{"type":"object","properties":{"version":{"type":"string","enum":["1"],"description":"Bundle format version."},"items":{"type":"object","additionalProperties":{"type":"object","properties":{"type":{"type":"string"}},"required":["type"],"additionalProperties":true},"description":"Map of bundle items keyed by ID. Each item has a `type` field: space-bundle-flow-item, space-bundle-project-item, space-bundle-agent-item, space-bundle-template-item, space-bundle-media-item, space-bundle-app-item."}},"required":["version","items"],"additionalProperties":false,"description":"The Workspace DNA bundle to import (SpaceBundleData v1)."}},"required":["workspaceId","bundleData"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"$ref":"#/components/schemas/BundleInstallation"}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/bundles/{spaceId}/export/zip":{"get":{"summary":"Export a space as a ZIP bundle. Returns raw binary with appropriate headers.","tags":["Bundle"],"parameters":[{"schema":{"type":"string","enum":["zip","tsk"],"default":"zip"},"in":"query","name":"format","required":false,"description":"Export format: \"zip\" (default) or \"tsk\" (.tsk app kit)."},{"schema":{"type":"string","minLength":1},"in":"path","name":"spaceId","required":true,"description":"The space (subspace / app) ID to export."}],"responses":{"200":{"description":"Default Response"}}}},"/uploadMedia":{"post":{"summary":"Upload a media file to a space. Send the file as the raw request body with the appropriate Content-Type header. Pass spaceId and filename as query parameters. Maximum file size: 25 MB.","tags":["Media"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"query","name":"spaceId","required":true,"description":"The space ID to upload media into (can be a root workspace or a subspace / app)."},{"schema":{"type":"string","minLength":1},"in":"query","name":"filename","required":true,"description":"Original filename of the uploaded file (e.g. \"photo.png\")."}],"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"type":"object","properties":{"mediaId":{"type":"string","description":"The SpaceMedia record ID (UUID)."},"fileId":{"type":"string","description":"The file ID used in S3."},"kind":{"type":"string","description":"Detected media kind (image, video, audio, document, etc.)."},"downloadUrl":{"type":"string","description":"Public URL to download the uploaded file."}},"required":["mediaId","fileId","kind","downloadUrl"],"additionalProperties":false}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/getMedia":{"post":{"summary":"Get media by ID","tags":["Media"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaId":{"type":"string","minLength":1,"description":"The media ID to retrieve."}},"required":["mediaId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"item":{"allOf":[{"$ref":"#/components/schemas/Media"}],"nullable":true}},"required":["ok","item"],"additionalProperties":false}}}}}}},"/deleteMedia":{"post":{"summary":"Delete a media by ID","tags":["Media"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"mediaId":{"type":"string","minLength":1,"description":"The media ID to delete."}},"required":["mediaId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]}},"required":["ok"],"additionalProperties":false}}}}}}},"/media/{mediaId}/content":{"get":{"summary":"Download a media file by ID. Returns raw binary with appropriate headers.","tags":["Media"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"mediaId","required":true,"description":"The media ID to download."}],"responses":{"200":{"description":"Default Response"}}}},"/media/spaces/{spaceId}/content":{"get":{"summary":"Download all media files from a space as a ZIP archive. Each file is stored as {mediaId}/metadata.json and {mediaId}/original. Maximum 100 files per space.","tags":["Media"],"parameters":[{"schema":{"type":"string","minLength":1},"in":"path","name":"spaceId","required":true,"description":"The space ID to download all media from."}],"responses":{"200":{"description":"Default Response"}}}},"/listMyProjects":{"post":{"summary":"List my recently viewed projects","tags":["Me"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"limit":{"type":"number","default":100},"page":{"type":"number","default":1},"sort":{"type":"string","enum":["viewed-asc","viewed-desc"],"default":"viewed-desc"}},"additionalProperties":false,"nullable":true}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"items":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}},"required":["id","name"],"additionalProperties":false}}},"required":["ok","items"],"additionalProperties":false}}}}}}},"/subscribeWebhook":{"post":{"summary":"Subscribe to a webhook for a Taskade event","tags":["Webhook"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetUrl":{"type":"string","format":"uri"},"triggerType":{"type":"string","enum":["task.due","comment.created","task.assigned","project.created","project.assigned","project.joined"]}},"required":["targetUrl","triggerType"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"hookId":{"type":"string"}},"required":["ok","hookId"],"additionalProperties":false}}}}}}},"/unsubscribeWebhook":{"post":{"summary":"Remove a previously-created webhook subscription","tags":["Webhook"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"hookId":{"type":"string","minLength":1}},"required":["hookId"],"additionalProperties":false}}}},"responses":{"200":{"description":"Default response","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean","enum":[true]},"deleted":{"type":"boolean"}},"required":["ok","deleted"],"additionalProperties":false}}}}}}}},"servers":[{"url":"https://www.taskade.com/api/v2","description":"Public API server"}],"security":[{"oAuthAuthorizationCode":[],"personalAccessToken":[]}]} \ No newline at end of file