Update DESIGN.md, TECHNICAL.md, and TODO.md for P4 Delivery Implementation
- Revised DESIGN.md to clarify the architecture of the P4 delivery process, emphasizing the separation of content generation and channel decision-making. - Expanded TECHNICAL.md with detailed notes on the DeliveryRequest structure, DeliveryContent generation, and the role of the Delivery Center in managing delivery channels. - Updated TODO.md to reflect the completion of the Delivery Agent setup and the integration of delivery preferences, ensuring comprehensive tracking of the P4 implementation progress. - Enhanced documentation to outline the new delivery channels and their configurations, including email and webhook options, for improved clarity and usability.
This commit is contained in:
parent
603ed69a9e
commit
9e14d8b7af
3 changed files with 844 additions and 82 deletions
|
|
@ -262,7 +262,7 @@ Human/Event: P1 → P2 → P3 → P4 → P5
|
|||
| P1 | Goal Gen | Report + history | Goals | Always |
|
||||
| P2 | Task Plan | Goals + tools | Tasks | Always |
|
||||
| P3 | Run + Valid | Tasks + Experts | TaskResults | Always |
|
||||
| P4 | Delivery | All results | Email/File | Always |
|
||||
| P4 | Delivery | All results | Email/Webhook | Always |
|
||||
| P5 | Learning | Summary | KB entries | Always |
|
||||
|
||||
### 4.2 P0: Inspiration (Clock only)
|
||||
|
|
@ -316,7 +316,7 @@ type Goals struct {
|
|||
}
|
||||
|
||||
type DeliveryTarget struct {
|
||||
Type DeliveryType // email | webhook | report | notification
|
||||
Type DeliveryType // Preferred delivery type (P4 will use Delivery Center)
|
||||
Recipients []string // email addresses, webhook URLs, user IDs
|
||||
Format string // markdown | html | json | text
|
||||
Template string // template name
|
||||
|
|
@ -489,13 +489,169 @@ Universal assertion library supporting 8 types:
|
|||
|
||||
### 4.6 P4: Deliver
|
||||
|
||||
Send output:
|
||||
P4 generates delivery content and pushes to Delivery Center. **Agent only generates content, Delivery Center decides channels.**
|
||||
|
||||
**Architecture:**
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ P4 Delivery Agent │
|
||||
│ Role: Generate content only (Summary, Body, Attachments) │
|
||||
│ NOT responsible for: Channel selection │
|
||||
└─────────────────────┬───────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ DeliveryRequest │
|
||||
│ - Content: Summary, Body, Attachments │
|
||||
│ - Context: robot_id, exec_id, trigger_type, team_id │
|
||||
│ (No Channels - Delivery Center decides) │
|
||||
└─────────────────────┬───────────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ Delivery Center │
|
||||
│ Role: │
|
||||
│ 1. Read Robot/User delivery preferences │
|
||||
│ 2. Decide which channels to use │
|
||||
│ 3. Execute delivery (email, webhook) │
|
||||
│ 4. Future: auto-notify based on user subscriptions │
|
||||
│ │
|
||||
│ (Current: internal, future: yao/delivery) │
|
||||
└─────────────────────────────────────────────────────────────┘
|
||||
```
|
||||
|
||||
**Key Design:**
|
||||
- **Separation of concerns**: Agent generates content, Delivery Center handles channels
|
||||
- **User preferences**: Channels decided by Robot/User configuration, not Agent
|
||||
- **Automatic delivery**: If webhook configured, every execution pushes automatically
|
||||
- **Future-ready**: Delivery Center can be extracted to `yao/delivery` package
|
||||
|
||||
**Delivery Request Structure:**
|
||||
|
||||
```go
|
||||
// DeliveryRequest - pushed to Delivery Center
|
||||
// No Channels field - Delivery Center decides based on preferences
|
||||
type DeliveryRequest struct {
|
||||
Content *DeliveryContent `json:"content"` // Agent-generated content
|
||||
Context *DeliveryContext `json:"context"` // Tracking info
|
||||
}
|
||||
|
||||
// DeliveryContent - content generated by Delivery Agent
|
||||
type DeliveryContent struct {
|
||||
Summary string `json:"summary"` // Brief 1-2 sentence summary
|
||||
Body string `json:"body"` // Full markdown report
|
||||
Attachments []DeliveryAttachment `json:"attachments,omitempty"` // Output artifacts
|
||||
}
|
||||
|
||||
// DeliveryAttachment - task output attachment with metadata
|
||||
type DeliveryAttachment struct {
|
||||
Title string `json:"title"` // Human-readable title
|
||||
Description string `json:"description,omitempty"` // What this artifact is
|
||||
TaskID string `json:"task_id,omitempty"` // Which task produced this
|
||||
File string `json:"file"` // Wrapper: __<uploader>://<fileID>
|
||||
}
|
||||
|
||||
// DeliveryContext - tracking and audit info
|
||||
type DeliveryContext struct {
|
||||
RobotID string `json:"robot_id"`
|
||||
ExecutionID string `json:"execution_id"`
|
||||
TriggerType TriggerType `json:"trigger_type"`
|
||||
TeamID string `json:"team_id"`
|
||||
}
|
||||
```
|
||||
|
||||
**File Wrapper Format:**
|
||||
|
||||
Attachments use the standard `yao/attachment` wrapper format:
|
||||
- Format: `__<uploader>://<fileID>`
|
||||
- Example: `__yao.attachment://ccd472d11feb96e03a3fc468f494045c`
|
||||
- Parse: `attachment.Parse(value)` → `(uploader, fileID, isWrapper)`
|
||||
- Read: `attachment.Base64(ctx, value)` → base64 content
|
||||
|
||||
**Delivery Channels (Delivery Center decides):**
|
||||
|
||||
| Channel | Description | When |
|
||||
|---------|-------------|------|
|
||||
| `email` | Send via yao/messenger | If configured in preferences |
|
||||
| `webhook` | POST to URL (Slack, 飞书, etc.) | If configured, every execution |
|
||||
| `notify` | In-app push notification | Based on user subscriptions (future) |
|
||||
|
||||
**Delivery Agent:**
|
||||
|
||||
The Delivery Agent **only generates content**, does NOT decide channels:
|
||||
|
||||
```go
|
||||
// Delivery Agent Input
|
||||
type DeliveryAgentInput struct {
|
||||
Robot *Robot `json:"robot"`
|
||||
TriggerType TriggerType `json:"trigger"`
|
||||
Inspiration *InspirationReport `json:"inspiration"` // P0
|
||||
Goals *Goals `json:"goals"` // P1
|
||||
Tasks []Task `json:"tasks"` // P2
|
||||
Results []TaskResult `json:"results"` // P3
|
||||
}
|
||||
|
||||
// Delivery Agent Output - only content, no channels
|
||||
type DeliveryAgentOutput struct {
|
||||
Content *DeliveryContent `json:"content"`
|
||||
}
|
||||
```
|
||||
|
||||
**Example Agent Output:**
|
||||
|
||||
```json
|
||||
{
|
||||
"content": {
|
||||
"summary": "Sales report completed: 15 new leads processed",
|
||||
"body": "## Weekly Sales Report\n\n### Summary\n...",
|
||||
"attachments": [
|
||||
{"title": "Sales Report.pdf", "file": "__yao.attachment://abc123"},
|
||||
{"title": "Lead Analysis.xlsx", "file": "__yao.attachment://def456"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Delivery Result:**
|
||||
|
||||
```go
|
||||
// DeliveryResult - returned by Delivery Center
|
||||
type DeliveryResult struct {
|
||||
RequestID string `json:"request_id"` // Delivery request ID
|
||||
Content *DeliveryContent `json:"content"` // What was delivered
|
||||
Success bool `json:"success"` // All channels succeeded
|
||||
Results []ChannelResult `json:"results"` // Per-channel results
|
||||
Error string `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
// ChannelResult - result for a single channel
|
||||
type ChannelResult struct {
|
||||
Type DeliveryType `json:"type"`
|
||||
Success bool `json:"success"`
|
||||
Recipients []string `json:"recipients,omitempty"` // For email
|
||||
Details interface{} `json:"details,omitempty"`
|
||||
Error string `json:"error,omitempty"`
|
||||
SentAt *time.Time `json:"sent_at,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
**Config (Delivery Preferences):**
|
||||
|
||||
Robot config defines delivery **preferences** (Delivery Center reads and executes):
|
||||
|
||||
```yaml
|
||||
delivery:
|
||||
type: email # email | file | webhook | notify
|
||||
opts:
|
||||
to: ["manager@company.com"]
|
||||
preferences:
|
||||
email:
|
||||
enabled: true
|
||||
to: ["manager@company.com"]
|
||||
cc: ["team@company.com"]
|
||||
webhook:
|
||||
enabled: true
|
||||
url: "https://slack.com/webhook/reports"
|
||||
# Every execution pushes to webhook automatically
|
||||
# Note: notify handled by Delivery Center based on user subscriptions (future)
|
||||
```
|
||||
|
||||
### 4.7 P5: Learn
|
||||
|
|
@ -564,10 +720,9 @@ const (
|
|||
type DeliveryType string
|
||||
|
||||
const (
|
||||
DeliveryEmail DeliveryType = "email"
|
||||
DeliveryFile DeliveryType = "file"
|
||||
DeliveryWebhook DeliveryType = "webhook"
|
||||
DeliveryNotify DeliveryType = "notify"
|
||||
DeliveryEmail DeliveryType = "email" // Email via yao/messenger
|
||||
DeliveryWebhook DeliveryType = "webhook" // POST to URL
|
||||
DeliveryNotify DeliveryType = "notify" // In-app notification (future)
|
||||
)
|
||||
|
||||
// ExecStatus - execution status enum
|
||||
|
|
|
|||
|
|
@ -854,10 +854,9 @@ const (
|
|||
type DeliveryType string
|
||||
|
||||
const (
|
||||
DeliveryEmail DeliveryType = "email"
|
||||
DeliveryFile DeliveryType = "file"
|
||||
DeliveryWebhook DeliveryType = "webhook"
|
||||
DeliveryNotify DeliveryType = "notify"
|
||||
DeliveryEmail DeliveryType = "email" // Email via yao/messenger
|
||||
DeliveryWebhook DeliveryType = "webhook" // POST to URL
|
||||
DeliveryNotify DeliveryType = "notify" // In-app notification (future)
|
||||
)
|
||||
|
||||
// DedupResult - deduplication result
|
||||
|
|
@ -1309,9 +1308,11 @@ type Goals struct {
|
|||
Delivery *DeliveryTarget `json:"delivery,omitempty"` // where to send results (for P4)
|
||||
}
|
||||
|
||||
// DeliveryTarget - where to deliver results (defined in P1, used in P4)
|
||||
// DeliveryTarget - where to deliver results (defined in P1, used by P4)
|
||||
// Note: This is a hint from P1 Goals. Actual delivery is handled by Delivery Center
|
||||
// based on Robot/User preferences, not strictly by this target.
|
||||
type DeliveryTarget struct {
|
||||
Type DeliveryType `json:"type"` // email | webhook | report | notification
|
||||
Type DeliveryType `json:"type"` // Preferred delivery type
|
||||
Recipients []string `json:"recipients,omitempty"` // email addresses, webhook URLs, user IDs
|
||||
Format string `json:"format,omitempty"` // markdown | html | json | text
|
||||
Template string `json:"template,omitempty"` // template name or inline template
|
||||
|
|
@ -1399,13 +1400,74 @@ type ValidationResult struct {
|
|||
ReplyContent string `json:"reply_content,omitempty"` // content for next turn (if NeedReply)
|
||||
}
|
||||
|
||||
// DeliveryResult - P4 delivery output
|
||||
// DeliveryRequest - pushed to Delivery Center
|
||||
// Agent only generates content, Delivery Center decides channels based on preferences
|
||||
type DeliveryRequest struct {
|
||||
Content *DeliveryContent `json:"content"` // Agent-generated content
|
||||
Context *DeliveryContext `json:"context"` // Tracking info
|
||||
// No Channels field - Delivery Center decides based on Robot/User preferences
|
||||
}
|
||||
|
||||
// DeliveryContent - content generated by Delivery Agent
|
||||
type DeliveryContent struct {
|
||||
Summary string `json:"summary"` // Brief summary (1-2 sentences)
|
||||
Body string `json:"body"` // Full markdown report
|
||||
Attachments []DeliveryAttachment `json:"attachments,omitempty"` // Output artifacts
|
||||
}
|
||||
|
||||
// DeliveryAttachment - task output attachment with metadata
|
||||
// File uses wrapper format: __<uploader>://<fileID>
|
||||
// Example: __yao.attachment://ccd472d11feb96e03a3fc468f494045c
|
||||
// Parse with attachment.Parse(value) → (uploader, fileID, isWrapper)
|
||||
type DeliveryAttachment struct {
|
||||
Title string `json:"title"` // Human-readable title, e.g., "Market Analysis Report"
|
||||
Description string `json:"description,omitempty"` // Description of what this artifact is
|
||||
TaskID string `json:"task_id,omitempty"` // Which task produced this artifact
|
||||
File string `json:"file"` // Wrapper format: __<uploader>://<fileID>
|
||||
}
|
||||
|
||||
// DeliveryContext - tracking and audit info
|
||||
type DeliveryContext struct {
|
||||
RobotID string `json:"robot_id"`
|
||||
ExecutionID string `json:"execution_id"`
|
||||
TriggerType TriggerType `json:"trigger_type"`
|
||||
TeamID string `json:"team_id"`
|
||||
}
|
||||
|
||||
// DeliveryPreferences - Robot/User delivery preferences (read by Delivery Center)
|
||||
type DeliveryPreferences struct {
|
||||
Email *EmailPreference `json:"email,omitempty"`
|
||||
Webhook *WebhookPreference `json:"webhook,omitempty"`
|
||||
// notify is handled automatically based on user subscriptions
|
||||
}
|
||||
|
||||
type EmailPreference struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
To []string `json:"to"`
|
||||
CC []string `json:"cc,omitempty"`
|
||||
}
|
||||
|
||||
type WebhookPreference struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
URL string `json:"url"`
|
||||
// If enabled, every execution pushes automatically
|
||||
}
|
||||
|
||||
// DeliveryResult - P4 delivery output (returned by Delivery Center)
|
||||
type DeliveryResult struct {
|
||||
Type DeliveryType `json:"type"`
|
||||
RequestID string `json:"request_id"` // Delivery request ID
|
||||
Content *DeliveryContent `json:"content,omitempty"` // What was delivered
|
||||
Success bool `json:"success"` // All channels succeeded
|
||||
Results []ChannelResult `json:"results,omitempty"` // Per-channel results
|
||||
Error string `json:"error,omitempty"` // Overall error if any
|
||||
}
|
||||
|
||||
// ChannelResult - result for a single delivery channel
|
||||
type ChannelResult struct {
|
||||
Type DeliveryType `json:"type"` // email | webhook | notify
|
||||
Success bool `json:"success"`
|
||||
Recipients []string `json:"recipients,omitempty"` // who received
|
||||
Content string `json:"content,omitempty"` // formatted content delivered
|
||||
Details interface{} `json:"details,omitempty"` // channel-specific response
|
||||
Recipients []string `json:"recipients,omitempty"` // Who received (for email)
|
||||
Details interface{} `json:"details,omitempty"` // Channel-specific response
|
||||
Error string `json:"error,omitempty"`
|
||||
SentAt *time.Time `json:"sent_at,omitempty"`
|
||||
}
|
||||
|
|
@ -1893,3 +1955,407 @@ Supported assertion types:
|
|||
- `type` - type checking (with optional path)
|
||||
- `script` - custom script validation
|
||||
- `agent` - AI agent validation
|
||||
|
||||
---
|
||||
|
||||
## 6. P4 Delivery Implementation
|
||||
|
||||
### 6.1 Overview
|
||||
|
||||
P4 Delivery summarizes P3 execution results and delivers to configured channels.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ delivery.go (P4 Entry) │
|
||||
│ - DeliveryExecution: main entry point │
|
||||
│ - Calls Delivery Agent with full execution context │
|
||||
│ - Routes DeliveryContent to configured channels │
|
||||
└─────────────────────┬───────────────────────────────────────┘
|
||||
│
|
||||
┌────────────┴────────────┐
|
||||
▼ ▼
|
||||
┌─────────────────┐ ┌─────────────────┐
|
||||
│ Delivery Agent │ │ Channel Handlers │
|
||||
│ - Summarize │ │ - Email │
|
||||
│ - Format body │ │ - Webhook │
|
||||
│ - List files │ │ - Notify │
|
||||
└─────────────────┘ │ - File │
|
||||
└─────────────────┘
|
||||
```
|
||||
|
||||
### 6.2 Delivery Request Structure
|
||||
|
||||
P4 generates a `DeliveryRequest` with **only content** and pushes to Delivery Center.
|
||||
**Delivery Center decides channels** based on Robot/User preferences.
|
||||
|
||||
```go
|
||||
// DeliveryRequest - pushed to Delivery Center
|
||||
// No Channels - Delivery Center decides based on preferences
|
||||
type DeliveryRequest struct {
|
||||
Content *DeliveryContent `json:"content"` // Agent-generated content
|
||||
Context *DeliveryContext `json:"context"` // Tracking info
|
||||
}
|
||||
|
||||
// DeliveryContent - content generated by Delivery Agent
|
||||
type DeliveryContent struct {
|
||||
Summary string `json:"summary"` // Brief 1-2 sentence summary
|
||||
Body string `json:"body"` // Full markdown report
|
||||
Attachments []DeliveryAttachment `json:"attachments,omitempty"` // Output artifacts from P3
|
||||
}
|
||||
|
||||
// DeliveryAttachment - file attachment with metadata
|
||||
type DeliveryAttachment struct {
|
||||
Title string `json:"title"` // Human-readable title
|
||||
Description string `json:"description,omitempty"` // What this artifact is
|
||||
TaskID string `json:"task_id,omitempty"` // Which task produced this
|
||||
File string `json:"file"` // Wrapper: __<uploader>://<fileID>
|
||||
}
|
||||
|
||||
// DeliveryContext - tracking and audit info
|
||||
type DeliveryContext struct {
|
||||
RobotID string `json:"robot_id"`
|
||||
ExecutionID string `json:"execution_id"`
|
||||
TriggerType TriggerType `json:"trigger_type"`
|
||||
TeamID string `json:"team_id"`
|
||||
}
|
||||
```
|
||||
|
||||
**Example DeliveryRequest:**
|
||||
|
||||
```json
|
||||
{
|
||||
"content": {
|
||||
"summary": "Sales report completed: 15 new leads",
|
||||
"body": "## Weekly Sales Report\n...",
|
||||
"attachments": [{"title": "Report.pdf", "file": "__yao.attachment://abc123"}]
|
||||
},
|
||||
"context": {
|
||||
"robot_id": "mem_abc123",
|
||||
"execution_id": "exec_xyz789",
|
||||
"trigger_type": "clock",
|
||||
"team_id": "team_123"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Channel Decision by Delivery Center:**
|
||||
|
||||
Delivery Center reads Robot/User preferences and decides channels:
|
||||
|
||||
```go
|
||||
// DeliveryPreferences - from Robot config
|
||||
type DeliveryPreferences struct {
|
||||
Email *EmailPreference `json:"email,omitempty"`
|
||||
Webhook *WebhookPreference `json:"webhook,omitempty"`
|
||||
}
|
||||
|
||||
type EmailPreference struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
To []string `json:"to"`
|
||||
CC []string `json:"cc,omitempty"`
|
||||
}
|
||||
|
||||
type WebhookPreference struct {
|
||||
Enabled bool `json:"enabled"`
|
||||
URL string `json:"url"`
|
||||
// If enabled, every execution pushes automatically
|
||||
}
|
||||
```
|
||||
|
||||
### 6.3 File Wrapper Format
|
||||
|
||||
Attachments use the standard `yao/attachment` wrapper format:
|
||||
|
||||
```go
|
||||
// Format: __<uploader>://<fileID>
|
||||
// Example: __yao.attachment://ccd472d11feb96e03a3fc468f494045c
|
||||
|
||||
import "github.com/yaoapp/yao/attachment"
|
||||
|
||||
// Parse wrapper to get uploader and fileID
|
||||
uploader, fileID, isWrapper := attachment.Parse(wrapper)
|
||||
// uploader: "__yao.attachment"
|
||||
// fileID: "ccd472d11feb96e03a3fc468f494045c"
|
||||
// isWrapper: true
|
||||
|
||||
// Get file info
|
||||
manager := attachment.Managers[uploader]
|
||||
fileInfo, err := manager.Info(ctx, fileID)
|
||||
|
||||
// Read file content as base64
|
||||
base64Content := attachment.Base64(ctx, wrapper)
|
||||
|
||||
// Read with data URI format
|
||||
dataURI := attachment.Base64(ctx, wrapper, true)
|
||||
// "data:image/png;base64,..."
|
||||
```
|
||||
|
||||
### 6.4 Delivery Agent
|
||||
|
||||
The Delivery Agent **only generates content**, does NOT decide channels.
|
||||
Channel decisions are made by Delivery Center based on Robot/User preferences.
|
||||
|
||||
**Input:**
|
||||
```go
|
||||
type DeliveryAgentInput struct {
|
||||
Robot *Robot `json:"robot"` // Robot identity and config
|
||||
TriggerType TriggerType `json:"trigger"` // clock | human | event
|
||||
Inspiration *InspirationReport `json:"inspiration"` // P0 (clock only)
|
||||
Goals *Goals `json:"goals"` // P1
|
||||
Tasks []Task `json:"tasks"` // P2
|
||||
Results []TaskResult `json:"results"` // P3
|
||||
}
|
||||
```
|
||||
|
||||
**Output:**
|
||||
```go
|
||||
// DeliveryAgentOutput - only content, no channels
|
||||
type DeliveryAgentOutput struct {
|
||||
Content *DeliveryContent `json:"content"` // Generated content
|
||||
}
|
||||
```
|
||||
|
||||
**Agent Responsibilities:**
|
||||
|
||||
The agent focuses on content generation:
|
||||
- **Summary**: Brief 1-2 sentence summary of execution results
|
||||
- **Body**: Full markdown report with details
|
||||
- **Attachments**: Select which P3-generated files to include
|
||||
|
||||
**Example Output:**
|
||||
|
||||
```json
|
||||
{
|
||||
"content": {
|
||||
"summary": "Sales report completed: 15 new leads processed, 3 high-priority",
|
||||
"body": "## Weekly Sales Report\n\n### Summary\n- Total leads: 15\n- High priority: 3\n...",
|
||||
"attachments": [
|
||||
{"title": "Sales Report.pdf", "task_id": "task_1", "file": "__yao.attachment://abc123"},
|
||||
{"title": "Lead Analysis.xlsx", "task_id": "task_2", "file": "__yao.attachment://def456"}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 6.5 Delivery Center
|
||||
|
||||
The Delivery Center receives `DeliveryRequest`, **decides channels based on preferences**, and executes delivery.
|
||||
|
||||
**Current implementation:** Internal to P4 (in `executor/delivery.go`)
|
||||
**Future:** Can be extracted to standalone `yao/delivery` package
|
||||
|
||||
```go
|
||||
// DeliveryCenter - handles channel decision and delivery execution
|
||||
type DeliveryCenter struct {
|
||||
handlers map[DeliveryType]ChannelHandler
|
||||
}
|
||||
|
||||
// ChannelHandler - interface for channel implementations
|
||||
type ChannelHandler interface {
|
||||
Deliver(ctx context.Context, content *DeliveryContent, opts map[string]interface{}) (*ChannelResult, error)
|
||||
}
|
||||
|
||||
// Deliver - main entry point
|
||||
func (dc *DeliveryCenter) Deliver(ctx context.Context, req *DeliveryRequest) *DeliveryResult {
|
||||
requestID := generateID()
|
||||
|
||||
// 1. Get Robot/User delivery preferences
|
||||
prefs := dc.getDeliveryPreferences(ctx, req.Context.RobotID)
|
||||
|
||||
// 2. Decide channels based on preferences
|
||||
channels := dc.decideChannels(prefs)
|
||||
|
||||
// 3. Execute delivery to each channel
|
||||
var results []ChannelResult
|
||||
allSuccess := true
|
||||
|
||||
for _, ch := range channels {
|
||||
handler, ok := dc.handlers[ch.Type]
|
||||
if !ok {
|
||||
results = append(results, ChannelResult{
|
||||
Type: ch.Type,
|
||||
Success: false,
|
||||
Error: fmt.Sprintf("unsupported channel: %s", ch.Type),
|
||||
})
|
||||
allSuccess = false
|
||||
continue
|
||||
}
|
||||
|
||||
result, err := handler.Deliver(ctx, req.Content, ch.Options)
|
||||
if err != nil {
|
||||
result = &ChannelResult{Type: ch.Type, Success: false, Error: err.Error()}
|
||||
allSuccess = false
|
||||
}
|
||||
results = append(results, *result)
|
||||
}
|
||||
|
||||
// 4. Future: check user subscriptions and send notifications
|
||||
// dc.sendNotifications(ctx, req)
|
||||
|
||||
return &DeliveryResult{
|
||||
RequestID: requestID,
|
||||
Content: req.Content,
|
||||
Success: allSuccess,
|
||||
Results: results,
|
||||
}
|
||||
}
|
||||
|
||||
// decideChannels - decide which channels to use based on preferences
|
||||
func (dc *DeliveryCenter) decideChannels(prefs *DeliveryPreferences) []channelWithOpts {
|
||||
var channels []channelWithOpts
|
||||
|
||||
if prefs.Email != nil && prefs.Email.Enabled {
|
||||
channels = append(channels, channelWithOpts{
|
||||
Type: DeliveryEmail,
|
||||
Options: map[string]interface{}{"to": prefs.Email.To, "cc": prefs.Email.CC},
|
||||
})
|
||||
}
|
||||
|
||||
if prefs.Webhook != nil && prefs.Webhook.Enabled {
|
||||
channels = append(channels, channelWithOpts{
|
||||
Type: DeliveryWebhook,
|
||||
Options: map[string]interface{}{"url": prefs.Webhook.URL},
|
||||
})
|
||||
}
|
||||
|
||||
return channels
|
||||
}
|
||||
```
|
||||
|
||||
### 6.6 Channel Handlers
|
||||
|
||||
Each delivery channel has a dedicated handler implementing `ChannelHandler`:
|
||||
|
||||
```go
|
||||
// EmailHandler - uses yao/messenger
|
||||
type EmailHandler struct {
|
||||
messenger *messenger.Manager
|
||||
}
|
||||
|
||||
func (h *EmailHandler) Deliver(ctx context.Context, content *DeliveryContent, opts map[string]interface{}) (*ChannelResult, error) {
|
||||
// Convert attachments to messenger format
|
||||
var attachments []messenger.Attachment
|
||||
for _, att := range content.Attachments {
|
||||
uploader, fileID, _ := attachment.Parse(att.File)
|
||||
manager := attachment.Managers[uploader]
|
||||
data, _ := manager.Read(ctx, fileID)
|
||||
info, _ := manager.Info(ctx, fileID)
|
||||
|
||||
attachments = append(attachments, messenger.Attachment{
|
||||
Filename: att.Title,
|
||||
ContentType: info.ContentType,
|
||||
Content: data,
|
||||
})
|
||||
}
|
||||
|
||||
to := opts["to"].([]string)
|
||||
err := h.messenger.Send(ctx, &messenger.Message{
|
||||
To: to,
|
||||
Subject: content.Summary, // Use summary as subject
|
||||
Body: content.Body,
|
||||
Attachments: attachments,
|
||||
})
|
||||
|
||||
now := time.Now()
|
||||
return &ChannelResult{
|
||||
Type: DeliveryEmail,
|
||||
Success: err == nil,
|
||||
Recipients: to,
|
||||
SentAt: &now,
|
||||
}, err
|
||||
}
|
||||
|
||||
// WebhookHandler - POST JSON to URL
|
||||
type WebhookHandler struct{}
|
||||
|
||||
func (h *WebhookHandler) Deliver(ctx context.Context, content *DeliveryContent, opts map[string]interface{}) (*ChannelResult, error) {
|
||||
payload, _ := json.Marshal(content)
|
||||
req, _ := http.NewRequestWithContext(ctx, "POST", opts["url"].(string), bytes.NewReader(payload))
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
|
||||
resp, err := http.DefaultClient.Do(req)
|
||||
if err != nil {
|
||||
return &ChannelResult{Type: DeliveryWebhook, Success: false}, err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode >= 400 {
|
||||
return &ChannelResult{Type: DeliveryWebhook, Success: false}, fmt.Errorf("webhook failed: %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
now := time.Now()
|
||||
return &ChannelResult{
|
||||
Type: DeliveryWebhook,
|
||||
Success: true,
|
||||
Details: map[string]interface{}{"status_code": resp.StatusCode},
|
||||
SentAt: &now,
|
||||
}, nil
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
**Note on Notifications:**
|
||||
|
||||
`notify` is NOT configured per-Robot. Future Delivery Center will:
|
||||
1. Check user subscription preferences after receiving DeliveryRequest
|
||||
2. Automatically send in-app notifications to subscribed users
|
||||
3. This is transparent to P4 and Delivery Agent
|
||||
|
||||
### 6.7 Execution Persistence
|
||||
|
||||
Robot execution history is stored in `__yao.agent_execution` table for UI display:
|
||||
|
||||
```go
|
||||
// Model: yao/models/agent/execution.mod.yao
|
||||
// Table: __yao.agent_execution
|
||||
|
||||
type ExecutionRecord struct {
|
||||
ID string `json:"id"` // Execution ID
|
||||
MemberID string `json:"member_id"` // Robot member ID
|
||||
TeamID string `json:"team_id"` // Team ID
|
||||
JobID string `json:"job_id"` // Linked job.Job ID
|
||||
TriggerType TriggerType `json:"trigger_type"` // clock | human | event
|
||||
Status ExecStatus `json:"status"` // pending | running | completed | failed
|
||||
Phase Phase `json:"phase"` // Current phase
|
||||
Input *TriggerInput `json:"input"` // Original trigger input
|
||||
Inspiration *InspirationReport `json:"inspiration"` // P0 result
|
||||
Goals *Goals `json:"goals"` // P1 result
|
||||
Tasks []Task `json:"tasks"` // P2 result
|
||||
Results []TaskResult `json:"results"` // P3 results
|
||||
Delivery *DeliveryResult `json:"delivery"` // P4 result
|
||||
Learning []LearningEntry `json:"learning"` // P5 entries
|
||||
Error string `json:"error"` // Error message if failed
|
||||
StartTime time.Time `json:"start_time"`
|
||||
EndTime *time.Time `json:"end_time"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
}
|
||||
```
|
||||
|
||||
**Store Interface:**
|
||||
|
||||
```go
|
||||
// store/execution.go
|
||||
type ExecutionStore interface {
|
||||
// Save creates or updates an execution record
|
||||
Save(ctx context.Context, record *ExecutionRecord) error
|
||||
|
||||
// Get retrieves an execution by ID
|
||||
Get(ctx context.Context, execID string) (*ExecutionRecord, error)
|
||||
|
||||
// List retrieves executions with filters
|
||||
List(ctx context.Context, opts ListOptions) ([]*ExecutionRecord, int, error)
|
||||
|
||||
// UpdatePhase updates the current phase
|
||||
UpdatePhase(ctx context.Context, execID string, phase Phase, data interface{}) error
|
||||
}
|
||||
|
||||
type ListOptions struct {
|
||||
MemberID string // Filter by robot
|
||||
TeamID string // Filter by team
|
||||
Status ExecStatus // Filter by status
|
||||
TriggerType TriggerType // Filter by trigger
|
||||
Page int
|
||||
PageSize int
|
||||
}
|
||||
```
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@
|
|||
- [x] `RobotStatus` - robot status (idle, working, paused, error, maintenance)
|
||||
- [x] `InterventionAction` - human actions (task.add, goal.adjust, etc.)
|
||||
- [x] `Priority` - priority levels (high, normal, low)
|
||||
- [x] `DeliveryType` - delivery types (email, file, webhook, notify)
|
||||
- [x] `DeliveryType` - delivery types (email, webhook, notify)
|
||||
- [x] `DedupResult` - dedup results (skip, merge, proceed)
|
||||
- [x] `EventSource` - event sources (webhook, database)
|
||||
- [x] `LearningType` - learning types (execution, feedback, insight)
|
||||
|
|
@ -555,7 +555,7 @@ yao-dev-app/assistants/
|
|||
|
||||
- [x] `robot/delivery/package.yao` - config
|
||||
- [x] `robot/delivery/prompts.yml` - system prompt:
|
||||
- Input: Task results, delivery target (email, report, notification)
|
||||
- Input: Full execution context (P0-P3 results)
|
||||
- Output: Formatted delivery content
|
||||
- Style: Clear, professional
|
||||
|
||||
|
|
@ -869,92 +869,231 @@ Created new `yao/assert` package for universal assertion/validation:
|
|||
|
||||
**Depends on:** Phase 9 (P3 Run)
|
||||
|
||||
### 10.1 Delivery Agent Setup
|
||||
### 10.1 Execution Persistence (Prerequisite)
|
||||
|
||||
> **Background:** Each Robot execution (P0-P5) needs persistent storage for UI history queries.
|
||||
|
||||
- [ ] `yao/models/agent/execution.mod.yao` - Execution record model (`agent_execution` table)
|
||||
- [ ] id, execution_id (unique)
|
||||
- [ ] member_id, team_id, job_id
|
||||
- [ ] trigger_type (enum: clock, human, event)
|
||||
- [ ] status (enum: pending, running, completed, failed, cancelled)
|
||||
- [ ] phase (enum: inspiration, goals, tasks, run, delivery, learning)
|
||||
- [ ] start_time, end_time, error
|
||||
- [ ] input (JSON) - trigger input
|
||||
- [ ] inspiration (JSON) - P0 output
|
||||
- [ ] goals (JSON) - P1 output
|
||||
- [ ] tasks (JSON) - P2 output
|
||||
- [ ] results (JSON) - P3 output
|
||||
- [ ] delivery (JSON) - P4 output
|
||||
- [ ] learning (JSON) - P5 output
|
||||
- [ ] Relations: member (hasOne __yao.member)
|
||||
- [ ] `agent/robot/store/execution.go` - Execution record storage
|
||||
- [ ] `SaveExecution()` - save/update execution record
|
||||
- [ ] `GetExecution()` - get execution by ID
|
||||
- [ ] `ListExecutions()` - query execution history by member_id
|
||||
- [ ] Integrate into Executor - update record after each phase
|
||||
|
||||
### 10.2 Messenger Attachment Support ✅
|
||||
|
||||
> **Conclusion:** `yao/messenger` already supports attachments
|
||||
|
||||
```go
|
||||
// messenger/types/types.go
|
||||
type Attachment struct {
|
||||
Filename string `json:"filename"`
|
||||
ContentType string `json:"content_type"`
|
||||
Content []byte `json:"content"`
|
||||
Inline bool `json:"inline,omitempty"`
|
||||
CID string `json:"cid,omitempty"`
|
||||
}
|
||||
```
|
||||
|
||||
Supported channels:
|
||||
- [x] Email - Full attachment support
|
||||
- [x] SMS - No attachment (text only)
|
||||
- [x] WhatsApp - TBD
|
||||
|
||||
### 10.3 Type Updates (Prerequisite)
|
||||
|
||||
- [ ] Update `types/enums.go` - Remove `DeliveryFile` from `DeliveryType`
|
||||
- [ ] Update `types/robot.go` - Delivery types for new architecture
|
||||
- [ ] `DeliveryResult` - update to new structure (RequestID, Content, Results[])
|
||||
- [ ] Add `DeliveryContent` struct
|
||||
- [ ] Add `DeliveryAttachment` struct
|
||||
- [ ] Add `DeliveryRequest` struct
|
||||
- [ ] Add `DeliveryContext` struct
|
||||
- [ ] Add `DeliveryPreferences` struct
|
||||
- [ ] Add `ChannelResult` struct
|
||||
- [ ] Update `types/enums_test.go` - Remove `DeliveryFile` test
|
||||
- [ ] Update `types/robot_test.go` - Update delivery result tests
|
||||
|
||||
### 10.4 Delivery Agent Setup
|
||||
|
||||
- [ ] `robot/delivery/package.yao` - Delivery Agent config
|
||||
- [ ] `robot/delivery/prompts.yml` - delivery prompts
|
||||
- [ ] Input: Full execution context (P0-P3 results)
|
||||
- [ ] Output: DeliveryContent (Summary, Body, Attachments) - **only content, no channels**
|
||||
- [ ] Agent focuses on content generation, NOT channel selection
|
||||
|
||||
### 10.2 Implementation
|
||||
### 10.5 Delivery Content Structure
|
||||
|
||||
- [ ] `executor/delivery.go` - `RunDelivery(ctx, exec, data)` - real implementation
|
||||
- [ ] `executor/delivery.go` - build delivery content from results
|
||||
- [ ] `executor/delivery.go` - support email delivery
|
||||
- [ ] `executor/delivery.go` - support file delivery
|
||||
- [ ] `executor/delivery.go` - support webhook delivery
|
||||
- [ ] `executor/delivery.go` - support notify delivery
|
||||
```go
|
||||
// DeliveryRequest - pushed to Delivery Center
|
||||
// No Channels - Delivery Center decides based on preferences
|
||||
type DeliveryRequest struct {
|
||||
Content *DeliveryContent `json:"content"` // Agent-generated content
|
||||
Context *DeliveryContext `json:"context"` // Tracking info
|
||||
}
|
||||
|
||||
### 10.3 Tests
|
||||
// DeliveryContent - Content generated by Delivery Agent (only content)
|
||||
type DeliveryContent struct {
|
||||
Summary string `json:"summary"` // Brief 1-2 sentence summary
|
||||
Body string `json:"body"` // Full markdown report
|
||||
Attachments []DeliveryAttachment `json:"attachments,omitempty"` // Output artifacts from P3
|
||||
}
|
||||
|
||||
// DeliveryAttachment - Task output attachment with metadata
|
||||
type DeliveryAttachment struct {
|
||||
Title string `json:"title"` // Human-readable title
|
||||
Description string `json:"description,omitempty"` // What this artifact is
|
||||
TaskID string `json:"task_id,omitempty"` // Which task produced this
|
||||
File string `json:"file"` // Wrapper: __<uploader>://<fileID>
|
||||
}
|
||||
|
||||
// DeliveryContext - tracking info
|
||||
type DeliveryContext struct {
|
||||
RobotID string `json:"robot_id"`
|
||||
ExecutionID string `json:"execution_id"`
|
||||
TriggerType string `json:"trigger_type"`
|
||||
TeamID string `json:"team_id"`
|
||||
}
|
||||
```
|
||||
|
||||
**Key Design:**
|
||||
- **Agent only generates content** (Summary, Body, Attachments)
|
||||
- **Delivery Center decides channels** based on Robot/User preferences
|
||||
- If webhook configured, every execution pushes automatically
|
||||
|
||||
**File Wrapper:**
|
||||
- Format: `__<uploader>://<fileID>`
|
||||
- Parse: `attachment.Parse(value)` → `(uploader, fileID, isWrapper)`
|
||||
- Read: `attachment.Base64(ctx, value)` → base64 content
|
||||
|
||||
**Delivery Channels (Delivery Center decides):**
|
||||
| Channel | Description |
|
||||
|---------|-------------|
|
||||
| `email` | Send via yao/messenger (if configured in preferences) |
|
||||
| `webhook` | POST JSON to URL (if configured, every execution) |
|
||||
| `notify` | In-app notification based on user subscriptions (future) |
|
||||
|
||||
### 10.6 Implementation
|
||||
|
||||
**P4 Entry (executor/delivery.go):**
|
||||
- [ ] `RunDelivery(ctx, exec, data)` - P4 entry point
|
||||
- [ ] Call Delivery Agent to generate content (only content, no channels)
|
||||
- [ ] Build DeliveryRequest (Content + Context)
|
||||
- [ ] Push to Delivery Center
|
||||
- [ ] Store DeliveryResult in exec.Delivery
|
||||
|
||||
**Delivery Center (executor/delivery.go, future: yao/delivery):**
|
||||
- [ ] `DeliveryCenter.Deliver(ctx, request)` - main entry
|
||||
- [ ] Read Robot/User delivery preferences
|
||||
- [ ] Decide which channels to use based on preferences
|
||||
- [ ] Call appropriate handler for each channel
|
||||
- [ ] Aggregate ChannelResults into DeliveryResult
|
||||
- [ ] `ChannelHandler` interface
|
||||
- [ ] `Deliver(ctx, content, opts) (*ChannelResult, error)`
|
||||
|
||||
**Channel Handlers:**
|
||||
- [ ] `EmailHandler` - uses yao/messenger
|
||||
- [ ] Convert DeliveryAttachment to messenger.Attachment
|
||||
- [ ] Use Summary as email subject
|
||||
- [ ] Support to, cc from preferences
|
||||
- [ ] `WebhookHandler` - POST JSON
|
||||
- [ ] POST DeliveryContent as JSON payload
|
||||
- [ ] If enabled, every execution pushes automatically
|
||||
|
||||
### 10.7 Tests
|
||||
|
||||
- [ ] `executor/delivery_test.go` - P4 delivery
|
||||
- [ ] Test: delivery content generated correctly
|
||||
- [ ] Test: email delivery (mock or real)
|
||||
- [ ] Test: file delivery to configured path
|
||||
- [ ] Test: Delivery Agent generates content (only content)
|
||||
- [ ] Test: DeliveryCenter reads preferences and decides channels
|
||||
- [ ] Test: DeliveryCenter dispatches to multiple channels
|
||||
- [ ] Test: EmailHandler with attachments
|
||||
- [ ] Test: WebhookHandler POST JSON
|
||||
- [ ] Test: Partial success (some channels fail)
|
||||
- [ ] Test: DeliveryResult aggregation
|
||||
|
||||
---
|
||||
|
||||
## Phase 11: P5 Learning Implementation
|
||||
## Phase 11: API & Integration
|
||||
|
||||
**Goal:** Implement P5 (Learning). Full execution flow complete.
|
||||
**Goal:** Complete API implementation, end-to-end tests. Main flow: P0 → P1 → P2 → P3 → P4.
|
||||
|
||||
**Depends on:** Phase 10 (P4 Delivery)
|
||||
|
||||
### 11.1 Learning Agent Setup
|
||||
> **Note:** P5 Learning is an advanced feature (async, background, user-invisible).
|
||||
> Main flow works without it. Moved to Phase 12 (Advanced Features).
|
||||
|
||||
- [ ] `robot/learning/package.yao` - Learning Agent config
|
||||
- [ ] `robot/learning/prompts.yml` - learning prompts
|
||||
|
||||
### 11.2 Store Implementation
|
||||
|
||||
- [ ] `store/store.go` - Store interface and struct
|
||||
- [ ] `store/kb.go` - KB operations (create, save, search)
|
||||
- [ ] `store/learning.go` - save learning entries to private KB
|
||||
|
||||
### 11.3 Implementation
|
||||
|
||||
- [ ] `executor/learning.go` - `RunLearning(ctx, exec, data)` - real implementation
|
||||
- [ ] `executor/learning.go` - extract learnings from execution
|
||||
- [ ] `executor/learning.go` - call Learning Agent
|
||||
- [ ] `executor/learning.go` - save to private KB
|
||||
|
||||
### 11.4 Tests
|
||||
|
||||
- [ ] `executor/learning_test.go` - P5 learning
|
||||
- [ ] Test: learnings extracted from execution
|
||||
- [ ] Test: learnings saved to KB
|
||||
- [ ] Test: KB can be queried for past learnings
|
||||
|
||||
---
|
||||
|
||||
## Phase 12: API & Integration
|
||||
|
||||
**Goal:** Complete API implementation, end-to-end tests.
|
||||
|
||||
### 12.1 API Implementation
|
||||
### 11.1 API Implementation
|
||||
|
||||
- [ ] `api/api.go` - implement all Go API functions
|
||||
- [ ] `api/process.go` - implement all Process handlers
|
||||
- [ ] `api/jsapi.go` - implement JSAPI
|
||||
|
||||
### 12.2 End-to-End Tests
|
||||
### 11.2 End-to-End Tests
|
||||
|
||||
- [ ] Full clock trigger flow (P0 → P5)
|
||||
- [ ] Human intervention flow (P1 → P5)
|
||||
- [ ] Event trigger flow (P1 → P5)
|
||||
- [ ] Full clock trigger flow (P0 → P1 → P2 → P3 → P4)
|
||||
- [ ] Human intervention flow (P1 → P2 → P3 → P4)
|
||||
- [ ] Event trigger flow (P1 → P2 → P3 → P4)
|
||||
- [ ] Concurrent execution test
|
||||
- [ ] Pause/Resume/Stop test
|
||||
|
||||
### 12.3 Integration with OpenAPI
|
||||
### 11.3 Integration with OpenAPI
|
||||
|
||||
- [ ] HTTP endpoints for human intervention
|
||||
- [ ] Webhook endpoints for events
|
||||
|
||||
---
|
||||
|
||||
## Phase 13: Advanced Features
|
||||
## Phase 12: Advanced Features
|
||||
|
||||
**Goal:** Implement dedup, semantic dedup, plan queue.
|
||||
**Goal:** Implement P5 Learning, dedup, semantic dedup, plan queue.
|
||||
|
||||
### 13.1 Fast Dedup (Time-Window)
|
||||
> **Note:** These are optional advanced features. Main flow works without them.
|
||||
|
||||
### 12.1 P5 Learning Implementation
|
||||
|
||||
> **Background:** P5 Learning is async, runs after P4 Delivery completes.
|
||||
> User doesn't wait for it. Results stored in private KB for future reference.
|
||||
|
||||
#### 12.1.1 Learning Agent Setup
|
||||
|
||||
- [ ] `robot/learning/package.yao` - Learning Agent config
|
||||
- [ ] `robot/learning/prompts.yml` - learning prompts
|
||||
|
||||
#### 12.1.2 Store Implementation
|
||||
|
||||
- [ ] `store/store.go` - Store interface and struct
|
||||
- [ ] `store/kb.go` - KB operations (create, save, search)
|
||||
- [ ] `store/learning.go` - save learning entries to private KB
|
||||
|
||||
#### 12.1.3 Implementation
|
||||
|
||||
- [ ] `executor/learning.go` - `RunLearning(ctx, exec, data)` - real implementation
|
||||
- [ ] `executor/learning.go` - extract learnings from execution
|
||||
- [ ] `executor/learning.go` - call Learning Agent
|
||||
- [ ] `executor/learning.go` - save to private KB
|
||||
|
||||
#### 12.1.4 Tests
|
||||
|
||||
- [ ] `executor/learning_test.go` - P5 learning
|
||||
- [ ] Test: learnings extracted from execution
|
||||
- [ ] Test: learnings saved to KB
|
||||
- [ ] Test: KB can be queried for past learnings
|
||||
|
||||
### 12.2 Fast Dedup (Time-Window)
|
||||
|
||||
> **Note:** Manager has `// TODO: dedup check` comment placeholder. Integrate after implementation.
|
||||
|
||||
|
|
@ -966,13 +1105,13 @@ Created new `yao/assert` package for universal assertion/validation:
|
|||
- [ ] Integrate into Manager.Tick()
|
||||
- [ ] Test: dedup check/mark, window expiry
|
||||
|
||||
### 13.2 Semantic Dedup
|
||||
### 12.3 Semantic Dedup
|
||||
|
||||
- [ ] `dedup/semantic.go` - call Dedup Agent for goal/task level dedup
|
||||
- [ ] Dedup Agent setup (`assistants/robot/dedup/`)
|
||||
- [ ] Test: semantic dedup with real LLM
|
||||
|
||||
### 13.3 Plan Queue
|
||||
### 12.4 Plan Queue
|
||||
|
||||
- [ ] `plan/plan.go` - plan queue implementation
|
||||
- [ ] Store planned tasks/goals
|
||||
|
|
@ -1100,13 +1239,15 @@ func TestWithLLM(t *testing.T) {
|
|||
| 7. P1 Goals | ✅ | Goal Generation Agent integration |
|
||||
| 8. P2 Tasks | ✅ | Task Planning Agent integration |
|
||||
| 9. P3 Run | ✅ | Task execution + validation + yao/assert + multi-turn conversation |
|
||||
| 10. P4 Delivery | ⬜ | Output delivery (email/file/webhook/notify) |
|
||||
| 11. P5 Learning | ⬜ | Learning Agent + KB save |
|
||||
| 12. API & Integration | ⬜ | Complete API, end-to-end tests |
|
||||
| 13. Advanced | ⬜ | Semantic dedup, plan queue, Sandbox mode (requires container infrastructure) |
|
||||
| 10. P4 Delivery | ⬜ | Output delivery (email/webhook, notify future) |
|
||||
| 11. API & Integration | ⬜ | Complete API, end-to-end tests (main flow: P0→P1→P2→P3→P4) |
|
||||
| 12. Advanced | ⬜ | P5 Learning, dedup, plan queue, Sandbox mode |
|
||||
|
||||
Legend: ⬜ Not started | 🟡 In progress | ✅ Complete
|
||||
|
||||
**Main Flow (MVP):** P0 Inspiration → P1 Goals → P2 Tasks → P3 Run → P4 Delivery
|
||||
**Advanced (Optional):** P5 Learning (async), Dedup, Plan Queue, Sandbox
|
||||
|
||||
---
|
||||
|
||||
## Quick Commands
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue