---
type: study
created: 2026-08-11
updated: 2026-08-11
sensitivity: private
status: active
tags:
  - study
  - langchain
  - managed-deep-agents
  - typescript
  - reliability
topic: Managed Deep Agents TypeScript 渠道调度与评估
sources:
  - https://docs.langchain.com/langsmith/javascript/managed-deep-agents-channels
  - https://docs.langchain.com/langsmith/javascript/managed-deep-agents-channels-slack
  - https://docs.langchain.com/langsmith/javascript/managed-deep-agents-schedules
  - https://docs.langchain.com/langsmith/javascript/managed-deep-agents-evals
last_verified: 2026-08-11
---

# Managed Deep Agents TypeScript：渠道、调度与评估

## 结论先行

Channels、schedules 和 evals 分别解决外部消息入口、无用户触发的定时运行、可重复行为验证。它们不是同一个运行路径：channel run 有 `runtime.channel`，普通 HTTP 和 scheduled run 没有；schedule 的结果投递必须显式指定 channel；MDA evals 只生成 Harbor handoff，不替 Harbor 运行 trial。

TypeScript 版的主要工程差异是 camelCase 配置、静态可提取的 schedule 声明、Node 原生测试 scaffold，以及 Slack 配置文档当前存在相互矛盾的 CLI 流程。自动化前必须以已安装版本的 `mda --help` 和实际 dry run 为准。

## Channels 模型

Channel 把外部消息系统连接到已部署 agent：验证并规范化事件，解析 caller identity 与 thread，启动 run，再把响应投递回原会话。

每个 `channels/<name>.ts` 导出命名对象 `channel`。文件名同时是运行时 channel 名和 inbound 路由的一部分：

```text
channels/support.ts -> POST /channels/support/events
```

约束：

- 一个文件一个 channel，项目内名称必须唯一。
- 不要把文件命名为 `channels/channel.ts`。
- channel-originated run 的 tools/middleware 可以读取 `runtime.channel`。
- 普通 HTTP 和 schedule run 的 `runtime.channel` 不存在，必须做空值分支。
- MCP connector 给 agent 增加远端工具；channel 接收消息并触发运行，两者不能混用。

默认 runner 会把最终回复发回 originating conversation。中间消息、显式最终消息和 schedule 定向投递应分别处理，避免重复发送。

## Slack TypeScript 配置

Slack 是 bring-your-own-app。项目维护 `channels/slack.ts` 和可编辑的 `slack-app-manifest.json`；`.mda/slack/**` 是生成产物，不应手工编辑或提交。

运行选项使用 camelCase：

| 选项 | 默认值 | 含义 |
| --- | --- | --- |
| `autoReply` | `true` | run 完成后自动发最终回复 |
| `mentionBehavior` | `"strip"` | 是否移除 mention token |
| `filters.includeConversations` | 全部 | conversation allowlist |
| `filters.excludeConversations` | 空 | conversation denylist |
| `filters.includeUsers` | 全部 | 完整 Slack identity allowlist |
| `filters.excludeUsers` | 空 | identity denylist |
| `conversation.appMention` | `"thread"` | mention 的 thread 映射 |
| `conversation.directMessage` | `"conversation"` | DM 的 thread 映射 |

映射值可以是 `thread`、`conversation` 或 `message`。默认支持 app mention、DM，以及 agent 已参与 thread 的非 mention 后续回复；顶层未 mention、bot、自身消息、不支持 subtype 和 filter 拒绝的事件不会启动 run。

### 回复语义

- `runtime.channel.post({ text }, { final: true })` 会把消息标记为最终回复，并抑制 `autoReply` 的重复发送。
- 不带 `final` 的 post 是中间消息，不会抑制自动最终回复。
- channel-originated run 只能向 originating Slack thread 发送，不能任意指定目的地。
- schedule 通过 `deliverTo` 指定 Slack conversation，不依赖 originating channel。

Slack caller identity 形如 `slack:<team>:<user>`，与 HTTP caller identity 分离，当前不支持 account linking。

### 安全与可靠性

- 每个请求基于 raw body 验签，超过五分钟窗口的签名被拒绝。
- `runtime.channel` 不暴露 bot token 或 provider credential。
- Slack Connect shared conversation 当前不支持，`allowSharedConversations: true` 也不能启用它。
- 事件去重仅在进程内；Slack retry 或多副本仍可能为同一逻辑事件启动多次 run。
- 所有会产生外部副作用的工具都必须幂等，不能依赖“channel 已去重”。

### 当前文档冲突

Slack 页面同时描述了两套不完全一致的 manifest 流程：

1. 一处要求先部署，再执行 `mda channel add slack .`，生成 template 与 final manifest，并称没有 bootstrap manifest。
2. CLI reference 与同页后文要求 `mda deploy --configure-slack`；缺少凭据时生成 bootstrap manifest 并在修改远端状态前退出，补齐凭据后再 waited deploy 生成 final manifest。

同页还分别建议用 `mda channel add slack .` 或 `mda deploy . --configure-slack` 重新生成配置。这是当前官方文档内部的不一致，不能静默选择一条当成稳定契约。

上线前应：固定 `managed-deepagents` 版本，查看该版本 `mda --help`，在 development deployment 验证生成文件和远端状态，再把确认过的命令写入 CI/runbook。无论采用哪条流程，都以 `slack-app-manifest.json` 为可编辑真源，生成文件不提交，credential 只进 secret channel。

## Schedules

每个 `schedules/<name>.ts` 导出命名 `schedule`，文件名成为托管 schedule 名。声明通过 `defineSchedule` 创建。

核心规则：

- 必须且只能设置 `prompt` 或结构化 `input` 之一。
- `cron` 使用标准五字段，不支持秒字段；未指定 `timezone` 时是 UTC。
- 默认每次运行创建 ephemeral thread，并在结束后请求删除。
- 只有确实需要跨次累积 thread state 时才用 `thread: { mode: "persistent", id: ... }`。
- Slack 投递用 `deliverTo`；该能力要求 `managed-deepagents >= 0.4.0`，且 bot 必须能访问目标 conversation。

### 静态提取约束

Schedule 在编译阶段提取，配置必须静态可序列化：

- 可以使用字面量、数组、对象和顶层字面量常量。
- 不能读取环境变量、调用函数、spread 对象或动态计算值。
- 动态业务行为应放到 agent、tool、middleware 或 runtime context。

这比普通 TypeScript 类型检查更严格：代码能通过 `tsc` 不代表 schedule 能被 MDA 编译器静态提取。需要用真实 `mda build` 验证。

### 部署一致性

Waited deploy 在 revision 达到 `DEPLOYED` 后，删除现有 MDA-owned cron 并按本地声明重建。删除本地 schedule 文件再部署，也会删除对应远端 cron。

`mda deploy --no-wait` 会在远端 build 完成前退出，因此该次不做 schedule reconciliation。只要 schedule 有新增、修改或删除，就必须执行 waited deploy 并核对远端 cron。

## Harbor Evals

MDA evals 就是 Harbor evals：`evals/tasks/` 是 canonical dataset，`evals/scaffold/` 只是可选的单向起点。

两种方式：

1. 直接在 `evals/tasks/<task>/` 写完整 Harbor task、environment 和 verifier。
2. 用 `mda evals init <name>` 创建 scaffold，再用 `mda evals compile` 生成同名 canonical task。

TypeScript scaffold 的语言原生测试使用 `node:test`、`node:assert/strict` 和 `.test.ts`。编译器会在缺少 `tests/test.sh` 时生成 wrapper，运行语言测试并写 `1` 或 `0` reward。

关键覆盖边界：

- 编译选中的 scaffold 会整体替换 `evals/tasks/<同名>/`，只改 canonical copy 的内容会丢失。
- 未选中的 canonical task 会保留。
- `--task` 可重复选择；不传时选择所有 task 并刷新全部 scaffold。
- `--model` 可重复记录多个模型，但生成 job config 使用第一个。
- MDA 生成 agent artifact、`mda_harbor` adapter、tasks 和 `harbor-job.json`，但不运行 trials。
- `evals/` 不进入 agent deployment；`evals/harbor-jobs/` 是本地 trial 输出，应排除版本控制。

### TypeScript 与 Harbor 的运行边界

即使 agent 是 TypeScript，官方 handoff 仍通过 `PYTHONPATH=evals/harbor-adapter` 和 Harbor Python 运行入口执行；本机需要 Harbor，或需要 `uv run --with harbor`。默认 Docker environment 还要求 Docker 正常运行。

Harbor 不读取项目 `.env`。生成 job config 只包含 `${VAR}` placeholder，实际 secret 必须由启动 Harbor 的进程环境提供。重复运行同一命令会恢复 job config 指向的 jobs directory；要开始全新试验，应重新编译或指定新的 Harbor job name。

Verifier 必须向 `/logs/verifier/reward.txt` 写数值 reward，或向 `/logs/verifier/reward.json` 写数值 metrics。测试脚本成功退出但没有有效 reward，不应被当作有效评估。

## 验证矩阵

| 能力 | 必测场景 |
| --- | --- |
| Slack ingress | 签名失败、过期 replay、重复 event、mention/DM/thread 映射、filter |
| Slack reply | 中间消息、`final: true`、autoReply 抑制、bot scope 与 retry |
| Slack setup | 安装版本对应的 `channel add` / `--configure-slack` 实际行为 |
| Schedule | 五字段 cron、timezone、静态提取、ephemeral/persistent thread |
| Reconciliation | 增删改 schedule、waited deploy、`--no-wait` 后的未对账状态 |
| Eval compile | scaffold 整目录替换、Node test wrapper、未选 task 保留 |
| Harbor run | Docker、环境变量、reward、失败 artifact 与新 job 隔离 |
| 副作用 | 同一 Slack event 多次运行仍只产生一次业务结果 |

## 关联

- [[01-TypeScript架构与项目模型|TypeScript 架构与项目模型]]
- [[02-TypeScript扩展能力与安全边界|TypeScript 扩展能力与安全边界]]
- [[04-TypeScript本地开发部署与CLI|TypeScript 本地开发、部署与 CLI]]
