diff --git a/pipeline-runner/doc/openapi.yaml b/pipeline-runner/doc/openapi.yaml new file mode 100644 index 0000000..1c0008a --- /dev/null +++ b/pipeline-runner/doc/openapi.yaml @@ -0,0 +1,565 @@ +openapi: "3.0.3" +info: + title: Pipeline Runner API + version: "0.1.0" + description: >- + REST API for managing and executing AI pipelines. Each pipeline consists + of ordered prompts that are executed sequentially via opencode. +servers: + - url: http://localhost:8080 + description: Local development server +tags: + - name: Pipelines + description: Pipeline CRUD operations + - name: Runs + description: Pipeline execution and monitoring +paths: + /api/pipelines: + get: + tags: + - Pipelines + summary: List all pipelines + description: Returns all stored pipelines as a JSON array. + operationId: listPipelines + responses: + "200": + description: A JSON array of all pipelines + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + application/json: + schema: + type: array + items: + $ref: '#/components/schemas/Pipeline' + example: + - id: "my-pipeline" + name: "My Pipeline" + working_dir: "/workspace" + created_at: "2025-01-15T10:30:00Z" + updated_at: "2025-01-15T10:30:00Z" + prompts: + - id: "p1" + text: "Summarize the document" + title: "Summarization" + order: 0 + - id: "p2" + text: "Translate to French" + title: "Translation" + order: 1 + "500": + description: Internal server error + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Internal server error" + post: + tags: + - Pipelines + summary: Create a new pipeline + description: >- + Creates a new pipeline and persists it as a JSON file. Returns the + created pipeline with generated timestamps. + operationId: createPipeline + requestBody: + required: true + description: Pipeline data to create + content: + application/json: + schema: + $ref: '#/components/schemas/CreatePipelineRequest' + example: + id: "my-pipeline" + name: "My Pipeline" + working_dir: "/workspace" + prompts: + - id: "p1" + text: "Summarize the document" + title: "Summarization" + order: 0 + - id: "p2" + text: "Translate to French" + title: "Translation" + order: 1 + responses: + "200": + description: Pipeline created successfully + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + application/json: + schema: + $ref: '#/components/schemas/Pipeline' + example: + id: "my-pipeline" + name: "My Pipeline" + working_dir: "/workspace" + created_at: "2025-01-15T10:30:00Z" + updated_at: "2025-01-15T10:30:00Z" + prompts: + - id: "p1" + text: "Summarize the document" + title: "Summarization" + order: 0 + "400": + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + invalidJson: + summary: Malformed JSON body + value: + error: "Invalid JSON" + missingFields: + summary: Missing required fields + value: + error: "id and name are required" + "409": + description: Pipeline with this ID already exists + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Pipeline already exists" + "500": + description: Failed to save pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Failed to save pipeline" + + /api/pipelines/{id}: + get: + tags: + - Pipelines + summary: Get a single pipeline by ID + description: Returns a specific pipeline by its ID. + operationId: getPipeline + parameters: + - name: id + in: path + required: true + description: The pipeline ID + schema: + type: string + responses: + "200": + description: Pipeline found + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + application/json: + schema: + $ref: '#/components/schemas/Pipeline' + "404": + description: Pipeline not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Pipeline not found" + delete: + tags: + - Pipelines + summary: Delete a pipeline + description: Deletes a pipeline by its ID. Removes the corresponding JSON file. + operationId: deletePipeline + parameters: + - name: id + in: path + required: true + description: The pipeline ID + schema: + type: string + responses: + "200": + description: Pipeline deleted successfully + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + application/json: + schema: + $ref: '#/components/schemas/DeletePipelineResponse' + example: + deleted: "my-pipeline" + "404": + description: Pipeline not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Pipeline not found" + "500": + description: Failed to delete pipeline + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Failed to delete pipeline" + + /api/runs: + post: + tags: + - Runs + summary: Start a pipeline execution + description: >- + Starts asynchronous execution of a pipeline. Each step runs + `opencode run --title ` with a 300-second timeout. + Execution stops on the first step error. + operationId: startRun + requestBody: + required: true + description: Pipeline ID to execute + content: + application/json: + schema: + $ref: '#/components/schemas/StartRunRequest' + example: + pipeline_id: "my-pipeline" + responses: + "200": + description: Run started successfully + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + application/json: + schema: + $ref: '#/components/schemas/StartRunResponse' + example: + run_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + pipeline_id: "my-pipeline" + status: "running" + "400": + description: Invalid request + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + examples: + invalidJson: + summary: Malformed JSON body + value: + error: "Invalid JSON" + missingPipelineId: + summary: Missing pipeline_id + value: + error: "pipeline_id is required" + "404": + description: Pipeline not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Pipeline not found" + "500": + description: Failed to start run + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Failed to start run" + + /api/runs/{run_id}/status: + get: + tags: + - Runs + summary: Get run status and step results + description: >- + Returns the current execution state of a run, including the status + of each step. Poll this endpoint to track progress. + operationId: getRunStatus + parameters: + - name: run_id + in: path + required: true + description: The run ID returned by POST /api/runs + schema: + type: string + responses: + "200": + description: Run state + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + application/json: + schema: + $ref: '#/components/schemas/RunState' + example: + run_id: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + pipeline_id: "my-pipeline" + status: "running" + current_step: 1 + steps: + - step_index: 0 + title: "Summarization" + status: "completed" + returncode: 0 + output: "Document summary generated." + error: "" + "404": + description: Run not found + content: + application/json: + schema: + $ref: '#/components/schemas/ErrorResponse' + example: + error: "Run not found" + + /api/runs/{run_id}/log: + get: + tags: + - Runs + summary: Get run log file contents + description: Returns the raw log file for a given run as plain text. + operationId: getRunLog + parameters: + - name: run_id + in: path + required: true + description: The run ID returned by POST /api/runs + schema: + type: string + responses: + "200": + description: Log file contents + headers: + Access-Control-Allow-Origin: + schema: + type: string + description: CORS wildcard origin + content: + text/plain: + schema: + type: string + description: Raw log contents + example: | + [2025-01-15T10:30:01Z] Starting pipeline: my-pipeline + [2025-01-15T10:30:01Z] Step 0: Summarization - running + [2025-01-15T10:30:05Z] Step 0: Summarization - completed (rc=0) + [2025-01-15T10:30:05Z] Step 1: Translation - running +components: + schemas: + Pipeline: + type: object + required: + - id + - name + - prompts + properties: + id: + type: string + description: Unique pipeline identifier + example: "my-pipeline" + name: + type: string + description: Human-readable pipeline name + example: "My Pipeline" + working_dir: + type: string + description: Working directory for pipeline execution + example: "/workspace" + created_at: + type: string + format: date-time + description: ISO 8601 timestamp of pipeline creation + example: "2025-01-15T10:30:00Z" + updated_at: + type: string + format: date-time + description: ISO 8601 timestamp of last update + example: "2025-01-15T10:30:00Z" + prompts: + type: array + description: Ordered list of prompts to execute + items: + $ref: '#/components/schemas/Prompt' + + Prompt: + type: object + required: + - id + - text + properties: + id: + type: string + description: Unique prompt identifier within the pipeline + example: "p1" + text: + type: string + description: Prompt text passed to `opencode run` + example: "Summarize the document" + title: + type: string + description: Display title for the step + example: "Summarization" + order: + type: integer + description: Execution order (lower values run first) + default: 0 + example: 0 + + CreatePipelineRequest: + type: object + required: + - id + - name + properties: + id: + type: string + description: Unique pipeline identifier + example: "my-pipeline" + name: + type: string + description: Human-readable pipeline name + example: "My Pipeline" + working_dir: + type: string + description: Working directory for pipeline execution + example: "/workspace" + prompts: + type: array + description: Ordered list of prompts to execute + items: + $ref: '#/components/schemas/Prompt' + + DeletePipelineResponse: + type: object + properties: + deleted: + type: string + description: ID of the deleted pipeline + example: "my-pipeline" + + StartRunRequest: + type: object + required: + - pipeline_id + properties: + pipeline_id: + type: string + description: ID of the pipeline to execute + example: "my-pipeline" + + StartRunResponse: + type: object + properties: + run_id: + type: string + description: Unique identifier for this execution run + example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + pipeline_id: + type: string + description: ID of the executed pipeline + example: "my-pipeline" + status: + type: string + enum: + - running + description: Initial status is always "running" + example: "running" + + RunState: + type: object + properties: + run_id: + type: string + description: Unique identifier for this execution run + example: "a1b2c3d4-e5f6-7890-abcd-ef1234567890" + pipeline_id: + type: string + description: ID of the executed pipeline + example: "my-pipeline" + status: + type: string + enum: + - pending + - running + - completed + - error + description: >- + Current status of the run. "pending" before execution begins, + "running" during execution, "completed" on success, "error" if + any step failed. + example: "running" + current_step: + type: integer + description: >- + Index of the step currently being executed, or -1 if not yet + started. + example: 1 + steps: + type: array + description: Results of each executed step in order + items: + $ref: '#/components/schemas/StepResult' + + StepResult: + type: object + properties: + step_index: + type: integer + description: Zero-based index of the step in the pipeline + example: 0 + title: + type: string + description: Display title of the step + example: "Summarization" + status: + type: string + enum: + - pending + - running + - completed + - error + description: Status of this individual step + example: "completed" + returncode: + type: integer + description: Process exit code (0 for success) + example: 0 + output: + type: string + description: Standard output from the step execution + example: "Document summary generated." + error: + type: string + description: Standard error or error message from the step + example: "" + + ErrorResponse: + type: object + properties: + error: + type: string + description: Human-readable error message + example: "Pipeline not found"