fix(agent): 修复 skill action 卡片调用约定、memory 强类型校验和死代码清理
- 所有 calendar action .md: skill/action 替换为 module/method + mode 字段 - handler_memory: 新增 Pydantic extra=forbid 模型替代手工 dict 校验 - memory/SKILL.md: 补充 UserMemoryContent/WorkProfileContent 全字段文档 - 移除 handler_calendar 死代码 _batch_status 和 runner 旧别名 AgentScopeReActRunner - PRD §5.2-5.6 和 sse-events 协议对齐实际 module/method 实现
This commit is contained in:
@@ -324,13 +324,14 @@ The worker still sees only:
|
||||
|
||||
## 5.2 New `project_cli` model-facing input contract
|
||||
|
||||
The new canonical model-facing payload is:
|
||||
The canonical model-facing payload is:
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "get_event",
|
||||
"module": "calendar",
|
||||
"method": "read",
|
||||
"input": {
|
||||
"mode": "event",
|
||||
"event_id": "<uuid>"
|
||||
}
|
||||
}
|
||||
@@ -338,91 +339,79 @@ The new canonical model-facing payload is:
|
||||
|
||||
Field meanings:
|
||||
|
||||
- `skill`: enabled business skill namespace
|
||||
- `action`: concrete business operation inside the skill
|
||||
- `input`: strict action-specific payload
|
||||
- `module`: enabled business module namespace (calendar, contacts, memory)
|
||||
- `method`: concrete business operation inside the module
|
||||
- `input`: strict method-specific payload
|
||||
|
||||
This is still one tool call. The worker is not choosing among many tools.
|
||||
|
||||
## 5.3 Calendar action protocol
|
||||
## 5.3 Calendar method protocol
|
||||
|
||||
The calendar skill should be redesigned around real business actions derived from `schedule_items` and `schedule_subscriptions`.
|
||||
The calendar module exposes the following methods registered in the CLI router:
|
||||
|
||||
### Event actions
|
||||
| Module | Method | Handler | Input Shape |
|
||||
|----------|----------------|----------------------------------|-------------|
|
||||
| calendar | read | `handle_calendar_list_day` | discriminated by `mode` |
|
||||
| calendar | create | `handle_calendar_create_event` | title, start_at, timezone, ... |
|
||||
| calendar | update | `handle_calendar_update_event` | event_id + patch |
|
||||
| calendar | delete | `handle_calendar_delete_event` | event_id |
|
||||
| calendar | share | `handle_calendar_invite_subscriber` | event_id, invitee, permissions |
|
||||
| calendar | accept_invite | `handle_calendar_accept_invite` | event_id |
|
||||
| calendar | reject_invite | `handle_calendar_reject_invite` | event_id |
|
||||
|
||||
1. `list_day`
|
||||
2. `list_range`
|
||||
3. `get_event`
|
||||
4. `create_event`
|
||||
5. `update_event`
|
||||
6. `delete_event`
|
||||
|
||||
### Subscription actions
|
||||
|
||||
1. `invite_subscriber`
|
||||
2. `accept_invite`
|
||||
3. `reject_invite`
|
||||
|
||||
### Why this action set
|
||||
|
||||
This set directly maps to current product behavior:
|
||||
|
||||
- user asks what is scheduled today -> `list_day`
|
||||
- user asks what is scheduled this week -> `list_range`
|
||||
- user asks for a known event's details -> `get_event`
|
||||
- user creates or edits a schedule item -> `create_event` / `update_event`
|
||||
- user removes a schedule item -> `delete_event`
|
||||
- user invites another person -> `invite_subscriber`
|
||||
- invite recipient responds -> `accept_invite` / `reject_invite`
|
||||
The `read` method uses a discriminated union with `mode` field to dispatch to list_day, list_range, or get_event internally.
|
||||
|
||||
This avoids overloading one label like `read` for two distinct business tasks.
|
||||
|
||||
## 5.4 Canonical calendar action shapes
|
||||
## 5.4 Canonical calendar method shapes
|
||||
|
||||
### `list_day`
|
||||
### `read` with mode=day (list one day)
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "list_day",
|
||||
"module": "calendar",
|
||||
"method": "read",
|
||||
"input": {
|
||||
"mode": "day",
|
||||
"date": "2026-04-23",
|
||||
"timezone": "Asia/Shanghai"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `list_range`
|
||||
### `read` with mode=range (list time range)
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "list_range",
|
||||
"module": "calendar",
|
||||
"method": "read",
|
||||
"input": {
|
||||
"mode": "range",
|
||||
"start_at": "2026-04-23T00:00:00+08:00",
|
||||
"end_at": "2026-04-24T00:00:00+08:00"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `get_event`
|
||||
### `read` with mode=event (get by ID)
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "get_event",
|
||||
"module": "calendar",
|
||||
"method": "read",
|
||||
"input": {
|
||||
"mode": "event",
|
||||
"event_id": "<uuid>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `create_event`
|
||||
### `create`
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "create_event",
|
||||
"module": "calendar",
|
||||
"method": "create",
|
||||
"input": {
|
||||
"title": "Project sync",
|
||||
"start_at": "2026-04-23T16:00:00+08:00",
|
||||
@@ -439,12 +428,12 @@ This avoids overloading one label like `read` for two distinct business tasks.
|
||||
}
|
||||
```
|
||||
|
||||
### `update_event`
|
||||
### `update`
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "update_event",
|
||||
"module": "calendar",
|
||||
"method": "update",
|
||||
"input": {
|
||||
"event_id": "<uuid>",
|
||||
"patch": {
|
||||
@@ -457,24 +446,24 @@ This avoids overloading one label like `read` for two distinct business tasks.
|
||||
}
|
||||
```
|
||||
|
||||
### `delete_event`
|
||||
### `delete`
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "delete_event",
|
||||
"module": "calendar",
|
||||
"method": "delete",
|
||||
"input": {
|
||||
"event_id": "<uuid>"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### `invite_subscriber`
|
||||
### `share`
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "invite_subscriber",
|
||||
"module": "calendar",
|
||||
"method": "share",
|
||||
"input": {
|
||||
"event_id": "<uuid>",
|
||||
"invitee": {
|
||||
@@ -493,8 +482,8 @@ This avoids overloading one label like `read` for two distinct business tasks.
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "accept_invite",
|
||||
"module": "calendar",
|
||||
"method": "accept_invite",
|
||||
"input": {
|
||||
"event_id": "<uuid>"
|
||||
}
|
||||
@@ -505,8 +494,8 @@ This avoids overloading one label like `read` for two distinct business tasks.
|
||||
|
||||
```json
|
||||
{
|
||||
"skill": "calendar",
|
||||
"action": "reject_invite",
|
||||
"module": "calendar",
|
||||
"method": "reject_invite",
|
||||
"input": {
|
||||
"event_id": "<uuid>"
|
||||
}
|
||||
@@ -556,21 +545,26 @@ This makes `view_skill_file` a real progressive-disclosure mechanism instead of
|
||||
|
||||
## 5.6 Error contract for self-correction
|
||||
|
||||
The redesigned CLI should return structured action-level validation feedback.
|
||||
The redesigned CLI returns structured validation feedback with field-level detail.
|
||||
|
||||
Canonical error example:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "failure",
|
||||
"ok": false,
|
||||
"module": "calendar",
|
||||
"method": "read",
|
||||
"error": {
|
||||
"code": "INVALID_ACTION_INPUT",
|
||||
"message": "action list_range requires start_at and end_at",
|
||||
"skill": "calendar",
|
||||
"action": "list_range",
|
||||
"missing_fields": ["start_at", "end_at"],
|
||||
"unexpected_fields": ["event_id"],
|
||||
"suggested_alternative_actions": ["get_event"]
|
||||
"message": "input does not match method schema",
|
||||
"retryable": false,
|
||||
"details": {
|
||||
"missing_fields": ["start_at", "end_at"],
|
||||
"invalid_fields": [],
|
||||
"alias_corrections": {
|
||||
"start_time": "start_at"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Reference in New Issue
Block a user