Changeset 0.29.3 (#198)

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit is contained in:
2026-03-18 00:15:18 +00:00
committed by xcaliber
parent 115004a3ab
commit 7f191e18cd
22 changed files with 1625 additions and 77 deletions

View File

@@ -104,8 +104,17 @@ Cascades: deletes all stages, versions, and active instances.
## Stages
Ordered steps within a workflow. Each stage has a driving persona and
optional human assignment team.
Ordered steps within a workflow. Each stage has a driving persona,
optional human assignment team, and a **stage mode** that controls
how data is collected.
### Stage Modes (v0.29.3)
| Mode | Description |
|------|-------------|
| `chat_only` | Default. Persona drives the conversation. |
| `form_only` | UI-rendered form, no LLM. Visitor fills out fields. |
| `form_chat` | Both form and chat available. Persona assists alongside the form. |
### List Stages
@@ -129,25 +138,64 @@ POST /workflows/:id/stages
"ordinal": 0,
"persona_id": "uuid|null",
"assignment_team_id": "uuid|null",
"form_template": { "fields": ["name", "email", "issue"] },
"stage_mode": "chat_only|form_only|form_chat",
"form_template": { "fields": [...] },
"history_mode": "full|summary|fresh",
"auto_transition": false,
"transition_rules": { "auto_assign": "round_robin" }
}
```
`stage_mode`: controls data collection method. Default: `chat_only`.
`form_only` and `form_chat` require a typed `form_template` with fields.
`history_mode`: what chat history the next stage sees. `full` = complete,
`summary` = utility-role summary, `fresh` = clean slate.
`form_template`: injected into the completion system prompt as guidance
for what the persona should collect. Not rendered as UI — the LLM is
told what to ask for.
`form_template`: when `stage_mode` is `form_only` or `form_chat`, the
template uses a typed schema (see below). For `chat_only` stages, legacy
freeform templates are still supported as guidance for the LLM.
`transition_rules.auto_assign`: `round_robin` assigns to team members
in rotation. Null = unassigned (manual claim).
**Auth:** `workflow.create` permission required.
### Typed Form Template (v0.29.3)
```json
{
"fields": [
{ "key": "name", "type": "text", "label": "Full Name", "required": true, "validation": { "min_length": 2 } },
{ "key": "email", "type": "email", "label": "Email", "required": true },
{ "key": "dept", "type": "select", "label": "Department", "options": [
{ "value": "eng", "label": "Engineering" },
{ "value": "sales", "label": "Sales" }
]},
{ "key": "notes", "type": "textarea", "label": "Additional Notes" }
],
"hooks": {
"package_id": "uuid",
"validate": "on_validate",
"on_submit": "on_form_submit"
}
}
```
**Field types:** `text`, `email`, `number`, `date`, `textarea`, `select`, `checkbox`, `file`.
**Validation rules** (in `validation` object per field):
- `min_length`, `max_length` — string length bounds
- `pattern` — regex pattern for text/email fields
- `min`, `max` — numeric bounds for number fields
- `min_date`, `max_date` — date range bounds (YYYY-MM-DD format)
**Hooks:** optional Starlark hooks via extension packages.
- `validate`: called before form submission is accepted; can return field errors
- `on_submit`: fire-and-forget hook after successful submission
Requires `forms.validate` extension permission.
### Update Stage
```
@@ -188,6 +236,7 @@ Sets ordinals based on array position.
"workflow_id": "uuid",
"ordinal": 0,
"name": "Collect Info",
"stage_mode": "chat_only",
"persona_id": "uuid|null",
"assignment_team_id": "uuid|null",
"form_template": {},
@@ -432,6 +481,64 @@ POST /api/v1/w/:id/completions
These use `AuthOrSession` middleware — the session cookie identifies
the visitor without requiring a JWT.
## Form Submission (v0.29.3)
For stages with `stage_mode` of `form_only` or `form_chat`, visitors
submit structured form data through dedicated endpoints.
### Get Form Template
```
GET /api/v1/w/:id/form
```
Returns the current stage's typed form template and submission status.
```json
{
"stage_mode": "form_only",
"stage_name": "Contact Info",
"form_template": { "fields": [...] },
"submitted": false
}
```
**Auth:** `AuthOrSession` (JWT or session cookie).
### Submit Form
```
POST /api/v1/w/:id/form-submit
```
```json
{
"name": "Jane Doe",
"email": "jane@example.com",
"dept": "eng"
}
```
Validates data against the typed form template. Returns field-level
errors on validation failure:
```json
{
"error": "validation failed",
"errors": [
{ "key": "email", "message": "invalid email format" },
{ "key": "name", "message": "required field missing" }
]
}
```
On success, merges data into `stage_data`. For `form_only` stages with
`auto_transition=true`, auto-advances to the next stage.
Emits `workflow.form_submitted` WebSocket event on success.
**Auth:** `AuthOrSession` (JWT or session cookie).
## Staleness Sweep
Background goroutine. Checks active workflow instances for staleness
@@ -470,3 +577,4 @@ before chaining.
| `workflow.completed` | Workflow finished |
| `workflow.assigned` | New assignment created |
| `workflow.claimed` | Assignment claimed by user |
| `workflow.form_submitted` | Form data submitted for a form stage |