From 855de03e2931d914e6c66d0b69831482df36d884 Mon Sep 17 00:00:00 2001 From: izak-fisher Date: Thu, 19 Mar 2026 15:49:08 +0200 Subject: [PATCH 1/2] feat(ai): upgrade to OpenAI Responses API and enhance template generation - Migrate from legacy Chat Completions API (openai SDK v0.27) to Responses API via direct HTTP calls - Add new model choices: gpt-4.1, gpt-4.1-mini, gpt-4.1-nano, gpt-5, gpt-5-mini, o3, o4-mini - Change default model from gpt-4o to gpt-4.1-mini - Enhance system prompt to generate templates with kickoff fields, output fields, and variable references - Preserve AI-provided api_name on fields so {{field-name}} references resolve correctly - Make OPENAI_API_ORG optional (only OPENAI_API_KEY required) - Replace single-line input with multi-line textarea in template generator UI - Add documentation: AI_GENERATION.md, SYSTEM_PROMPT.md, CHANGES.md, RUN_BRANCH.md - Update tests for new Responses API integration Co-Authored-By: Claude Opus 4.6 (1M context) --- .gitignore | 1 + AI_GENERATION.md | 117 ++++ CHANGES.md | 100 +++ CLAUDE.md | 62 ++ RUN_BRANCH.md | 102 +++ SYSTEM_PROMPT.md | 75 +++ backend/CLAUDE.md | 99 +++ backend/src/ai/enums.py | 31 +- ...4_add_model_choices_and_template_target.py | 40 ++ .../migrations/0005_update_model_choices.py | 35 + backend/src/ai/querysets.py | 3 + .../src/processes/services/templates/ai.py | 601 +++++++++++++++--- .../test_ai/test_anon_open_ai_service.py | 147 ++++- .../test_ai/test_open_ai_service.py | 563 ++-------------- docker-compose.yml | 6 + frontend/CLAUDE.md | 95 +++ .../TemplateAIModal/TemplateAIModal.css | 33 +- .../TemplateAIModal/TemplateAIModal.tsx | 17 +- start.sh | 0 19 files changed, 1487 insertions(+), 640 deletions(-) create mode 100644 AI_GENERATION.md create mode 100644 CHANGES.md create mode 100644 CLAUDE.md create mode 100644 RUN_BRANCH.md create mode 100644 SYSTEM_PROMPT.md create mode 100644 backend/CLAUDE.md create mode 100644 backend/src/ai/migrations/0004_add_model_choices_and_template_target.py create mode 100644 backend/src/ai/migrations/0005_update_model_choices.py create mode 100644 frontend/CLAUDE.md mode change 100644 => 100755 start.sh diff --git a/.gitignore b/.gitignore index 9055f035f..af8176a97 100644 --- a/.gitignore +++ b/.gitignore @@ -12,4 +12,5 @@ firebase-push.json .cursor/ .agent/ .antigravity/ +CLAUDE.md diff --git a/AI_GENERATION.md b/AI_GENERATION.md new file mode 100644 index 000000000..380ebdc1a --- /dev/null +++ b/AI_GENERATION.md @@ -0,0 +1,117 @@ +# AI Template Generation + +Pneumatic can generate workflow templates from natural language descriptions using OpenAI. This document explains how it works and how to customize it. + +## How it works + +1. A user enters a business process description in the template editor +2. The backend sends the description to the OpenAI Responses API along with a system prompt (instructions) +3. OpenAI returns a JSON template with tasks, kickoff fields, and output fields +4. The template is parsed and loaded into the editor for the user to review and adjust + +## Requirements + +In your `.env` file: + +```env +AI=yes +OPENAI_API_KEY=sk-your-key-here +``` + +`OPENAI_API_ORG` is optional. If omitted, OpenAI will use the default organization for your API key. + +## Defaults (no configuration needed) + +Out of the box, the system uses: + +- **Model**: `gpt-4.1-mini` +- **System prompt**: A hardcoded instruction that tells the AI to generate workflow template JSON with kickoff fields, task output fields, and variable references + +The default system prompt is defined in `backend/src/processes/services/templates/ai.py` as `DEFAULT_TEMPLATE_INSTRUCTION`. It instructs the AI to: + +- Return valid JSON matching the Pneumatic template structure +- Include kickoff fields (information needed to start the workflow) +- Include task output fields (information produced during each task) +- Use `api_name` identifiers on fields (e.g., `field-project-name`) +- Reference field values in task descriptions using `{{field-project-name}}` syntax +- Support field types: string, text, radio, checkbox, date, url, dropdown, file, user, number + +These defaults are used when no custom prompt is configured in Django Admin. + +## Customizing via Django Admin + +You can override the default model and system prompt by creating a prompt configuration in the Django Admin panel. + +### Step 1: Access the admin panel + +Go to http://localhost:8001/admin/ai/openaiprompt/ and log in. + +### Step 2: Create a new prompt + +Click "Add OpenAI Prompt" and configure: + +| Field | Description | +|-------|-------------| +| **Is active** | Must be checked. Only one active prompt per target is allowed | +| **Target** | Select **"Get full template (JSON)"** | +| **Model** | Choose from the dropdown (see available models below) | +| **Temperature** | Controls randomness (0 = deterministic, 2 = creative). Default: 1 | +| **Top p** | Nucleus sampling (0-2). Alternative to temperature. Default: 1 | +| **Presence penalty** | Encourages new topics (-2 to 2). Default: 0 | +| **Frequency penalty** | Discourages repetition (-2 to 2). Default: 0 | + +### Step 3: Add messages + +Add messages (inline at the bottom of the form) to define the conversation sent to OpenAI: + +| Order | Role | Content | +|-------|------|---------| +| 1 | **system** | Your custom system prompt (instructions for the AI) | +| 2 | **user** | `{{ user_description }}` | + +The `{{ user_description }}` placeholder is replaced with the actual text the user enters in the template generator. + +**Example system message:** + +``` +You are a workflow template designer for a marketing agency. +Generate templates with detailed task descriptions and relevant fields. +Always include a review/approval step. +Return ONLY valid JSON matching the Pneumatic template structure. +``` + +### Priority + +- If an **active** prompt with target "Get full template (JSON)" exists in the database, its messages and model are used +- If no such prompt exists, the hardcoded `DEFAULT_TEMPLATE_INSTRUCTION` and `gpt-4.1-mini` are used + +## Available models + +| Model | Best for | +|-------|----------| +| **gpt-4.1-mini** (recommended) | Best balance of quality, speed, and cost for structured JSON generation | +| gpt-4.1 | Higher quality, slower, more expensive | +| gpt-4.1-nano | Cheapest and fastest, good for simple templates | +| gpt-5 | Latest flagship model | +| gpt-5-mini | Latest smaller model | +| o3 | Advanced reasoning (for complex multi-step processes) | +| o4-mini | Fast reasoning model | +| gpt-4o | Previous generation, still capable | +| gpt-4o-mini | Previous generation, smaller | + +## Template variables + +The AI generates fields with `api_name` identifiers that can be referenced in task descriptions: + +- A kickoff field with `api_name: "field-project-name"` can be referenced in any task description as `{{field-project-name}}` +- A task output field can be referenced in subsequent task descriptions using the same syntax +- This allows data to flow through the workflow from kickoff to completion + +## Architecture + +The AI service code lives in: + +- `backend/src/processes/services/templates/ai.py` — Main service (API calls, JSON parsing, template construction) +- `backend/src/ai/models.py` — Django models for prompt configuration +- `backend/src/ai/enums.py` — Available models and prompt targets +- `frontend/src/public/components/TemplateAIModal/` — Frontend UI component diff --git a/CHANGES.md b/CHANGES.md new file mode 100644 index 000000000..32789fc7c --- /dev/null +++ b/CHANGES.md @@ -0,0 +1,100 @@ +# Changes in this branch + +## Backend + +### OpenAI API migration: Chat Completions → Responses API + +**File**: `backend/src/processes/services/templates/ai.py` + +- Replaced the legacy `openai.ChatCompletion.create()` calls (openai SDK v0.27) with direct HTTP calls to the OpenAI Responses API (`https://api.openai.com/v1/responses`) +- The Responses API uses `instructions` (system prompt) + `input` (user message) instead of a `messages` array +- Used the `requests` library (already a dependency) for HTTP calls instead of upgrading the `openai` package, which would require Python 3.8+ (the container runs Python 3.7) +- Removed the `import openai` dependency from the service module entirely +- Updated error handling: replaced `openai.error.OpenAIError` references with generic `Exception` handling and simplified Sentry logging payloads +- Added `_call_responses_api()` method to `BaseAiService` that handles the HTTP call and response parsing +- Added `_openai_headers()` helper for auth header construction +- Removed the requirement for `OPENAI_API_ORG` — only `OPENAI_API_KEY` is now needed (org is optional) + +### Updated model list + +**File**: `backend/src/ai/enums.py` + +Added new models to `OpenAiModel`: +- `gpt-4.1`, `gpt-4.1-mini`, `gpt-4.1-nano` +- `gpt-5`, `gpt-5-mini` +- `o3`, `o4-mini` + +The dropdown in Django Admin now shows these models with `gpt-4.1-mini` listed first as recommended. All legacy models (gpt-3.5-turbo, gpt-4, gpt-4o, etc.) are still available. + +**Migration**: `backend/src/ai/migrations/0005_update_model_choices.py` + +### Default model changed + +**File**: `backend/src/processes/services/templates/ai.py` + +- Changed from `gpt-4o` to `gpt-4.1-mini` as the default model when no prompt is configured in Django Admin + +### Enhanced system prompt for template generation + +**File**: `backend/src/processes/services/templates/ai.py` + +The `DEFAULT_TEMPLATE_INSTRUCTION` was rewritten to produce richer templates: +- Fields now include `api_name` (e.g., `field-project-name`) that the AI specifies directly +- Task descriptions can reference kickoff and previous task field values using `{{field-project-name}}` syntax +- The `_normalize_field()` method now preserves the AI-provided `api_name` instead of always generating a random one, so variable references in task descriptions actually resolve correctly + +### Test response updated + +**File**: `backend/src/processes/services/templates/ai.py` + +- The `_test_response()` (honey harvesting template used when no API key is set) now includes `api_name` on all fields to match the new format + +### Tests updated + +**File**: `backend/src/processes/tests/test_services/test_templates/test_ai/test_open_ai_service.py` + +- Rewrote tests to mock `_call_responses_api` instead of `openai.ChatCompletion.create` +- Removed `import openai.error` dependency +- Added tests for the Responses API integration + +## Frontend + +### Multi-line prompt input + +**Files**: +- `frontend/src/public/components/TemplateAIModal/TemplateAIModal.tsx` +- `frontend/src/public/components/TemplateAIModal/TemplateAIModal.css` + +- Replaced the single-line `` with a `