chore(format): 撤销误入提交的整体重排,并关闭本仓库的格式化器
# 发生了什么 pi-lens 内置「安全格式化」:它会自动安装 biome 并对**编辑过的文件**跑 `biome format --write`。本机原先没有任何 biome 配置,于是 biome 用它自己的 默认值 —— tab 缩进 + 双引号 —— 把文件整体重写。 我在19a3161那次提交里用了 `git add -A`,把这批与功能无关的重排一起扫了进去: 约 7000 行改动散落在 20 个文件上,使那次提交无法审查,还掩盖了 server/internal/handler/permission.go 的一处删行(实为文件末尾空行,无代码丢失)。 # 为什么是「关掉」而不是「配置成我们的风格」 试过把缩进/引号/lineWidth 全部对齐本仓库习惯(biome.json + space/2/single/ lineWidth 120):`biome format --write` 仍然改动 17 个文件。原因是本仓库从未按 biome 的规则排版过 —— 注释按语义换行、数组与调用按可读性手工折行, 这些无法由格式化器还原。也就是说只要格式化器开着,每次编辑都会产生与内容无关的 大面积 diff,把真正的改动埋掉。 因此 biome.jsonc 里 formatter 与 linter 都关闭:本仓库的静态检查由 tsc / go vet / tree-sitter / ast-grep 与各自测试套件承担,不引入会改动无关行的 自动修复。 (pi-lens 这一版把 format 服务的 enabled 硬编码为 true,没有配置开关, 所以只能在仓库侧用 biome 配置让它不动文件;已验证 `biome format --write` 对这些文件零改动。) # 本提交内容 把19a3161里除「有意改动」外的 20 个文件还原到重排前的样子。19a3161中真正有意的改动是 deploy/install.sh 的扩展注册与 plugins/pi-mail-bridge/extension/index.ts 新文件,两者原样保留。 验证:Go 全量、三桥插件(320/362/409)、前端 196 全绿; `biome format --write` 对还原后的文件零改动。
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -1,139 +1,139 @@
|
||||
export interface User {
|
||||
user_id: string;
|
||||
username: string;
|
||||
display_name: string;
|
||||
role: "admin" | "user";
|
||||
status: "active" | "disabled";
|
||||
allowed_agents: string[];
|
||||
allowed_paths: string[];
|
||||
last_login?: string;
|
||||
created_at?: string;
|
||||
user_id: string;
|
||||
username: string;
|
||||
display_name: string;
|
||||
role: 'admin' | 'user';
|
||||
status: 'active' | 'disabled';
|
||||
allowed_agents: string[];
|
||||
allowed_paths: string[];
|
||||
last_login?: string;
|
||||
created_at?: string;
|
||||
}
|
||||
|
||||
export interface Workspace {
|
||||
name: string;
|
||||
path: string;
|
||||
name: string;
|
||||
path: string;
|
||||
}
|
||||
|
||||
export interface Agent {
|
||||
agent_id?: string;
|
||||
agent_name: string;
|
||||
workspaces: Workspace[];
|
||||
platform: string;
|
||||
status: string;
|
||||
/** 派给该 Agent 的新任务默认多少个来回(0 = 不限) */
|
||||
default_rounds?: number;
|
||||
agent_id?: string;
|
||||
agent_name: string;
|
||||
workspaces: Workspace[];
|
||||
platform: string;
|
||||
status: string;
|
||||
/** 派给该 Agent 的新任务默认多少个来回(0 = 不限) */
|
||||
default_rounds?: number;
|
||||
}
|
||||
|
||||
export interface Address {
|
||||
name: string;
|
||||
path: string;
|
||||
session: string;
|
||||
raw: string;
|
||||
name: string;
|
||||
path: string;
|
||||
session: string;
|
||||
raw: string;
|
||||
}
|
||||
|
||||
export interface Session {
|
||||
session_id: string;
|
||||
session_alias: string | null;
|
||||
from_agent: string;
|
||||
subject: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
mail_count?: number;
|
||||
/**
|
||||
* 别名是谁定的:
|
||||
* platform = Agent 平台自动同步来的,后续同步可以覆盖
|
||||
* manual = 人显式指定(手工改名或接受了 Agent 的提议),平台同步不得覆盖
|
||||
*/
|
||||
alias_source?: "platform" | "manual";
|
||||
/** 用户驳回过的改名提议 */
|
||||
rename_dismissed?: string;
|
||||
/**
|
||||
* 本任务的往返预算(0 = 本会话不限,仅受 Agent 全局配额约束)。
|
||||
*
|
||||
* 配额的语义是「这件事值得多少个来回」—— 那是任务的属性而非 Agent 的属性,
|
||||
* 所以在写信时给、在对话页里随时调,而不是去管理员页面改某个 Agent 的全局配额。
|
||||
*/
|
||||
max_rounds?: number;
|
||||
used_rounds?: number;
|
||||
/** 权限档位:plan / workspace / full */
|
||||
permission_mode?: string;
|
||||
/** 档位实际强制力:native / advisory */
|
||||
permission_enforcement?: string;
|
||||
session_id: string;
|
||||
session_alias: string | null;
|
||||
from_agent: string;
|
||||
subject: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
mail_count?: number;
|
||||
/**
|
||||
* 别名是谁定的:
|
||||
* platform = Agent 平台自动同步来的,后续同步可以覆盖
|
||||
* manual = 人显式指定(手工改名或接受了 Agent 的提议),平台同步不得覆盖
|
||||
*/
|
||||
alias_source?: 'platform' | 'manual';
|
||||
/** 用户驳回过的改名提议 */
|
||||
rename_dismissed?: string;
|
||||
/**
|
||||
* 本任务的往返预算(0 = 本会话不限,仅受 Agent 全局配额约束)。
|
||||
*
|
||||
* 配额的语义是「这件事值得多少个来回」—— 那是任务的属性而非 Agent 的属性,
|
||||
* 所以在写信时给、在对话页里随时调,而不是去管理员页面改某个 Agent 的全局配额。
|
||||
*/
|
||||
max_rounds?: number;
|
||||
used_rounds?: number;
|
||||
/** 权限档位:plan / workspace / full */
|
||||
permission_mode?: string;
|
||||
/** 档位实际强制力:native / advisory */
|
||||
permission_enforcement?: string;
|
||||
}
|
||||
|
||||
/** 会话往返预算快照 */
|
||||
export interface SessionBudget {
|
||||
session_id: string;
|
||||
max_rounds: number;
|
||||
used_rounds: number;
|
||||
/** 不限时为 -1 */
|
||||
remaining: number;
|
||||
unlimited: boolean;
|
||||
session_id: string;
|
||||
max_rounds: number;
|
||||
used_rounds: number;
|
||||
/** 不限时为 -1 */
|
||||
remaining: number;
|
||||
unlimited: boolean;
|
||||
}
|
||||
|
||||
/** 附件元数据。内容存盘,按 sha256 内容寻址;同内容重复上传不占额外空间。 */
|
||||
export interface Attachment {
|
||||
attachment_id: string;
|
||||
/** 为 null 表示已上传但尚未随邮件发出 */
|
||||
mail_id: string | null;
|
||||
uploader: string;
|
||||
filename: string;
|
||||
content_type: string;
|
||||
size_bytes: number;
|
||||
sha256: string;
|
||||
created_at: string;
|
||||
attachment_id: string;
|
||||
/** 为 null 表示已上传但尚未随邮件发出 */
|
||||
mail_id: string | null;
|
||||
uploader: string;
|
||||
filename: string;
|
||||
content_type: string;
|
||||
size_bytes: number;
|
||||
sha256: string;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface Mail {
|
||||
mail_id: string;
|
||||
session_id: string;
|
||||
parent_mail_id: string | null;
|
||||
from_name: string;
|
||||
from_workspace: string;
|
||||
to_name: string;
|
||||
to_workspace: string;
|
||||
cc_list: Address[];
|
||||
subject: string;
|
||||
body: string;
|
||||
mail_type: "normal" | "permission_request";
|
||||
permission_options: string[] | null;
|
||||
permission_result: string | null;
|
||||
/**
|
||||
* 待办类型:`permission`(危险操作审批)/ `question`(模型主动提问)。
|
||||
*
|
||||
* 两者共用 permission_request 这个 mail_type,但**该渲染什么完全不同**:
|
||||
* 前者是「批准 / 拒绝」,后者是「回答问题」(勾选 + 自由文本)。
|
||||
* 混用一套 UI 会让人把「回答问题」当成「批准执行」。
|
||||
*/
|
||||
permission_kind?: string;
|
||||
/** 仅 question 使用:是否允许多选(对应 DSH 的 multi_select)。 */
|
||||
permission_multi_select?: boolean;
|
||||
status: "unread" | "read" | "archived";
|
||||
created_at: string;
|
||||
hop_limit?: number;
|
||||
session_alias?: string;
|
||||
/**
|
||||
* **这条会话**的工作目录(sessions.workspace)。
|
||||
*
|
||||
* 不能用 from_workspace / to_workspace 代替:
|
||||
* - 人 → Agent:to_workspace 是真路径,from_workspace 为空(人没有工作目录)
|
||||
* - Agent → 人:to_workspace 为空,而 **from_workspace 存的是 Agent 名**
|
||||
* 而不是路径(历史遗留)
|
||||
*
|
||||
* 于是「Agent 发来的这封信,那个 Agent 在哪个目录干活」只能从会话上取。
|
||||
* 界面上曾显示成 `dsh@dsh`,就是拿 from_workspace 当路径拼的。
|
||||
*/
|
||||
session_workspace?: string;
|
||||
body_preview?: string;
|
||||
attachments?: Attachment[];
|
||||
/** 发件方是人类用户而不是 Agent(服务端 EXISTS users 判的) */
|
||||
from_human: boolean;
|
||||
/** 收件方是人类用户而不是 Agent */
|
||||
to_human: boolean;
|
||||
permission_mode?: string;
|
||||
permission_enforcement?: string;
|
||||
mail_id: string;
|
||||
session_id: string;
|
||||
parent_mail_id: string | null;
|
||||
from_name: string;
|
||||
from_workspace: string;
|
||||
to_name: string;
|
||||
to_workspace: string;
|
||||
cc_list: Address[];
|
||||
subject: string;
|
||||
body: string;
|
||||
mail_type: 'normal' | 'permission_request';
|
||||
permission_options: string[] | null;
|
||||
permission_result: string | null;
|
||||
/**
|
||||
* 待办类型:`permission`(危险操作审批)/ `question`(模型主动提问)。
|
||||
*
|
||||
* 两者共用 permission_request 这个 mail_type,但**该渲染什么完全不同**:
|
||||
* 前者是「批准 / 拒绝」,后者是「回答问题」(勾选 + 自由文本)。
|
||||
* 混用一套 UI 会让人把「回答问题」当成「批准执行」。
|
||||
*/
|
||||
permission_kind?: string;
|
||||
/** 仅 question 使用:是否允许多选(对应 DSH 的 multi_select)。 */
|
||||
permission_multi_select?: boolean;
|
||||
status: 'unread' | 'read' | 'archived';
|
||||
created_at: string;
|
||||
hop_limit?: number;
|
||||
session_alias?: string;
|
||||
/**
|
||||
* **这条会话**的工作目录(sessions.workspace)。
|
||||
*
|
||||
* 不能用 from_workspace / to_workspace 代替:
|
||||
* - 人 → Agent:to_workspace 是真路径,from_workspace 为空(人没有工作目录)
|
||||
* - Agent → 人:to_workspace 为空,而 **from_workspace 存的是 Agent 名**
|
||||
* 而不是路径(历史遗留)
|
||||
*
|
||||
* 于是「Agent 发来的这封信,那个 Agent 在哪个目录干活」只能从会话上取。
|
||||
* 界面上曾显示成 `dsh@dsh`,就是拿 from_workspace 当路径拼的。
|
||||
*/
|
||||
session_workspace?: string;
|
||||
body_preview?: string;
|
||||
attachments?: Attachment[];
|
||||
/** 发件方是人类用户而不是 Agent(服务端 EXISTS users 判的) */
|
||||
from_human: boolean;
|
||||
/** 收件方是人类用户而不是 Agent */
|
||||
to_human: boolean;
|
||||
permission_mode?: string;
|
||||
permission_enforcement?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -145,30 +145,30 @@ export interface Mail {
|
||||
* depth 是**相对锚点**的层级:0 = 锚点,负数 = 祖先,正数 = 子孙。
|
||||
* 分块加载时根可能还没取到,所以不用「距根深度」。
|
||||
*/
|
||||
export interface ThreadNode extends Omit<Mail, "body"> {
|
||||
/** 距**线索根**的层级:0 = 根,1 = 它的直接回复 */
|
||||
depth: number;
|
||||
attachment_count: number;
|
||||
/** 父邮件不在当前已加载集合里(无权查看,或还没滑到) */
|
||||
detached?: boolean;
|
||||
/** 父邮件确实存在但无权查看(区别于「尚未加载」) */
|
||||
parent_hidden?: boolean;
|
||||
body?: string;
|
||||
export interface ThreadNode extends Omit<Mail, 'body'> {
|
||||
/** 距**线索根**的层级:0 = 根,1 = 它的直接回复 */
|
||||
depth: number;
|
||||
attachment_count: number;
|
||||
/** 父邮件不在当前已加载集合里(无权查看,或还没滑到) */
|
||||
detached?: boolean;
|
||||
/** 父邮件确实存在但无权查看(区别于「尚未加载」) */
|
||||
parent_hidden?: boolean;
|
||||
body?: string;
|
||||
}
|
||||
|
||||
export interface ThreadPage {
|
||||
anchor_mail_id: string;
|
||||
/** 线索根的 mail_id:整棵树从它展开 */
|
||||
root_mail_id: string;
|
||||
/** 锚点距根的层数,用于高亮定位 */
|
||||
anchor_depth: number;
|
||||
nodes: ThreadNode[];
|
||||
total: number;
|
||||
/** 因权限被过滤掉的节点数 */
|
||||
hidden: number;
|
||||
has_more: boolean;
|
||||
/** 下一页 offset,原样回传即可 */
|
||||
next_offset: number;
|
||||
anchor_mail_id: string;
|
||||
/** 线索根的 mail_id:整棵树从它展开 */
|
||||
root_mail_id: string;
|
||||
/** 锚点距根的层数,用于高亮定位 */
|
||||
anchor_depth: number;
|
||||
nodes: ThreadNode[];
|
||||
total: number;
|
||||
/** 因权限被过滤掉的节点数 */
|
||||
hidden: number;
|
||||
has_more: boolean;
|
||||
/** 下一页 offset,原样回传即可 */
|
||||
next_offset: number;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -179,69 +179,69 @@ export interface ThreadPage {
|
||||
* 提议 + 人点头,既让 Agent 表达意图,又保证寻址稳定性由人掌握。
|
||||
*/
|
||||
export interface RenameProposal {
|
||||
/** 已由服务端规范化,可直接提交给 PUT /sessions/:id/alias */
|
||||
alias: string;
|
||||
reason?: string;
|
||||
/** 已由服务端规范化,可直接提交给 PUT /sessions/:id/alias */
|
||||
alias: string;
|
||||
reason?: string;
|
||||
}
|
||||
|
||||
export interface Contact {
|
||||
session_id: string;
|
||||
agent_name: string;
|
||||
path: string;
|
||||
session_alias: string;
|
||||
address: string;
|
||||
status: string;
|
||||
mail_count: number;
|
||||
unread_count: number;
|
||||
last_activity: string;
|
||||
/** 会话主题(多由 Agent 平台的模型生成的摘要) */
|
||||
subject: string;
|
||||
/** 本任务的往返预算(0 = 不限) */
|
||||
max_rounds: number;
|
||||
used_rounds: number;
|
||||
permission_mode?: string;
|
||||
permission_enforcement?: string;
|
||||
/** 最后一封邮件的发件人与正文摘要(服务端已按字符截断) */
|
||||
last_from: string;
|
||||
last_preview: string;
|
||||
session_id: string;
|
||||
agent_name: string;
|
||||
path: string;
|
||||
session_alias: string;
|
||||
address: string;
|
||||
status: string;
|
||||
mail_count: number;
|
||||
unread_count: number;
|
||||
last_activity: string;
|
||||
/** 会话主题(多由 Agent 平台的模型生成的摘要) */
|
||||
subject: string;
|
||||
/** 本任务的往返预算(0 = 不限) */
|
||||
max_rounds: number;
|
||||
used_rounds: number;
|
||||
permission_mode?: string;
|
||||
permission_enforcement?: string;
|
||||
/** 最后一封邮件的发件人与正文摘要(服务端已按字符截断) */
|
||||
last_from: string;
|
||||
last_preview: string;
|
||||
}
|
||||
|
||||
export interface PermissionRequest {
|
||||
request_id: string;
|
||||
mail_id: string;
|
||||
session_id: string;
|
||||
agent_name: string;
|
||||
question: string;
|
||||
options: string[];
|
||||
context: string;
|
||||
result: string | null;
|
||||
decided_at: string | null;
|
||||
created_at: string;
|
||||
request_id: string;
|
||||
mail_id: string;
|
||||
session_id: string;
|
||||
agent_name: string;
|
||||
question: string;
|
||||
options: string[];
|
||||
context: string;
|
||||
result: string | null;
|
||||
decided_at: string | null;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
export interface SessionDetail {
|
||||
session: Session;
|
||||
mails: Mail[];
|
||||
session: Session;
|
||||
mails: Mail[];
|
||||
}
|
||||
|
||||
export interface HumanSession {
|
||||
session_id: string;
|
||||
session_alias: string | null;
|
||||
from_agent: string;
|
||||
subject: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
mail_count: number;
|
||||
unread_count: number;
|
||||
/** 本任务的往返预算(0 = 不限) */
|
||||
max_rounds?: number;
|
||||
used_rounds?: number;
|
||||
permission_mode?: string;
|
||||
permission_enforcement?: string;
|
||||
session_id: string;
|
||||
session_alias: string | null;
|
||||
from_agent: string;
|
||||
subject: string;
|
||||
status: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
mail_count: number;
|
||||
unread_count: number;
|
||||
/** 本任务的往返预算(0 = 不限) */
|
||||
max_rounds?: number;
|
||||
used_rounds?: number;
|
||||
permission_mode?: string;
|
||||
permission_enforcement?: string;
|
||||
}
|
||||
|
||||
export type SuggestKind = "name" | "path" | "session";
|
||||
export type SuggestKind = 'name' | 'path' | 'session';
|
||||
|
||||
/**
|
||||
* 会话候选项的来源。
|
||||
@ -249,38 +249,38 @@ export type SuggestKind = "name" | "path" | "session";
|
||||
* platform 平台侧会话镜像(人直接在 opencode/DSH 界面上开的)
|
||||
* new 新建会话的哨兵项
|
||||
*/
|
||||
export type SessionCandidateSource = "mail" | "platform" | "new";
|
||||
export type SessionCandidateSource = 'mail' | 'platform' | 'new';
|
||||
|
||||
export interface SessionCandidate {
|
||||
/** 填进 session 位的值 */
|
||||
alias: string;
|
||||
/** 给人看,用来分辨两条别名相似的会话在谈什么 */
|
||||
title?: string;
|
||||
source: SessionCandidateSource;
|
||||
/** 仅 mail 来源有意义 */
|
||||
unread?: number;
|
||||
/** 填进 session 位的值 */
|
||||
alias: string;
|
||||
/** 给人看,用来分辨两条别名相似的会话在谈什么 */
|
||||
title?: string;
|
||||
source: SessionCandidateSource;
|
||||
/** 仅 mail 来源有意义 */
|
||||
unread?: number;
|
||||
}
|
||||
|
||||
export interface SuggestResult {
|
||||
kind: SuggestKind;
|
||||
suggestions: string[];
|
||||
/**
|
||||
* 带标题与来源的完整候选,与 suggestions 同序。
|
||||
* 仅 kind === 'session' 时返回;suggestions 保留纯字符串形式是为了
|
||||
* 不打破已部署的前端与第三方客户端。
|
||||
*/
|
||||
candidates?: SessionCandidate[];
|
||||
kind: SuggestKind;
|
||||
suggestions: string[];
|
||||
/**
|
||||
* 带标题与来源的完整候选,与 suggestions 同序。
|
||||
* 仅 kind === 'session' 时返回;suggestions 保留纯字符串形式是为了
|
||||
* 不打破已部署的前端与第三方客户端。
|
||||
*/
|
||||
candidates?: SessionCandidate[];
|
||||
}
|
||||
|
||||
/** 系统初始化状态 */
|
||||
export interface SetupStatus {
|
||||
needs_setup: boolean;
|
||||
needs_setup: boolean;
|
||||
}
|
||||
|
||||
/** 管理员可授权范围候选 */
|
||||
export interface AdminScopes {
|
||||
agents: string[];
|
||||
paths: string[];
|
||||
agents: string[];
|
||||
paths: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
@ -291,58 +291,58 @@ export interface AdminScopes {
|
||||
* 对 Agent 来说就是一封普通邮件,它不知道也不需要知道信来自日历。
|
||||
*/
|
||||
export interface CalendarEvent {
|
||||
event_id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
/**
|
||||
* 提醒邮件的正文。留空时后端按 title/time/description 生成默认模板。
|
||||
* 支持 {title} {time} {description} 三个变量,触发时替换。
|
||||
*/
|
||||
reminder_text: string;
|
||||
/**
|
||||
* 收件 Agent 名 / 完整地址 —— **单收件人时代的字段**。
|
||||
* 保留作兼容与兜底:recipients 为空时才用它们。
|
||||
* 新代码一律用 effectiveRecipients()。
|
||||
*/
|
||||
agent_name: string;
|
||||
to_address: string;
|
||||
/**
|
||||
* 收件人列表,每项是完整三维地址串。
|
||||
*
|
||||
* 存原始串而不是结构化地址:session 位的 new/别名三态该在**触发那一刻**
|
||||
* 解析。存结构化的话「.new」这种一次性语义在建事件时就被固化,
|
||||
* 而重复事件每次触发都该重新决定落到哪条会话。
|
||||
*/
|
||||
recipients: string[];
|
||||
/**
|
||||
* 多收件人的投递方式。
|
||||
* separate = 各发一封、落各自会话、互相看不到
|
||||
* together = 首个为主收件人,其余进抄送、共享同一条线索
|
||||
*
|
||||
* 两种都要而不是二选一:「三个 Agent 各自独立汇报」与「pi 主办、dsh 知情」
|
||||
* 是完全不同的任务形态。用错 together 会让本该独立判断的 Agent 互相
|
||||
* 看到回复而趋同,那种污染事后无法分离。
|
||||
*/
|
||||
delivery_mode: DeliveryMode;
|
||||
/** ISO 8601 */
|
||||
event_time: string;
|
||||
/** 提前多少分钟提醒;0 = 到点才提醒 */
|
||||
remind_before: number;
|
||||
recurrence: Recurrence;
|
||||
/** 重复终止时间;越过它事件自动置为 cancelled */
|
||||
recurrence_end?: string;
|
||||
status: "active" | "paused" | "cancelled";
|
||||
/** 上次触发的墙上时钟 */
|
||||
last_fired_at?: string;
|
||||
/**
|
||||
* 已触发的那个 occurrence(值 = 当时的 event_time)。
|
||||
* 去重靠它与 event_time 相等判断,不是拿 last_fired_at 比大小 ——
|
||||
* 后端 DueEvents 有 60 秒 lookahead,后者在窗口内恒为真会导致每 tick 重发。
|
||||
*/
|
||||
fired_for?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: string;
|
||||
event_id: string;
|
||||
title: string;
|
||||
description: string;
|
||||
/**
|
||||
* 提醒邮件的正文。留空时后端按 title/time/description 生成默认模板。
|
||||
* 支持 {title} {time} {description} 三个变量,触发时替换。
|
||||
*/
|
||||
reminder_text: string;
|
||||
/**
|
||||
* 收件 Agent 名 / 完整地址 —— **单收件人时代的字段**。
|
||||
* 保留作兼容与兜底:recipients 为空时才用它们。
|
||||
* 新代码一律用 effectiveRecipients()。
|
||||
*/
|
||||
agent_name: string;
|
||||
to_address: string;
|
||||
/**
|
||||
* 收件人列表,每项是完整三维地址串。
|
||||
*
|
||||
* 存原始串而不是结构化地址:session 位的 new/别名三态该在**触发那一刻**
|
||||
* 解析。存结构化的话「.new」这种一次性语义在建事件时就被固化,
|
||||
* 而重复事件每次触发都该重新决定落到哪条会话。
|
||||
*/
|
||||
recipients: string[];
|
||||
/**
|
||||
* 多收件人的投递方式。
|
||||
* separate = 各发一封、落各自会话、互相看不到
|
||||
* together = 首个为主收件人,其余进抄送、共享同一条线索
|
||||
*
|
||||
* 两种都要而不是二选一:「三个 Agent 各自独立汇报」与「pi 主办、dsh 知情」
|
||||
* 是完全不同的任务形态。用错 together 会让本该独立判断的 Agent 互相
|
||||
* 看到回复而趋同,那种污染事后无法分离。
|
||||
*/
|
||||
delivery_mode: DeliveryMode;
|
||||
/** ISO 8601 */
|
||||
event_time: string;
|
||||
/** 提前多少分钟提醒;0 = 到点才提醒 */
|
||||
remind_before: number;
|
||||
recurrence: Recurrence;
|
||||
/** 重复终止时间;越过它事件自动置为 cancelled */
|
||||
recurrence_end?: string;
|
||||
status: 'active' | 'paused' | 'cancelled';
|
||||
/** 上次触发的墙上时钟 */
|
||||
last_fired_at?: string;
|
||||
/**
|
||||
* 已触发的那个 occurrence(值 = 当时的 event_time)。
|
||||
* 去重靠它与 event_time 相等判断,不是拿 last_fired_at 比大小 ——
|
||||
* 后端 DueEvents 有 60 秒 lookahead,后者在窗口内恒为真会导致每 tick 重发。
|
||||
*/
|
||||
fired_for?: string;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
created_by: string;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -353,38 +353,38 @@ export interface CalendarEvent {
|
||||
* 也没有 lunar_weekly(农历没有「周」这个单位)。
|
||||
*/
|
||||
export type Recurrence =
|
||||
| "none"
|
||||
| "daily"
|
||||
| "weekly"
|
||||
| "monthly"
|
||||
| "yearly"
|
||||
| "lunar_monthly"
|
||||
| "lunar_yearly";
|
||||
| 'none'
|
||||
| 'daily'
|
||||
| 'weekly'
|
||||
| 'monthly'
|
||||
| 'yearly'
|
||||
| 'lunar_monthly'
|
||||
| 'lunar_yearly';
|
||||
|
||||
export type DeliveryMode = "separate" | "together";
|
||||
export type DeliveryMode = 'separate' | 'together';
|
||||
|
||||
/** 事件附件(随提醒邮件一起发出) */
|
||||
export interface CalendarAttachment {
|
||||
attachment_id: string;
|
||||
event_id: string;
|
||||
filename: string;
|
||||
sha256: string;
|
||||
size_bytes: number;
|
||||
created_at: string;
|
||||
attachment_id: string;
|
||||
event_id: string;
|
||||
filename: string;
|
||||
sha256: string;
|
||||
size_bytes: number;
|
||||
created_at: string;
|
||||
}
|
||||
|
||||
/** 新建/编辑事件的请求体。event_time 必填,其余可省。 */
|
||||
export interface CalendarEventInput {
|
||||
title: string;
|
||||
description?: string;
|
||||
reminder_text?: string;
|
||||
agent_name?: string;
|
||||
to_address?: string;
|
||||
recipients?: string[];
|
||||
delivery_mode?: DeliveryMode;
|
||||
event_time: string;
|
||||
remind_before?: number;
|
||||
recurrence?: Recurrence;
|
||||
recurrence_end?: string | null;
|
||||
status?: "active" | "paused" | "cancelled";
|
||||
title: string;
|
||||
description?: string;
|
||||
reminder_text?: string;
|
||||
agent_name?: string;
|
||||
to_address?: string;
|
||||
recipients?: string[];
|
||||
delivery_mode?: DeliveryMode;
|
||||
event_time: string;
|
||||
remind_before?: number;
|
||||
recurrence?: Recurrence;
|
||||
recurrence_end?: string | null;
|
||||
status?: 'active' | 'paused' | 'cancelled';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user