741 lines
20 KiB
YAML
741 lines
20 KiB
YAML
openapi: 3.0.3
|
|
info:
|
|
title: DeerFlow Workflow Studio API (Draft v1)
|
|
version: "1.0.0-draft"
|
|
description: |
|
|
Wire models: deerflow.workflows.schemas / events / errors.
|
|
|
|
Paths marked `x-implemented: false` are still sketches; everything else is
|
|
mounted today (app/gateway/routers/workflow*.py). Where the phase-0 sketch
|
|
and the implementation disagreed, this file follows the implementation.
|
|
servers:
|
|
- url: http://localhost:8001
|
|
description: Local Gateway
|
|
tags:
|
|
- name: workflows
|
|
- name: runs
|
|
- name: resources
|
|
- name: data-sources
|
|
- name: embed
|
|
- name: coze-compat
|
|
paths:
|
|
/api/workflows:
|
|
get:
|
|
tags: [workflows]
|
|
summary: List workflow definitions
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
post:
|
|
tags: [workflows]
|
|
summary: Create workflow definition
|
|
responses:
|
|
"201":
|
|
description: Created
|
|
/api/workflows/{workflow_id}:
|
|
get:
|
|
tags: [workflows]
|
|
summary: Get workflow definition
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
patch:
|
|
tags: [workflows]
|
|
summary: Update workflow metadata
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
delete:
|
|
tags: [workflows]
|
|
summary: Soft-delete / archive
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"204":
|
|
description: Archived
|
|
/api/workflows/{workflow_id}/copy:
|
|
post:
|
|
tags: [workflows]
|
|
summary: Duplicate a workflow as a new draft owned by the caller
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"200":
|
|
description: Created copy
|
|
/api/workflows/{workflow_id}/draft:
|
|
put:
|
|
tags: [workflows]
|
|
summary: Save draft (optimistic lock)
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [expectedRevision, graph]
|
|
properties:
|
|
expectedRevision:
|
|
type: integer
|
|
graph:
|
|
$ref: "#/components/schemas/WorkflowGraph"
|
|
responses:
|
|
"200":
|
|
description: Saved
|
|
"409":
|
|
description: Draft revision conflict
|
|
/api/workflows/{workflow_id}/validate:
|
|
post:
|
|
tags: [workflows]
|
|
summary: Validate draft without publishing
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"200":
|
|
description: Validation result
|
|
/api/workflows/{workflow_id}/publish:
|
|
post:
|
|
tags: [workflows]
|
|
summary: Publish immutable version
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"201":
|
|
description: Version created
|
|
/api/workflows/{workflow_id}/versions:
|
|
get:
|
|
tags: [workflows]
|
|
summary: List published versions
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/{workflow_id}/versions/{version_id}:
|
|
get:
|
|
tags: [workflows]
|
|
summary: Get one published version snapshot
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
- $ref: "#/components/parameters/VersionId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/node-types:
|
|
get:
|
|
tags: [resources]
|
|
summary: List supported node types
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/resources/agents:
|
|
get:
|
|
tags: [resources]
|
|
summary: Agents available to workflow nodes
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/resources/skills:
|
|
get:
|
|
tags: [resources]
|
|
summary: Skills available to workflow nodes
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/resources/data-sources:
|
|
get:
|
|
tags: [resources]
|
|
summary: Registered read-only data sources
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/resources/subworkflows:
|
|
get:
|
|
tags: [resources]
|
|
summary: Published workflows usable as subworkflows
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/data-sources:
|
|
get:
|
|
tags: [data-sources]
|
|
summary: List data sources visible to the caller (own + shared)
|
|
description: |
|
|
Never returns the DSN or credential headers — only `masked_target`.
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
post:
|
|
tags: [data-sources]
|
|
summary: Register a data source (`shared: true` is admin-only)
|
|
description: |
|
|
`kind: sql` requires `dsn`; `kind: http` requires `headers`. The secret
|
|
is encrypted on write and only ever decrypted inside the run executor.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/DataSourceCreate"
|
|
responses:
|
|
"200":
|
|
description: Created (masked view)
|
|
"503":
|
|
description: WORKFLOW_SECRET_KEY not configured
|
|
/api/workflows/data-sources/{id}:
|
|
get:
|
|
tags: [data-sources]
|
|
summary: Get one data source (masked view)
|
|
parameters:
|
|
- $ref: "#/components/parameters/DataSourceId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
put:
|
|
tags: [data-sources]
|
|
summary: Update data source (owner or admin)
|
|
parameters:
|
|
- $ref: "#/components/parameters/DataSourceId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
delete:
|
|
tags: [data-sources]
|
|
summary: Delete data source (owner or admin)
|
|
parameters:
|
|
- $ref: "#/components/parameters/DataSourceId"
|
|
responses:
|
|
"200":
|
|
description: '{ "deleted": true }'
|
|
/api/workflows/data-sources/{id}/introspect:
|
|
post:
|
|
tags: [data-sources]
|
|
summary: Introspect whitelisted schema/table/column metadata
|
|
description: Returns the configured table allowlist only. Never returns sample rows or secrets.
|
|
parameters:
|
|
- $ref: "#/components/parameters/DataSourceId"
|
|
responses:
|
|
"200":
|
|
description: '{ dataSourceId, kind, tables, schemas }'
|
|
/api/workflows/data-sources/{id}/validate-query:
|
|
post:
|
|
tags: [data-sources]
|
|
summary: Validate SQL against read-only policy (no execution)
|
|
parameters:
|
|
- $ref: "#/components/parameters/DataSourceId"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [statement]
|
|
properties:
|
|
statement:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: '{ ok: true, statement }'
|
|
"400":
|
|
description: WORKFLOW_SQL_POLICY_DENIED
|
|
/api/workflows/{workflow_id}/runs:
|
|
post:
|
|
tags: [runs]
|
|
summary: Start a run against a published version
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/StartRunRequest"
|
|
responses:
|
|
"200":
|
|
description: |
|
|
Run view plus `created`; `created: false` means the idempotencyKey
|
|
matched an existing run (scoped per workflow).
|
|
"400":
|
|
description: WORKFLOW_INPUT_INVALID / WORKFLOW_VERSION_NOT_FOUND
|
|
"429":
|
|
description: WORKFLOW_LIMIT_EXCEEDED (per-user concurrent runs)
|
|
get:
|
|
tags: [runs]
|
|
summary: List runs for a workflow
|
|
parameters:
|
|
- $ref: "#/components/parameters/WorkflowId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/runs/{run_id}:
|
|
get:
|
|
tags: [runs]
|
|
summary: Get run status projection plus current node runs
|
|
description: |
|
|
Never includes `resumeToken` — that is delivered on the event stream only.
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
"403":
|
|
description: WORKFLOW_FORBIDDEN (not owner, not admin)
|
|
"404":
|
|
description: WORKFLOW_RUN_NOT_FOUND
|
|
/api/workflows/runs/{run_id}/events:
|
|
get:
|
|
tags: [runs]
|
|
summary: Page durable events
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
- name: after
|
|
in: query
|
|
description: Exclusive `seq` cursor. `after_seq` is accepted as an alias.
|
|
schema:
|
|
type: integer
|
|
default: 0
|
|
- name: after_seq
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
- name: limit
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 200
|
|
maximum: 1000
|
|
responses:
|
|
"200":
|
|
description: '{ "events": [...], "lastSeq": 42 }'
|
|
/api/workflows/runs/{run_id}/stream:
|
|
get:
|
|
tags: [runs]
|
|
summary: SSE replay + live tail
|
|
description: |
|
|
Replays from `Last-Event-ID` (preferred) or `after` / `after_seq`, then
|
|
tails live. Closes on the first terminal event; if the run is already
|
|
terminal without one, a synthesised terminal frame is emitted so the
|
|
client never hangs.
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
- name: after
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
default: 0
|
|
- name: after_seq
|
|
in: query
|
|
schema:
|
|
type: integer
|
|
- name: Last-Event-ID
|
|
in: header
|
|
schema:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: text/event-stream
|
|
headers:
|
|
X-Workflow-Run-Status:
|
|
description: Run status at connection time.
|
|
schema:
|
|
type: string
|
|
content:
|
|
text/event-stream:
|
|
schema:
|
|
type: string
|
|
/api/workflows/runs/{run_id}/cancel:
|
|
post:
|
|
tags: [runs]
|
|
summary: Request cancellation (idempotent)
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
responses:
|
|
"200":
|
|
description: |
|
|
Run view plus `cancelled`; `false` means it was already terminal.
|
|
/api/workflows/runs/{run_id}/resume:
|
|
post:
|
|
tags: [runs]
|
|
summary: Resume after human_input
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
$ref: "#/components/schemas/ResumeRunRequest"
|
|
responses:
|
|
"200":
|
|
description: Requeued
|
|
"409":
|
|
description: WORKFLOW_RUN_NOT_RESUMABLE / WORKFLOW_RESUME_TOKEN_INVALID
|
|
/api/workflows/runs/{run_id}/retry:
|
|
post:
|
|
tags: [runs]
|
|
summary: Retry a failed run from the first unfinished node
|
|
description: |
|
|
Creates a new queued run with `retryOfRunId` pointing at the failed
|
|
original. Completed `workflow_node_runs` are copied so the engine
|
|
resumes from the failed node; if nothing is replayable it is a full
|
|
re-run of the same version and inputs. Only `failed` runs are retryable.
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
responses:
|
|
"201":
|
|
description: '{ ..., retryOfRunId, created: true }'
|
|
"409":
|
|
description: WORKFLOW_RUN_NOT_RETRYABLE
|
|
"429":
|
|
description: WORKFLOW_LIMIT_EXCEEDED
|
|
/api/workflows/runs/{run_id}/artifacts:
|
|
get:
|
|
tags: [runs]
|
|
summary: List artifacts for a run
|
|
parameters:
|
|
- $ref: "#/components/parameters/RunId"
|
|
responses:
|
|
"200":
|
|
description: OK
|
|
/api/workflows/embed/tickets:
|
|
post:
|
|
tags: [embed]
|
|
summary: Issue a short-lived iframe ticket (authenticated parent)
|
|
description: |
|
|
`origin` must exactly match `workflows.embed.allowed_origins`. The
|
|
response also carries `frameAncestors` for the host's CSP.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [workflowId, origin]
|
|
properties:
|
|
workflowId:
|
|
type: string
|
|
origin:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: '{ ticket, expiresIn, origin, frameAncestors }'
|
|
"403":
|
|
description: WORKFLOW_EMBED_ORIGIN_DENIED / WORKFLOW_FORBIDDEN
|
|
"503":
|
|
description: No signing key configured
|
|
/api/workflows/embed/verify:
|
|
post:
|
|
tags: [embed]
|
|
summary: Verify a ticket (single-use, best effort per process)
|
|
description: |
|
|
A ticket proves "this origin may embed this workflow for this user right
|
|
now". It is NOT an API credential — embedded pages still authenticate
|
|
their API calls with the normal session.
|
|
requestBody:
|
|
required: true
|
|
content:
|
|
application/json:
|
|
schema:
|
|
type: object
|
|
required: [ticket]
|
|
properties:
|
|
ticket:
|
|
type: string
|
|
origin:
|
|
type: string
|
|
responses:
|
|
"200":
|
|
description: '{ ok, workflowId, userId, origin, expiresAt }'
|
|
"401":
|
|
description: WORKFLOW_EMBED_TICKET_INVALID (expired or replayed)
|
|
"403":
|
|
description: WORKFLOW_EMBED_ORIGIN_DENIED (origin mismatch)
|
|
/api/workflow_api/canvas:
|
|
post:
|
|
tags: [coze-compat]
|
|
summary: Coze canvas load adapter
|
|
responses:
|
|
"200":
|
|
description: Coze DTO
|
|
/api/workflow_api/save:
|
|
post:
|
|
tags: [coze-compat]
|
|
summary: Coze canvas save adapter
|
|
responses:
|
|
"200":
|
|
description: Saved
|
|
/api/workflow_api/create:
|
|
post:
|
|
tags: [coze-compat]
|
|
summary: Coze create workflow adapter
|
|
responses:
|
|
"200":
|
|
description: Created
|
|
/api/workflow_api/node_template_list:
|
|
post:
|
|
tags: [coze-compat]
|
|
summary: Coze node template list adapter
|
|
responses:
|
|
"200":
|
|
description: Templates
|
|
components:
|
|
parameters:
|
|
WorkflowId:
|
|
name: workflow_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
VersionId:
|
|
name: version_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
RunId:
|
|
name: run_id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
DataSourceId:
|
|
name: id
|
|
in: path
|
|
required: true
|
|
schema:
|
|
type: string
|
|
schemas:
|
|
WorkflowGraph:
|
|
type: object
|
|
description: Internal standard graph (see WORKFLOW_SCHEMA_V1_ZH.md)
|
|
required: [schemaVersion, id, nodes, edges]
|
|
properties:
|
|
schemaVersion:
|
|
type: string
|
|
enum: ["1.0"]
|
|
id:
|
|
type: string
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
inputSchema:
|
|
type: object
|
|
outputSchema:
|
|
type: object
|
|
nodes:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/WorkflowNode"
|
|
edges:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/WorkflowEdge"
|
|
settings:
|
|
$ref: "#/components/schemas/WorkflowGraphSettings"
|
|
WorkflowNode:
|
|
type: object
|
|
required: [id, type]
|
|
properties:
|
|
id:
|
|
type: string
|
|
type:
|
|
type: string
|
|
enum:
|
|
- start
|
|
- output
|
|
- agent
|
|
- skill
|
|
- http
|
|
- sql_read
|
|
- code
|
|
- transform
|
|
- condition
|
|
- merge
|
|
- human_input
|
|
- subworkflow
|
|
- loop
|
|
name:
|
|
type: string
|
|
config:
|
|
type: object
|
|
WorkflowEdge:
|
|
type: object
|
|
required: [id, source, target]
|
|
properties:
|
|
id:
|
|
type: string
|
|
source:
|
|
type: string
|
|
target:
|
|
type: string
|
|
sourcePort:
|
|
type: string
|
|
nullable: true
|
|
WorkflowGraphSettings:
|
|
type: object
|
|
properties:
|
|
runTimeoutSeconds:
|
|
type: integer
|
|
default: 1800
|
|
nodeTimeoutSeconds:
|
|
type: integer
|
|
default: 300
|
|
maxSteps:
|
|
type: integer
|
|
default: 200
|
|
maxLoopIterations:
|
|
type: integer
|
|
default: 5
|
|
maxParallelism:
|
|
type: integer
|
|
default: 4
|
|
NodeResult:
|
|
type: object
|
|
properties:
|
|
data:
|
|
type: object
|
|
messages:
|
|
type: array
|
|
items:
|
|
type: object
|
|
artifacts:
|
|
type: array
|
|
items:
|
|
$ref: "#/components/schemas/ArtifactRef"
|
|
metadata:
|
|
type: object
|
|
warnings:
|
|
type: array
|
|
items:
|
|
type: string
|
|
ArtifactRef:
|
|
type: object
|
|
required: [artifactId, name]
|
|
properties:
|
|
artifactId:
|
|
type: string
|
|
name:
|
|
type: string
|
|
mimeType:
|
|
type: string
|
|
path:
|
|
type: string
|
|
sizeBytes:
|
|
type: integer
|
|
nullable: true
|
|
preview:
|
|
type: string
|
|
nullable: true
|
|
StartRunRequest:
|
|
type: object
|
|
properties:
|
|
versionId:
|
|
type: string
|
|
description: Omit to use the latest published version.
|
|
inputs:
|
|
type: object
|
|
idempotencyKey:
|
|
type: string
|
|
maxLength: 128
|
|
executionMode:
|
|
type: string
|
|
enum: [normal]
|
|
default: normal
|
|
ResumeRunRequest:
|
|
type: object
|
|
required: [resumeToken]
|
|
properties:
|
|
resumeToken:
|
|
type: string
|
|
nodeId:
|
|
type: string
|
|
description: Defaults to the paused node from `pendingInput`.
|
|
action:
|
|
type: string
|
|
default: submit
|
|
values:
|
|
type: object
|
|
DataSourceCreate:
|
|
type: object
|
|
required: [name]
|
|
properties:
|
|
name:
|
|
type: string
|
|
description:
|
|
type: string
|
|
kind:
|
|
type: string
|
|
enum: [sql, http]
|
|
default: sql
|
|
dsn:
|
|
type: string
|
|
description: Write-only; required for `kind: sql`.
|
|
headers:
|
|
type: object
|
|
additionalProperties:
|
|
type: string
|
|
description: Write-only; required for `kind: http`.
|
|
maxRows:
|
|
type: integer
|
|
default: 1000
|
|
allowedTables:
|
|
type: array
|
|
items:
|
|
type: string
|
|
enabled:
|
|
type: boolean
|
|
default: true
|
|
shared:
|
|
type: boolean
|
|
default: false
|
|
description: Admin-only. Shared sources have a null owner.
|
|
WorkflowEventEnvelope:
|
|
type: object
|
|
required: [schemaVersion, runId, workflowId, versionId, seq, event]
|
|
properties:
|
|
schemaVersion:
|
|
type: string
|
|
enum: ["1.0"]
|
|
runId:
|
|
type: string
|
|
workflowId:
|
|
type: string
|
|
versionId:
|
|
type: string
|
|
seq:
|
|
type: integer
|
|
event:
|
|
type: string
|
|
nodeId:
|
|
type: string
|
|
nullable: true
|
|
nodeRunId:
|
|
type: string
|
|
nullable: true
|
|
timestamp:
|
|
type: string
|
|
format: date-time
|
|
data:
|
|
type: object
|
|
WorkflowErrorBody:
|
|
type: object
|
|
required: [code, message]
|
|
properties:
|
|
code:
|
|
type: string
|
|
message:
|
|
type: string
|
|
retryable:
|
|
type: boolean
|
|
nodeId:
|
|
type: string
|
|
nullable: true
|
|
details:
|
|
type: object
|