mirror of
https://github.com/crewAIInc/crewAI.git
synced 2026-04-23 11:22:38 +00:00
Compare commits
5 Commits
devin/1765
...
devin/1765
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fc7bc2ae94 | ||
|
|
1cdbe79b34 | ||
|
|
84328d9311 | ||
|
|
88d3c0fa97 | ||
|
|
75ff7dce0c |
23
.github/workflows/publish.yml
vendored
23
.github/workflows/publish.yml
vendored
@@ -1,9 +1,14 @@
|
||||
name: Publish to PyPI
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [ published ]
|
||||
repository_dispatch:
|
||||
types: [deployment-tests-passed]
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
release_tag:
|
||||
description: 'Release tag to publish'
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build:
|
||||
@@ -12,7 +17,21 @@ jobs:
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Determine release tag
|
||||
id: release
|
||||
run: |
|
||||
# Priority: workflow_dispatch input > repository_dispatch payload > default branch
|
||||
if [ -n "${{ inputs.release_tag }}" ]; then
|
||||
echo "tag=${{ inputs.release_tag }}" >> $GITHUB_OUTPUT
|
||||
elif [ -n "${{ github.event.client_payload.release_tag }}" ]; then
|
||||
echo "tag=${{ github.event.client_payload.release_tag }}" >> $GITHUB_OUTPUT
|
||||
else
|
||||
echo "tag=" >> $GITHUB_OUTPUT
|
||||
fi
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
ref: ${{ steps.release.outputs.tag || github.ref }}
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v5
|
||||
|
||||
18
.github/workflows/trigger-deployment-tests.yml
vendored
Normal file
18
.github/workflows/trigger-deployment-tests.yml
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
name: Trigger Deployment Tests
|
||||
|
||||
on:
|
||||
release:
|
||||
types: [published]
|
||||
|
||||
jobs:
|
||||
trigger:
|
||||
name: Trigger deployment tests
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Trigger deployment tests
|
||||
uses: peter-evans/repository-dispatch@v3
|
||||
with:
|
||||
token: ${{ secrets.CREWAI_DEPLOYMENTS_PAT }}
|
||||
repository: ${{ secrets.CREWAI_DEPLOYMENTS_REPOSITORY }}
|
||||
event-type: crewai-release
|
||||
client-payload: '{"release_tag": "${{ github.event.release.tag_name }}", "release_name": "${{ github.event.release.name }}"}'
|
||||
@@ -16,16 +16,17 @@ Welcome to the CrewAI AOP API reference. This API allows you to programmatically
|
||||
Navigate to your crew's detail page in the CrewAI AOP dashboard and copy your Bearer Token from the Status tab.
|
||||
</Step>
|
||||
|
||||
<Step title="Discover Required Inputs">
|
||||
Use the `GET /inputs` endpoint to see what parameters your crew expects.
|
||||
</Step>
|
||||
<Step title="Discover Required Inputs">
|
||||
Use the `GET /inputs` endpoint to see what parameters your crew expects.
|
||||
</Step>
|
||||
|
||||
<Step title="Start a Crew Execution">
|
||||
Call `POST /kickoff` with your inputs to start the crew execution and receive a `kickoff_id`.
|
||||
</Step>
|
||||
<Step title="Start a Crew Execution">
|
||||
Call `POST /kickoff` with your inputs to start the crew execution and receive
|
||||
a `kickoff_id`.
|
||||
</Step>
|
||||
|
||||
<Step title="Monitor Progress">
|
||||
Use `GET /status/{kickoff_id}` to check execution status and retrieve results.
|
||||
Use `GET /{kickoff_id}/status` to check execution status and retrieve results.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
@@ -40,13 +41,14 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" \
|
||||
|
||||
### Token Types
|
||||
|
||||
| Token Type | Scope | Use Case |
|
||||
|:-----------|:--------|:----------|
|
||||
| **Bearer Token** | Organization-level access | Full crew operations, ideal for server-to-server integration |
|
||||
| **User Bearer Token** | User-scoped access | Limited permissions, suitable for user-specific operations |
|
||||
| Token Type | Scope | Use Case |
|
||||
| :-------------------- | :------------------------ | :----------------------------------------------------------- |
|
||||
| **Bearer Token** | Organization-level access | Full crew operations, ideal for server-to-server integration |
|
||||
| **User Bearer Token** | User-scoped access | Limited permissions, suitable for user-specific operations |
|
||||
|
||||
<Tip>
|
||||
You can find both token types in the Status tab of your crew's detail page in the CrewAI AOP dashboard.
|
||||
You can find both token types in the Status tab of your crew's detail page in
|
||||
the CrewAI AOP dashboard.
|
||||
</Tip>
|
||||
|
||||
## Base URL
|
||||
@@ -63,29 +65,33 @@ Replace `your-crew-name` with your actual crew's URL from the dashboard.
|
||||
|
||||
1. **Discovery**: Call `GET /inputs` to understand what your crew needs
|
||||
2. **Execution**: Submit inputs via `POST /kickoff` to start processing
|
||||
3. **Monitoring**: Poll `GET /status/{kickoff_id}` until completion
|
||||
3. **Monitoring**: Poll `GET /{kickoff_id}/status` until completion
|
||||
4. **Results**: Extract the final output from the completed response
|
||||
|
||||
## Error Handling
|
||||
|
||||
The API uses standard HTTP status codes:
|
||||
|
||||
| Code | Meaning |
|
||||
|------|:--------|
|
||||
| `200` | Success |
|
||||
| `400` | Bad Request - Invalid input format |
|
||||
| `401` | Unauthorized - Invalid bearer token |
|
||||
| `404` | Not Found - Resource doesn't exist |
|
||||
| Code | Meaning |
|
||||
| ----- | :----------------------------------------- |
|
||||
| `200` | Success |
|
||||
| `400` | Bad Request - Invalid input format |
|
||||
| `401` | Unauthorized - Invalid bearer token |
|
||||
| `404` | Not Found - Resource doesn't exist |
|
||||
| `422` | Validation Error - Missing required inputs |
|
||||
| `500` | Server Error - Contact support |
|
||||
| `500` | Server Error - Contact support |
|
||||
|
||||
## Interactive Testing
|
||||
|
||||
<Info>
|
||||
**Why no "Send" button?** Since each CrewAI AOP user has their own unique crew URL, we use **reference mode** instead of an interactive playground to avoid confusion. This shows you exactly what the requests should look like without non-functional send buttons.
|
||||
**Why no "Send" button?** Since each CrewAI AOP user has their own unique crew
|
||||
URL, we use **reference mode** instead of an interactive playground to avoid
|
||||
confusion. This shows you exactly what the requests should look like without
|
||||
non-functional send buttons.
|
||||
</Info>
|
||||
|
||||
Each endpoint page shows you:
|
||||
|
||||
- ✅ **Exact request format** with all parameters
|
||||
- ✅ **Response examples** for success and error cases
|
||||
- ✅ **Code samples** in multiple languages (cURL, Python, JavaScript, etc.)
|
||||
@@ -103,6 +109,7 @@ Each endpoint page shows you:
|
||||
</CardGroup>
|
||||
|
||||
**Example workflow:**
|
||||
|
||||
1. **Copy this cURL example** from any endpoint page
|
||||
2. **Replace `your-actual-crew-name.crewai.com`** with your real crew URL
|
||||
3. **Replace the Bearer token** with your real token from the dashboard
|
||||
@@ -111,10 +118,18 @@ Each endpoint page shows you:
|
||||
## Need Help?
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Enterprise Support" icon="headset" href="mailto:support@crewai.com">
|
||||
<Card
|
||||
title="Enterprise Support"
|
||||
icon="headset"
|
||||
href="mailto:support@crewai.com"
|
||||
>
|
||||
Get help with API integration and troubleshooting
|
||||
</Card>
|
||||
<Card title="Enterprise Dashboard" icon="chart-line" href="https://app.crewai.com">
|
||||
<Card
|
||||
title="Enterprise Dashboard"
|
||||
icon="chart-line"
|
||||
href="https://app.crewai.com"
|
||||
>
|
||||
Manage your crews and view execution logs
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: "GET /status/{kickoff_id}"
|
||||
title: "GET /{kickoff_id}/status"
|
||||
description: "Get execution status"
|
||||
openapi: "/enterprise-api.en.yaml GET /status/{kickoff_id}"
|
||||
openapi: "/enterprise-api.en.yaml GET /{kickoff_id}/status"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ info:
|
||||
|
||||
1. **Discover inputs** using `GET /inputs`
|
||||
2. **Start execution** using `POST /kickoff`
|
||||
3. **Monitor progress** using `GET /status/{kickoff_id}`
|
||||
3. **Monitor progress** using `GET /{kickoff_id}/status`
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: CrewAI Support
|
||||
@@ -63,7 +63,7 @@ paths:
|
||||
Use this endpoint to discover what inputs you need to provide when starting a crew execution.
|
||||
operationId: getRequiredInputs
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successfully retrieved required inputs
|
||||
content:
|
||||
application/json:
|
||||
@@ -84,13 +84,21 @@ paths:
|
||||
outreach_crew:
|
||||
summary: Outreach crew inputs
|
||||
value:
|
||||
inputs: ["name", "title", "company", "industry", "our_product", "linkedin_url"]
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFoundError'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
inputs:
|
||||
[
|
||||
"name",
|
||||
"title",
|
||||
"company",
|
||||
"industry",
|
||||
"our_product",
|
||||
"linkedin_url",
|
||||
]
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/kickoff:
|
||||
post:
|
||||
@@ -170,7 +178,7 @@ paths:
|
||||
taskWebhookUrl: "https://api.example.com/webhooks/task"
|
||||
crewWebhookUrl: "https://api.example.com/webhooks/crew"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Crew execution started successfully
|
||||
content:
|
||||
application/json:
|
||||
@@ -182,24 +190,24 @@ paths:
|
||||
format: uuid
|
||||
description: Unique identifier for tracking this execution
|
||||
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
'400':
|
||||
"400":
|
||||
description: Invalid request body or missing required inputs
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'422':
|
||||
$ref: "#/components/schemas/Error"
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"422":
|
||||
description: Validation error - ensure all required inputs are provided
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
$ref: "#/components/schemas/ValidationError"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/status/{kickoff_id}:
|
||||
/{kickoff_id}/status:
|
||||
get:
|
||||
summary: Get Execution Status
|
||||
description: |
|
||||
@@ -222,15 +230,15 @@ paths:
|
||||
format: uuid
|
||||
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successfully retrieved execution status
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/ExecutionRunning'
|
||||
- $ref: '#/components/schemas/ExecutionCompleted'
|
||||
- $ref: '#/components/schemas/ExecutionError'
|
||||
- $ref: "#/components/schemas/ExecutionRunning"
|
||||
- $ref: "#/components/schemas/ExecutionCompleted"
|
||||
- $ref: "#/components/schemas/ExecutionError"
|
||||
examples:
|
||||
running:
|
||||
summary: Execution in progress
|
||||
@@ -262,19 +270,19 @@ paths:
|
||||
status: "error"
|
||||
error: "Task execution failed: Invalid API key for external service"
|
||||
execution_time: 23.1
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
description: Kickoff ID not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Execution not found"
|
||||
message: "No execution found with ID: abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/resume:
|
||||
post:
|
||||
@@ -354,7 +362,7 @@ paths:
|
||||
taskWebhookUrl: "https://api.example.com/webhooks/task"
|
||||
crewWebhookUrl: "https://api.example.com/webhooks/crew"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Execution resumed successfully
|
||||
content:
|
||||
application/json:
|
||||
@@ -381,28 +389,28 @@ paths:
|
||||
value:
|
||||
status: "retrying"
|
||||
message: "Task will be retried with your feedback"
|
||||
'400':
|
||||
"400":
|
||||
description: Invalid request body or execution not in pending state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Invalid Request"
|
||||
message: "Execution is not in pending human input state"
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
description: Execution ID or Task ID not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Not Found"
|
||||
message: "Execution ID not found"
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
@@ -458,7 +466,7 @@ components:
|
||||
tasks:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TaskResult'
|
||||
$ref: "#/components/schemas/TaskResult"
|
||||
execution_time:
|
||||
type: number
|
||||
description: Total execution time in seconds
|
||||
@@ -536,7 +544,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Unauthorized"
|
||||
message: "Invalid or missing bearer token"
|
||||
@@ -546,7 +554,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Not Found"
|
||||
message: "The requested resource was not found"
|
||||
@@ -556,7 +564,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Internal Server Error"
|
||||
message: "An unexpected error occurred"
|
||||
|
||||
@@ -35,7 +35,7 @@ info:
|
||||
|
||||
1. **Discover inputs** using `GET /inputs`
|
||||
2. **Start execution** using `POST /kickoff`
|
||||
3. **Monitor progress** using `GET /status/{kickoff_id}`
|
||||
3. **Monitor progress** using `GET /{kickoff_id}/status`
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: CrewAI Support
|
||||
@@ -63,7 +63,7 @@ paths:
|
||||
Use this endpoint to discover what inputs you need to provide when starting a crew execution.
|
||||
operationId: getRequiredInputs
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successfully retrieved required inputs
|
||||
content:
|
||||
application/json:
|
||||
@@ -84,13 +84,21 @@ paths:
|
||||
outreach_crew:
|
||||
summary: Outreach crew inputs
|
||||
value:
|
||||
inputs: ["name", "title", "company", "industry", "our_product", "linkedin_url"]
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFoundError'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
inputs:
|
||||
[
|
||||
"name",
|
||||
"title",
|
||||
"company",
|
||||
"industry",
|
||||
"our_product",
|
||||
"linkedin_url",
|
||||
]
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/kickoff:
|
||||
post:
|
||||
@@ -170,7 +178,7 @@ paths:
|
||||
taskWebhookUrl: "https://api.example.com/webhooks/task"
|
||||
crewWebhookUrl: "https://api.example.com/webhooks/crew"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Crew execution started successfully
|
||||
content:
|
||||
application/json:
|
||||
@@ -182,24 +190,24 @@ paths:
|
||||
format: uuid
|
||||
description: Unique identifier for tracking this execution
|
||||
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
'400':
|
||||
"400":
|
||||
description: Invalid request body or missing required inputs
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'422':
|
||||
$ref: "#/components/schemas/Error"
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"422":
|
||||
description: Validation error - ensure all required inputs are provided
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ValidationError'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
$ref: "#/components/schemas/ValidationError"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/status/{kickoff_id}:
|
||||
/{kickoff_id}/status:
|
||||
get:
|
||||
summary: Get Execution Status
|
||||
description: |
|
||||
@@ -222,15 +230,15 @@ paths:
|
||||
format: uuid
|
||||
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successfully retrieved execution status
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/ExecutionRunning'
|
||||
- $ref: '#/components/schemas/ExecutionCompleted'
|
||||
- $ref: '#/components/schemas/ExecutionError'
|
||||
- $ref: "#/components/schemas/ExecutionRunning"
|
||||
- $ref: "#/components/schemas/ExecutionCompleted"
|
||||
- $ref: "#/components/schemas/ExecutionError"
|
||||
examples:
|
||||
running:
|
||||
summary: Execution in progress
|
||||
@@ -262,19 +270,19 @@ paths:
|
||||
status: "error"
|
||||
error: "Task execution failed: Invalid API key for external service"
|
||||
execution_time: 23.1
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
description: Kickoff ID not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Execution not found"
|
||||
message: "No execution found with ID: abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/resume:
|
||||
post:
|
||||
@@ -354,7 +362,7 @@ paths:
|
||||
taskWebhookUrl: "https://api.example.com/webhooks/task"
|
||||
crewWebhookUrl: "https://api.example.com/webhooks/crew"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Execution resumed successfully
|
||||
content:
|
||||
application/json:
|
||||
@@ -381,28 +389,28 @@ paths:
|
||||
value:
|
||||
status: "retrying"
|
||||
message: "Task will be retried with your feedback"
|
||||
'400':
|
||||
"400":
|
||||
description: Invalid request body or execution not in pending state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Invalid Request"
|
||||
message: "Execution is not in pending human input state"
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
description: Execution ID or Task ID not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Not Found"
|
||||
message: "Execution ID not found"
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
@@ -458,7 +466,7 @@ components:
|
||||
tasks:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TaskResult'
|
||||
$ref: "#/components/schemas/TaskResult"
|
||||
execution_time:
|
||||
type: number
|
||||
description: Total execution time in seconds
|
||||
@@ -536,7 +544,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Unauthorized"
|
||||
message: "Invalid or missing bearer token"
|
||||
@@ -546,7 +554,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Not Found"
|
||||
message: "The requested resource was not found"
|
||||
@@ -556,7 +564,7 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Internal Server Error"
|
||||
message: "An unexpected error occurred"
|
||||
|
||||
@@ -84,7 +84,7 @@ paths:
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
|
||||
/status/{kickoff_id}:
|
||||
/{kickoff_id}/status:
|
||||
get:
|
||||
summary: 실행 상태 조회
|
||||
description: |
|
||||
|
||||
@@ -35,7 +35,7 @@ info:
|
||||
|
||||
1. **Descubra os inputs** usando `GET /inputs`
|
||||
2. **Inicie a execução** usando `POST /kickoff`
|
||||
3. **Monitore o progresso** usando `GET /status/{kickoff_id}`
|
||||
3. **Monitore o progresso** usando `GET /{kickoff_id}/status`
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: CrewAI Suporte
|
||||
@@ -56,7 +56,7 @@ paths:
|
||||
Retorna a lista de parâmetros de entrada que sua crew espera.
|
||||
operationId: getRequiredInputs
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Inputs requeridos obtidos com sucesso
|
||||
content:
|
||||
application/json:
|
||||
@@ -69,12 +69,12 @@ paths:
|
||||
type: string
|
||||
description: Nomes dos parâmetros de entrada
|
||||
example: ["budget", "interests", "duration", "age"]
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFoundError'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "#/components/responses/NotFoundError"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/kickoff:
|
||||
post:
|
||||
@@ -104,7 +104,7 @@ paths:
|
||||
age: "35"
|
||||
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Execução iniciada com sucesso
|
||||
content:
|
||||
application/json:
|
||||
@@ -115,12 +115,12 @@ paths:
|
||||
type: string
|
||||
format: uuid
|
||||
example: "abcd1234-5678-90ef-ghij-klmnopqrstuv"
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/status/{kickoff_id}:
|
||||
/{kickoff_id}/status:
|
||||
get:
|
||||
summary: Obter Status da Execução
|
||||
description: |
|
||||
@@ -136,25 +136,25 @@ paths:
|
||||
type: string
|
||||
format: uuid
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Status recuperado com sucesso
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
oneOf:
|
||||
- $ref: '#/components/schemas/ExecutionRunning'
|
||||
- $ref: '#/components/schemas/ExecutionCompleted'
|
||||
- $ref: '#/components/schemas/ExecutionError'
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
- $ref: "#/components/schemas/ExecutionRunning"
|
||||
- $ref: "#/components/schemas/ExecutionCompleted"
|
||||
- $ref: "#/components/schemas/ExecutionError"
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
description: Kickoff ID não encontrado
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
$ref: "#/components/schemas/Error"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
/resume:
|
||||
post:
|
||||
@@ -234,7 +234,7 @@ paths:
|
||||
taskWebhookUrl: "https://api.example.com/webhooks/task"
|
||||
crewWebhookUrl: "https://api.example.com/webhooks/crew"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Execution resumed successfully
|
||||
content:
|
||||
application/json:
|
||||
@@ -261,28 +261,28 @@ paths:
|
||||
value:
|
||||
status: "retrying"
|
||||
message: "Task will be retried with your feedback"
|
||||
'400':
|
||||
"400":
|
||||
description: Invalid request body or execution not in pending state
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Invalid Request"
|
||||
message: "Execution is not in pending human input state"
|
||||
'401':
|
||||
$ref: '#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
"401":
|
||||
$ref: "#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
description: Execution ID or Task ID not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
example:
|
||||
error: "Not Found"
|
||||
message: "Execution ID not found"
|
||||
'500':
|
||||
$ref: '#/components/responses/ServerError'
|
||||
"500":
|
||||
$ref: "#/components/responses/ServerError"
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
@@ -324,7 +324,7 @@ components:
|
||||
tasks:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/TaskResult'
|
||||
$ref: "#/components/schemas/TaskResult"
|
||||
execution_time:
|
||||
type: number
|
||||
|
||||
@@ -380,16 +380,16 @@ components:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
NotFoundError:
|
||||
description: Recurso não encontrado
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
ServerError:
|
||||
description: Erro interno do servidor
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
@@ -16,16 +16,17 @@ CrewAI 엔터프라이즈 API 참고 자료에 오신 것을 환영합니다.
|
||||
CrewAI AOP 대시보드에서 자신의 crew 상세 페이지로 이동하여 Status 탭에서 Bearer Token을 복사하세요.
|
||||
</Step>
|
||||
|
||||
<Step title="필수 입력값 확인하기">
|
||||
`GET /inputs` 엔드포인트를 사용하여 crew가 기대하는 파라미터를 확인하세요.
|
||||
</Step>
|
||||
<Step title="필수 입력값 확인하기">
|
||||
`GET /inputs` 엔드포인트를 사용하여 crew가 기대하는 파라미터를 확인하세요.
|
||||
</Step>
|
||||
|
||||
<Step title="Crew 실행 시작하기">
|
||||
입력값과 함께 `POST /kickoff`를 호출하여 crew 실행을 시작하고 `kickoff_id`를 받으세요.
|
||||
</Step>
|
||||
<Step title="Crew 실행 시작하기">
|
||||
입력값과 함께 `POST /kickoff`를 호출하여 crew 실행을 시작하고 `kickoff_id`를
|
||||
받으세요.
|
||||
</Step>
|
||||
|
||||
<Step title="진행 상황 모니터링">
|
||||
`GET /status/{kickoff_id}`를 사용하여 실행 상태를 확인하고 결과를 조회하세요.
|
||||
`GET /{kickoff_id}/status`를 사용하여 실행 상태를 확인하고 결과를 조회하세요.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
@@ -40,13 +41,14 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" \
|
||||
|
||||
### 토큰 유형
|
||||
|
||||
| 토큰 유형 | 범위 | 사용 사례 |
|
||||
|:-----------|:--------|:----------|
|
||||
| **Bearer Token** | 조직 단위 접근 | 전체 crew 운영, 서버 간 통합에 이상적 |
|
||||
| **User Bearer Token** | 사용자 범위 접근 | 제한된 권한, 사용자별 작업에 적합 |
|
||||
| 토큰 유형 | 범위 | 사용 사례 |
|
||||
| :-------------------- | :--------------- | :------------------------------------ |
|
||||
| **Bearer Token** | 조직 단위 접근 | 전체 crew 운영, 서버 간 통합에 이상적 |
|
||||
| **User Bearer Token** | 사용자 범위 접근 | 제한된 권한, 사용자별 작업에 적합 |
|
||||
|
||||
<Tip>
|
||||
두 토큰 유형 모두 CrewAI AOP 대시보드의 crew 상세 페이지 Status 탭에서 확인할 수 있습니다.
|
||||
두 토큰 유형 모두 CrewAI AOP 대시보드의 crew 상세 페이지 Status 탭에서 확인할
|
||||
수 있습니다.
|
||||
</Tip>
|
||||
|
||||
## 기본 URL
|
||||
@@ -63,29 +65,33 @@ https://your-crew-name.crewai.com
|
||||
|
||||
1. **탐색**: `GET /inputs`를 호출하여 crew가 필요한 것을 파악합니다.
|
||||
2. **실행**: `POST /kickoff`를 통해 입력값을 제출하여 처리를 시작합니다.
|
||||
3. **모니터링**: 완료될 때까지 `GET /status/{kickoff_id}`를 주기적으로 조회합니다.
|
||||
3. **모니터링**: 완료될 때까지 `GET /{kickoff_id}/status`를 주기적으로 조회합니다.
|
||||
4. **결과**: 완료된 응답에서 최종 출력을 추출합니다.
|
||||
|
||||
## 오류 처리
|
||||
|
||||
API는 표준 HTTP 상태 코드를 사용합니다:
|
||||
|
||||
| 코드 | 의미 |
|
||||
|------|:--------|
|
||||
| `200` | 성공 |
|
||||
| `400` | 잘못된 요청 - 잘못된 입력 형식 |
|
||||
| `401` | 인증 실패 - 잘못된 베어러 토큰 |
|
||||
| 코드 | 의미 |
|
||||
| ----- | :------------------------------------ |
|
||||
| `200` | 성공 |
|
||||
| `400` | 잘못된 요청 - 잘못된 입력 형식 |
|
||||
| `401` | 인증 실패 - 잘못된 베어러 토큰 |
|
||||
| `404` | 찾을 수 없음 - 리소스가 존재하지 않음 |
|
||||
| `422` | 유효성 검사 오류 - 필수 입력 누락 |
|
||||
| `500` | 서버 오류 - 지원팀에 문의하십시오 |
|
||||
| `422` | 유효성 검사 오류 - 필수 입력 누락 |
|
||||
| `500` | 서버 오류 - 지원팀에 문의하십시오 |
|
||||
|
||||
## 인터랙티브 테스트
|
||||
|
||||
<Info>
|
||||
**왜 "전송" 버튼이 없나요?** 각 CrewAI AOP 사용자는 고유한 crew URL을 가지므로, 혼동을 피하기 위해 인터랙티브 플레이그라운드 대신 **참조 모드**를 사용합니다. 이를 통해 비작동 전송 버튼 없이 요청이 어떻게 생겼는지 정확히 보여줍니다.
|
||||
**왜 "전송" 버튼이 없나요?** 각 CrewAI AOP 사용자는 고유한 crew URL을
|
||||
가지므로, 혼동을 피하기 위해 인터랙티브 플레이그라운드 대신 **참조 모드**를
|
||||
사용합니다. 이를 통해 비작동 전송 버튼 없이 요청이 어떻게 생겼는지 정확히
|
||||
보여줍니다.
|
||||
</Info>
|
||||
|
||||
각 엔드포인트 페이지에서는 다음을 확인할 수 있습니다:
|
||||
|
||||
- ✅ 모든 파라미터가 포함된 **정확한 요청 형식**
|
||||
- ✅ 성공 및 오류 사례에 대한 **응답 예시**
|
||||
- ✅ 여러 언어(cURL, Python, JavaScript 등)로 제공되는 **코드 샘플**
|
||||
@@ -103,6 +109,7 @@ API는 표준 HTTP 상태 코드를 사용합니다:
|
||||
</CardGroup>
|
||||
|
||||
**예시 작업 흐름:**
|
||||
|
||||
1. **cURL 예제를 복사**합니다 (엔드포인트 페이지에서)
|
||||
2. **`your-actual-crew-name.crewai.com`**을(를) 실제 crew URL로 교체합니다
|
||||
3. **Bearer 토큰을** 대시보드에서 복사한 실제 토큰으로 교체합니다
|
||||
@@ -111,10 +118,18 @@ API는 표준 HTTP 상태 코드를 사용합니다:
|
||||
## 도움이 필요하신가요?
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Enterprise Support" icon="headset" href="mailto:support@crewai.com">
|
||||
<Card
|
||||
title="Enterprise Support"
|
||||
icon="headset"
|
||||
href="mailto:support@crewai.com"
|
||||
>
|
||||
API 통합 및 문제 해결에 대한 지원을 받으세요
|
||||
</Card>
|
||||
<Card title="Enterprise Dashboard" icon="chart-line" href="https://app.crewai.com">
|
||||
<Card
|
||||
title="Enterprise Dashboard"
|
||||
icon="chart-line"
|
||||
href="https://app.crewai.com"
|
||||
>
|
||||
crew를 관리하고 실행 로그를 확인하세요
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: "GET /status/{kickoff_id}"
|
||||
title: "GET /{kickoff_id}/status"
|
||||
description: "실행 상태 조회"
|
||||
openapi: "/enterprise-api.ko.yaml GET /status/{kickoff_id}"
|
||||
openapi: "/enterprise-api.ko.yaml GET /{kickoff_id}/status"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -16,16 +16,17 @@ Bem-vindo à referência da API do CrewAI AOP. Esta API permite que você intera
|
||||
Navegue até a página de detalhes do seu crew no painel do CrewAI AOP e copie seu Bearer Token na aba Status.
|
||||
</Step>
|
||||
|
||||
<Step title="Descubra os Inputs Necessários">
|
||||
Use o endpoint `GET /inputs` para ver quais parâmetros seu crew espera.
|
||||
</Step>
|
||||
<Step title="Descubra os Inputs Necessários">
|
||||
Use o endpoint `GET /inputs` para ver quais parâmetros seu crew espera.
|
||||
</Step>
|
||||
|
||||
<Step title="Inicie uma Execução de Crew">
|
||||
Chame `POST /kickoff` com seus inputs para iniciar a execução do crew e receber um `kickoff_id`.
|
||||
</Step>
|
||||
<Step title="Inicie uma Execução de Crew">
|
||||
Chame `POST /kickoff` com seus inputs para iniciar a execução do crew e
|
||||
receber um `kickoff_id`.
|
||||
</Step>
|
||||
|
||||
<Step title="Monitore o Progresso">
|
||||
Use `GET /status/{kickoff_id}` para checar o status da execução e recuperar os resultados.
|
||||
Use `GET /{kickoff_id}/status` para checar o status da execução e recuperar os resultados.
|
||||
</Step>
|
||||
</Steps>
|
||||
|
||||
@@ -40,13 +41,14 @@ curl -H "Authorization: Bearer YOUR_CREW_TOKEN" \
|
||||
|
||||
### Tipos de Token
|
||||
|
||||
| Tipo de Token | Escopo | Caso de Uso |
|
||||
|:--------------------|:------------------------|:---------------------------------------------------------|
|
||||
| **Bearer Token** | Acesso em nível de organização | Operações completas de crew, ideal para integração server-to-server |
|
||||
| **User Bearer Token** | Acesso com escopo de usuário | Permissões limitadas, adequado para operações específicas de usuário |
|
||||
| Tipo de Token | Escopo | Caso de Uso |
|
||||
| :-------------------- | :----------------------------- | :------------------------------------------------------------------- |
|
||||
| **Bearer Token** | Acesso em nível de organização | Operações completas de crew, ideal para integração server-to-server |
|
||||
| **User Bearer Token** | Acesso com escopo de usuário | Permissões limitadas, adequado para operações específicas de usuário |
|
||||
|
||||
<Tip>
|
||||
Você pode encontrar ambos os tipos de token na aba Status da página de detalhes do seu crew no painel do CrewAI AOP.
|
||||
Você pode encontrar ambos os tipos de token na aba Status da página de
|
||||
detalhes do seu crew no painel do CrewAI AOP.
|
||||
</Tip>
|
||||
|
||||
## URL Base
|
||||
@@ -63,29 +65,33 @@ Substitua `your-crew-name` pela URL real do seu crew no painel.
|
||||
|
||||
1. **Descoberta**: Chame `GET /inputs` para entender o que seu crew precisa
|
||||
2. **Execução**: Envie os inputs via `POST /kickoff` para iniciar o processamento
|
||||
3. **Monitoramento**: Faça polling em `GET /status/{kickoff_id}` até a conclusão
|
||||
3. **Monitoramento**: Faça polling em `GET /{kickoff_id}/status` até a conclusão
|
||||
4. **Resultados**: Extraia o output final da resposta concluída
|
||||
|
||||
## Tratamento de Erros
|
||||
|
||||
A API utiliza códigos de status HTTP padrão:
|
||||
|
||||
| Código | Significado |
|
||||
|--------|:--------------------------------------|
|
||||
| `200` | Sucesso |
|
||||
| `400` | Requisição Inválida - Formato de input inválido |
|
||||
| `401` | Não Autorizado - Bearer token inválido |
|
||||
| `404` | Não Encontrado - Recurso não existe |
|
||||
| Código | Significado |
|
||||
| ------ | :----------------------------------------------- |
|
||||
| `200` | Sucesso |
|
||||
| `400` | Requisição Inválida - Formato de input inválido |
|
||||
| `401` | Não Autorizado - Bearer token inválido |
|
||||
| `404` | Não Encontrado - Recurso não existe |
|
||||
| `422` | Erro de Validação - Inputs obrigatórios ausentes |
|
||||
| `500` | Erro no Servidor - Contate o suporte |
|
||||
| `500` | Erro no Servidor - Contate o suporte |
|
||||
|
||||
## Testes Interativos
|
||||
|
||||
<Info>
|
||||
**Por que não há botão "Enviar"?** Como cada usuário do CrewAI AOP possui sua própria URL de crew, utilizamos o **modo referência** em vez de um playground interativo para evitar confusão. Isso mostra exatamente como as requisições devem ser feitas, sem botões de envio não funcionais.
|
||||
**Por que não há botão "Enviar"?** Como cada usuário do CrewAI AOP possui sua
|
||||
própria URL de crew, utilizamos o **modo referência** em vez de um playground
|
||||
interativo para evitar confusão. Isso mostra exatamente como as requisições
|
||||
devem ser feitas, sem botões de envio não funcionais.
|
||||
</Info>
|
||||
|
||||
Cada página de endpoint mostra para você:
|
||||
|
||||
- ✅ **Formato exato da requisição** com todos os parâmetros
|
||||
- ✅ **Exemplos de resposta** para casos de sucesso e erro
|
||||
- ✅ **Exemplos de código** em várias linguagens (cURL, Python, JavaScript, etc.)
|
||||
@@ -103,6 +109,7 @@ Cada página de endpoint mostra para você:
|
||||
</CardGroup>
|
||||
|
||||
**Exemplo de fluxo:**
|
||||
|
||||
1. **Copie este exemplo cURL** de qualquer página de endpoint
|
||||
2. **Substitua `your-actual-crew-name.crewai.com`** pela URL real do seu crew
|
||||
3. **Substitua o Bearer token** pelo seu token real do painel
|
||||
@@ -111,10 +118,18 @@ Cada página de endpoint mostra para você:
|
||||
## Precisa de Ajuda?
|
||||
|
||||
<CardGroup cols={2}>
|
||||
<Card title="Suporte Enterprise" icon="headset" href="mailto:support@crewai.com">
|
||||
<Card
|
||||
title="Suporte Enterprise"
|
||||
icon="headset"
|
||||
href="mailto:support@crewai.com"
|
||||
>
|
||||
Obtenha ajuda com integração da API e resolução de problemas
|
||||
</Card>
|
||||
<Card title="Painel Enterprise" icon="chart-line" href="https://app.crewai.com">
|
||||
<Card
|
||||
title="Painel Enterprise"
|
||||
icon="chart-line"
|
||||
href="https://app.crewai.com"
|
||||
>
|
||||
Gerencie seus crews e visualize logs de execução
|
||||
</Card>
|
||||
</CardGroup>
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
---
|
||||
title: "GET /status/{kickoff_id}"
|
||||
title: "GET /{kickoff_id}/status"
|
||||
description: "Obter o status da execução"
|
||||
openapi: "/enterprise-api.pt-BR.yaml GET /status/{kickoff_id}"
|
||||
openapi: "/enterprise-api.pt-BR.yaml GET /{kickoff_id}/status"
|
||||
mode: "wide"
|
||||
---
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ dependencies = [
|
||||
"pytube~=15.0.0",
|
||||
"requests~=2.32.5",
|
||||
"docker~=7.1.0",
|
||||
"crewai==1.7.0",
|
||||
"crewai==1.7.1",
|
||||
"lancedb~=0.5.4",
|
||||
"tiktoken~=0.8.0",
|
||||
"beautifulsoup4~=4.13.4",
|
||||
|
||||
@@ -291,4 +291,4 @@ __all__ = [
|
||||
"ZapierActionTools",
|
||||
]
|
||||
|
||||
__version__ = "1.7.0"
|
||||
__version__ = "1.7.1"
|
||||
|
||||
@@ -10,7 +10,7 @@ requires-python = ">=3.10, <3.14"
|
||||
dependencies = [
|
||||
# Core Dependencies
|
||||
"pydantic~=2.11.9",
|
||||
"openai>=1.83.0,<3",
|
||||
"openai~=1.83.0",
|
||||
"instructor>=1.3.3",
|
||||
# Text Processing
|
||||
"pdfplumber~=0.11.4",
|
||||
@@ -49,7 +49,7 @@ Repository = "https://github.com/crewAIInc/crewAI"
|
||||
|
||||
[project.optional-dependencies]
|
||||
tools = [
|
||||
"crewai-tools==1.7.0",
|
||||
"crewai-tools==1.7.1",
|
||||
]
|
||||
embeddings = [
|
||||
"tiktoken~=0.8.0"
|
||||
|
||||
@@ -40,7 +40,7 @@ def _suppress_pydantic_deprecation_warnings() -> None:
|
||||
|
||||
_suppress_pydantic_deprecation_warnings()
|
||||
|
||||
__version__ = "1.7.0"
|
||||
__version__ = "1.7.1"
|
||||
_telemetry_submitted = False
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
|
||||
authors = [{ name = "Your Name", email = "you@example.com" }]
|
||||
requires-python = ">=3.10,<3.14"
|
||||
dependencies = [
|
||||
"crewai[tools]==1.7.0"
|
||||
"crewai[tools]==1.7.1"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -5,7 +5,7 @@ description = "{{name}} using crewAI"
|
||||
authors = [{ name = "Your Name", email = "you@example.com" }]
|
||||
requires-python = ">=3.10,<3.14"
|
||||
dependencies = [
|
||||
"crewai[tools]==1.7.0"
|
||||
"crewai[tools]==1.7.1"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
|
||||
@@ -169,7 +169,18 @@ def handle_max_iterations_exceeded(
|
||||
)
|
||||
raise ValueError("Invalid response from LLM call - None or empty.")
|
||||
|
||||
formatted = format_answer(answer=answer)
|
||||
try:
|
||||
formatted = format_answer(answer=answer)
|
||||
except OutputParserError:
|
||||
printer.print(
|
||||
content="Failed to parse forced final answer. Returning raw response.",
|
||||
color="yellow",
|
||||
)
|
||||
return AgentFinish(
|
||||
thought="Failed to parse LLM response during max iterations",
|
||||
output=answer,
|
||||
text=answer,
|
||||
)
|
||||
|
||||
# If format_answer returned an AgentAction, convert it to AgentFinish
|
||||
if isinstance(formatted, AgentFinish):
|
||||
@@ -206,9 +217,15 @@ def format_answer(answer: str) -> AgentAction | AgentFinish:
|
||||
|
||||
Returns:
|
||||
Either an AgentAction or AgentFinish
|
||||
|
||||
Raises:
|
||||
OutputParserError: If parsing fails due to malformed LLM output format.
|
||||
This allows the retry logic in _invoke_loop() to handle the error.
|
||||
"""
|
||||
try:
|
||||
return parse(answer)
|
||||
except OutputParserError:
|
||||
raise
|
||||
except Exception:
|
||||
return AgentFinish(
|
||||
thought="Failed to parse LLM response",
|
||||
|
||||
@@ -1,154 +0,0 @@
|
||||
"""Tests for OpenAI SDK version compatibility.
|
||||
|
||||
These tests verify that crewAI's openai dependency constraint allows
|
||||
installation alongside packages that require openai 2.x (like litellm[proxy]).
|
||||
|
||||
Related to GitHub issue #4079: CrewAI dependency conflict with litellm[proxy]
|
||||
"""
|
||||
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
from packaging.specifiers import SpecifierSet
|
||||
|
||||
|
||||
def test_openai_version_constraint_allows_2x():
|
||||
"""Test that the openai version constraint in pyproject.toml allows openai 2.x.
|
||||
|
||||
This test verifies the fix for issue #4079 where crewAI could not be installed
|
||||
alongside litellm[proxy]>=1.74.9 due to conflicting openai version requirements.
|
||||
|
||||
The constraint should allow openai>=1.83.0,<3 to support both:
|
||||
- Existing users on openai 1.83.x
|
||||
- Users who need openai 2.x for litellm[proxy] compatibility
|
||||
"""
|
||||
try:
|
||||
import tomllib
|
||||
except ImportError:
|
||||
import tomli as tomllib
|
||||
|
||||
# Find the pyproject.toml file
|
||||
tests_dir = Path(__file__).parent
|
||||
pyproject_path = tests_dir.parent / "pyproject.toml"
|
||||
|
||||
with open(pyproject_path, "rb") as f:
|
||||
pyproject = tomllib.load(f)
|
||||
|
||||
dependencies = pyproject.get("project", {}).get("dependencies", [])
|
||||
|
||||
# Find the openai dependency
|
||||
openai_dep = None
|
||||
for dep in dependencies:
|
||||
if dep.startswith("openai"):
|
||||
openai_dep = dep
|
||||
break
|
||||
|
||||
assert openai_dep is not None, "openai dependency not found in pyproject.toml"
|
||||
|
||||
# Extract the version specifier from the dependency string
|
||||
# e.g., "openai>=1.83.0,<3" -> ">=1.83.0,<3"
|
||||
version_spec = openai_dep.replace("openai", "").strip()
|
||||
specifier = SpecifierSet(version_spec)
|
||||
|
||||
# Test that the specifier allows openai 2.8.0 (required by litellm[proxy])
|
||||
assert "2.8.0" in specifier, (
|
||||
f"openai constraint '{openai_dep}' does not allow version 2.8.0 "
|
||||
"which is required by litellm[proxy]>=1.74.9"
|
||||
)
|
||||
|
||||
# Test that the specifier still allows openai 1.83.0 (backward compatibility)
|
||||
assert "1.83.0" in specifier, (
|
||||
f"openai constraint '{openai_dep}' does not allow version 1.83.0 "
|
||||
"which breaks backward compatibility"
|
||||
)
|
||||
|
||||
# Test that the specifier has an upper bound (to prevent future breaks)
|
||||
assert "<3" in version_spec or "<3.0" in version_spec, (
|
||||
f"openai constraint '{openai_dep}' should have an upper bound <3 "
|
||||
"to prevent future breaking changes"
|
||||
)
|
||||
|
||||
|
||||
def test_openai_provider_imports_are_valid():
|
||||
"""Test that all imports used by the OpenAI provider are valid.
|
||||
|
||||
This test verifies that the OpenAI SDK exports all the classes and types
|
||||
that crewAI's OpenAI provider depends on. This ensures compatibility
|
||||
across different openai SDK versions.
|
||||
"""
|
||||
# Test core client imports
|
||||
from openai import APIConnectionError, AsyncOpenAI, NotFoundError, OpenAI, Stream
|
||||
|
||||
assert OpenAI is not None
|
||||
assert AsyncOpenAI is not None
|
||||
assert Stream is not None
|
||||
assert APIConnectionError is not None
|
||||
assert NotFoundError is not None
|
||||
|
||||
# Test streaming imports
|
||||
from openai.lib.streaming.chat import ChatCompletionStream
|
||||
|
||||
assert ChatCompletionStream is not None
|
||||
|
||||
# Test type imports
|
||||
from openai.types.chat import ChatCompletion, ChatCompletionChunk
|
||||
from openai.types.chat.chat_completion import Choice
|
||||
from openai.types.chat.chat_completion_chunk import ChoiceDelta
|
||||
|
||||
assert ChatCompletion is not None
|
||||
assert ChatCompletionChunk is not None
|
||||
assert Choice is not None
|
||||
assert ChoiceDelta is not None
|
||||
|
||||
|
||||
def test_openai_client_instantiation():
|
||||
"""Test that OpenAI clients can be instantiated with a test API key.
|
||||
|
||||
This verifies that the OpenAI SDK client initialization is compatible
|
||||
with crewAI's usage patterns.
|
||||
"""
|
||||
from openai import AsyncOpenAI, OpenAI
|
||||
|
||||
# Test sync client instantiation
|
||||
client = OpenAI(api_key="test-key-for-instantiation-test")
|
||||
assert client is not None
|
||||
assert hasattr(client, "chat")
|
||||
assert hasattr(client.chat, "completions")
|
||||
|
||||
# Test async client instantiation
|
||||
async_client = AsyncOpenAI(api_key="test-key-for-instantiation-test")
|
||||
assert async_client is not None
|
||||
assert hasattr(async_client, "chat")
|
||||
assert hasattr(async_client.chat, "completions")
|
||||
|
||||
|
||||
def test_openai_completion_provider_can_be_imported():
|
||||
"""Test that crewAI's OpenAI completion provider can be imported.
|
||||
|
||||
This verifies that the OpenAI provider module loads correctly with
|
||||
the installed openai SDK version.
|
||||
"""
|
||||
from crewai.llms.providers.openai.completion import OpenAICompletion
|
||||
|
||||
assert OpenAICompletion is not None
|
||||
|
||||
|
||||
def test_openai_completion_provider_instantiation():
|
||||
"""Test that OpenAICompletion can be instantiated.
|
||||
|
||||
This verifies that crewAI's OpenAI provider works correctly with
|
||||
the installed openai SDK version.
|
||||
"""
|
||||
from crewai.llms.providers.openai.completion import OpenAICompletion
|
||||
|
||||
# Instantiate with a test API key
|
||||
completion = OpenAICompletion(
|
||||
model="gpt-4o",
|
||||
api_key="test-key-for-instantiation-test",
|
||||
)
|
||||
|
||||
assert completion is not None
|
||||
assert completion.model == "gpt-4o"
|
||||
assert completion.client is not None
|
||||
assert completion.async_client is not None
|
||||
272
lib/crewai/tests/utilities/test_agent_utils.py
Normal file
272
lib/crewai/tests/utilities/test_agent_utils.py
Normal file
@@ -0,0 +1,272 @@
|
||||
"""Tests for agent_utils module.
|
||||
|
||||
These tests cover the format_answer() and handle_max_iterations_exceeded() functions,
|
||||
specifically testing the fix for issue #4113 where OutputParserError was being
|
||||
swallowed instead of being re-raised for retry logic.
|
||||
"""
|
||||
|
||||
from unittest.mock import MagicMock, patch
|
||||
|
||||
import pytest
|
||||
|
||||
from crewai.agents.parser import (
|
||||
AgentAction,
|
||||
AgentFinish,
|
||||
OutputParserError,
|
||||
)
|
||||
from crewai.utilities.agent_utils import (
|
||||
format_answer,
|
||||
handle_max_iterations_exceeded,
|
||||
process_llm_response,
|
||||
)
|
||||
|
||||
|
||||
class TestFormatAnswer:
|
||||
"""Tests for the format_answer function."""
|
||||
|
||||
def test_format_answer_with_valid_action(self) -> None:
|
||||
"""Test that format_answer correctly parses a valid action."""
|
||||
answer = "Thought: Let's search\nAction: search\nAction Input: query"
|
||||
result = format_answer(answer)
|
||||
assert isinstance(result, AgentAction)
|
||||
assert result.tool == "search"
|
||||
assert result.tool_input == "query"
|
||||
|
||||
def test_format_answer_with_valid_final_answer(self) -> None:
|
||||
"""Test that format_answer correctly parses a valid final answer."""
|
||||
answer = "Thought: I found the answer\nFinal Answer: The result is 42"
|
||||
result = format_answer(answer)
|
||||
assert isinstance(result, AgentFinish)
|
||||
assert result.output == "The result is 42"
|
||||
|
||||
def test_format_answer_raises_output_parser_error_for_malformed_output(
|
||||
self,
|
||||
) -> None:
|
||||
"""Test that format_answer re-raises OutputParserError for malformed output.
|
||||
|
||||
This is the core fix for issue #4113. Previously, format_answer would catch
|
||||
all exceptions and return AgentFinish, which broke the retry logic.
|
||||
"""
|
||||
malformed_answer = """Thought
|
||||
The user wants to verify something.
|
||||
Action
|
||||
Video Analysis Tool
|
||||
Action Input:
|
||||
{"query": "Is there something?"}"""
|
||||
|
||||
with pytest.raises(OutputParserError):
|
||||
format_answer(malformed_answer)
|
||||
|
||||
def test_format_answer_raises_output_parser_error_missing_action(self) -> None:
|
||||
"""Test that format_answer re-raises OutputParserError when Action is missing."""
|
||||
answer = "Thought: Let's search\nAction Input: query"
|
||||
with pytest.raises(OutputParserError) as exc_info:
|
||||
format_answer(answer)
|
||||
assert "Action:" in str(exc_info.value)
|
||||
|
||||
def test_format_answer_raises_output_parser_error_missing_action_input(
|
||||
self,
|
||||
) -> None:
|
||||
"""Test that format_answer re-raises OutputParserError when Action Input is missing."""
|
||||
answer = "Thought: Let's search\nAction: search"
|
||||
with pytest.raises(OutputParserError) as exc_info:
|
||||
format_answer(answer)
|
||||
assert "Action Input:" in str(exc_info.value)
|
||||
|
||||
def test_format_answer_returns_agent_finish_for_generic_exception(self) -> None:
|
||||
"""Test that format_answer returns AgentFinish for non-OutputParserError exceptions."""
|
||||
with patch(
|
||||
"crewai.utilities.agent_utils.parse",
|
||||
side_effect=ValueError("Unexpected error"),
|
||||
):
|
||||
result = format_answer("some answer")
|
||||
assert isinstance(result, AgentFinish)
|
||||
assert result.thought == "Failed to parse LLM response"
|
||||
assert result.output == "some answer"
|
||||
|
||||
|
||||
class TestProcessLlmResponse:
|
||||
"""Tests for the process_llm_response function."""
|
||||
|
||||
def test_process_llm_response_raises_output_parser_error(self) -> None:
|
||||
"""Test that process_llm_response propagates OutputParserError."""
|
||||
malformed_answer = "Thought\nMissing colons\nAction\nSome Tool"
|
||||
with pytest.raises(OutputParserError):
|
||||
process_llm_response(malformed_answer, use_stop_words=True)
|
||||
|
||||
def test_process_llm_response_with_valid_action(self) -> None:
|
||||
"""Test that process_llm_response correctly processes a valid action."""
|
||||
answer = "Thought: Let's search\nAction: search\nAction Input: query"
|
||||
result = process_llm_response(answer, use_stop_words=True)
|
||||
assert isinstance(result, AgentAction)
|
||||
assert result.tool == "search"
|
||||
|
||||
def test_process_llm_response_with_valid_final_answer(self) -> None:
|
||||
"""Test that process_llm_response correctly processes a valid final answer."""
|
||||
answer = "Thought: Done\nFinal Answer: The result"
|
||||
result = process_llm_response(answer, use_stop_words=True)
|
||||
assert isinstance(result, AgentFinish)
|
||||
assert result.output == "The result"
|
||||
|
||||
|
||||
class TestHandleMaxIterationsExceeded:
|
||||
"""Tests for the handle_max_iterations_exceeded function."""
|
||||
|
||||
def test_handle_max_iterations_exceeded_with_valid_final_answer(self) -> None:
|
||||
"""Test that handle_max_iterations_exceeded returns AgentFinish for valid output."""
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.call.return_value = "Thought: Done\nFinal Answer: The final result"
|
||||
mock_printer = MagicMock()
|
||||
mock_i18n = MagicMock()
|
||||
mock_i18n.errors.return_value = "Please provide final answer"
|
||||
|
||||
result = handle_max_iterations_exceeded(
|
||||
formatted_answer=None,
|
||||
printer=mock_printer,
|
||||
i18n=mock_i18n,
|
||||
messages=[],
|
||||
llm=mock_llm,
|
||||
callbacks=[],
|
||||
)
|
||||
|
||||
assert isinstance(result, AgentFinish)
|
||||
assert result.output == "The final result"
|
||||
|
||||
def test_handle_max_iterations_exceeded_with_valid_action_converts_to_finish(
|
||||
self,
|
||||
) -> None:
|
||||
"""Test that handle_max_iterations_exceeded converts AgentAction to AgentFinish."""
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.call.return_value = (
|
||||
"Thought: Using tool\nAction: search\nAction Input: query"
|
||||
)
|
||||
mock_printer = MagicMock()
|
||||
mock_i18n = MagicMock()
|
||||
mock_i18n.errors.return_value = "Please provide final answer"
|
||||
|
||||
result = handle_max_iterations_exceeded(
|
||||
formatted_answer=None,
|
||||
printer=mock_printer,
|
||||
i18n=mock_i18n,
|
||||
messages=[],
|
||||
llm=mock_llm,
|
||||
callbacks=[],
|
||||
)
|
||||
|
||||
assert isinstance(result, AgentFinish)
|
||||
|
||||
def test_handle_max_iterations_exceeded_catches_output_parser_error(self) -> None:
|
||||
"""Test that handle_max_iterations_exceeded catches OutputParserError and returns AgentFinish.
|
||||
|
||||
This prevents infinite loops when the forced final answer is malformed.
|
||||
Without this safeguard, the OutputParserError would bubble up to _invoke_loop(),
|
||||
which would retry, hit max iterations again, and loop forever.
|
||||
"""
|
||||
malformed_response = """Thought
|
||||
Missing colons everywhere
|
||||
Action
|
||||
Some Tool
|
||||
Action Input:
|
||||
{"query": "test"}"""
|
||||
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.call.return_value = malformed_response
|
||||
mock_printer = MagicMock()
|
||||
mock_i18n = MagicMock()
|
||||
mock_i18n.errors.return_value = "Please provide final answer"
|
||||
|
||||
result = handle_max_iterations_exceeded(
|
||||
formatted_answer=None,
|
||||
printer=mock_printer,
|
||||
i18n=mock_i18n,
|
||||
messages=[],
|
||||
llm=mock_llm,
|
||||
callbacks=[],
|
||||
)
|
||||
|
||||
assert isinstance(result, AgentFinish)
|
||||
assert result.output == malformed_response
|
||||
assert "Failed to parse LLM response during max iterations" in result.thought
|
||||
mock_printer.print.assert_any_call(
|
||||
content="Failed to parse forced final answer. Returning raw response.",
|
||||
color="yellow",
|
||||
)
|
||||
|
||||
def test_handle_max_iterations_exceeded_with_previous_formatted_answer(
|
||||
self,
|
||||
) -> None:
|
||||
"""Test that handle_max_iterations_exceeded uses previous answer text."""
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.call.return_value = "Thought: Done\nFinal Answer: New result"
|
||||
mock_printer = MagicMock()
|
||||
mock_i18n = MagicMock()
|
||||
mock_i18n.errors.return_value = "Please provide final answer"
|
||||
|
||||
previous_answer = AgentAction(
|
||||
thought="Previous thought",
|
||||
tool="search",
|
||||
tool_input="query",
|
||||
text="Previous text",
|
||||
)
|
||||
|
||||
result = handle_max_iterations_exceeded(
|
||||
formatted_answer=previous_answer,
|
||||
printer=mock_printer,
|
||||
i18n=mock_i18n,
|
||||
messages=[],
|
||||
llm=mock_llm,
|
||||
callbacks=[],
|
||||
)
|
||||
|
||||
assert isinstance(result, AgentFinish)
|
||||
assert result.output == "New result"
|
||||
|
||||
def test_handle_max_iterations_exceeded_raises_on_empty_response(self) -> None:
|
||||
"""Test that handle_max_iterations_exceeded raises ValueError for empty response."""
|
||||
mock_llm = MagicMock()
|
||||
mock_llm.call.return_value = ""
|
||||
mock_printer = MagicMock()
|
||||
mock_i18n = MagicMock()
|
||||
mock_i18n.errors.return_value = "Please provide final answer"
|
||||
|
||||
with pytest.raises(ValueError, match="Invalid response from LLM call"):
|
||||
handle_max_iterations_exceeded(
|
||||
formatted_answer=None,
|
||||
printer=mock_printer,
|
||||
i18n=mock_i18n,
|
||||
messages=[],
|
||||
llm=mock_llm,
|
||||
callbacks=[],
|
||||
)
|
||||
|
||||
|
||||
class TestRetryLogicIntegration:
|
||||
"""Integration tests to verify the retry logic works correctly with the fix."""
|
||||
|
||||
def test_malformed_output_allows_retry_in_format_answer(self) -> None:
|
||||
"""Test that malformed output raises OutputParserError which can be caught for retry.
|
||||
|
||||
This simulates what happens in _invoke_loop() when the LLM returns malformed output.
|
||||
The OutputParserError should be raised so the loop can catch it and retry.
|
||||
"""
|
||||
malformed_outputs = [
|
||||
"Thought\nMissing colon after Thought",
|
||||
"Thought: OK\nAction\nMissing colon after Action",
|
||||
"Thought: OK\nAction: tool\nAction Input\nMissing colon",
|
||||
"Random text without any structure",
|
||||
]
|
||||
|
||||
for malformed in malformed_outputs:
|
||||
with pytest.raises(OutputParserError):
|
||||
format_answer(malformed)
|
||||
|
||||
def test_valid_output_does_not_raise(self) -> None:
|
||||
"""Test that valid outputs are parsed correctly without raising."""
|
||||
valid_outputs = [
|
||||
("Thought: Let's search\nAction: search\nAction Input: query", AgentAction),
|
||||
("Thought: Done\nFinal Answer: The result", AgentFinish),
|
||||
]
|
||||
|
||||
for output, expected_type in valid_outputs:
|
||||
result = format_answer(output)
|
||||
assert isinstance(result, expected_type)
|
||||
@@ -1,3 +1,3 @@
|
||||
"""CrewAI development tools."""
|
||||
|
||||
__version__ = "1.7.0"
|
||||
__version__ = "1.7.1"
|
||||
|
||||
@@ -323,13 +323,17 @@ def cli() -> None:
|
||||
"--dry-run", is_flag=True, help="Show what would be done without making changes"
|
||||
)
|
||||
@click.option("--no-push", is_flag=True, help="Don't push changes to remote")
|
||||
def bump(version: str, dry_run: bool, no_push: bool) -> None:
|
||||
@click.option(
|
||||
"--no-commit", is_flag=True, help="Don't commit changes (just update files)"
|
||||
)
|
||||
def bump(version: str, dry_run: bool, no_push: bool, no_commit: bool) -> None:
|
||||
"""Bump version across all packages in lib/.
|
||||
|
||||
Args:
|
||||
version: New version to set (e.g., 1.0.0, 1.0.0a1).
|
||||
dry_run: Show what would be done without making changes.
|
||||
no_push: Don't push changes to remote.
|
||||
no_commit: Don't commit changes (just update files).
|
||||
"""
|
||||
try:
|
||||
# Check prerequisites
|
||||
@@ -397,51 +401,60 @@ def bump(version: str, dry_run: bool, no_push: bool) -> None:
|
||||
else:
|
||||
console.print("[dim][DRY RUN][/dim] Would run: uv sync")
|
||||
|
||||
branch_name = f"feat/bump-version-{version}"
|
||||
if not dry_run:
|
||||
console.print(f"\nCreating branch {branch_name}...")
|
||||
run_command(["git", "checkout", "-b", branch_name])
|
||||
console.print("[green]✓[/green] Branch created")
|
||||
|
||||
console.print("\nCommitting changes...")
|
||||
run_command(["git", "add", "."])
|
||||
run_command(["git", "commit", "-m", f"feat: bump versions to {version}"])
|
||||
console.print("[green]✓[/green] Changes committed")
|
||||
|
||||
if not no_push:
|
||||
console.print("\nPushing branch...")
|
||||
run_command(["git", "push", "-u", "origin", branch_name])
|
||||
console.print("[green]✓[/green] Branch pushed")
|
||||
if no_commit:
|
||||
console.print("\nSkipping git operations (--no-commit flag set)")
|
||||
else:
|
||||
console.print(f"[dim][DRY RUN][/dim] Would create branch: {branch_name}")
|
||||
console.print(
|
||||
f"[dim][DRY RUN][/dim] Would commit: feat: bump versions to {version}"
|
||||
)
|
||||
if not no_push:
|
||||
console.print(f"[dim][DRY RUN][/dim] Would push branch: {branch_name}")
|
||||
branch_name = f"feat/bump-version-{version}"
|
||||
if not dry_run:
|
||||
console.print(f"\nCreating branch {branch_name}...")
|
||||
run_command(["git", "checkout", "-b", branch_name])
|
||||
console.print("[green]✓[/green] Branch created")
|
||||
|
||||
if not dry_run and not no_push:
|
||||
console.print("\nCreating pull request...")
|
||||
run_command(
|
||||
[
|
||||
"gh",
|
||||
"pr",
|
||||
"create",
|
||||
"--base",
|
||||
"main",
|
||||
"--title",
|
||||
f"feat: bump versions to {version}",
|
||||
"--body",
|
||||
"",
|
||||
]
|
||||
)
|
||||
console.print("[green]✓[/green] Pull request created")
|
||||
elif dry_run:
|
||||
console.print(
|
||||
f"[dim][DRY RUN][/dim] Would create PR: feat: bump versions to {version}"
|
||||
)
|
||||
else:
|
||||
console.print("\nSkipping PR creation (--no-push flag set)")
|
||||
console.print("\nCommitting changes...")
|
||||
run_command(["git", "add", "."])
|
||||
run_command(
|
||||
["git", "commit", "-m", f"feat: bump versions to {version}"]
|
||||
)
|
||||
console.print("[green]✓[/green] Changes committed")
|
||||
|
||||
if not no_push:
|
||||
console.print("\nPushing branch...")
|
||||
run_command(["git", "push", "-u", "origin", branch_name])
|
||||
console.print("[green]✓[/green] Branch pushed")
|
||||
else:
|
||||
console.print(
|
||||
f"[dim][DRY RUN][/dim] Would create branch: {branch_name}"
|
||||
)
|
||||
console.print(
|
||||
f"[dim][DRY RUN][/dim] Would commit: feat: bump versions to {version}"
|
||||
)
|
||||
if not no_push:
|
||||
console.print(
|
||||
f"[dim][DRY RUN][/dim] Would push branch: {branch_name}"
|
||||
)
|
||||
|
||||
if not dry_run and not no_push:
|
||||
console.print("\nCreating pull request...")
|
||||
run_command(
|
||||
[
|
||||
"gh",
|
||||
"pr",
|
||||
"create",
|
||||
"--base",
|
||||
"main",
|
||||
"--title",
|
||||
f"feat: bump versions to {version}",
|
||||
"--body",
|
||||
"",
|
||||
]
|
||||
)
|
||||
console.print("[green]✓[/green] Pull request created")
|
||||
elif dry_run:
|
||||
console.print(
|
||||
f"[dim][DRY RUN][/dim] Would create PR: feat: bump versions to {version}"
|
||||
)
|
||||
else:
|
||||
console.print("\nSkipping PR creation (--no-push flag set)")
|
||||
|
||||
console.print(f"\n[green]✓[/green] Version bump to {version} complete!")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user