- 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.
1809 lines
58 KiB
Markdown
1809 lines
58 KiB
Markdown
# Robot Agent
|
|
|
|
## 1. What is it?
|
|
|
|
A **Robot Agent** is an AI team member. It works on its own, makes decisions, and runs tasks without waiting for user input.
|
|
|
|
**Key points:**
|
|
|
|
- Belongs to a Team, managed like human members
|
|
- Has clear job duties (e.g., "Sales Manager: track KPIs, make reports")
|
|
- Created and deleted via Team API
|
|
- Runs on schedule, or when triggered by humans or events
|
|
- Learns from each run, stores knowledge in private KB
|
|
|
|
---
|
|
|
|
## 2. Architecture
|
|
|
|
### 2.1 System Flow
|
|
|
|
> **Architecture Note:** All trigger types flow through Manager.
|
|
>
|
|
> - Clock: `Manager.Tick()` (internal ticker)
|
|
> - Human: `Manager.Intervene()` (API call)
|
|
> - Event: `Manager.HandleEvent()` (webhook/db trigger)
|
|
>
|
|
> The `trigger/` package provides utilities only (validation, clock matching, execution control).
|
|
|
|
```mermaid
|
|
flowchart TB
|
|
subgraph Triggers["Triggers"]
|
|
WC[/"⏰ Clock"/]
|
|
HI[/"👤 Human"/]
|
|
EV[/"📡 Event"/]
|
|
end
|
|
|
|
subgraph Manager["Manager (Central Orchestrator)"]
|
|
TC{"Enabled?"}
|
|
Cache[("Cache")]
|
|
Dedup{"Dedup?"}
|
|
Queue["Queue"]
|
|
end
|
|
|
|
subgraph Pool["Workers"]
|
|
W1["Worker"]
|
|
W2["Worker"]
|
|
W3["Worker"]
|
|
end
|
|
|
|
subgraph Executor["Executor"]
|
|
TT{"Trigger?"}
|
|
P0["P0: Inspiration"]
|
|
P1["P1: Goals"]
|
|
P2["P2: Tasks"]
|
|
P3["P3: Run"]
|
|
P4["P4: Deliver"]
|
|
P5["P5: Learn"]
|
|
end
|
|
|
|
subgraph Storage["Storage"]
|
|
KB[("KB")]
|
|
DB[("DB")]
|
|
Job[("Job")]
|
|
end
|
|
|
|
WC --> TC
|
|
HI & EV --> TC
|
|
TC -->|Yes| Cache
|
|
TC -->|No| X[/Skip/]
|
|
Cache --> Dedup
|
|
Dedup -->|OK| Queue
|
|
Dedup -->|Dup| Cache
|
|
Queue --> W1 & W2 & W3
|
|
W1 & W2 & W3 --> TT
|
|
TT -->|Clock| P0
|
|
TT -->|Human/Event| P1
|
|
P0 --> P1 --> P2 --> P3 --> P4 --> P5
|
|
P5 --> KB & DB & Job
|
|
KB -.->|History| P0
|
|
```
|
|
|
|
### 2.2 Executor Modes
|
|
|
|
Executor supports multiple execution modes for different use cases:
|
|
|
|
| Mode | Use Case | Status |
|
|
| -------- | --------------------------------------- | ------------------ |
|
|
| Standard | Production with real Agent calls | ✅ Implemented |
|
|
| DryRun | Tests, demos, preview without LLM calls | ✅ Implemented |
|
|
| Sandbox | Container-isolated for untrusted code | ⬜ Not Implemented |
|
|
|
|
**Standard Mode:** Real execution with LLM calls, Job integration, full phase execution.
|
|
|
|
**DryRun Mode:** Simulated execution without LLM calls. Used for:
|
|
|
|
- Unit tests and integration tests
|
|
- Demo and preview modes
|
|
- Scheduling and concurrency testing
|
|
|
|
**Sandbox Mode (Future):** Container-level isolation (Docker/gVisor/Firecracker) for:
|
|
|
|
- Untrusted robot configurations
|
|
- Multi-tenant environments
|
|
- Resource-limited execution
|
|
|
|
> **⚠️ Sandbox requires infrastructure support.** Current placeholder behaves like DryRun.
|
|
|
|
### 2.3 Team Structure
|
|
|
|
Uses existing `__yao.member` model (`yao/models/member.mod.yao`):
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Team │
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
│ │ Robot Members │ │
|
|
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
|
|
│ │ │Sales Manager│ │Data Analyst │ │CS Specialist│ │ │
|
|
│ │ │ • Track KPIs│ │ • Analyze │ │ • Tickets │ │ │
|
|
│ │ │ • Reports │ │ • Reports │ │ • Inquiries │ │ │
|
|
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|
│ ┌─────────────────────────────────────────────────────────┐ │
|
|
│ │ User Members │ │
|
|
│ │ ┌─────────────┐ ┌─────────────┐ │ │
|
|
│ │ │ John (Owner)│ │ Jane (Admin)│ │ │
|
|
│ │ └─────────────┘ └─────────────┘ │ │
|
|
│ └─────────────────────────────────────────────────────────┘ │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Key fields in `__yao.member` for robot agents:**
|
|
|
|
| Field | Type | Description |
|
|
| ----------------- | ------ | ----------------------------------------------------------- |
|
|
| `member_type` | enum | `user` \| `robot` |
|
|
| `autonomous_mode` | bool | Enable robot execution |
|
|
| `robot_config` | JSON | Agent configuration (see section 5) |
|
|
| `robot_status` | enum | `idle` \| `working` \| `paused` \| `error` \| `maintenance` |
|
|
| `system_prompt` | text | Identity & role prompt |
|
|
| `agents` | JSON | Accessible agents list |
|
|
| `mcp_servers` | JSON | Accessible MCP servers |
|
|
| `manager_id` | string | Direct manager user ID |
|
|
|
|
---
|
|
|
|
## 3. How It Works
|
|
|
|
### 3.1 Flow: Trigger → Schedule → Run
|
|
|
|
```mermaid
|
|
sequenceDiagram
|
|
autonumber
|
|
participant T as Trigger
|
|
participant M as Manager
|
|
participant S as Scheduler
|
|
participant W as Worker
|
|
participant E as Executor
|
|
participant A as Phase Agents
|
|
participant KB as KB
|
|
|
|
T->>M: Event
|
|
M->>M: Check enabled
|
|
M->>M: Get from cache
|
|
M->>M: Check dedup
|
|
M->>S: Submit
|
|
|
|
S->>S: Check quota
|
|
S->>S: Sort by priority
|
|
S->>W: Dispatch
|
|
|
|
W->>E: Run
|
|
|
|
alt Clock trigger
|
|
E->>A: P0: Inspiration (with clock context)
|
|
A-->>E: Report
|
|
end
|
|
|
|
loop P1 to P5
|
|
E->>A: Call agent
|
|
A-->>E: Result
|
|
end
|
|
|
|
E->>KB: Save learning
|
|
E-->>W: Done
|
|
```
|
|
|
|
### 3.2 Triggers
|
|
|
|
| Type | What | Config | Handler |
|
|
| --------- | ----------------------------- | -------------------- | ----------------------- |
|
|
| **Clock** | Timer (times/interval/daemon) | `triggers.clock` | `Manager.Tick()` |
|
|
| **Human** | Manual action | `triggers.intervene` | `Manager.Intervene()` |
|
|
| **Event** | Webhook, DB change | `triggers.event` | `Manager.HandleEvent()` |
|
|
|
|
All on by default. Turn off per agent:
|
|
|
|
```yaml
|
|
triggers:
|
|
clock: { enabled: true }
|
|
intervene: { enabled: true, actions: ["task.add", "goal.adjust"] }
|
|
event: { enabled: false }
|
|
```
|
|
|
|
### 3.3 Concurrency
|
|
|
|
Two levels to prevent one agent from using all resources:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Global Pool (10 workers) │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│ │ │
|
|
▼ ▼ ▼
|
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
│ Sales Manager │ │ Data Analyst │ │ CS Specialist │
|
|
│ Limit: 3 │ │ Limit: 2 │ │ Limit: 3 │
|
|
│ Now: 2 ✓ │ │ Now: 2 (full) │ │ Now: 1 ✓ │
|
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
```
|
|
|
|
### 3.4 Dedup
|
|
|
|
**Fast check** (in memory):
|
|
|
|
```go
|
|
key := memberID + ":" + triggerType + ":" + window
|
|
if has(key) { skip }
|
|
```
|
|
|
|
**Smart check** (for goals/tasks):
|
|
|
|
- Dedup Agent looks at history
|
|
- Returns: `skip` | `merge` | `proceed`
|
|
|
|
### 3.5 Cache
|
|
|
|
Keeps agents in memory. No DB query on each tick:
|
|
|
|
```go
|
|
type AgentCache struct {
|
|
agents map[string]*Agent // member_id -> agent
|
|
byTeam map[string][]string // team_id -> member_ids
|
|
}
|
|
// Refresh: on start, on change, every hour
|
|
```
|
|
|
|
---
|
|
|
|
## 4. Phases
|
|
|
|
### 4.1 Overview
|
|
|
|
```
|
|
Clock: P0 → P1 → P2 → P3 → P4 → P5
|
|
Human/Event: P1 → P2 → P3 → P4 → P5
|
|
```
|
|
|
|
| Phase | Agent | In | Out | When |
|
|
| ----- | ----------- | ------------------- | --------------- | ---------- |
|
|
| P0 | Inspiration | Clock + Data + News | Report | Clock only |
|
|
| 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/Webhook | Always |
|
|
| P5 | Learning | Summary | KB entries | Always |
|
|
|
|
### 4.2 P0: Inspiration (Clock only)
|
|
|
|
**Skipped for Human/Event triggers.** They already have clear intent.
|
|
|
|
Gathers info to help make good goals. **Clock context is key input** - Agent knows what time it is and can decide what to do (e.g., 5pm Friday → write weekly report).
|
|
|
|
```go
|
|
type InspirationReport struct {
|
|
Clock *ClockContext `json:"clock"` // time context
|
|
Content string `json:"content"` // markdown text for LLM
|
|
}
|
|
// Content is markdown like:
|
|
// ## Summary
|
|
// ...
|
|
// ## Highlights
|
|
// - [High] Sales up 50%
|
|
// ## Opportunities / Risks / World News / Pending
|
|
// ...
|
|
|
|
type ClockContext struct {
|
|
Now time.Time // Current time
|
|
Hour int // 0-23
|
|
DayOfWeek string // Monday, Tuesday...
|
|
DayOfMonth int // 1-31
|
|
IsWeekend bool
|
|
IsMonthStart bool // 1st-3rd
|
|
IsMonthEnd bool // last 3 days
|
|
IsQuarterEnd bool
|
|
// Agent uses this to decide: "It's 5pm Friday, time for weekly report"
|
|
}
|
|
```
|
|
|
|
**Sources:**
|
|
|
|
- **Clock**: Current time, day of week, month end, etc.
|
|
- Internal: Data changes, events, feedback, pending work
|
|
- External: Web search (news, competitors)
|
|
|
|
### 4.3 P1: Goals
|
|
|
|
**For Clock:** Uses inspiration report (with clock context) to make goals. Agent decides based on time what's important now.
|
|
|
|
**For Human/Event:** Uses the input directly as goals (or to generate goals).
|
|
|
|
```go
|
|
type Goals struct {
|
|
Content string // markdown text (for LLM)
|
|
Delivery *DeliveryTarget // where to send results (for P4)
|
|
}
|
|
|
|
type DeliveryTarget struct {
|
|
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
|
|
Options map[string]interface{}
|
|
}
|
|
```
|
|
|
|
**Example prompt:**
|
|
|
|
```
|
|
You are [Sales Manager]. Your job: [track KPIs, make reports].
|
|
|
|
## Report
|
|
### Key Items
|
|
- [High] Data: 15 new sales (+50%)
|
|
- [High] Deadline: Friday report due
|
|
- [High] News: Competitor launched product
|
|
|
|
### Chances
|
|
- Sales up 20% vs last week
|
|
- Market growing
|
|
|
|
Make today's goals.
|
|
```
|
|
|
|
**Note:** Validation criteria (`ExpectedOutput`, `ValidationRules`) are defined at the **Task level** (P2), not Goals level. This allows each task to have specific validation rules for P3.
|
|
|
|
### 4.4 P2: Tasks
|
|
|
|
P2 Agent reads Goals markdown and breaks into executable tasks:
|
|
|
|
```go
|
|
type Task struct {
|
|
ID string // unique task ID
|
|
Messages []context.Message // original input (text, images, files, audio)
|
|
GoalRef string // reference to goal (e.g., "Goal 1")
|
|
Source TaskSource // auto | human | event
|
|
ExecutorType ExecutorType // assistant | mcp | process
|
|
ExecutorID string // agent ID or mcp tool name
|
|
Args []any // arguments for executor
|
|
Order int // execution order
|
|
|
|
// Validation criteria (used in P3)
|
|
ExpectedOutput string // what the task should produce
|
|
ValidationRules []string // specific checks to perform
|
|
}
|
|
```
|
|
|
|
### 4.5 P3: Run
|
|
|
|
**Architecture:** P3 uses a modular design with three components:
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────┐
|
|
│ run.go (P3 Entry) │
|
|
│ - RunConfig: ContinueOnFailure, ValidationThreshold, │
|
|
│ MaxTurnsPerTask │
|
|
│ - RunExecution: main loop with task dependency passing │
|
|
└─────────────────────┬───────────────────────────────────────┘
|
|
│
|
|
┌────────────┴────────────┐
|
|
▼ ▼
|
|
┌─────────────────┐ ┌─────────────────┐
|
|
│ runner.go │ │ validator.go │
|
|
│ - Runner │ │ - Validator │
|
|
│ - Multi-turn │ │ - Two-layer │
|
|
│ conversation │ │ - Rule+Semantic│
|
|
│ - Task context │ │ - NeedReply │
|
|
│ building │ │ - ReplyContent │
|
|
└────────┬────────┘ └────────┬────────┘
|
|
│ │
|
|
│ ▼
|
|
│ ┌─────────────────┐
|
|
│ │ yao/assert │
|
|
│ │ - Asserter │
|
|
│ │ - 8 types │
|
|
│ │ - Extensible │
|
|
│ └─────────────────┘
|
|
▼
|
|
┌─────────────────────────────────────────┐
|
|
│ Executor Types │
|
|
│ - ExecutorAssistant → Multi-turn AI │
|
|
│ - ExecutorMCP → Single-call MCP tool │
|
|
│ - ExecutorProcess → Single-call Process │
|
|
└─────────────────────────────────────────┘
|
|
```
|
|
|
|
**Execution Flow:**
|
|
|
|
For each task:
|
|
|
|
1. **Build Context**: Include previous task results as context
|
|
2. **Execute**: Call appropriate executor (Assistant/MCP/Process)
|
|
3. **Validate**: Use two-layer validation (rule-based + semantic)
|
|
4. **Continue or Complete**:
|
|
- For Assistant tasks: If `NeedReply`, continue conversation with `ReplyContent`
|
|
- For MCP/Process tasks: Single-call execution, no multi-turn
|
|
5. **Update**: Set task status and store result
|
|
|
|
**Task Dependency**: Previous task results are automatically passed as context to subsequent tasks via `Runner.BuildTaskContext()` and formatted using `FormatPreviousResultsAsContext()`.
|
|
|
|
**Two-Layer Validation:**
|
|
|
|
| Layer | Method | Speed | Use Case |
|
|
|-------|--------|-------|----------|
|
|
| 1. Rule-based | `yao/assert` | Fast | Type check, contains, regex, json_path |
|
|
| 2. Semantic | Validation Agent | Slow | ExpectedOutput, complex criteria |
|
|
|
|
**Executor Types:**
|
|
|
|
| Type | ExecutorID Format | Example |
|
|
|------|-------------------|---------|
|
|
| `assistant` | Agent ID | `experts.text-writer` |
|
|
| `mcp` | `clientID.toolName` | `filesystem.read_file` |
|
|
| `process` | Process name | `models.user.Find` |
|
|
|
|
**Multi-Turn Conversation Flow:**
|
|
|
|
For assistant tasks, P3 uses a multi-turn conversation approach:
|
|
1. **Call**: Call assistant and get result
|
|
2. **Validate**: Validate result (determines: passed, complete, needReply, replyContent)
|
|
3. **Reply**: If needReply, continue conversation with replyContent
|
|
4. **Repeat**: Until complete or max turns exceeded
|
|
|
|
The `Validator.ValidateWithContext()` method determines:
|
|
- `Complete`: Whether the expected result is obtained
|
|
- `NeedReply`: Whether to continue conversation
|
|
- `ReplyContent`: What to send in the next turn (validation feedback, clarification request, etc.)
|
|
|
|
This replaces the traditional retry mechanism with intelligent conversation continuation.
|
|
|
|
```go
|
|
// RunConfig configures P3 execution behavior
|
|
type RunConfig struct {
|
|
ContinueOnFailure bool // continue to next task even if current fails (default: false)
|
|
ValidationThreshold float64 // minimum score to pass validation (default: 0.6)
|
|
MaxTurnsPerTask int // max conversation turns per task (default: 10)
|
|
}
|
|
|
|
// ValidationResult with multi-turn conversation support
|
|
type ValidationResult struct {
|
|
// Basic validation result
|
|
Passed bool // overall validation passed
|
|
Score float64 // 0-1 confidence score
|
|
Issues []string // what failed
|
|
Suggestions []string // how to improve
|
|
Details string // detailed report (markdown)
|
|
|
|
// Execution state (for multi-turn conversation control)
|
|
Complete bool // whether expected result is obtained
|
|
NeedReply bool // whether to continue conversation
|
|
ReplyContent string // content for next turn (if NeedReply)
|
|
}
|
|
```
|
|
|
|
**yao/assert Package:**
|
|
|
|
Universal assertion library supporting 8 types:
|
|
|
|
| Type | Description | Example |
|
|
|------|-------------|---------|
|
|
| `equals` | Exact match | `{"type": "equals", "value": "success"}` |
|
|
| `contains` | Substring check | `{"type": "contains", "value": "total"}` |
|
|
| `not_contains` | Negative check | `{"type": "not_contains", "value": "error"}` |
|
|
| `json_path` | JSON path extraction | `{"type": "json_path", "path": "data.count", "value": 10}` |
|
|
| `regex` | Pattern matching | `{"type": "regex", "value": "^[A-Z].*"}` |
|
|
| `type` | Type checking | `{"type": "type", "value": "array"}` |
|
|
| `script` | Custom script | `{"type": "script", "script": "scripts.validate"}` |
|
|
| `agent` | AI validation | `{"type": "agent", "use": "validator"}` |
|
|
|
|
### 4.6 P4: Deliver
|
|
|
|
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:
|
|
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
|
|
|
|
Save to KB:
|
|
|
|
| Type | Examples |
|
|
| ----------- | ------------------------ |
|
|
| `execution` | What worked, what failed |
|
|
| `feedback` | Errors, fixes |
|
|
| `insight` | Patterns, tips |
|
|
|
|
---
|
|
|
|
## 5. Config
|
|
|
|
### 5.1 Structure
|
|
|
|
```go
|
|
type Config struct {
|
|
Triggers *Triggers `json:"triggers,omitempty"`
|
|
Clock *Clock `json:"clock,omitempty"`
|
|
Identity *Identity `json:"identity"`
|
|
Quota *Quota `json:"quota"`
|
|
KB *KB `json:"kb,omitempty"` // shared KB (same as assistant)
|
|
DB *DB `json:"db,omitempty"` // shared DB (same as assistant)
|
|
Learn *Learn `json:"learn,omitempty"` // learning for private KB
|
|
Resources *Resources `json:"resources"`
|
|
Delivery *Delivery `json:"delivery"`
|
|
Events []Event `json:"events,omitempty"`
|
|
Executor *Executor `json:"executor,omitempty"` // executor mode settings
|
|
}
|
|
```
|
|
|
|
### 5.2 Types
|
|
|
|
```go
|
|
// Phase - execution phase enum
|
|
type Phase string
|
|
|
|
const (
|
|
PhaseInspiration Phase = "inspiration" // P0: Clock only
|
|
PhaseGoals Phase = "goals" // P1
|
|
PhaseTasks Phase = "tasks" // P2
|
|
PhaseRun Phase = "run" // P3 (execution + validation)
|
|
PhaseDelivery Phase = "delivery" // P4
|
|
PhaseLearning Phase = "learning" // P5
|
|
)
|
|
|
|
// AllPhases for iteration
|
|
var AllPhases = []Phase{
|
|
PhaseInspiration, PhaseGoals, PhaseTasks,
|
|
PhaseRun, PhaseDelivery, PhaseLearning,
|
|
}
|
|
|
|
// ClockMode - clock trigger mode enum
|
|
type ClockMode string
|
|
|
|
const (
|
|
ClockModeTimes ClockMode = "times" // run at specific times
|
|
ClockModeInterval ClockMode = "interval" // run every X duration
|
|
ClockModeDaemon ClockMode = "daemon" // run continuously
|
|
)
|
|
|
|
// DeliveryType - output delivery type enum
|
|
type DeliveryType string
|
|
|
|
const (
|
|
DeliveryEmail DeliveryType = "email" // Email via yao/messenger
|
|
DeliveryWebhook DeliveryType = "webhook" // POST to URL
|
|
DeliveryNotify DeliveryType = "notify" // In-app notification (future)
|
|
)
|
|
|
|
// ExecStatus - execution status enum
|
|
type ExecStatus string
|
|
|
|
const (
|
|
ExecPending ExecStatus = "pending"
|
|
ExecRunning ExecStatus = "running"
|
|
ExecCompleted ExecStatus = "completed"
|
|
ExecFailed ExecStatus = "failed"
|
|
)
|
|
|
|
// RobotStatus - matches __yao.member.robot_status enum
|
|
type RobotStatus string
|
|
|
|
const (
|
|
RobotIdle RobotStatus = "idle" // ready to run
|
|
RobotWorking RobotStatus = "working" // currently executing
|
|
RobotPaused RobotStatus = "paused" // manually paused
|
|
RobotError RobotStatus = "error" // encountered error
|
|
RobotMaintenance RobotStatus = "maintenance" // under maintenance
|
|
)
|
|
|
|
// Triggers - all on by default
|
|
type Triggers struct {
|
|
Clock *Trigger `json:"clock,omitempty"`
|
|
Intervene *Trigger `json:"intervene,omitempty"`
|
|
Event *Trigger `json:"event,omitempty"`
|
|
}
|
|
|
|
type Trigger struct {
|
|
Enabled bool `json:"enabled"`
|
|
Actions []string `json:"actions,omitempty"` // for intervene
|
|
}
|
|
|
|
// Clock - when to wake up
|
|
type Clock struct {
|
|
Mode ClockMode `json:"mode"`
|
|
Times []string `json:"times"` // for times: ["09:00", "14:00"]
|
|
Days []string `json:"days"` // ["Mon", "Tue"...] or ["*"]
|
|
Every string `json:"every"` // for interval: "30m", "1h"
|
|
TZ string `json:"tz"` // Asia/Shanghai
|
|
Timeout string `json:"timeout"` // max run time
|
|
}
|
|
|
|
// Identity
|
|
type Identity struct {
|
|
Role string `json:"role"`
|
|
Duties []string `json:"duties"`
|
|
Rules []string `json:"rules"`
|
|
}
|
|
|
|
// Quota
|
|
type Quota struct {
|
|
Max int `json:"max"` // max running (default: 2)
|
|
Queue int `json:"queue"` // queue size (default: 10)
|
|
Priority int `json:"priority"` // 1-10 (default: 5)
|
|
}
|
|
|
|
// KB
|
|
// KB - shared knowledge base (same as assistant)
|
|
type KB struct {
|
|
Collections []string `json:"collections,omitempty"` // KB collection IDs
|
|
Options map[string]interface{} `json:"options,omitempty"`
|
|
}
|
|
|
|
// DB - shared database (same as assistant)
|
|
type DB struct {
|
|
Models []string `json:"models,omitempty"` // database model names
|
|
Options map[string]interface{} `json:"options,omitempty"`
|
|
}
|
|
|
|
// Learn - learning config for robot's private KB
|
|
// Private KB auto-created: robot_{team_id}_{member_id}_kb
|
|
type Learn struct {
|
|
On bool `json:"on"`
|
|
Types []string `json:"types"` // execution, feedback, insight
|
|
Keep int `json:"keep"` // days, 0 = forever
|
|
}
|
|
|
|
// Resources
|
|
type Resources struct {
|
|
Phases map[Phase]string `json:"phases,omitempty"` // optional, defaults to __yao.{phase}
|
|
Agents []string `json:"agents"`
|
|
MCP []MCP `json:"mcp"`
|
|
}
|
|
|
|
type MCP struct {
|
|
ID string `json:"id"`
|
|
Tools []string `json:"tools,omitempty"` // empty = all
|
|
}
|
|
|
|
// Delivery
|
|
type Delivery struct {
|
|
Type DeliveryType `json:"type"`
|
|
Opts map[string]interface{} `json:"opts"`
|
|
}
|
|
|
|
// ExecutorMode - executor mode enum
|
|
type ExecutorMode string
|
|
|
|
const (
|
|
ExecutorStandard ExecutorMode = "standard" // real Agent calls (default)
|
|
ExecutorDryRun ExecutorMode = "dryrun" // simulated, no LLM calls
|
|
ExecutorSandbox ExecutorMode = "sandbox" // container-isolated (NOT IMPLEMENTED)
|
|
)
|
|
|
|
// Executor - executor settings
|
|
type Executor struct {
|
|
Mode ExecutorMode `json:"mode,omitempty"` // standard | dryrun | sandbox
|
|
MaxDuration string `json:"max_duration,omitempty"` // max execution time (e.g., "30m")
|
|
}
|
|
// Note: Sandbox mode requires container infrastructure (Docker/gVisor).
|
|
// Current implementation falls back to DryRun behavior.
|
|
|
|
// Monitor
|
|
```
|
|
|
|
### 5.3 Example
|
|
|
|
Example record in `__yao.member` table:
|
|
|
|
```json
|
|
{
|
|
"member_id": "mem_abc123",
|
|
"team_id": "team_xyz",
|
|
"member_type": "robot",
|
|
"display_name": "Sales Bot",
|
|
"autonomous_mode": true,
|
|
"robot_status": "idle",
|
|
"system_prompt": "You are a sales analyst...",
|
|
"robot_config": {
|
|
"triggers": {
|
|
"clock": { "enabled": true },
|
|
"intervene": { "enabled": true },
|
|
"event": { "enabled": false }
|
|
},
|
|
"clock": {
|
|
"mode": "times",
|
|
"times": ["09:00", "14:00", "17:00"],
|
|
"days": ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
|
"tz": "Asia/Shanghai",
|
|
"timeout": "30m"
|
|
},
|
|
"identity": {
|
|
"role": "Sales Analyst",
|
|
"duties": ["Analyze sales", "Make weekly reports"],
|
|
"rules": ["Only access sales data"]
|
|
},
|
|
"quota": { "max": 2, "queue": 10, "priority": 5 },
|
|
"kb": { "collections": ["sales-policies", "products"] },
|
|
"db": { "models": ["sales", "customers"] },
|
|
"learn": {
|
|
"on": true,
|
|
"types": ["execution", "feedback", "insight"],
|
|
"keep": 90
|
|
},
|
|
"resources": {
|
|
"phases": {
|
|
"inspiration": "__yao.inspiration",
|
|
"goals": "__yao.goals",
|
|
"tasks": "__yao.tasks",
|
|
"validation": "__yao.validation",
|
|
"delivery": "__yao.delivery",
|
|
"learning": "__yao.learning"
|
|
},
|
|
"agents": ["data-analyst", "chart-gen"],
|
|
"mcp": [{ "id": "database", "tools": ["query"] }]
|
|
},
|
|
"delivery": {
|
|
"type": "email",
|
|
"opts": { "to": ["manager@company.com"] }
|
|
},
|
|
"executor": {
|
|
"mode": "standard",
|
|
"max_duration": "30m"
|
|
}
|
|
},
|
|
"agents": ["data-analyst", "chart-gen"],
|
|
"mcp_servers": ["database"]
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## 6. Lifecycle
|
|
|
|
### 6.1 Agent States
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Idle: POST create
|
|
Idle --> Working: trigger
|
|
Working --> Idle: done
|
|
Idle --> Paused: PATCH pause
|
|
Working --> Paused: PATCH pause
|
|
Paused --> Idle: PATCH resume
|
|
Idle --> Error: error
|
|
Working --> Error: error
|
|
Error --> Idle: PATCH reset
|
|
Idle --> [*]: DELETE
|
|
Paused --> [*]: DELETE
|
|
```
|
|
|
|
| From | To | How |
|
|
| ------- | ------- | --------------------------- |
|
|
| - | idle | POST create |
|
|
| idle | working | trigger (clock/human/event) |
|
|
| working | idle | execution done |
|
|
| idle | paused | PATCH robot_status="paused" |
|
|
| paused | idle | PATCH robot_status="idle" |
|
|
| any | error | execution error |
|
|
| error | idle | PATCH robot_status="idle" |
|
|
| any | deleted | DELETE |
|
|
|
|
### 6.2 On Create
|
|
|
|
1. Check config
|
|
2. Generate member_id if missing
|
|
3. Create KB: `robot_{team_id}_{member_id}_kb`
|
|
4. Add to cache
|
|
5. Create Job
|
|
6. Set active
|
|
|
|
### 6.3 On Delete
|
|
|
|
1. Stop running jobs
|
|
2. Remove from cache
|
|
3. Delete Job
|
|
4. Delete or archive KB
|
|
5. Soft delete record
|
|
|
|
### 6.4 Execution Flow
|
|
|
|
Single execution flow, depends on trigger type:
|
|
|
|
```mermaid
|
|
flowchart LR
|
|
subgraph Trigger
|
|
T{Trigger}
|
|
end
|
|
|
|
subgraph Schedule Path
|
|
P0[P0: Inspiration]
|
|
end
|
|
|
|
subgraph Common Path
|
|
P1[P1: Goals]
|
|
P2[P2: Tasks]
|
|
P3[P3: Run]
|
|
P4[P4: Deliver]
|
|
P5[P5: Learn]
|
|
end
|
|
|
|
T -->|Clock| P0
|
|
T -->|Human/Event| P1
|
|
P0 --> P1
|
|
P1 --> P2 --> P3 --> P4 --> P5
|
|
```
|
|
|
|
```mermaid
|
|
stateDiagram-v2
|
|
[*] --> Triggered
|
|
Triggered --> P0_Inspiration: Clock
|
|
Triggered --> P1_Goals: Human/Event
|
|
P0_Inspiration --> P1_Goals
|
|
P1_Goals --> P2_Tasks
|
|
P2_Tasks --> P3_Run
|
|
P3_Run --> P4_Deliver
|
|
P4_Deliver --> P5_Learn
|
|
P5_Learn --> [*]
|
|
```
|
|
|
|
---
|
|
|
|
## 7. Integrations
|
|
|
|
### 7.1 Job System
|
|
|
|
**Relationship:** 1 Robot : N Executions (concurrent), 1 Execution = 1 job.Job
|
|
|
|
Each trigger creates a new Execution, mapped to a `job.Job` for monitoring.
|
|
|
|
```
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Activity Monitor (UI) │
|
|
│ • List jobs │
|
|
│ • See progress │
|
|
│ • View logs │
|
|
│ • Cancel/retry │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
│
|
|
▼
|
|
┌─────────────────────────────────────────────────────────────────┐
|
|
│ Job Framework │
|
|
│ Job → Execution → Progress → Logs │
|
|
└─────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
**Go APIs (yao/job package):**
|
|
|
|
| Action | API |
|
|
| ------------ | -------------------------------------------------------- |
|
|
| List Jobs | `job.ListJobs(param, page, pagesize)` |
|
|
| Get Job | `job.GetJob(jobID, param)` |
|
|
| Save Job | `job.SaveJob(j)` |
|
|
| List Execs | `job.ListExecutions(param, page, pagesize)` |
|
|
| Get Exec | `job.GetExecution(execID, param)` |
|
|
| Save Exec | `job.SaveExecution(exec)` |
|
|
| List Logs | `job.ListLogs(param, page, pagesize)` |
|
|
| Save Log | `job.SaveLog(log)` |
|
|
| Push (start) | `j.Push()` |
|
|
| Stop | `j.Stop()` |
|
|
| Destroy | `j.Destroy()` |
|
|
| Active Jobs | `job.GetActiveJobs()` |
|
|
| Query by Cat | `job.ListJobs({Wheres: [{Column: "category_id", ...}]})` |
|
|
|
|
### 7.2 Private KB
|
|
|
|
Made on robot member create: `robot_{team_id}_{member_id}_kb`
|
|
|
|
**What it stores:**
|
|
|
|
- `execution`: What worked, what failed
|
|
- `feedback`: Errors, fixes
|
|
- `insight`: Patterns, tips
|
|
|
|
**When:**
|
|
|
|
- Create: On robot member create
|
|
- Update: After P5
|
|
- Clean: Based on `keep` days
|
|
- Delete: On robot member delete
|
|
|
|
### 7.3 External Input
|
|
|
|
**Types:**
|
|
|
|
- `clock`: Timer (with time context)
|
|
- `intervene`: Human action
|
|
- `event`: Webhook, DB change
|
|
- `callback`: Async result
|
|
|
|
**Human actions (InterventionAction):**
|
|
|
|
- `task.add`: Add a new task
|
|
- `task.cancel`: Cancel a task
|
|
- `task.update`: Update task details
|
|
- `goal.adjust`: Modify current goal
|
|
- `goal.add`: Add a new goal
|
|
- `goal.complete`: Mark goal as complete
|
|
- `goal.cancel`: Cancel a goal
|
|
- `plan.add`: Schedule for later
|
|
- `plan.remove`: Remove from plan queue
|
|
- `plan.update`: Update planned item
|
|
- `instruct`: Direct instruction to robot
|
|
|
|
**Plan Queue:**
|
|
|
|
- Holds tasks for later
|
|
- Runs at next cycle start
|
|
|
|
---
|
|
|
|
## 8. API
|
|
|
|
### 8.1 Manager (Internal)
|
|
|
|
> **Note:** Manager is the central orchestrator, handling all trigger types.
|
|
|
|
```go
|
|
type Manager interface {
|
|
// Lifecycle
|
|
Start() error
|
|
Stop() error
|
|
|
|
// Clock trigger (internal, called by ticker)
|
|
Tick(ctx *Context, now time.Time) error
|
|
|
|
// Manual trigger (for testing/API)
|
|
TriggerManual(ctx *Context, memberID string, trigger TriggerType, data interface{}) (string, error)
|
|
|
|
// Human intervention (called by API)
|
|
Intervene(ctx *Context, req *InterveneRequest) (*ExecutionResult, error)
|
|
|
|
// Event trigger (called by webhook/db trigger)
|
|
HandleEvent(ctx *Context, req *EventRequest) (*ExecutionResult, error)
|
|
|
|
// Execution control
|
|
PauseExecution(ctx *Context, execID string) error
|
|
ResumeExecution(ctx *Context, execID string) error
|
|
StopExecution(ctx *Context, execID string) error
|
|
|
|
// Cache access
|
|
Cache() Cache
|
|
}
|
|
```
|
|
|
|
### 8.2 Trigger (Integrated into Manager)
|
|
|
|
> **Note:** Trigger logic is integrated into Manager, not a separate interface.
|
|
> The `trigger/` package provides utilities (validation, clock matching, execution control).
|
|
|
|
```go
|
|
// TriggerType enum
|
|
type TriggerType string
|
|
|
|
const (
|
|
TriggerClock TriggerType = "clock"
|
|
TriggerHuman TriggerType = "human"
|
|
TriggerEvent TriggerType = "event"
|
|
)
|
|
|
|
// Manager handles all trigger types:
|
|
// - Clock: Manager.Tick() called by internal ticker
|
|
// - Human: Manager.Intervene() called by API
|
|
// - Event: Manager.HandleEvent() called by webhook/db trigger
|
|
|
|
// trigger/ package provides utilities:
|
|
// - trigger.ValidateIntervention(req) - validate human intervention request
|
|
// - trigger.ValidateEvent(req) - validate event request
|
|
// - trigger.BuildEventInput(req) - build TriggerInput from event
|
|
// - trigger.ClockMatcher - reusable clock matching logic
|
|
// - trigger.ExecutionController - pause/resume/stop execution
|
|
|
|
type InterveneRequest struct {
|
|
TeamID string
|
|
MemberID string
|
|
Action InterventionAction // task.add | goal.adjust | task.cancel | plan.add | instruct
|
|
Messages []context.Message // user input (text, images, files)
|
|
PlanTime *time.Time // for action=plan.add
|
|
ExecutorMode ExecutorMode // optional: standard | dryrun (override robot config)
|
|
}
|
|
|
|
type EventRequest struct {
|
|
MemberID string
|
|
Source string // webhook path or table name
|
|
EventType string // lead.created, etc.
|
|
Data map[string]interface{}
|
|
ExecutorMode ExecutorMode // optional: standard | dryrun (override robot config)
|
|
}
|
|
|
|
type ExecutionResult struct {
|
|
ExecutionID string // Job execution ID
|
|
Status ExecStatus // pending | running | completed | failed
|
|
Message string // status message
|
|
}
|
|
|
|
type RobotState struct {
|
|
MemberID string // member_id from __yao.member
|
|
Status RobotStatus // idle | working | paused | error | maintenance
|
|
LastRun time.Time
|
|
NextRun time.Time
|
|
Running int // current running execution count
|
|
MaxRunning int // max concurrent executions (from Quota.Max)
|
|
RunningIDs []string // list of running execution IDs
|
|
}
|
|
```
|
|
|
|
### 8.3 Execution (Uses Job System)
|
|
|
|
No separate `autonomous_executions` table. Uses existing Job system.
|
|
|
|
**Each trigger creates a new job.Job:**
|
|
|
|
```go
|
|
// On each trigger (clock/human/event), create a new Job
|
|
execID := gonanoid.Must()
|
|
j, _ := job.Once(job.GOROUTINE, map[string]interface{}{
|
|
"job_id": "robot_exec_" + execID, // unique per execution
|
|
"category_id": "autonomous_robot",
|
|
"name": fmt.Sprintf("%s - %s", member.DisplayName, triggerType),
|
|
"metadata": map[string]interface{}{
|
|
"member_id": memberID,
|
|
"team_id": teamID,
|
|
"trigger_type": triggerType,
|
|
"exec_id": execID,
|
|
},
|
|
})
|
|
job.SaveJob(j)
|
|
|
|
// Configure and start
|
|
j.ExecutionConfig = &job.ExecutionConfig{
|
|
Type: job.ExecutionTypeProcess,
|
|
ProcessName: "robot.Execute",
|
|
ProcessArgs: []interface{}{memberID, execID, triggerData},
|
|
}
|
|
j.Push()
|
|
```
|
|
|
|
**Query executions for a robot:**
|
|
|
|
```go
|
|
// List all executions for a robot member
|
|
param := model.QueryParam{
|
|
Wheres: []model.QueryWhere{
|
|
{Column: "category_id", Value: "autonomous_robot"},
|
|
{Column: "metadata->member_id", Value: memberID},
|
|
},
|
|
Orders: []model.QueryOrder{{Column: "created_at", Option: "desc"}},
|
|
}
|
|
jobs, _ := job.ListJobs(param, 1, 10)
|
|
```
|
|
|
|
**Query examples:**
|
|
|
|
```go
|
|
// List all robot jobs (all robots, all executions)
|
|
param := model.QueryParam{
|
|
Wheres: []model.QueryWhere{
|
|
{Column: "category_id", Value: "autonomous_robot"},
|
|
},
|
|
}
|
|
jobs, _ := job.ListJobs(param, 1, 20)
|
|
|
|
// Get executions for a robot
|
|
execParam := model.QueryParam{
|
|
Wheres: []model.QueryWhere{
|
|
{Column: "job_id", Value: "robot_" + memberID},
|
|
},
|
|
Orders: []model.QueryOrder{{Column: "created_at", Option: "desc"}},
|
|
}
|
|
execs, _ := job.ListExecutions(execParam, 1, 10)
|
|
|
|
// Get logs for an execution
|
|
logParam := model.QueryParam{
|
|
Wheres: []model.QueryWhere{
|
|
{Column: "execution_id", Value: execID},
|
|
},
|
|
}
|
|
logs, _ := job.ListLogs(logParam, 1, 100)
|
|
```
|
|
|
|
---
|
|
|
|
## 9. Security
|
|
|
|
1. **Team only**: Agent sees only its team's data
|
|
2. **Role rules**: Uses role_id permissions
|
|
3. **Limited tools**: Only what's in `resources`
|
|
4. **Timeout**: Stops if runs too long
|
|
5. **Logs**: All runs saved
|
|
|
|
---
|
|
|
|
## 10. Quick Ref
|
|
|
|
### Triggers
|
|
|
|
```yaml
|
|
triggers:
|
|
clock: { enabled: true }
|
|
intervene: { enabled: true, actions: [...] }
|
|
event: { enabled: false }
|
|
```
|
|
|
|
### Clock
|
|
|
|
```yaml
|
|
# Mode 1: Specific times
|
|
clock:
|
|
mode: times
|
|
times: ["09:00", "14:00", "17:00"]
|
|
days: ["Mon", "Tue", "Wed", "Thu", "Fri"]
|
|
tz: Asia/Shanghai
|
|
timeout: 30m
|
|
|
|
# Mode 2: Interval
|
|
clock:
|
|
mode: interval
|
|
every: 30m # run every 30 minutes
|
|
timeout: 10m
|
|
|
|
# Mode 3: Daemon (continuous thinking/analysis)
|
|
clock:
|
|
mode: daemon # restart immediately after each run
|
|
timeout: 10m # max time per run
|
|
# Use case: Research analyst, market monitor
|
|
```
|
|
|
|
### Phase Agents
|
|
|
|
```yaml
|
|
# Optional - defaults to __yao.{phase} if not specified
|
|
resources:
|
|
phases:
|
|
inspiration: "__yao.inspiration" # Clock only
|
|
goals: "__yao.goals"
|
|
tasks: "__yao.tasks"
|
|
validation: "__yao.validation"
|
|
delivery: "__yao.delivery"
|
|
learning: "__yao.learning"
|
|
```
|
|
|
|
### Quota
|
|
|
|
```yaml
|
|
quota:
|
|
max: 2 # max running
|
|
queue: 10 # queue size
|
|
priority: 5 # 1-10
|
|
```
|
|
|
|
### Executor
|
|
|
|
```yaml
|
|
# Standard mode (default) - real Agent calls
|
|
executor:
|
|
mode: standard
|
|
max_duration: 30m
|
|
|
|
# DryRun mode - simulated execution (for testing/demos)
|
|
executor:
|
|
mode: dryrun
|
|
|
|
# Sandbox mode (NOT IMPLEMENTED) - container-isolated
|
|
# Requires Docker/gVisor infrastructure
|
|
# executor:
|
|
# mode: sandbox
|
|
# max_duration: 10m
|
|
```
|
|
|
|
**API Override:**
|
|
|
|
```javascript
|
|
// Override executor mode per trigger
|
|
const result = Process("robot.Trigger", "mem_abc123", {
|
|
type: "human",
|
|
action: "task.add",
|
|
messages: [{ role: "user", content: "Test task" }],
|
|
executor_mode: "dryrun", // override robot config
|
|
});
|
|
```
|
|
|
|
---
|
|
|
|
## 11. Examples
|
|
|
|
Each example shows a different trigger mode:
|
|
|
|
| Example | Trigger | Mode | Scenario |
|
|
| ------- | ------- | --------- | -------------------------------------------- |
|
|
| 11.1 | Clock | times | SEO/GEO Content - daily content optimization |
|
|
| 11.2 | Clock | interval | Competitor Monitor - check every 2 hours |
|
|
| 11.3 | Clock | daemon | Research Analyst - continuous insight mining |
|
|
| 11.4 | Human | intervene | Sales Assistant - manager assigns tasks |
|
|
| 11.5 | Event | webhook | Lead Processor - qualify and route new leads |
|
|
|
|
---
|
|
|
|
### 11.1 SEO/GEO Content Agent (Clock: times)
|
|
|
|
**Trigger:** Clock - specific times daily
|
|
|
|
**Role:** AI Marketing - auto-generate and optimize SEO/GEO content.
|
|
|
|
```json
|
|
// robot_config for SEO Content Agent
|
|
{
|
|
"triggers": {
|
|
"clock": { "enabled": true },
|
|
"intervene": { "enabled": true }
|
|
},
|
|
"clock": {
|
|
"mode": "times",
|
|
"times": ["06:00", "18:00"],
|
|
"days": ["Mon", "Tue", "Wed", "Thu", "Fri"],
|
|
"tz": "Asia/Shanghai"
|
|
},
|
|
"identity": {
|
|
"role": "SEO/GEO Content Specialist",
|
|
"duties": [
|
|
"Research trending keywords in our industry",
|
|
"Generate SEO-optimized articles (2-3 per day)",
|
|
"Optimize existing content for GEO (AI search)",
|
|
"Track keyword rankings and adjust strategy",
|
|
"A/B test titles and meta descriptions"
|
|
]
|
|
},
|
|
"resources": {
|
|
"agents": ["keyword-researcher", "content-writer", "seo-optimizer"],
|
|
"mcp": [
|
|
{ "id": "google-search", "tools": ["trends", "rankings"] },
|
|
{ "id": "cms", "tools": ["create", "update", "publish"] }
|
|
]
|
|
},
|
|
"delivery": {
|
|
"type": "notify",
|
|
"opts": { "channel": "marketing-team" }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example run at 06:00 Monday:**
|
|
|
|
```
|
|
P0 Inspiration:
|
|
Clock: Monday 06:00, start of week
|
|
Data:
|
|
- Keyword "AI app development" trending (+45% this week)
|
|
- Our article ranks #8, competitor #2
|
|
- 3 articles need GEO optimization
|
|
World: New AI regulation announced last Friday
|
|
|
|
P1 Goals:
|
|
1. Write new article targeting "AI app development"
|
|
2. Optimize 3 old articles for GEO
|
|
3. Update meta descriptions for top 5 pages
|
|
|
|
P2 Tasks:
|
|
1. Research "AI app development" keywords → keyword-researcher
|
|
2. Write article with SEO structure → content-writer
|
|
3. Add FAQ schema for GEO → seo-optimizer
|
|
4. Publish to CMS → cms.publish
|
|
|
|
P3 Execute:
|
|
- Keywords: "AI app development", "build AI apps", "AI dev guide" (12 total)
|
|
- Article: 2500 words, 8 sections, FAQ schema added
|
|
- Published to CMS, indexed by Google
|
|
|
|
P4 Delivery:
|
|
→ Notify: "Published: 'Complete Guide to AI App Development' - targeting 12 keywords"
|
|
|
|
P5 Learn:
|
|
- "AI app development" articles perform well on Monday morning
|
|
- FAQ schema improves GEO visibility by 30%
|
|
```
|
|
|
|
---
|
|
|
|
### 11.2 Competitor Monitor (Clock: interval)
|
|
|
|
**Trigger:** Clock - every 2 hours
|
|
|
|
**Role:** Monitor competitors, track market changes, alert on important updates.
|
|
|
|
```json
|
|
// robot_config for Competitor Monitor
|
|
{
|
|
"triggers": {
|
|
"clock": { "enabled": true }
|
|
},
|
|
"clock": {
|
|
"mode": "interval",
|
|
"every": "2h"
|
|
},
|
|
"identity": {
|
|
"role": "Competitor Intelligence Analyst",
|
|
"duties": [
|
|
"Monitor competitor websites for changes",
|
|
"Track competitor pricing updates",
|
|
"Watch for new product launches",
|
|
"Analyze competitor content strategy",
|
|
"Alert team on significant changes"
|
|
]
|
|
},
|
|
"resources": {
|
|
"agents": ["web-scraper", "diff-analyzer", "report-writer"],
|
|
"mcp": [{ "id": "web-search", "tools": ["search", "news"] }]
|
|
},
|
|
"delivery": {
|
|
"type": "webhook",
|
|
"opts": { "url": "https://slack.com/webhook/competitor-alerts" }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example run detecting competitor change:**
|
|
|
|
```
|
|
P0 Inspiration:
|
|
Clock: Tuesday 14:00
|
|
Data:
|
|
- Competitor A: pricing page changed
|
|
- Competitor B: new blog post about "AI agents"
|
|
- Competitor C: no changes
|
|
|
|
P1 Goals:
|
|
1. Analyze Competitor A pricing change
|
|
2. Summarize Competitor B's new content
|
|
3. Assess impact on our positioning
|
|
|
|
P2 Tasks:
|
|
1. Scrape old vs new pricing → web-scraper
|
|
2. Compare pricing tiers → diff-analyzer
|
|
3. Generate competitive analysis → report-writer
|
|
|
|
P3 Execute:
|
|
- Competitor A: dropped price 20% on enterprise tier
|
|
- Competitor B: targeting same keywords as us
|
|
|
|
P4 Delivery:
|
|
→ Slack: "🚨 Competitor A cut enterprise price 20% - review needed"
|
|
|
|
P5 Learn:
|
|
- Competitor A tends to change pricing on Tuesdays
|
|
- Price changes often precede feature launches
|
|
```
|
|
|
|
---
|
|
|
|
### 11.3 Industry Research Analyst (Clock: daemon)
|
|
|
|
**Trigger:** Clock - continuous daemon mode
|
|
|
|
**Role:** Continuously read industry news, papers, social media; extract insights; build knowledge.
|
|
|
|
```json
|
|
// robot_config for Research Analyst
|
|
{
|
|
"triggers": {
|
|
"clock": { "enabled": true }
|
|
},
|
|
"clock": {
|
|
"mode": "daemon",
|
|
"timeout": "10m"
|
|
},
|
|
"identity": {
|
|
"role": "Industry Research Analyst",
|
|
"duties": [
|
|
"Continuously scan industry news and papers",
|
|
"Analyze trends and extract key insights",
|
|
"Identify emerging technologies and competitors",
|
|
"Build and maintain industry knowledge base",
|
|
"Alert team on significant developments"
|
|
]
|
|
},
|
|
"resources": {
|
|
"agents": ["content-reader", "insight-extractor", "report-writer"],
|
|
"mcp": [
|
|
{ "id": "web-search", "tools": ["search", "news"] },
|
|
{ "id": "arxiv", "tools": ["search", "fetch"] },
|
|
{ "id": "twitter", "tools": ["search", "trends"] }
|
|
]
|
|
},
|
|
"delivery": {
|
|
"type": "notify",
|
|
"opts": { "channel": "research-insights" }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example continuous run:**
|
|
|
|
```
|
|
Run #1 (09:00):
|
|
P0: Scan sources
|
|
- 15 new AI news articles
|
|
- 3 new papers on arXiv
|
|
- Twitter: "AI Agent" trending
|
|
P1: Goals:
|
|
1. Read and analyze new content
|
|
2. Extract insights relevant to our business
|
|
3. Update knowledge base
|
|
P2: Tasks:
|
|
1. Read articles → content-reader
|
|
2. Analyze papers → content-reader
|
|
3. Extract insights → insight-extractor
|
|
P3: Execute:
|
|
- Article: "OpenAI releases new agent framework"
|
|
Insight: Validates our direction, watch for API changes
|
|
- Paper: "Multi-agent collaboration patterns"
|
|
Insight: Useful for our agent design, save to KB
|
|
- Twitter: Sentiment positive on AI agents
|
|
P4: Notify: "📚 3 new insights added to KB"
|
|
P5: Learn: OpenAI news = high relevance, prioritize
|
|
→ Restart immediately
|
|
|
|
Run #2 (09:12):
|
|
P0: Scan sources
|
|
- 2 new articles (low relevance)
|
|
- No new papers
|
|
- Twitter: Normal activity
|
|
P1: Low-value content, skip deep analysis
|
|
P5: Learn: Mid-morning usually quiet
|
|
→ Restart immediately
|
|
|
|
Run #3 (09:25):
|
|
P0: Scan sources
|
|
- Breaking: "Competitor X raises $100M for AI platform"
|
|
P1: Goals:
|
|
1. Deep analyze competitor news
|
|
2. Assess impact on our market
|
|
3. Alert team immediately
|
|
P2: Tasks:
|
|
1. Gather all competitor X info → web-search
|
|
2. Analyze their positioning → insight-extractor
|
|
3. Write competitive brief → report-writer
|
|
P3: Execute:
|
|
- Competitor X: Focus on enterprise, similar target market
|
|
- Funding: Will likely expand sales team
|
|
- Threat level: Medium-High
|
|
P4: Notify: "🚨 Competitor X raised $100M - brief attached"
|
|
P5: Learn: Funding news = always high priority
|
|
→ Restart immediately
|
|
```
|
|
|
|
---
|
|
|
|
### 11.4 Sales Assistant (Human: intervene)
|
|
|
|
**Trigger:** Human intervention - sales manager assigns tasks
|
|
|
|
**Role:** Help sales team with research, proposals, follow-ups when manager assigns work.
|
|
|
|
```json
|
|
// robot_config for Sales Assistant
|
|
{
|
|
"triggers": {
|
|
"clock": { "enabled": false },
|
|
"intervene": {
|
|
"enabled": true,
|
|
"actions": ["task.add", "goal.adjust", "instruct"]
|
|
}
|
|
},
|
|
"identity": {
|
|
"role": "Sales Assistant",
|
|
"duties": [
|
|
"Research assigned prospects and companies",
|
|
"Prepare customized proposals and presentations",
|
|
"Draft follow-up emails",
|
|
"Analyze deal history and suggest strategies",
|
|
"Prepare meeting briefs"
|
|
]
|
|
},
|
|
"resources": {
|
|
"agents": ["company-researcher", "proposal-writer", "email-drafter"],
|
|
"mcp": [
|
|
{ "id": "crm", "tools": ["query", "update"] },
|
|
{ "id": "linkedin", "tools": ["search", "profile"] },
|
|
{ "id": "email", "tools": ["draft", "send"] }
|
|
]
|
|
},
|
|
"delivery": {
|
|
"type": "email",
|
|
"opts": { "to": ["sales-manager@company.com"] }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example: Sales manager assigns task:**
|
|
|
|
```
|
|
Sales Manager Input:
|
|
Action: task.add
|
|
Messages: [{ role: "user", content: "Meeting with BigCorp CTO tomorrow. Prepare materials.
|
|
They do smart manufacturing, $150M revenue, digital transformation." }]
|
|
|
|
Agent Execution (no P0 for human trigger):
|
|
P1 Goals (from human input):
|
|
1. Research BigCorp and their CTO
|
|
2. Prepare meeting brief
|
|
3. Draft customized proposal
|
|
|
|
P2 Tasks:
|
|
1. Research BigCorp → company-researcher
|
|
- Company background, recent news
|
|
- Digital transformation status
|
|
- Potential pain points
|
|
2. Research CTO profile → linkedin.profile
|
|
- Background, interests
|
|
- Recent posts/articles
|
|
3. Prepare meeting brief → proposal-writer
|
|
4. Draft proposal → proposal-writer
|
|
|
|
P3 Execute:
|
|
- BigCorp: Leading smart manufacturing, 3 factories, implementing MES
|
|
- CTO John: Ex-Google, focused on AI+Manufacturing, recent post on "AI QC"
|
|
- Pain point: High QC labor cost, 2% defect miss rate
|
|
- Opportunity: Our AI QC solution can reduce miss rate to 0.1%
|
|
|
|
P4 Delivery:
|
|
→ Email to sales manager:
|
|
- Attachment 1: BigCorp Research Report (PDF)
|
|
- Attachment 2: CTO Profile Brief
|
|
- Attachment 3: Custom Proposal - AI QC Solution
|
|
- Attachment 4: Meeting Agenda Suggestion
|
|
|
|
Sales Manager Follow-up:
|
|
Action: task.add
|
|
Messages: [{ role: "user", content: "Also prepare some similar case studies, manufacturing preferred" }]
|
|
|
|
Agent Continues:
|
|
P1: Find similar manufacturing case studies
|
|
P2: Search CRM for manufacturing wins
|
|
P3: Found 3 cases: Auto parts factory, Electronics plant, Food processing
|
|
P4: Email: "3 manufacturing case studies attached"
|
|
P5: Learn: Manufacturing prospects often need QC case studies
|
|
```
|
|
|
|
---
|
|
|
|
### 11.5 Lead Processor (Event: webhook)
|
|
|
|
**Trigger:** Event - new lead from website/CRM
|
|
|
|
**Role:** Instantly process and qualify new leads, route to sales.
|
|
|
|
```json
|
|
// robot_config for Lead Processor
|
|
{
|
|
"triggers": {
|
|
"clock": { "enabled": false },
|
|
"event": { "enabled": true }
|
|
},
|
|
"events": [
|
|
{
|
|
"type": "webhook",
|
|
"source": "/webhook/leads",
|
|
"filter": { "event_types": ["lead.created"] }
|
|
},
|
|
{
|
|
"type": "database",
|
|
"source": "crm_leads",
|
|
"filter": { "trigger": "insert" }
|
|
}
|
|
],
|
|
"identity": {
|
|
"role": "Lead Qualification Specialist",
|
|
"duties": [
|
|
"Instantly process new leads",
|
|
"Enrich lead data (company info, LinkedIn)",
|
|
"Score lead quality (1-100)",
|
|
"Route hot leads to sales immediately",
|
|
"Add cold leads to nurture sequence"
|
|
]
|
|
},
|
|
"resources": {
|
|
"agents": ["data-enricher", "lead-scorer"],
|
|
"mcp": [
|
|
{ "id": "clearbit", "tools": ["enrich"] },
|
|
{ "id": "crm", "tools": ["update", "assign"] },
|
|
{ "id": "email", "tools": ["send"] }
|
|
]
|
|
},
|
|
"delivery": {
|
|
"type": "webhook",
|
|
"opts": { "url": "https://slack.com/webhook/sales-leads" }
|
|
}
|
|
}
|
|
```
|
|
|
|
**Example: New lead event:**
|
|
|
|
```
|
|
Event Received:
|
|
Type: lead.created
|
|
Data: {
|
|
name: "John Smith",
|
|
email: "john@bigcorp.com",
|
|
company: "BigCorp",
|
|
message: "Interested in Enterprise pricing, team of 50"
|
|
}
|
|
|
|
Agent Execution (no P0 for events):
|
|
P1 Goals:
|
|
1. Enrich lead data
|
|
2. Score lead quality
|
|
3. Route appropriately
|
|
|
|
P2 Tasks:
|
|
1. Lookup company info → clearbit.enrich
|
|
2. Calculate lead score → lead-scorer
|
|
3. Update CRM → crm.update
|
|
4. Notify sales → slack webhook
|
|
|
|
P3 Execute:
|
|
- Company: BigCorp, 500 employees, Series C
|
|
- LinkedIn: VP of Engineering
|
|
- Lead Score: 85/100 (HOT)
|
|
- Reason: Enterprise inquiry, decision maker, funded company
|
|
|
|
P4 Delivery:
|
|
→ Slack: "🔥 HOT LEAD (85/100): John Smith @ BigCorp
|
|
- 500 employees, Series C
|
|
- Interested in Enterprise (50 seats)
|
|
- Assigned to: Sales Rep A"
|
|
→ CRM: Lead updated, assigned to Sales Rep A
|
|
→ Email to lead: "Thanks for your inquiry. Our sales rep will contact you within 1 hour."
|
|
|
|
P5 Learn:
|
|
- BigCorp profile saved for future reference
|
|
- VP-level leads from funded companies = high conversion
|
|
```
|