@tbox.cn/app-template-agent 0.10.21 → 0.10.23

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/INTEGRATION.md DELETED
@@ -1,95 +0,0 @@
1
- # INTEGRATION —— 自定义服务集成指引(真源)
2
-
3
- 本文件是应用「自定义服务集成」指引的唯一真源;发现入口 = 根 `AGENTS.md`
4
- 「自定义服务集成(provider-custom)」节(该节为指针,勿在其下扩展内容)。
5
-
6
- **自定义 API** = 服务的真实后端由你自己对接:声明住在 `config/integrations.json`,adapter
7
- 代码住在 `packages/provider-custom/`。服务后端三选一:Mock(演示数据,装 provider-mock
8
- 即用)/ 自定义 API(你自己的后端接口——本文件流程)/ 服务商集成(官方 provider 包,
9
- `module add` + `provider bind`)。
10
-
11
- ## 任务路由
12
-
13
- | 你的任务 | 按此读取 |
14
- |---|---|
15
- | 为一个服务接入 | `packages/contracts-mall/src/services/<域>.ts`(Port 定义)+ `packages/provider-custom/INTEGRATION.md` |
16
- | 为某模块全部服务接入 | `packages/<module>/INTEGRATION.md` + `packages/<module>/tbox.module.json` + 该域 Port 文件 + `packages/provider-custom/INTEGRATION.md` |
17
- | 应用全部服务接入 | `tbox-app module list` 后逐模块按上行 |
18
- | 实施与排障 | `packages/provider-custom/INTEGRATION.md`(声明/骨架/注册/凭据/完成判据全链) |
19
-
20
- ## 四步流程
21
-
22
- 收到「为某服务/模块/应用接入自定义 API」(或「对接我的 API」「先要接口清单」等同义
23
- 说法)的请求时按四步走:
24
-
25
- 1. **说明并产出接入材料清单**(规范见下节)。目标不在已装模块服务槽词汇内 → 说明未装
26
- 该模块,引导 `module add` 或 `new module`,不进入后续步骤。用户已给出的信息不重复问。
27
- 未实施前调用报 `PROVIDER_NOT_IMPLEMENTED` 属预期中间态。
28
- 2. **落声明**:目标槽已有内联声明则跳过;否则直接编辑 `config/integrations.json`
29
- (CLI provider 命令仅支持字符串厂商)按「声明落点」表写入。
30
- 3. **实施 adapter**:按 `packages/provider-custom/INTEGRATION.md` 实施。
31
- 4. **验收**:`pnpm typecheck && pnpm build` 通过 + `npx --yes @tbox.cn/app-cli module
32
- doctor`;平台重启后该服务的调用不再报 `PROVIDER_NOT_IMPLEMENTED`(resolveService
33
- 惰性——调用时观测;doctor 对通配槽凭据不设防,运行时判据为最终裁判)。
34
-
35
- ### 第 1 步:接入材料清单规范
36
-
37
- 清单回答**「你的后端需要提供什么」**——从用户需要准备的材料出发;不解释槽/Port/registry/
38
- 级联等平台内部机制(用户追问除外)。
39
-
40
- **信息源(按序读,勿凭空编造)**:
41
-
42
- - 槽位清单与必选性 → `packages/<module>/tbox.module.json`(`declare.consumes` 消费需求、
43
- `declare.owns` 服务归属);
44
- - 接口签名细节 → 消费模块 `src/server/ports.ts` 或 `packages/contracts-mall/src/services/<域>.ts`
45
- (每个 Port 方法 = 后端需提供的一个接口);
46
- - 该模块接入语义(顺序/依赖/可选降级)→ `packages/<module>/INTEGRATION.md`。
47
-
48
- **清单交付项**(每服务一份,模块/应用维度 = 逐服务罗列):
49
-
50
- - 服务槽:展示名 + 一句业务说明;
51
- - 每个接口(Port 方法):接口语义(查询什么/写入什么);入参中来自平台的定位键
52
- (如 userId / plateNo——平台传入,你的后端按它定位用户/车辆);返回**必选**字段与
53
- **可选**字段;可选方法(`?` 结尾)缺席时的产品降级行为;
54
- - 连接材料:API 地址(baseUrl)、认证方式(静态请求头 → `static-headers-v1`;Bearer/
55
- 自定义签名 → 自定义认证策略)、其他可选连接参数(超时等);
56
- - 依赖与顺序:接入该服务前需要先接入的其他服务/模块;`*.snapshot` 聚合槽由底层服务
57
- 派生——落声明时跳过;
58
- - 材料收集后仍缺的信息(baseUrl / 认证 / 密钥放置方式)明确列出请用户补充。
59
-
60
- **纯询问即停**:用户仅询问「需要提供哪些接口/材料」(未给连接信息)→ 产出清单即停,
61
- 等用户补充材料后再落声明与实施。密钥等敏感值不写进 prompt/代码/明文——经平台凭据
62
- (`credentialRef`)配置,见 `packages/provider-custom/INTEGRATION.md`「认证与凭据」。
63
-
64
- **中文名称寻址**:用户用中文展示名指代(如「会员积分」模块)→ 经 `packages/*/tbox.module.json`
65
- 的 `name`/`id` 或 `tbox-app module list` 解析到模块;解析歧义时向用户确认。
66
-
67
- ## 声明落点
68
-
69
- | 维度 | 绑定(单点) | 激活 | 共享连接参数落点 |
70
- |---|---|---|---|
71
- | 指定服务 | `services.<slot>.provider = "provider-custom"` | 节点本身 | 槽/实例级 `config` |
72
- | 指定模块 | `modules[<install id>].provider = "provider-custom"`(**单点作用于全部 ownedServices**) | owned 槽补 `{}` 通配节点 | `modules[<install id>].config` |
73
- | 应用 | root `provider = "provider-custom"` | 同左逐槽 | root `config` |
74
-
75
- 推荐 CLI(等价路径):`tbox-app provider use provider-custom --module <install id>`(模块)/
76
- `provider use provider-custom`(应用)/ `provider bind <slot> provider-custom`(服务)。
77
-
78
- 关键形态约束:
79
-
80
- - **绑定与激活正交**:provider 选择单点落绑定层;激活 = `services[<slot>]` 节点在场
81
- (`{}` 空槽 = 通配激活,实例差异化再补 instances 键)。只写绑定不写激活 → 服务保持
82
- `service-not-configured`(诚实暴露,非错误)。
83
- - **内联 provider 声明(对象形态)已弃用(v8)**:存量兼容读;迁移 =
84
- `tbox-app provider migrate --write`(内联 → provider-custom 统一落点,迁移后 ⚠ 待接入,
85
- 按 provider-custom/INTEGRATION.md 实施转 ok)。
86
- - 完整字段语义(各层级联、instances 激活等)单源 = `@tbox.cn/app-contracts` 的
87
- integrations-config(zod 校验,与运行时同一解析面)。
88
- - **provider 名三处一致**(声明/注册/凭据)规则与失败信号见
89
- `packages/provider-custom/INTEGRATION.md`「provider 名三处一致」。
90
-
91
- ## 验收
92
-
93
- - `pnpm typecheck && pnpm build` 通过 + `npx --yes @tbox.cn/app-cli module doctor`;
94
- - 平台重启后该服务的调用不再报 `PROVIDER_NOT_IMPLEMENTED`(resolveService 惰性——
95
- 调用时观测;doctor 对通配槽凭据不设防,运行时判据为最终裁判)。
@@ -1,185 +0,0 @@
1
- # provider-custom —— 自定义 API 实施落点(真源)
2
-
3
- 本包是**自定义 API(内联声明)的 adapter 代码落点**:某服务槽在 `config/integrations.json`
4
- 保存内联声明(provider 为对象 + implementation 字面量)而 adapter 未实施时,服务调用报
5
- `PROVIDER_NOT_IMPLEMENTED`——按本指引在本包实施,注册命中后即恢复。
6
-
7
- 接入材料清单规范与任务路由(哪些服务、要向用户收集什么)见应用根 `INTEGRATION.md` 第 1 步
8
- (本文件管实施侧);声明写法与维度选择见应用根 `INTEGRATION.md`「声明落点」。
9
-
10
- ## 实施三步
11
-
12
- 1. **读声明**:`config/integrations.json` 中目标服务(如 `parking.query`)的 `provider`
13
- 为对象(`{ provider, credentialType, configSchema? }`)+ `implementation` 字面量——这是
14
- 厂商身份与凭据约定。
15
- 2. **实现 adapter**:在 `src/server/` 新建实现文件,实现该服务对应模块的 Port 接口(接口
16
- 定义见消费模块 `src/server/ports.ts`(或 `ports/` 目录)或 `@app/contracts-mall`
17
- 契约包——本包按需加 `@app/contracts-mall` 依赖并 `import type`)。HTTP 调用一律经
18
- `input.transport`(baseUrl 取自绑定 config;熔断/HTTPS 强制(localhost 的 http 豁免)/
19
- 响应体 1MB 上限内建):
20
- `await input.transport.request({ path, method, body, query })`。
21
- 3. **注册**:在 `src/server/index.ts` 的 `register(ctx)` 中调用
22
- `ctx.integrations?.registerAdapter('<provider 名>', 'inline', factory)`——**注册键
23
- implementation 段恒为 `'inline'`**(内联声明运行时按合成 `'inline'` 寻址,与声明中的
24
- implementation 字面量无关)。
25
-
26
- **多服务单键**:同一 provider 名的全部服务共享唯一注册键——重复注册后者覆盖前者。同一
27
- 后端接多个服务 = 只注册一次,factory 内按 `input.service` 分支返回各 Port 实现;或每服务
28
- 用不同 provider 名分键。adapter 内取凭据值(如自签名):`input.credential()` 惰性 getter
29
- (返回 `{ scope, type, value }`;未配 credentialRef → undefined)。
30
-
31
- ## 声明形态 ⇔ 实现落点(先选对形态再动手)
32
-
33
- | 声明形态(services.<slot>.provider) | adapter 落点 | 失配信号 |
34
- |---|---|---|
35
- | 内联对象 `{ provider, credentialType }` | **本包**(provider-custom) | 未注册 → `PROVIDER_NOT_IMPLEMENTED` |
36
- | 字符串厂商名(如 `"mall-demo"`) | 对应正式 provider 包(catalog 来源;`packages/provider-mock` 为样例) | catalog 无此厂商 → **`PROVIDER_NOT_FOUND`** |
37
-
38
- **v8 起:字符串声明 `"provider-custom"` = 唯一推荐声明形态**——本包经
39
- `declare.providers.id` 自声明入 provider catalog(零槽起步,AI 实施即补槽声明:
40
- `{ service, provider: 'provider-custom', implementation, credentialType, configSchema? }`)。
41
- 历史条款「禁止配字符串声明」随零槽形态退役。存量内联对象声明运行时按
42
- catalog 查表,必报 `PROVIDER_NOT_FOUND`(错误文案「provider 未命中
43
- catalog」≠ 名字拼错,是**形态落错**)。
44
-
45
- ## 内联声明 JSON 片段(可复制形态)
46
-
47
- `config/integrations.json` 槽级写法(`provider` 对象与 `implementation`
48
- 是**兄弟键**——implementation 不在对象内;省略 `instances` = 通配激活):
49
-
50
- ```json
51
- {
52
- "services": {
53
- "parking.query": {
54
- "provider": { "provider": "my-api", "credentialType": "static-headers-v1" },
55
- "implementation": "my-api@1",
56
- "config": { "baseUrl": "https://api.example.com" },
57
- "credentialRef": "secret://my-api-parking.query"
58
- }
59
- }
60
- }
61
- ```
62
-
63
- **错误形态对照**:
64
-
65
- | ❌ 错误 | 原因 |
66
- |---|---|
67
- | `"provider": { "provider": "my-api", "implementation": "my-api@1" }` | `implementation` 不是内联对象字段(zod 拒)——v8 弃用形态,存量迁移 `tbox-app provider migrate --write` |
68
- | `"provider": "my-api"` 而 adapter 在本包 | catalog 查表失配 → `PROVIDER_NOT_FOUND`(见上节) |
69
- | `"instances": {}` | 零激活(省略 = 通配激活) |
70
-
71
- 实参(config 值 / 凭据 stem / 槽名)按用户 API 文档填;凭据真值只进
72
- `config/credentials/<stem>.json` 嵌套形(格式见「认证与凭据」)。
73
-
74
- ## 最小代码骨架
75
-
76
- 类型 import 双源(全部 `import type`——typecheck 首祸排除):
77
-
78
- - `ServiceAdapterFactory` / `ServerContext` ← `@tbox.cn/app-agent-sdk-server`
79
- - Port 接口 ← 服务域契约包(mall 域 = `@app/contracts-mall`;消费模块
80
- `src/server/ports.ts` 的 import 行可反查正确来源——如 `parking.query` 的
81
- 供给接口 `ParkingQueryPort`;本包 `package.json` 按需补该依赖)
82
-
83
- ```ts
84
- // packages/provider-custom/src/server/my-api.ts
85
- import type { ServiceAdapterFactory } from '@tbox.cn/app-agent-sdk-server';
86
- import type { ParkingQueryPort } from '@app/contracts-mall';
87
-
88
- export const myApiFactory: ServiceAdapterFactory = (input) => {
89
- const impl: ParkingQueryPort = {
90
- async queryFee(q, req) {
91
- // input.transport:HTTP 通道(baseUrl/认证/熔断/HTTPS 强制内建)
92
- const res = await input.transport.request({
93
- path: '/v1/parking/fee',
94
- method: 'POST',
95
- body: { plateNo: req.plateNo },
96
- });
97
- return mapFee(res);
98
- },
99
- // ...Port 其余方法签名照抄接口定义
100
- };
101
- return impl;
102
- };
103
- ```
104
-
105
- **Port 形状检索工作法(零猜测)**:
106
-
107
- ```sh
108
- rg "export (interface|type) .*Port" packages/<消费模块>/src/server/ports.ts
109
- rg "<接口名>" packages/contracts-mall/src/
110
- ```
111
-
112
- - Port 方法签名 = 实现清单——逐个照抄(参数/返回值与工具语义一一对应);
113
- - 厂商响应 → contracts 结构转换后返回,不透传厂商字段名。
114
-
115
- 注册(`src/server/index.ts` 的 `register(ctx)` 内):
116
-
117
- ```ts
118
- import type { ServerContext } from '@tbox.cn/app-agent-sdk-server';
119
- import { myApiFactory } from './my-api';
120
-
121
- // register(ctx) 内:
122
- ctx.integrations?.registerAdapter('provider-custom', '<implementation>', myApiFactory);
123
- ```
124
-
125
- 单 factory 多服务:按 `input.service` 分支返回不同 Port 实现(服务清单见
126
- 消费模块 `tbox.module.json` `declare.owns`);或每服务独立 provider 名
127
- 分键注册。`input` 字段全集见 `src/server/index.ts` 签名示例注释。
128
-
129
- ## provider 名三处一致
130
-
131
- 取的 provider 名必须下三处同名(任一处失配则运行时报 `PROVIDER_NOT_IMPLEMENTED`——
132
- resolveService 惰性查表查不到对应 adapter):
133
-
134
- 1. **声明侧**:`config/integrations.json` 中 `services.<slot>.provider.provider` 字段
135
- (内联声明对象内的 `provider` 键;若声明是字符串厂商则该键名直接是名字)
136
- 2. **注册侧**:`packages/provider-custom/src/server/index.ts` 中
137
- `ctx.integrations?.registerAdapter('<同名>', 'inline', factory)` 第一参
138
- 3. **凭据侧**:`config/credentials/${provider名}-${service}.json` 的 stem 前缀
139
- (服务级);共享 stem = `${provider名}-global`;实例差异化另见
140
- `${provider名}-${instanceId}-${domain}` 形(凭据文件嵌套形格式见下节)
141
-
142
- > 多服务单键只是注册侧共享,三处同名规则不放宽——同一 provider 名的全部服务 stem 仍各自
143
- > 含 `-<service>` 段;只有注册键(registerAdapter 第一参)一次("单键")。
144
-
145
- ## 认证与凭据
146
-
147
- | 认证形态 | credentialType(声明与凭据文件一致) | 机制 |
148
- |---|---|---|
149
- | 静态头(x-api-key 等白名单头名) | `static-headers-v1`(SDK 内置) | 头自动注入,adapter 全部经 `input.transport` |
150
- | 其他(Bearer / 自定义签名…) | 自定(如 `bearer-v1`) | 本包 `register(ctx)` 先 `ctx.authStrategies.register({ credentialType, apply(input) {...} })` 注册策略(SDK `ProviderAuthStrategy`),adapter 同走 `input.transport` |
151
-
152
- - **勿用 `'-'`**:非 local 供给在 transport 构造期抛「未知认证类型」。
153
- - 静态头白名单(本应用 `apps/server/src/app.ts`):`content-type` / `sign` / `timestamp` /
154
- `publickey` / `x-api-key`;白名单外头名走自定义策略。
155
- - 凭据文件(**嵌套形**,运行时读取格式)`config/credentials/<stem>.json`:
156
- `{ "type": "<credentialType>", "value": { "<头名/参数名>": "<真值>" } }`(省略 `scope` =
157
- 全域通配)。声明/实例持 `credentialRef: "secret://<stem>"`;服务级 stem =
158
- `${provider}-${service}`,共享 stem = `${provider}-global`(按实例差异化凭据另有
159
- `${provider}-${instanceId}-${domain}` 形)。
160
- - 槽 `instances` 省略 = 通配激活(**勿写空对象 `{}`** = 零激活);已绑字符串厂商的槽整组
161
- 替换前先向用户确认。
162
-
163
- ### 数据可见性边界(config / configSchema / 凭据)
164
-
165
- | 数据 | 落点 | 类型/形态 | 能否进 prompt / 代码 / 入库文档 |
166
- |---|---|---|---|
167
- | `config` 字段(baseUrl / 超时 / 路径前缀等连接参数;`services[slot].config`、`modules[].config`、root `config` 等所有 `config*`) | `config/integrations.json` | 明文真实值——直接写,可见即设计意图 | ⚠ 可见,但禁作"密钥代用品" |
168
- | `configSchema`(内联声明中的可选字段) | `integrations.json` 写路径字符串,文件本体在 `config/<路径>.json` | 可选 schema 制品——相对应用 `config/` 的路径;无强制格式;写则 doctor 谓词校验,不写则跳过 | ✅ 可见(非真值)。**AI 接自定义集成任务不要因为没 schema 而拒绝落声明** |
169
- | 凭据真值(API key / token / 签名 secret / OAuth secret 等) | `config/credentials/<stem>.json` 嵌套形 或 平台 env | `{ "type": "<credentialType>", "value": { "<头名>": "<真值>" } }` | ❌ **禁**入 prompt / 代码 / integrations.json 的 `config.*` / 入库文档 |
170
- | `credentialRef: "secret://<stem>"` 引用本身 | `config/integrations.json` 明文 | 仅 stem 引用,非真值 | ✅ 可见 |
171
- | AGENTS.md / INTEGRATION.md / 模板出厂文档 | 仓库 | — | ❌ 不含 `secret://` 真值(仅描述引用形态) |
172
-
173
- ## 完成判据
174
-
175
- - `pnpm typecheck && pnpm build` 通过;
176
- - 对话或 curl 触发一次该服务的工具调用,确认正常出结果(typecheck/build 与 doctor
177
- 均不触运行时——resolveService 惰性,调用时才判 `PROVIDER_NOT_IMPLEMENTED`);
178
- - 通配槽下 doctor 不检查凭据,运行时为最终裁判。
179
-
180
- ## 真实厂商接入
181
-
182
- 对外提供正式 API 的厂商(支付/会员等大规模集成)走官方 provider 包形态:manifest
183
- `declare.providers.slots` 声明供给 + 独立包发布 + `tbox-app module add` 装配 +
184
- `tbox-app provider bind` 绑定。样例:`tbox-app module add @tbox.cn/app-provider-mock --mode
185
- codegen --source @tbox.cn/app-provider-mock` 后参照 `packages/provider-mock` 结构。