Assistant Mode · templateCode = ASSISTANT

一个助理,一段不分段的对话

统一会话的 7×24 协同助理:善用记忆与数据、代你行动、委派长程、回答可追溯

Tanka 的 Assistant 模式不是「一问一答的机器人」,而是一个 7×24 在线的 Tanka AI 助理——Tanka 的核心是企业协同。它在同一个会话里长期工作:没有「新建会话」的概念,同一个 room_id 就是它全部的记忆锚点。它以用户的第一人称视角代为产出与对外沟通(替你写文章、起草发言、发消息,而不是用旁观者口吻),但本质是助理:凡代表你做的关键动作都要先经你授权。它向内拥有持久的检查点与工作区,向外伸出五条能力触手:长期记忆、第一方数据、第一方 Action API、第三方 Link 数据、第三方 Link API;面对漫长或复杂的工作,它会委派(handoff)给专属的 flow session 并从这个座位上掌舵,结果以 session_report 自动回传;而它给出的每个结论都可追溯到真实来源(引用)

会话模型 · room_id = thread_id,不分 session 模式 · templateCode = ASSISTANT 能力 · 5 触手 + 委派 + 引用 入口 · POST /api/tanka/work/stream_chat
§ 00

设计公理

在看模块图之前,先认同五条立场——它们决定了后面每一个机制为什么是这样设计的。来源:assistant/prompts/assistant.jinja 的 agent_identity 与 handoff 心智块。

Identity

用户视角,本质是助理

这是一个 7×24 在线的 Tanka AI 助理(Tanka 核心是企业协同)。它以用户的第一人称视角替你产出与对外沟通——写文章、起草发言、发消息时用「我」而非旁观者口吻;但它本质是助理、不是你本人:凡代表你做的关键动作(对外可见的创建 / 变更 / 删除)都要先经你授权

Availability + Handoff

可用是职责,委派是选择

默认不是「好的」,而是「我来办」。保持可用是职责——不把自己埋进长任务;大活委派给专属 flow session 并从这个座位掌舵。委派是为了保持可用,不是能力上限:它本可以亲自做。

Evidence-first

先取证,不靠记忆

对人和对象动作前,现查 ID、现读状态,绝不凭对话里记得的旧值。给出结论时还要标明来源(引用)。这是正确性与可信的地基。

Communicate-first

行动前先言明

代表用户行动前先announce、先gather context、先draft plan 再confirm。读操作可以主动,写操作必须经人审(HITL)。

Continuity

一段连续的关系

不分 session 意味着上下文、授权、待办、工作区都沉淀在同一条时间线上。压缩与 Turn Summary 让这条线可以无限延长而不丢事实。

§ 01

顶层架构

用户与一个统一会话内核对话;内核向「读/感知」「写/行动」「委派/长程」三个方向伸出能力。读路径自由,写路径过 HITL,长程路径委派给子会话、结果经 session_messaging 收件箱自动回传。仅 templateCode=ASSISTANT 的房间开放委派(create/send)。

图 A · Assistant 顶层模块
Assistant 顶层模块架构图:中央统一会话内核(Flow Agent · ASSISTANT + checkpoint room_id=thread_id + Workspace VFS)连接用户,并向读·感知(① 长期记忆 / ② 第一方数据 / ④ 第三方 Link 数据)、写·行动 HITL(③ 第一方 Action API / ⑤ 第三方 Link API)、委派·长程 Handoff(⑥ 委派 flow session create/send / ⑥ reminder 异步跟进)三束能力发散;一枚 ⑦ 引用 Citation 徽标表示来源可追溯;写路径回弹确认卡、委派/长程路径以 session_report 与 pull-wakeup 回传。
读路径(绿底→米底)自由调用;写路径(→琥珀)经确认卡;委派/长程路径(→灰底)以 session_report、pull-wakeup 经 session_messaging 回传;⑦ 引用贯穿读路径,结论可追溯。

这张图回答一个问题:同一个助理,如何既"懂我"又"能替我办事"还能"盯着长期的事"? 答案是把能力按数据流向分成三束。读/感知束让它先理解——从长期记忆、第一方业务数据、第三方文件中取证,并给结论标注来源(引用);写/行动束让它落地——但每个对外可见的动作都被一张确认卡拦在用户面前;委派/长程束让它跨越单次回合的边界——把漫长或复杂的工作委派给专属 flow session(create/send),自己留在座位上保持可用,结果以 session_report 经 session_messaging 收件箱自动回到这条会话时间线。

§ 02

统一会话内核

"不分 session"不是省略,而是一种刻意的设计:单一会话、近乎无限的上下文——用一个稳定的 room_id 作为全部状态的锚,让记忆、授权与工作产物在一条时间线上累积;近期原样在场,远期压缩成摘要,要原文时再按检索回捞。

图 B · 一个回合的生命周期(内核视角)
graph LR IN["用户消息<br/>organize_messages 挂载附件/备忘/房间"] --> LOAD["加载 checkpoint<br/>thread_id = room_id"] LOAD --> CTX["注入上下文<br/>系统提醒 + 技能目录 + 历史"] CTX --> LLM["模型回合<br/>abefore_model 压缩预处理"] LLM --> ACT{"要行动?"} ACT -->|读取| READ["search / im_* / MCP 只读"] ACT -->|写入| HITL["确认卡 HITL → tanka_api / MCP 写"] ACT -->|长程| FORK["委派子会话 / 设 reminder"] READ --> LLM HITL --> LLM LLM --> SAVE["保存 checkpoint + Turn Summary<br/>outline.md / 原始 chunk"] SAVE --> IN style LLM fill:#c8e6c9 style HITL fill:#ffe0b2
同一 room_id 的每个回合都从同一份 checkpoint 续写;Turn Summary 双轨备份让历史可压缩、可回溯。

三个让对话"长得了"的机制

单一锚点
room_id 即 langgraph checkpointer 的 thread_id。messages、always_allow 授权、action_log、pending 确认全部随 AsyncPostgresSaver 持久化。重启不丢、跨天续写。
上下文分层
近期发生的事原样留在上下文;远期对话被压缩成摘要——Claude 走 ClaudeCompressionMiddleware(cache_edits 增量),Gemini 走 TankaCompressionMiddleware(30K 触发 / 60K 摘要),让近乎无限的历史维持在预算内。
原文可回捞
摘要不是终点:TurnSummaryMiddleware 每回合写 outline.md(一行索引)+ 原始 chunk(滚动全文),并提供原始对话查询 API——压缩后的助理读索引,需要时按检索回到历史对话的原文,"事实永不丢失"。
§ 03

能力版图:读 · 写 · 委派 · 可追溯

五条数据/Action 触手覆盖"读什么、写什么、内外之分";再加两项贯穿能力——把长程交给子会话的委派,以及给每个结论标注真实来源的引用。读自由、写过审、委派回传、引用可溯。

① 读 · 感知

长期记忆

agentic memory · Tanka Work Memory

被 AI 深度处理、跨会话沉淀的记忆——不是原始消息,而是从中提炼出的结构化记忆。(原始第一方数据见 ②、第三方文件见 ④,此处不重复。)经 search_tools 检索召回。

  • 情景记忆 Episodic Memory
  • Worklog(Tanka Work Memory)
  • 用户画像 Profile · 偏好 Preference
  • 语义记忆 Semantic · 实体/关系/行为
  • RunMode:WORK / COMPANION
② 读 · 感知

第一方数据

im_* handlers · GET 路由(免确认)

Tanka 平台原生业务对象的精确读取,结构化、可过滤。

  • 消息 / 群 / 联系人(人与群)
  • 日历 / 会议(Zoom 摘要)
  • 邮件 / 备忘 / 投票
  • Followup 待办 · 可用时段查询
③ 写 · 行动

第一方 Action API

tanka_api + RouteRegistry · HITL

约 22 个写操作,经 ConfirmationSpec 渲染确认卡,提交到 TankaServerAPI 后端。

  • 发消息 · 建群 · 增/删成员
  • 建/改/取消日历 · 建会议
  • 发邮件 · 建/操作投票
  • 导入/起草备忘 · Followup 派发
④ 读 · 感知

第三方 Link 数据

MCP 只读 + 文件入记忆

已绑定第三方应用的只读访问;部分文件型数据(Dropbox/GDrive/Notion)直接进入长期记忆索引。

  • 工具名前缀判定只读(list_/get_/search_…)
  • Jira/Linear/GitHub/Confluence 读
  • 云盘/文档/表格读
  • italent 等纯读应用
⑤ 写 · 行动

第三方 Link API

MCP 写工具 · 三种传输

第三方应用的写操作,统一经 POST /thirdparty/{app},同样过确认卡,未绑定则引导绑定。

  • oh-link 网关(多数应用)
  • direct OAuth(huggingFace/apify)
  • PipeDream(clickup/line/…)
  • 26 个 enabled app
⑥ 委派 · 长程

委派与提醒

flow_session_manage · reminder · 仅 ASSISTANT

跨越单次回合:大活委派给可复用的 flow session;需要盯的事设成 reminder(异步跟进),由事件/时间触发自动回来;两者都经 session_messaging 收件箱回传或唤醒。底层由 wait_task 引擎驱动。

  • 委派 handoff:create / send / list / get / semantic_search
  • reminder 异步跟进:事件 CHAT/EMAIL/ARENA/VOTE · 时间 POINT/CRON
  • 回传:session_report / reminder 触发经 NOTIFY
  • INV-1:ROOT 可派生,DERIVED 不可再生
⑦ 贯穿 · 可追溯

引用 Citation

CitationMiddleware · 仅 ASSISTANT

读到的每条数据都能成为可点击的来源:结论里嵌 ref_N 标记,落地为 source:// 深链,答案成为一条可回溯的信息链。

  • 可引用:聊天/备忘/邮件/日历/联系人/文件
  • ref_N 标记 → source:// 深链
  • referenceSources SSE 事件给前端
  • 只引真实来源,绝不杜撰

跨源检索:把记忆与数据"想起来"

检索不是外部服务,而是助理自己的 agentic 行为:它自行决定打法、发起检索、判断够不够、不够就再来一轮。打法有两种,由 query_rewrite_and_route 按任务意图自行路由:

泛场景 · 目标模糊
先用高价值 / 高命中概率的能力做广度扫描,锁定线索后,再用具体数据 API 深度下钻。先广后深,避免一上来就盲目并发。
明确目标
已知要找什么时直接并发多源检索,一次打捞,不绕广度扫描这一步。

两种打法的召回结果都先经 rerank 重排去重 + 预处理,助理再据此判断是否够用——下图是助理这套自驱的检索回路。

图 C · 助理自驱的 agentic 检索(两种打法)
graph LR Q(["助理发起检索"]) --> RT{"自行判断<br/>目标是否明确?"} RT -->|明确目标| MS["并发多源检索<br/>tanka_search 跨源 + web_search<br/>一次打捞"] RT -->|泛场景 · 模糊| BR["广度扫描<br/>高价值 / 高命中能力优先"] BR --> DP["深度下钻<br/>具体数据 API 精取"] MS --> RR["rerank_results<br/>重排去重 + 预处理"] DP --> RR RR --> EV{"助理判断<br/>够不够 · 满意度 ≥ 80?"} EV -->|否 · 自己再来一轮| RT EV -->|是| OUT(["助理据结果继续作答 / 行动"]) style Q fill:#c8e6c9 style OUT fill:#c8e6c9 style BR fill:#fbf7ee style DP fill:#fbf7ee
整条回路都是助理自己的 agentic 行为:它发起检索、选打法、判断够不够、不够就再来一轮——不是外部服务把结果"塞回"它的上下文。

委派与回传:Handoff + session_messaging

委派的判据不是任务看起来多大,而是「回完这句话,事情是否就结束了」:一次性问答留在主会话;有下一轮的工作(草稿要评审、交付物要修订、一条线要持续跟进)交给一个能承载这条弧线的 flow session。flow session 是耐用的——可复用、可数月承接一条线;房间格局属于用户,先 list 看已有房间、把活路由到已经在做这条线的房间,别为一句话能办完的事新开房间。委派后 send 持续追加指令(fire-and-forget),完成时结果自动回传

所有「回传/唤醒」都走统一的 session_messaging 收件箱:子会话完成 → COMPLETION(即 session_report,带摘要 + 产物);子会话撞到确认卡 → NEEDS_CONFIRMATION 回报父助理;reminder 触发 → NOTIFY。投递采用 TankaServerAPI pull-wakeup:push 只是「有事了」的信号(best-effort),真正的真相源是 pull /work/watcher/events 的 drain——按 immediate / deferred / passive 的 activation 分桶,稳定 message_id 保证不丢不重。

图 E · 委派、等待与 session_messaging 回传
graph TB A(["助理 · ASSISTANT 房间"]) A -->|create 委派 / send 追加| CH["flow session 子会话<br/>DERIVED · 耐用可复用 · 独立工作区"] A -.->|设 reminder| WT["reminder 异步跟进<br/>事件 CHAT/EMAIL/ARENA/VOTE<br/>时间 POINT/CRON"] CH -->|"完成 → session_report(摘要 + 产物)"| BOX[("session_messaging 收件箱<br/>SessionMessage · 稳定 message_id")] CH -.->|"子会话待确认 → NEEDS_CONFIRMATION"| BOX WT -->|"触发 → NOTIFY"| BOX BOX -->|"push:仅信号 (best-effort)"| MM["TankaServerAPI"] MM -->|"pull /work/watcher/events 才是真相 · drain 合并"| A style A fill:#c8e6c9 style BOX fill:#fbf7ee
旧的 dispatch-CAS / M2 唤醒 / event_outbox 已被取代——委派关系只靠 parent_room_id,回传只走 session_messaging,子会话可复用、不进终态。

可追溯回答:引用与来源

助理读到的数据不止用于作答,还能成为可点击的来源。整条链路由 CitationMiddleware(仅 ASSISTANT 房间挂载)驱动:读类 tanka_api 结果带回 source_items,中间件在 awrap_tool_call登记来源、发号 ref_N 并把 ref 注入工具结果 XML(原始 artifact 阅后即焚,不进 checkpoint);助理在文本里用 #ref_N 标注;stream rewriter 边出边把标记改写成 source:// 深链,并在结尾发一个 referenceSources SSE 事件给前端;回合结束再把 ref 标记从历史里剥干净。铁律:只引真实发过号的 ref、绝不杜撰,同源去重、按出现顺序排列。可引用的对象覆盖聊天消息、备忘、邮件、日历、联系人、链接与文件。

图 F · 引用链路:从读结果到可点击来源
graph LR T["tanka_api 读结果<br/>search / list / get"] --> REG["CitationMiddleware<br/>awrap_tool_call:登记来源 → 发号 ref_N"] REG --> INJ["把 ref 注入工具结果 XML<br/>原始 artifact 阅后即焚"] INJ --> LLM["助理作答<br/>文本里标注 #ref_N"] LLM --> RW["stream rewriter<br/>#ref_N 改写成 source:// 深链"] RW --> UI["前端 referenceSources 事件<br/>可点击来源"] LLM -.->|回合结束| STRIP["aafter:从历史剥除 ref 标记"] style REG fill:#c8e6c9 style UI fill:#fbf7ee
per-turn registry 登记号、awrap_tool_call 注入、stream rewriter 落地深链、aafter 清洗历史——非 ASSISTANT 场景不挂此链,零开销。
§ 04

用户 ↔ 助理 用例

把上面的设计放进真实对话。每个用例标注「在起作用的能力」,看同一套机制如何应对不同场景。

用例 01 · 读 · 感知

跨源晨间回顾

"我昨天错过了什么重要的事?"

助理先用跨源检索召回近期第一方数据(聊天/邮件/备忘/投票),并结合你的长期记忆(画像 / Worklog)判断什么值得关注,再用第一方数据精确拉取细节,按主题归纳成简报——每条结论都带可点击来源(引用)。不是把信息倒给你,而是替你判断什么重要、且每句都可回溯。

交互时序
sequenceDiagram participant U as 用户 participant A as 助理 (Flow Agent) participant S as search_tools participant IM as im_* 第一方数据 U->>A: 我昨天错过了什么重要的事? A->>S: 检索 memory_cellular(聊天/邮件/备忘/投票) S-->>A: 跨源召回 + 语义重排结果 A->>IM: GET /im/messages · /im/emails · /im/votes (近 1 天) IM-->>A: 结构化第一方数据 A-->>U: 分主题简报 + @[相关人] + 待办建议(每条带 source:// 来源)
能力映射 ① 长期记忆 ② 第一方数据 ⑦ 引用
用例 02 · 写 · 行动

代我办事

"建个 Q3 复盘群把张三李四拉进来,约周四下午的会。"

助理先现查联系人 ID(不靠记忆)并 Precheck(群成员数、时段空闲),再把"建群 + 日历邀请"渲染成确认卡。用户可逐项 approve / edit / reject,也可对"建群"选 always-allow——此后同类操作本会话内免确认。

交互时序
sequenceDiagram participant U as 用户 participant A as 助理 participant P as Permission / HITL participant API as tanka_api → TankaServerAPI U->>A: 建"Q3 复盘"群拉上张三李四, 约周四下午 A->>A: 解析联系人(现查 ID) + Precheck(群≥成员 / 时段空闲) A->>P: 提交确认: 创建群 + 日历邀请 P-->>U: PENDING 卡 (approve / edit / reject / always-allow) U->>P: approve, 并对"建群"选 always-allow P->>API: POST /im/create_group · POST /im/calendar API-->>A: SUCCESS (group_id, calendar_id) A-->>U: 已建群并发出会议邀请, 周四 15:00
能力映射 ② 第一方数据 ③ 第一方 Action
用例 04 · 长程 · 提醒

长程提醒与唤醒

"等财务回复'预算'那封邮件,就提醒我,并帮我起草下一步。"

这超出了单次回合——助理设一个 EVENT_EMAIL reminder(异步跟进),本回合即结束,会话保持但不阻塞。数小时后财务回信,单实例 Kafka 消费者判级 COMPLETE,以 NOTIFY 投进 session_messaging 收件箱(deferred activation、稳定 message_id);TankaServerAPI 在合适时机 pull /work/watcher/events、drain 渲染成提醒注入新回合,助理"想起来"该接着办了。push 只是信号,pull 才是真相——不丢不重。

交互时序(跨数小时)
sequenceDiagram participant U as 用户 participant A as 助理 participant W as reminder participant K as Kafka 消费者 U->>A: 等财务回复预算邮件就提醒我并起草下一步 A->>W: 设 EVENT_EMAIL reminder,盯预算邮件回复 Note over A,U: 本回合结束,会话保持但不阻塞 K->>W: 财务回信,LLM 判级 COMPLETE W->>A: 经收件箱投 NOTIFY,TankaServerAPI pull 唤醒注入 A-->>U: 财务已批准,已起草回信草稿待确认
能力映射 ⑥ reminder(事件) ② 第一方(邮件) ③ 起草(写)
用例 05 · 委派 · 并行

复杂任务扇出

"调研这三个竞品,每个各出一页要点,最后给我横向对比。"

一个回合扛不动三份深度调研。助理把每个竞品委派给一个专属 flow session(create,fire-and-forget),自己留在座位上继续别的事、保持可用。每个子会话独立工作,完成时以 session_report(COMPLETION)经 session_messaging 自动回传摘要 + 产物;助理读各自 .flow/<id>/artifacts(父可读路径)汇成横向对比。要追加要求时用 send——子会话耐用、可复用。

交互时序(委派 · 并行)
sequenceDiagram participant U as 用户 participant A as 助理 ROOT participant C1 as 子会话 A participant C2 as 子会话 B participant C3 as 子会话 C U->>A: 调研三个竞品,各出一页要点 A->>C1: create 委派竞品A,不阻塞 A->>C2: create 委派竞品B A->>C3: create 委派竞品C Note over A: 助理继续保持可用 C1-->>A: 完成,session_report 经收件箱回传 C2-->>A: 完成,session_report 回传 C3-->>A: 完成,session_report 回传 A->>A: 读子会话产物汇总 A-->>U: 三页竞品要点加横向对比,附来源引用
能力映射 ⑥ 委派(并行) ① 长期记忆 ④ 第三方/web 读 ⑦ 引用
用例 06 · 长程 · 定时

定时主动跟进

"每周五 17:00 帮我催一下未完成的 followup。"

助理设一个 TIME_CRON reminder(经 RedBeat)。每周五到点,以 NOTIFY 经 session_messaging pull-wakeup 唤醒,它读第一方 followup 清单,对未完成项的负责人发消息催办——主动性来自时间触发,而行动仍走第一方 Action(并按需过确认)。

交互时序(周期性)
sequenceDiagram participant U as 用户 participant A as 助理 participant B as RedBeat 调度 participant API as tanka_api U->>A: 每周五 17:00 催未完成的 followup A->>B: 设 TIME_CRON reminder 周五17:00 B->>A: 到点 → NOTIFY → pull-wakeup 注入 A->>API: GET /im/followup/list (status=pending) API-->>A: 未完成清单 A->>API: POST /im/messages 催办 @[负责人] A-->>U: 已提醒 3 项未完成 followup 的负责人
能力映射 ⑥ reminder(时间) ② 第一方(followup) ③ 发消息(写)
§ 05

一次长程旅程

把六个用例串成一条跨越数天的真实时间线——同一个会话、同一个助理,记忆 + 委派 + reminder 经 session_messaging 协同。

D0 · 09:00 — 开局

"帮我推进 Q3 复盘"

助理调取你的长期记忆(Worklog / 画像)并跨源检索近期第一方数据(聊天/邮件/备忘),理解项目当前状态,提出行动计划并请你确认方向。

① 长期记忆 · ② 第一方数据
D0 · 09:10 — 落地第一步

建群、约会、起草议程

确认卡逐项授权;建"Q3 复盘"群、发出周四会议邀请、把议程草稿写进备忘。用户对"建群/发邀请"选 always-allow。

③ 第一方 Action(HITL)
D0 · 09:15 — 挂起等待

盯着两件还没发生的事

设两个 reminder:一个 EVENT_EMAIL 等财务批预算,一个 EVENT_CHAT 等产品在群里确认排期。本回合结束,会话保持。

⑥ reminder(事件)
D1 · 14:30 — 外部事件唤醒

财务回信了

Kafka 消费者判级 COMPLETE,以 NOTIFY 进 session_messaging;TankaServerAPI pull-wakeup 注入下一回合,助理"想起"该接着办,起草批复回信待确认。

⑥ 等待唤醒 · ② 邮件 · ③ 起草
D1 · 15:00 — 扇出深做

"顺便调研三个竞品"

委派(create)三个 flow session 并行调研,fire-and-forget。父会话继续处理别的事,保持可用。

⑥ 委派(并行) · ④ 第三方/web 读
D2 · 10:00 — 汇总交付

三份调研回来了

三个子会话以 session_report 自动回传(经 session_messaging),助理读各自 .flow/<id>/artifacts,汇成横向对比、附来源引用,连同复盘进展一并交付。整段过程,用户只经历了"一次对话"。

⑥ 委派回传 · ① 记忆贯穿 · ⑦ 引用
§ 06

设计原则与边界

能力越大,边界越要清楚。这些约束既是安全护栏,也是这套架构能长期可信运行的前提。

借用身份
助理以用户身份对外行事,绝不暴露 AI 身份或系统内部(ID/路径/工具名)。对外一律第一人称,@提及用 @[姓名] 格式。
证据优先
对人/对象动作前现查 ID、现读状态,绝不凭记忆里的旧值;写路由的 ID 必须标明出处。这是写正确性的根。
人审写操作
所有对外可见的改动都过 HITL 确认卡(approve/edit/reject/always-allow);第三方写同样过卡,未绑定先引导绑定。读操作可主动、免确认。
可审计
action_log 记录每次行动,TurnSummary 双轨备份每个回合;授权 grant 按 target/app/tool 粒度记录在会话状态里。
push 是信号,pull 才是真相
回传/唤醒走统一的 session_messaging 收件箱(稳定 message_id,不丢不重);push 到 TankaServerAPI 仅是 best-effort 信号,真正的真相源是 pull /work/watcher/events 的 drain,按 immediate / deferred / passive 分桶消费。旧的 event_outbox + OutboxMiddleware 注入已被取代。
委派的纵深与边界
委派关系只靠 parent_room_id(无 dispatch-CAS / M2);INV-1:ROOT 可派生 DERIVED、DERIVED 不可再生子(防深层嵌套)。子会话耐用、可复用、不进终态;Kafka 消费者仍须单实例(内存防抖不可分布)。
委派粒度归用户
判据是「回完这句事情是否就结束」——有下一轮的才委派。房间格局属于用户:先 list 看已有房间、把活路由到已经在做这条线的房间,别为一句话能办完的事新开房间,也别把一件事拆成一堆小房间。
引用不杜撰
只引用真实发过号的 ref_N,绝不编造;同源去重、按出现顺序排列;原始 source artifact 阅后即焚不进 checkpoint;非 ASSISTANT 场景不挂引用链,零开销。
凭证不落地
PipeDream 传输下用户的第三方 OAuth 托管在 PipeDream 侧,本仓只持应用级共享凭证、不存用户 token;direct 传输才用用户自有 Bearer。