@tbox.cn/app-template-agent 0.10.13 → 0.10.14

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.
@@ -2,196 +2,40 @@
2
2
 
3
3
  本包是**自定义 API(内联声明)的 adapter 代码落点**:某服务槽在 `config/integrations.json`
4
4
  保存内联声明(provider 为对象 + implementation 字面量)而 adapter 未实施时,服务调用报
5
- `PROVIDER_NOT_IMPLEMENTED`——由 AI 助手按本指引在本包实施,注册命中后即恢复。声明写法与
6
- 维度选择见应用根 `AGENTS.md`「自定义服务集成」。
5
+ `PROVIDER_NOT_IMPLEMENTED`——按指引实施并注册命中后即恢复。
6
+
7
+ 收到接入请求或需要实施排障时:**完整实施指引(实施三步 / 声明形态对照 / 可复制 JSON
8
+ 片段 / 代码骨架 / provider 名三处一致 / 认证与凭据 / 完成判据)见本包 `INTEGRATION.md`
9
+ ——先读它再动手**。接入材料清单规范与任务路由见应用根 `INTEGRATION.md`。
7
10
 
8
11
  ## 实施三步
9
12
 
10
- 1. **读声明**:`config/integrations.json` 中目标服务(如 `parking.query`)的 `provider`
11
- 为对象(`{ provider, credentialType, configSchema? }`)+ `implementation` 字面量——这是
12
- 厂商身份与凭据约定。
13
- 2. **实现 adapter**:在 `src/server/` 新建实现文件,实现该服务对应模块的 Port 接口(接口
14
- 定义见消费模块 `src/server/ports.ts`(或 `ports/` 目录)或 `@app/contracts-mall`
15
- 契约包——本包按需加 `@app/contracts-mall` 依赖并 `import type`)。HTTP 调用一律经
16
- `input.transport`(baseUrl 取自绑定 config;熔断/HTTPS 强制(localhost 的 http 豁免)/
17
- 响应体 1MB 上限内建):
18
- `await input.transport.request({ path, method, body, query })`。
19
- 3. **注册**:在 `src/server/index.ts` 的 `register(ctx)` 中调用
20
- `ctx.integrations?.registerAdapter('<provider 名>', 'inline', factory)`——**注册键
21
- implementation 段恒为 `'inline'`**(内联声明运行时按合成 `'inline'` 寻址,与声明中的
22
- implementation 字面量无关)。
23
-
24
- **多服务单键**:同一 provider 名的全部服务共享唯一注册键——重复注册后者覆盖前者。同一
25
- 后端接多个服务 = 只注册一次,factory 内按 `input.service` 分支返回各 Port 实现;或每服务
26
- 用不同 provider 名分键。adapter 内取凭据值(如自签名):`input.credential()` 惰性 getter
27
- (返回 `{ scope, type, value }`;未配 credentialRef → undefined)。
13
+ 见本包 `INTEGRATION.md`「实施三步」。
28
14
 
29
15
  ## 声明形态 ⇔ 实现落点(先选对形态再动手)
30
16
 
31
- | 声明形态(services.<slot>.provider) | adapter 落点 | 失配信号 |
32
- |---|---|---|
33
- | 内联对象 `{ provider, credentialType }` | **本包**(provider-custom) | 未注册 → `PROVIDER_NOT_IMPLEMENTED` |
34
- | 字符串厂商名(如 `"mall-demo"`) | 对应正式 provider 包(catalog 来源;`packages/provider-mock` 为样例) | catalog 无此厂商 → **`PROVIDER_NOT_FOUND`** |
35
-
36
- **本包 adapter 禁止配字符串声明**:本包零贡献(manifest 无
37
- `declare.providers.slots`),永不进 provider catalog——字符串声明运行时按
38
- catalog 查表,必报 `PROVIDER_NOT_FOUND`(错误文案「provider 未命中
39
- catalog」≠ 名字拼错,是**形态落错**)。
17
+ 见本包 `INTEGRATION.md`「声明形态 ⇔ 实现落点」。
40
18
 
41
19
  ## 内联声明 JSON 片段(可复制形态)
42
20
 
43
- `config/integrations.json` 槽级写法(`provider` 对象与 `implementation`
44
- 是**兄弟键**——implementation 不在对象内;省略 `instances` = 通配激活):
45
-
46
- ```json
47
- {
48
- "services": {
49
- "parking.query": {
50
- "provider": { "provider": "my-api", "credentialType": "static-headers-v1" },
51
- "implementation": "my-api@1",
52
- "config": { "baseUrl": "https://api.example.com" },
53
- "credentialRef": "secret://my-api-parking.query"
54
- }
55
- }
56
- }
57
- ```
58
-
59
- **错误形态对照**:
60
-
61
- | ❌ 错误 | 原因 |
62
- |---|---|
63
- | `"provider": { "provider": "my-api", "implementation": "my-api@1" }` | `implementation` 不是内联对象字段(zod 拒) |
64
- | `"provider": "my-api"` 而 adapter 在本包 | catalog 查表失配 → `PROVIDER_NOT_FOUND`(见上节) |
65
- | `"instances": {}` | 零激活(省略 = 通配激活) |
66
-
67
- 实参(config 值 / 凭据 stem / 槽名)按用户 API 文档填;凭据真值只进
68
- `config/credentials/<stem>.json` 嵌套形(格式见「认证与凭据」)。
21
+ 见本包 `INTEGRATION.md`「内联声明 JSON 片段」。
69
22
 
70
23
  ## 最小代码骨架
71
24
 
72
- 类型 import 双源(全部 `import type`——typecheck 首祸排除):
73
-
74
- - `ServiceAdapterFactory` / `ServerContext` ← `@tbox.cn/app-agent-sdk-server`
75
- - Port 接口 ← 服务域契约包(mall 域 = `@app/contracts-mall`;消费模块
76
- `src/server/ports.ts` 的 import 行可反查正确来源——如 `parking.query` 的
77
- 供给接口 `ParkingQueryPort`;本包 `package.json` 按需补该依赖)
78
-
79
- ```ts
80
- // packages/provider-custom/src/server/my-api.ts
81
- import type { ServiceAdapterFactory } from '@tbox.cn/app-agent-sdk-server';
82
- import type { ParkingQueryPort } from '@app/contracts-mall';
83
-
84
- export const myApiFactory: ServiceAdapterFactory = (input) => {
85
- const impl: ParkingQueryPort = {
86
- async queryFee(q, req) {
87
- // input.transport:HTTP 通道(baseUrl/认证/熔断/HTTPS 强制内建)
88
- const res = await input.transport.request({
89
- path: '/v1/parking/fee',
90
- method: 'POST',
91
- body: { plateNo: req.plateNo },
92
- });
93
- return mapFee(res);
94
- },
95
- // ...Port 其余方法签名照抄接口定义
96
- };
97
- return impl;
98
- };
99
- ```
100
-
101
- **Port 形状检索工作法(零猜测)**:
102
-
103
- ```sh
104
- rg "export (interface|type) .*Port" packages/<消费模块>/src/server/ports.ts
105
- rg "<接口名>" packages/contracts-mall/src/
106
- ```
107
-
108
- - Port 方法签名 = 实现清单——逐个照抄(参数/返回值与工具语义一一对应);
109
- - 厂商响应 → contracts 结构转换后返回,不透传厂商字段名。
110
-
111
- 注册(`src/server/index.ts` 的 `register(ctx)` 内):
112
-
113
- ```ts
114
- import type { ServerContext } from '@tbox.cn/app-agent-sdk-server';
115
- import { myApiFactory } from './my-api';
116
-
117
- // register(ctx) 内:
118
- ctx.integrations?.registerAdapter('my-api', 'inline', myApiFactory);
119
- ```
120
-
121
- 单 factory 多服务:按 `input.service` 分支返回不同 Port 实现(服务清单见
122
- 消费模块 `tbox.module.json` `declare.owns`);或每服务独立 provider 名
123
- 分键注册。`input` 字段全集见 `src/server/index.ts` 签名示例注释。
25
+ 见本包 `INTEGRATION.md`「最小代码骨架」。
124
26
 
125
27
  ## provider 名三处一致
126
28
 
127
- 取的 provider 名必须下三处同名(任一处失配则运行时报 `PROVIDER_NOT_IMPLEMENTED`——
128
- resolveService 惰性查表查不到对应 adapter):
129
-
130
- 1. **声明侧**:`config/integrations.json` 中 `services.<slot>.provider.provider` 字段
131
- (内联声明对象内的 `provider` 键;若声明是字符串厂商则该键名直接是名字)
132
- 2. **注册侧**:`packages/provider-custom/src/server/index.ts` 中
133
- `ctx.integrations?.registerAdapter('<同名>', 'inline', factory)` 第一参
134
- 3. **凭据侧**:`config/credentials/${provider名}-${service}.json` 的 stem 前缀
135
- (服务级);共享 stem = `${provider名}-global`;实例差异化另见
136
- `${provider名}-${instanceId}-${domain}` 形(凭据文件嵌套形格式见下节)
137
-
138
- > 多服务单键只是注册侧共享,三处同名规则不放宽——同一 provider 名的全部服务 stem 仍各自
139
- > 含 `-<service>` 段;只有注册键(registerAdapter 第一参)一次("单键")。
29
+ 见本包 `INTEGRATION.md`「provider 名三处一致」(全仓唯一真源在本节对应处)。
140
30
 
141
31
  ## 认证与凭据
142
32
 
143
- | 认证形态 | credentialType(声明与凭据文件一致) | 机制 |
144
- |---|---|---|
145
- | 静态头(x-api-key 等白名单头名) | `static-headers-v1`(SDK 内置) | 头自动注入,adapter 全部经 `input.transport` |
146
- | 其他(Bearer / 自定义签名…) | 自定(如 `bearer-v1`) | 本包 `register(ctx)` 先 `ctx.authStrategies.register({ credentialType, apply(input) {...} })` 注册策略(SDK `ProviderAuthStrategy`),adapter 同走 `input.transport` |
147
-
148
- - **勿用 `'-'`**:非 local 供给在 transport 构造期抛「未知认证类型」。
149
- - 静态头白名单(本应用 `apps/server/src/app.ts`):`content-type` / `sign` / `timestamp` /
150
- `publickey` / `x-api-key`;白名单外头名走自定义策略。
151
- - 凭据文件(**嵌套形**,运行时读取格式)`config/credentials/<stem>.json`:
152
- `{ "type": "<credentialType>", "value": { "<头名/参数名>": "<真值>" } }`(省略 `scope` =
153
- 全域通配)。声明/实例持 `credentialRef: "secret://<stem>"`;服务级 stem =
154
- `${provider}-${service}`,共享 stem = `${provider}-global`(按实例差异化凭据另有
155
- `${provider}-${instanceId}-${domain}` 形)。真值只进凭据文件或平台
156
- env——不进 integrations.json、代码与 prompt。
157
- - 槽 `instances` 省略 = 通配激活(**勿写空对象 `{}`** = 零激活);已绑字符串厂商的槽整组
158
- 替换前先向用户确认。
159
-
160
- ### config 与 configSchema 的区别
161
-
162
- | 字段 | 落点 | 类型 | 内容形态 |
163
- |---|---|---|---|
164
- | `services[slot].config` / `modules[].config` / root `config` / `instances[].config` 等所有 `config*` 字段 | `config/integrations.json` | `Record<string, unknown>` 真实值 | **明文连接参数**——baseUrl / 路径前缀 / 超时 / 重试等。直接进 integrations.json(可见、非密钥) |
165
- | `services[slot].provider.configSchema`(内联声明中的可选字段) | `integrations.json` 写路径字符串,文件本体在 `config/<路径>.json` | `string` 路径 + 开发者自写文件 | **可选 schema 制品**——相对应用 `config/` 的路径;当前无强制 schema 格式;写则 doctor 谓词可消费校验,不写则不校验 |
166
-
167
- **`config` 不替代凭据**:嵌在 `config.*` 字段里的值是"可见的连接配置",不是"凭据真值"。任何形式
168
- 的密钥(API key / token / 签名 secret / OAuth secret)经 `credentialRef: "secret://<stem>"`
169
- 引用,真值只进 `config/credentials/<stem>.json`(嵌套形)或平台 env——**禁**直接进 `config.*`
170
- 字段明文,也禁进 prompt、代码、入库文档。
171
-
172
- **`configSchema` 不强制**:framework 不要求每条内联声明都配 schema 文件,schema 形态由开发者自选
173
- (推荐自身可读、可校验的 JSON schema 或自定义格式)。doctor 谓词对存在 `configSchema` 的声明做受
174
- 控子集校验;不存在则跳过。AI 接自定义集成任务不要因为没 schema 而拒绝落声明。
175
-
176
- ### 配置值与凭据真值的可见性边界
177
-
178
- | 数据 | 落点 | 是否进 prompt / 代码 / 入库文档 |
179
- |---|---|---|
180
- | `*.config` 字段(baseUrl / 超时 / 路径前缀等连接参数) | `config/integrations.json` 明文 | ⚠ 可见(明文即设计意图),但不应成"密钥代用品" |
181
- | 凭据真值(API key / token / 签名 secret / OAuth secret 等) | `config/credentials/<stem>.json` 嵌套形 或 平台 env | ❌ 禁入 prompt / 代码 / integrations.json / 入库文档 |
182
- | `credentialRef: "secret://<stem>"` 引用本身 | `config/integrations.json` 明文 | ✅ 可见(非真值,仅 stem 引用) |
183
- | AGENTS.md / 模板出厂文档 | 仓库 | ❌ 不含 `secret://` 真值(仅描述引用形态) |
33
+ 见本包 `INTEGRATION.md`「认证与凭据」(含 config/configSchema/凭据数据可见性边界表)。
184
34
 
185
35
  ## 完成判据
186
36
 
187
- - `pnpm typecheck && pnpm build` 通过;
188
- - 对话或 curl 触发一次该服务的工具调用,确认正常出结果(typecheck/build 与 doctor
189
- 均不触运行时——resolveService 惰性,调用时才判 `PROVIDER_NOT_IMPLEMENTED`);
190
- - 通配槽下 doctor 不检查凭据,运行时为最终裁判。
37
+ 见本包 `INTEGRATION.md`「完成判据」。
191
38
 
192
39
  ## 真实厂商接入
193
40
 
194
- 对外提供正式 API 的厂商(支付/会员等大规模集成)走官方 provider 包形态:manifest
195
- `declare.providers.slots` 声明供给 + 独立包发布 + `tbox-app module add` 装配 +
196
- `tbox-app provider bind` 绑定。样例:`tbox-app module add @tbox.cn/app-provider-mock --mode
197
- codegen --source @tbox.cn/app-provider-mock` 后参照 `packages/provider-mock` 结构。
41
+ 见本包 `INTEGRATION.md`「真实厂商接入」。
@@ -0,0 +1,183 @@
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
+ **本包 adapter 禁止配字符串声明**:本包零贡献(manifest 无
39
+ `declare.providers.slots`),永不进 provider catalog——字符串声明运行时按
40
+ catalog 查表,必报 `PROVIDER_NOT_FOUND`(错误文案「provider 未命中
41
+ catalog」≠ 名字拼错,是**形态落错**)。
42
+
43
+ ## 内联声明 JSON 片段(可复制形态)
44
+
45
+ `config/integrations.json` 槽级写法(`provider` 对象与 `implementation`
46
+ 是**兄弟键**——implementation 不在对象内;省略 `instances` = 通配激活):
47
+
48
+ ```json
49
+ {
50
+ "services": {
51
+ "parking.query": {
52
+ "provider": { "provider": "my-api", "credentialType": "static-headers-v1" },
53
+ "implementation": "my-api@1",
54
+ "config": { "baseUrl": "https://api.example.com" },
55
+ "credentialRef": "secret://my-api-parking.query"
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ **错误形态对照**:
62
+
63
+ | ❌ 错误 | 原因 |
64
+ |---|---|
65
+ | `"provider": { "provider": "my-api", "implementation": "my-api@1" }` | `implementation` 不是内联对象字段(zod 拒) |
66
+ | `"provider": "my-api"` 而 adapter 在本包 | catalog 查表失配 → `PROVIDER_NOT_FOUND`(见上节) |
67
+ | `"instances": {}` | 零激活(省略 = 通配激活) |
68
+
69
+ 实参(config 值 / 凭据 stem / 槽名)按用户 API 文档填;凭据真值只进
70
+ `config/credentials/<stem>.json` 嵌套形(格式见「认证与凭据」)。
71
+
72
+ ## 最小代码骨架
73
+
74
+ 类型 import 双源(全部 `import type`——typecheck 首祸排除):
75
+
76
+ - `ServiceAdapterFactory` / `ServerContext` ← `@tbox.cn/app-agent-sdk-server`
77
+ - Port 接口 ← 服务域契约包(mall 域 = `@app/contracts-mall`;消费模块
78
+ `src/server/ports.ts` 的 import 行可反查正确来源——如 `parking.query` 的
79
+ 供给接口 `ParkingQueryPort`;本包 `package.json` 按需补该依赖)
80
+
81
+ ```ts
82
+ // packages/provider-custom/src/server/my-api.ts
83
+ import type { ServiceAdapterFactory } from '@tbox.cn/app-agent-sdk-server';
84
+ import type { ParkingQueryPort } from '@app/contracts-mall';
85
+
86
+ export const myApiFactory: ServiceAdapterFactory = (input) => {
87
+ const impl: ParkingQueryPort = {
88
+ async queryFee(q, req) {
89
+ // input.transport:HTTP 通道(baseUrl/认证/熔断/HTTPS 强制内建)
90
+ const res = await input.transport.request({
91
+ path: '/v1/parking/fee',
92
+ method: 'POST',
93
+ body: { plateNo: req.plateNo },
94
+ });
95
+ return mapFee(res);
96
+ },
97
+ // ...Port 其余方法签名照抄接口定义
98
+ };
99
+ return impl;
100
+ };
101
+ ```
102
+
103
+ **Port 形状检索工作法(零猜测)**:
104
+
105
+ ```sh
106
+ rg "export (interface|type) .*Port" packages/<消费模块>/src/server/ports.ts
107
+ rg "<接口名>" packages/contracts-mall/src/
108
+ ```
109
+
110
+ - Port 方法签名 = 实现清单——逐个照抄(参数/返回值与工具语义一一对应);
111
+ - 厂商响应 → contracts 结构转换后返回,不透传厂商字段名。
112
+
113
+ 注册(`src/server/index.ts` 的 `register(ctx)` 内):
114
+
115
+ ```ts
116
+ import type { ServerContext } from '@tbox.cn/app-agent-sdk-server';
117
+ import { myApiFactory } from './my-api';
118
+
119
+ // register(ctx) 内:
120
+ ctx.integrations?.registerAdapter('my-api', 'inline', myApiFactory);
121
+ ```
122
+
123
+ 单 factory 多服务:按 `input.service` 分支返回不同 Port 实现(服务清单见
124
+ 消费模块 `tbox.module.json` `declare.owns`);或每服务独立 provider 名
125
+ 分键注册。`input` 字段全集见 `src/server/index.ts` 签名示例注释。
126
+
127
+ ## provider 名三处一致
128
+
129
+ 取的 provider 名必须下三处同名(任一处失配则运行时报 `PROVIDER_NOT_IMPLEMENTED`——
130
+ resolveService 惰性查表查不到对应 adapter):
131
+
132
+ 1. **声明侧**:`config/integrations.json` 中 `services.<slot>.provider.provider` 字段
133
+ (内联声明对象内的 `provider` 键;若声明是字符串厂商则该键名直接是名字)
134
+ 2. **注册侧**:`packages/provider-custom/src/server/index.ts` 中
135
+ `ctx.integrations?.registerAdapter('<同名>', 'inline', factory)` 第一参
136
+ 3. **凭据侧**:`config/credentials/${provider名}-${service}.json` 的 stem 前缀
137
+ (服务级);共享 stem = `${provider名}-global`;实例差异化另见
138
+ `${provider名}-${instanceId}-${domain}` 形(凭据文件嵌套形格式见下节)
139
+
140
+ > 多服务单键只是注册侧共享,三处同名规则不放宽——同一 provider 名的全部服务 stem 仍各自
141
+ > 含 `-<service>` 段;只有注册键(registerAdapter 第一参)一次("单键")。
142
+
143
+ ## 认证与凭据
144
+
145
+ | 认证形态 | credentialType(声明与凭据文件一致) | 机制 |
146
+ |---|---|---|
147
+ | 静态头(x-api-key 等白名单头名) | `static-headers-v1`(SDK 内置) | 头自动注入,adapter 全部经 `input.transport` |
148
+ | 其他(Bearer / 自定义签名…) | 自定(如 `bearer-v1`) | 本包 `register(ctx)` 先 `ctx.authStrategies.register({ credentialType, apply(input) {...} })` 注册策略(SDK `ProviderAuthStrategy`),adapter 同走 `input.transport` |
149
+
150
+ - **勿用 `'-'`**:非 local 供给在 transport 构造期抛「未知认证类型」。
151
+ - 静态头白名单(本应用 `apps/server/src/app.ts`):`content-type` / `sign` / `timestamp` /
152
+ `publickey` / `x-api-key`;白名单外头名走自定义策略。
153
+ - 凭据文件(**嵌套形**,运行时读取格式)`config/credentials/<stem>.json`:
154
+ `{ "type": "<credentialType>", "value": { "<头名/参数名>": "<真值>" } }`(省略 `scope` =
155
+ 全域通配)。声明/实例持 `credentialRef: "secret://<stem>"`;服务级 stem =
156
+ `${provider}-${service}`,共享 stem = `${provider}-global`(按实例差异化凭据另有
157
+ `${provider}-${instanceId}-${domain}` 形)。
158
+ - 槽 `instances` 省略 = 通配激活(**勿写空对象 `{}`** = 零激活);已绑字符串厂商的槽整组
159
+ 替换前先向用户确认。
160
+
161
+ ### 数据可见性边界(config / configSchema / 凭据)
162
+
163
+ | 数据 | 落点 | 类型/形态 | 能否进 prompt / 代码 / 入库文档 |
164
+ |---|---|---|---|
165
+ | `config` 字段(baseUrl / 超时 / 路径前缀等连接参数;`services[slot].config`、`modules[].config`、root `config` 等所有 `config*`) | `config/integrations.json` | 明文真实值——直接写,可见即设计意图 | ⚠ 可见,但禁作"密钥代用品" |
166
+ | `configSchema`(内联声明中的可选字段) | `integrations.json` 写路径字符串,文件本体在 `config/<路径>.json` | 可选 schema 制品——相对应用 `config/` 的路径;无强制格式;写则 doctor 谓词校验,不写则跳过 | ✅ 可见(非真值)。**AI 接自定义集成任务不要因为没 schema 而拒绝落声明** |
167
+ | 凭据真值(API key / token / 签名 secret / OAuth secret 等) | `config/credentials/<stem>.json` 嵌套形 或 平台 env | `{ "type": "<credentialType>", "value": { "<头名>": "<真值>" } }` | ❌ **禁**入 prompt / 代码 / integrations.json 的 `config.*` / 入库文档 |
168
+ | `credentialRef: "secret://<stem>"` 引用本身 | `config/integrations.json` 明文 | 仅 stem 引用,非真值 | ✅ 可见 |
169
+ | AGENTS.md / INTEGRATION.md / 模板出厂文档 | 仓库 | — | ❌ 不含 `secret://` 真值(仅描述引用形态) |
170
+
171
+ ## 完成判据
172
+
173
+ - `pnpm typecheck && pnpm build` 通过;
174
+ - 对话或 curl 触发一次该服务的工具调用,确认正常出结果(typecheck/build 与 doctor
175
+ 均不触运行时——resolveService 惰性,调用时才判 `PROVIDER_NOT_IMPLEMENTED`);
176
+ - 通配槽下 doctor 不检查凭据,运行时为最终裁判。
177
+
178
+ ## 真实厂商接入
179
+
180
+ 对外提供正式 API 的厂商(支付/会员等大规模集成)走官方 provider 包形态:manifest
181
+ `declare.providers.slots` 声明供给 + 独立包发布 + `tbox-app module add` 装配 +
182
+ `tbox-app provider bind` 绑定。样例:`tbox-app module add @tbox.cn/app-provider-mock --mode
183
+ codegen --source @tbox.cn/app-provider-mock` 后参照 `packages/provider-mock` 结构。
@@ -39,6 +39,7 @@
39
39
  "tsconfig.json",
40
40
  "tsup.config.ts",
41
41
  "AGENTS.md",
42
+ "INTEGRATION.md",
42
43
  "README.md",
43
44
  "LICENSE"
44
45
  ],
@@ -1,5 +1,5 @@
1
1
  /**
2
- * 自定义厂商实施落点空包入口(ai-build D10:空包落点——「声明 → AI 实施 → 面板转 ok」闭环载体)。
2
+ * 自定义厂商实施落点空包入口(ai-build 空包落点——「声明 → AI 实施 → 面板转 ok」闭环载体)。
3
3
  * 服务端能力经 `./server` 子路径(与官方 provider 包同构);无 client 入口。
4
4
  */
5
5
  export const providerId = 'provider-custom';