@harrylabsj/kiwi 0.7.9 → 0.7.10
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/contracts/commerce-intent/1.0/schema.json +124 -0
- package/contracts/delegation-policy/1.0/schema.json +143 -0
- package/contracts/effective-authorization/1.0/schema.json +167 -0
- package/contracts/kiwi-contracts.lock.json +1 -1
- package/contracts/manifest.json +25 -1
- package/contracts/persistent-task/1.0/schema.json +191 -0
- package/contracts/vectors/commerce-intent.invalid-no-items.json +7 -0
- package/contracts/vectors/commerce-intent.valid.json +32 -0
- package/contracts/vectors/delegation-policy.invalid-payment-auto.json +15 -0
- package/contracts/vectors/delegation-policy.valid.json +25 -0
- package/contracts/vectors/effective-authorization.invalid-deny-wins.json +20 -0
- package/contracts/vectors/effective-authorization.valid.json +23 -0
- package/contracts/vectors/persistent-task.invalid-no-idempotency.json +7 -0
- package/contracts/vectors/persistent-task.valid.json +45 -0
- package/dist/a2a/client/url-policy.js +52 -14
- package/dist/a2a/client/url-policy.js.map +1 -1
- package/dist/a2a/node.js +4 -1
- package/dist/a2a/node.js.map +1 -1
- package/dist/a2a/signing-key.js +18 -0
- package/dist/a2a/signing-key.js.map +1 -1
- package/dist/buyer-core/build-service.d.ts +28 -0
- package/dist/buyer-core/build-service.js +58 -0
- package/dist/buyer-core/build-service.js.map +1 -0
- package/dist/buyer-core/errors.d.ts +31 -0
- package/dist/buyer-core/errors.js +52 -0
- package/dist/buyer-core/errors.js.map +1 -0
- package/dist/buyer-core/merchant-index.d.ts +53 -0
- package/dist/buyer-core/merchant-index.js +138 -0
- package/dist/buyer-core/merchant-index.js.map +1 -0
- package/dist/buyer-core/negotiator.d.ts +51 -0
- package/dist/buyer-core/negotiator.js +181 -0
- package/dist/buyer-core/negotiator.js.map +1 -0
- package/dist/buyer-core/quote-fetcher.d.ts +46 -0
- package/dist/buyer-core/quote-fetcher.js +166 -0
- package/dist/buyer-core/quote-fetcher.js.map +1 -0
- package/dist/buyer-core/service.d.ts +192 -0
- package/dist/buyer-core/service.js +510 -0
- package/dist/buyer-core/service.js.map +1 -0
- package/dist/buyer-core/store.d.ts +84 -0
- package/dist/buyer-core/store.js +256 -0
- package/dist/buyer-core/store.js.map +1 -0
- package/dist/cli.js +25 -0
- package/dist/cli.js.map +1 -1
- package/dist/contracts/northbound-schema.d.ts +27 -0
- package/dist/contracts/northbound-schema.js +102 -0
- package/dist/contracts/northbound-schema.js.map +1 -0
- package/dist/handoff/destination.js +16 -5
- package/dist/handoff/destination.js.map +1 -1
- package/dist/http/cli.d.ts +16 -0
- package/dist/http/cli.js +111 -0
- package/dist/http/cli.js.map +1 -0
- package/dist/http/server.d.ts +39 -0
- package/dist/http/server.js +297 -0
- package/dist/http/server.js.map +1 -0
- package/dist/mcp/cli.d.ts +61 -0
- package/dist/mcp/cli.js +125 -0
- package/dist/mcp/cli.js.map +1 -0
- package/dist/mcp/server.d.ts +41 -0
- package/dist/mcp/server.js +141 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/mcp/tools.d.ts +28 -0
- package/dist/mcp/tools.js +230 -0
- package/dist/mcp/tools.js.map +1 -0
- package/dist/mcp/types.d.ts +107 -0
- package/dist/mcp/types.js +50 -0
- package/dist/mcp/types.js.map +1 -0
- package/dist/merchant/ops.d.ts +80 -0
- package/dist/merchant/ops.js +75 -0
- package/dist/merchant/ops.js.map +1 -0
- package/dist/merchant/ucp-profile.d.ts +39 -0
- package/dist/merchant/ucp-profile.js +55 -0
- package/dist/merchant/ucp-profile.js.map +1 -0
- package/dist/product-cli.d.ts +1 -1
- package/dist/product-cli.js +1 -1
- package/dist/product-cli.js.map +1 -1
- package/dist/trust/identity/auth-verifier.js +19 -1
- package/dist/trust/identity/auth-verifier.js.map +1 -1
- package/dist/trust/identity/message-signature.js +14 -8
- package/dist/trust/identity/message-signature.js.map +1 -1
- package/package.json +4 -2
|
@@ -0,0 +1,510 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
/**
|
|
17
|
+
* KiwiBuyerService —— kiwi-buyer-mcp 薄 Buyer Core(战略 v2.5 §5.1/§5.5/§6.2)。
|
|
18
|
+
*
|
|
19
|
+
* 设计原则(§5.1):Host Agent owns conversation;UCP owns standard commerce
|
|
20
|
+
* primitives;Kiwi owns cross-merchant sourcing and commercial negotiation。
|
|
21
|
+
* 本服务 LLM-independent:宿主 Agent 负责自然语言理解,Kiwi 确定性完成
|
|
22
|
+
* discovery routing、RFQ fan-out、offer normalization、policy evaluation、
|
|
23
|
+
* counteroffer、ledger、recovery 与 agreement。
|
|
24
|
+
*
|
|
25
|
+
* 唯一权威:TaskApprovalStore 持久存储;EffectiveAuthorization 五层交集
|
|
26
|
+
* deny 优先;写操作幂等;AcceptNonbinding/handoff 绑定持久 approval_id。
|
|
27
|
+
*
|
|
28
|
+
* 执行 seam(Phase 2 接线真实 merchant 网络):MerchantIndex / QuoteFetcher /
|
|
29
|
+
* Negotiator 为可注入接口。v0.1 默认使用 Static 实现或由宿主注入。
|
|
30
|
+
*/
|
|
31
|
+
import { contentDigest } from "../negotiation/jcs.js";
|
|
32
|
+
import { uuidv7 } from "@earendil-works/pi-ai";
|
|
33
|
+
import { assertNorthboundContractValid, validateCommerceIntent, validateEffectiveAuthorization, } from "../contracts/northbound-schema.js";
|
|
34
|
+
import { McpError } from "./errors.js";
|
|
35
|
+
import { TaskApprovalStore } from "./store.js";
|
|
36
|
+
function utcNow() {
|
|
37
|
+
return new Date().toISOString();
|
|
38
|
+
}
|
|
39
|
+
function policyActionMode(policy, action) {
|
|
40
|
+
return policy.actions[action]?.mode ?? "never";
|
|
41
|
+
}
|
|
42
|
+
export class KiwiBuyerService {
|
|
43
|
+
store;
|
|
44
|
+
principal;
|
|
45
|
+
buyerAgentId;
|
|
46
|
+
sessionId;
|
|
47
|
+
policy;
|
|
48
|
+
merchantIndex;
|
|
49
|
+
quoteFetcher;
|
|
50
|
+
negotiator;
|
|
51
|
+
now;
|
|
52
|
+
constructor(options) {
|
|
53
|
+
this.store = options.store;
|
|
54
|
+
this.principal = options.principal;
|
|
55
|
+
this.buyerAgentId = options.buyerAgentId;
|
|
56
|
+
this.sessionId = options.sessionId;
|
|
57
|
+
const clock = options.now ?? utcNow;
|
|
58
|
+
this.now = () => new Date(Date.parse(clock())).toISOString();
|
|
59
|
+
this.policy = options.delegationPolicy;
|
|
60
|
+
this.merchantIndex = options.merchantIndex;
|
|
61
|
+
this.quoteFetcher = options.quoteFetcher;
|
|
62
|
+
this.negotiator = options.negotiator;
|
|
63
|
+
}
|
|
64
|
+
// ---- Northbound:kiwi_search ----------------------------------------------
|
|
65
|
+
async search(input) {
|
|
66
|
+
if (this.merchantIndex === undefined) {
|
|
67
|
+
return { merchants: [], note: "merchant index not wired; discovery pending" };
|
|
68
|
+
}
|
|
69
|
+
try {
|
|
70
|
+
const merchants = await this.merchantIndex.search(input.query, {
|
|
71
|
+
category: input.category,
|
|
72
|
+
region: input.region,
|
|
73
|
+
});
|
|
74
|
+
return { merchants };
|
|
75
|
+
}
|
|
76
|
+
catch (error) {
|
|
77
|
+
// catalog 不可达:降级为可解释 note,不编造商家(§3.2 Discovery & Routing)。
|
|
78
|
+
return {
|
|
79
|
+
merchants: [],
|
|
80
|
+
note: `merchant index unreachable: ${error instanceof Error ? error.message : String(error)}`,
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ---- Northbound:kiwi_request_quotes --------------------------------------
|
|
85
|
+
async requestQuotes(input) {
|
|
86
|
+
// 契约校验(§5.2):CommerceIntent 必须合法;无效即拒绝,不落库。
|
|
87
|
+
const intentErrors = validateCommerceIntent(input.intent);
|
|
88
|
+
if (intentErrors.length > 0) {
|
|
89
|
+
throw new McpError("contract_violation", `CommerceIntent 违反冻结契约:${intentErrors.join("; ")}`);
|
|
90
|
+
}
|
|
91
|
+
const policyId = this.policy.policy_id;
|
|
92
|
+
const expiresAt = this.policy.expires_at;
|
|
93
|
+
const idempotencyKey = input.idempotency_key ?? `req-${uuidv7()}`;
|
|
94
|
+
const taskId = `task-${uuidv7()}`;
|
|
95
|
+
const created = this.now();
|
|
96
|
+
// 无 fetcher 时记录确定性 fan-out 槽位(§6.2 部分失败可解释);有 fetcher 时
|
|
97
|
+
// 只写真实结果,不预建槽位,避免候选重复。
|
|
98
|
+
const preCandidates = this.quoteFetcher === undefined
|
|
99
|
+
? (input.merchant_ids ?? []).map((merchantId) => ({
|
|
100
|
+
candidate_id: `cand-${uuidv7()}`,
|
|
101
|
+
merchant_id: merchantId,
|
|
102
|
+
status: "pending",
|
|
103
|
+
retryable: true,
|
|
104
|
+
}))
|
|
105
|
+
: [];
|
|
106
|
+
const task = {
|
|
107
|
+
task_id: taskId,
|
|
108
|
+
task_kind: "request_quotes",
|
|
109
|
+
status: "in_progress",
|
|
110
|
+
idempotency_key: idempotencyKey,
|
|
111
|
+
intent_id: String(input.intent.intent_id),
|
|
112
|
+
delegation_policy_id: policyId,
|
|
113
|
+
created_at: created,
|
|
114
|
+
updated_at: created,
|
|
115
|
+
expires_at: expiresAt,
|
|
116
|
+
resumable: true,
|
|
117
|
+
payload: JSON.stringify({
|
|
118
|
+
task_id: taskId,
|
|
119
|
+
task_kind: "request_quotes",
|
|
120
|
+
status: "in_progress",
|
|
121
|
+
idempotency_key: idempotencyKey,
|
|
122
|
+
intent_id: input.intent.intent_id,
|
|
123
|
+
delegation_policy_id: policyId,
|
|
124
|
+
created_at: created,
|
|
125
|
+
updated_at: created,
|
|
126
|
+
expires_at: expiresAt,
|
|
127
|
+
resumable: true,
|
|
128
|
+
candidates: preCandidates,
|
|
129
|
+
intent: input.intent,
|
|
130
|
+
}),
|
|
131
|
+
};
|
|
132
|
+
const { task: persisted, created: isCreated } = this.store.createTask(task);
|
|
133
|
+
if (!isCreated) {
|
|
134
|
+
// 幂等命中:相同 idempotency_key 的重复提交返回原任务,不产生重复写入(§6.2)。
|
|
135
|
+
return { task: this.decodeTask(persisted), created: false };
|
|
136
|
+
}
|
|
137
|
+
for (const candidate of preCandidates) {
|
|
138
|
+
this.store.addCandidate(taskId, candidate);
|
|
139
|
+
}
|
|
140
|
+
// 真实 fan-out 交给注入的 QuoteFetcher(Phase 2 接线 A2A/UCP)。v0.1 无 fetcher
|
|
141
|
+
// 时任务保持 in_progress + resumable,可恢复;有 fetcher 时按部分失败语义回写。
|
|
142
|
+
let status = "in_progress";
|
|
143
|
+
if (this.quoteFetcher !== undefined) {
|
|
144
|
+
const merchants = input.merchant_ids ?? [];
|
|
145
|
+
const index = this.merchantIndex;
|
|
146
|
+
// 用意图的商品查询解析商家(拿到各自 matching_skus,供 RFQ 用商家自有 SKU)。
|
|
147
|
+
const resolved = index !== undefined ? await index.search(this.firstQuery(input.intent)) : [];
|
|
148
|
+
const merchantRecords = merchants.map((m) => resolved.find((r) => r.merchant_id === m) ?? {
|
|
149
|
+
merchant_id: m,
|
|
150
|
+
name: m,
|
|
151
|
+
verified: false,
|
|
152
|
+
capabilities: [],
|
|
153
|
+
});
|
|
154
|
+
const results = await this.quoteFetcher.requestQuotes(input.intent, merchantRecords);
|
|
155
|
+
const successes = results.filter((r) => r.status === "succeeded").length;
|
|
156
|
+
if (results.length > 0) {
|
|
157
|
+
for (const r of results) {
|
|
158
|
+
this.store.addCandidate(taskId, {
|
|
159
|
+
candidate_id: `cand-${uuidv7()}`,
|
|
160
|
+
merchant_id: r.merchant_id,
|
|
161
|
+
status: r.status,
|
|
162
|
+
provenance: r.provenance,
|
|
163
|
+
failure: r.failure,
|
|
164
|
+
retryable: r.status === "failed" ? (r.failure?.retryable ?? false) : false,
|
|
165
|
+
});
|
|
166
|
+
}
|
|
167
|
+
status = successes === results.length ? "succeeded" : "partial_success";
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
const updated = this.store.updateTask(taskId, {
|
|
171
|
+
status,
|
|
172
|
+
resumable: true,
|
|
173
|
+
payload: JSON.stringify({
|
|
174
|
+
...this.decodeTask(task),
|
|
175
|
+
status,
|
|
176
|
+
updated_at: this.now(),
|
|
177
|
+
candidates: this.store.listCandidates(taskId),
|
|
178
|
+
}),
|
|
179
|
+
});
|
|
180
|
+
const decoded = this.decodeTask(updated);
|
|
181
|
+
// 冻结契约强制:持久任务记录必须满足 persistent-task/1.0 schema(§6.2)。
|
|
182
|
+
assertNorthboundContractValid("persistent-task", decoded, "requestQuotes result");
|
|
183
|
+
return { task: decoded, created: true };
|
|
184
|
+
}
|
|
185
|
+
// ---- Northbound:kiwi_get_task --------------------------------------------
|
|
186
|
+
getTask(taskId) {
|
|
187
|
+
const task = this.store.getTask(taskId);
|
|
188
|
+
if (task === undefined)
|
|
189
|
+
throw new McpError("task_not_found", `task ${taskId} not found`);
|
|
190
|
+
if (task.expires_at !== undefined && Date.parse(task.expires_at) < Date.parse(this.now())) {
|
|
191
|
+
throw new McpError("task_expired", `task ${taskId} expired at ${task.expires_at}`);
|
|
192
|
+
}
|
|
193
|
+
return { task: this.decodeTask(task) };
|
|
194
|
+
}
|
|
195
|
+
// ---- Northbound:kiwi_negotiate -------------------------------------------
|
|
196
|
+
async negotiate(input) {
|
|
197
|
+
const task = this.store.getTask(input.task_id);
|
|
198
|
+
if (task === undefined)
|
|
199
|
+
throw new McpError("task_not_found", `task ${input.task_id} not found`);
|
|
200
|
+
if (task.expires_at !== undefined && Date.parse(task.expires_at) < Date.parse(this.now())) {
|
|
201
|
+
throw new McpError("task_expired", `task ${input.task_id} expired`);
|
|
202
|
+
}
|
|
203
|
+
const mode = policyActionMode(this.policy, "counter_offer");
|
|
204
|
+
if (mode === "never") {
|
|
205
|
+
throw new McpError("delegation_denied", "counter_offer 未获委托(never)");
|
|
206
|
+
}
|
|
207
|
+
const rounds = this.currentRounds(task);
|
|
208
|
+
const maxRounds = this.policy.limits?.max_rounds ?? 3;
|
|
209
|
+
if (rounds >= maxRounds) {
|
|
210
|
+
throw new McpError("delegation_denied", `counter_offer 超出委托轮次上限(max_rounds=${maxRounds})`);
|
|
211
|
+
}
|
|
212
|
+
let step = {
|
|
213
|
+
round: rounds + 1,
|
|
214
|
+
action: input.action,
|
|
215
|
+
summary: input.summary,
|
|
216
|
+
};
|
|
217
|
+
if (this.negotiator !== undefined) {
|
|
218
|
+
step = await this.negotiator.negotiate(input.task_id, {}, step, this.store.listCandidates(input.task_id));
|
|
219
|
+
}
|
|
220
|
+
const decoded = this.decodeTask(task);
|
|
221
|
+
const prior = Array.isArray(decoded.steps)
|
|
222
|
+
? decoded.steps
|
|
223
|
+
: [];
|
|
224
|
+
const steps = [...prior, step];
|
|
225
|
+
const currentStatus = typeof decoded.status === "string" ? decoded.status : "in_progress";
|
|
226
|
+
const updated = this.store.updateTask(input.task_id, {
|
|
227
|
+
status: currentStatus === "pending" ? "in_progress" : currentStatus,
|
|
228
|
+
payload: JSON.stringify({ ...decoded, steps, updated_at: this.now() }),
|
|
229
|
+
});
|
|
230
|
+
return { task: this.decodeTask(updated), step };
|
|
231
|
+
}
|
|
232
|
+
// ---- Northbound:kiwi_accept_agreement ------------------------------------
|
|
233
|
+
async acceptAgreement(input) {
|
|
234
|
+
const task = this.store.getTask(input.task_id);
|
|
235
|
+
if (task === undefined)
|
|
236
|
+
throw new McpError("task_not_found", `task ${input.task_id} not found`);
|
|
237
|
+
if (task.expires_at !== undefined && Date.parse(task.expires_at) < Date.parse(this.now())) {
|
|
238
|
+
throw new McpError("task_expired", `task ${input.task_id} expired`);
|
|
239
|
+
}
|
|
240
|
+
const candidate = this.store
|
|
241
|
+
.listCandidates(input.task_id)
|
|
242
|
+
.find((c) => c.candidate_id === input.candidate_id);
|
|
243
|
+
if (candidate === undefined) {
|
|
244
|
+
throw new McpError("invalid_params", `candidate ${input.candidate_id} not found on task`);
|
|
245
|
+
}
|
|
246
|
+
const termsDigest = contentDigest(candidate);
|
|
247
|
+
const authorization = await this.evaluateAuthorization("accept_nonbinding", {
|
|
248
|
+
taskId: input.task_id,
|
|
249
|
+
candidateId: input.candidate_id,
|
|
250
|
+
candidateDigest: termsDigest,
|
|
251
|
+
approvalId: input.approval_id,
|
|
252
|
+
});
|
|
253
|
+
if (authorization.effective_decision !== "granted") {
|
|
254
|
+
throw new McpError("authorization_denied", "AcceptNonbinding 未获五层授权", {
|
|
255
|
+
authorization,
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const agreementId = `agreement-${uuidv7()}`;
|
|
259
|
+
const now = this.now();
|
|
260
|
+
const agreement = {
|
|
261
|
+
agreement_id: agreementId,
|
|
262
|
+
task_id: input.task_id,
|
|
263
|
+
negotiation_id: candidate.provenance
|
|
264
|
+
?.negotiation_id,
|
|
265
|
+
terms_digest: termsDigest,
|
|
266
|
+
created_at: now,
|
|
267
|
+
binding_effect: "nonbinding",
|
|
268
|
+
creates_order: false,
|
|
269
|
+
reserves_inventory: false,
|
|
270
|
+
authorizes_payment: false,
|
|
271
|
+
accepted_candidate_id: input.candidate_id,
|
|
272
|
+
authorization_id: authorization.authorization_id,
|
|
273
|
+
};
|
|
274
|
+
this.store.createAgreement({
|
|
275
|
+
agreement_id: agreementId,
|
|
276
|
+
task_id: input.task_id,
|
|
277
|
+
negotiation_id: agreement.negotiation_id,
|
|
278
|
+
terms_digest: termsDigest,
|
|
279
|
+
created_at: now,
|
|
280
|
+
expires_at: undefined,
|
|
281
|
+
payload: JSON.stringify(agreement),
|
|
282
|
+
});
|
|
283
|
+
const updated = this.store.updateTask(input.task_id, {
|
|
284
|
+
status: "succeeded",
|
|
285
|
+
payload: JSON.stringify({
|
|
286
|
+
...this.decodeTask(task),
|
|
287
|
+
agreement_id: agreementId,
|
|
288
|
+
status: "succeeded",
|
|
289
|
+
updated_at: now,
|
|
290
|
+
}),
|
|
291
|
+
});
|
|
292
|
+
return { task: this.decodeTask(updated), agreement, authorization };
|
|
293
|
+
}
|
|
294
|
+
// ---- Northbound:kiwi_get_agreement ---------------------------------------
|
|
295
|
+
getAgreement(agreementId) {
|
|
296
|
+
const stored = this.store.getAgreement(agreementId);
|
|
297
|
+
if (stored === undefined) {
|
|
298
|
+
throw new McpError("agreement_not_found", `agreement ${agreementId} not found`);
|
|
299
|
+
}
|
|
300
|
+
return { agreement: this.parsePayload(stored.payload) };
|
|
301
|
+
}
|
|
302
|
+
// ---- Northbound:kiwi_handoff ---------------------------------------------
|
|
303
|
+
async handoff(input) {
|
|
304
|
+
const stored = this.store.getAgreement(input.agreement_id);
|
|
305
|
+
if (stored === undefined) {
|
|
306
|
+
throw new McpError("agreement_not_found", `agreement ${input.agreement_id} not found`);
|
|
307
|
+
}
|
|
308
|
+
const authorization = await this.evaluateAuthorization("handoff", {
|
|
309
|
+
taskId: stored.task_id,
|
|
310
|
+
approvalId: input.approval_id,
|
|
311
|
+
});
|
|
312
|
+
if (authorization.effective_decision !== "granted") {
|
|
313
|
+
throw new McpError("authorization_denied", "Handoff 未获五层授权", { authorization });
|
|
314
|
+
}
|
|
315
|
+
const handoffRef = {
|
|
316
|
+
handoff_id: `handoff-${uuidv7()}`,
|
|
317
|
+
destination_type: input.destination_type,
|
|
318
|
+
...(input.url !== undefined ? { url: input.url } : {}),
|
|
319
|
+
};
|
|
320
|
+
return { handoff_ref: handoffRef, authorization };
|
|
321
|
+
}
|
|
322
|
+
// ---- 持久审批(宿主适配面,非 7 个 MCP 工具)-------------------------------
|
|
323
|
+
/** 创建 pending 审批记录(ASK 动作触发)。返回持久 approval_id。 */
|
|
324
|
+
requestApproval(input) {
|
|
325
|
+
const task = this.store.getTask(input.task_id);
|
|
326
|
+
if (task === undefined)
|
|
327
|
+
throw new McpError("task_not_found", `task ${input.task_id} not found`);
|
|
328
|
+
const approvalId = `approval-${uuidv7()}`;
|
|
329
|
+
const approval = {
|
|
330
|
+
approval_id: approvalId,
|
|
331
|
+
task_id: input.task_id,
|
|
332
|
+
action: input.action,
|
|
333
|
+
status: "pending",
|
|
334
|
+
candidate_digest: input.candidate_digest,
|
|
335
|
+
expires_at: task.expires_at,
|
|
336
|
+
};
|
|
337
|
+
this.store.setApproval(input.task_id, approval);
|
|
338
|
+
return { approval_id: approvalId };
|
|
339
|
+
}
|
|
340
|
+
/** 批准一个 pending 审批(绑定授权记录)。 */
|
|
341
|
+
approveApproval(input) {
|
|
342
|
+
const stored = this.store.getApproval(input.approval_id);
|
|
343
|
+
if (stored === undefined)
|
|
344
|
+
throw new McpError("invalid_params", `approval ${input.approval_id} not found`);
|
|
345
|
+
if (stored.expires_at !== undefined && Date.parse(stored.expires_at) < Date.parse(this.now())) {
|
|
346
|
+
throw new McpError("approval_denied", `approval ${input.approval_id} 已过期`);
|
|
347
|
+
}
|
|
348
|
+
this.store.setApproval(stored.task_id, {
|
|
349
|
+
...stored,
|
|
350
|
+
status: "approved",
|
|
351
|
+
decided_at: this.now(),
|
|
352
|
+
authorization_json: JSON.stringify(input.authorization),
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
/** 拒绝一个 pending 审批(deny 路径;deny 优先,§5.5)。 */
|
|
356
|
+
rejectApproval(input) {
|
|
357
|
+
const stored = this.store.getApproval(input.approval_id);
|
|
358
|
+
if (stored === undefined)
|
|
359
|
+
throw new McpError("invalid_params", `approval ${input.approval_id} not found`);
|
|
360
|
+
this.store.setApproval(stored.task_id, {
|
|
361
|
+
...stored,
|
|
362
|
+
status: "denied",
|
|
363
|
+
decided_at: this.now(),
|
|
364
|
+
authorization_json: JSON.stringify({
|
|
365
|
+
reason: input.reason ?? "rejected by operator",
|
|
366
|
+
decided_at: this.now(),
|
|
367
|
+
}),
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
// ---- 五层授权(§5.5 deny 优先)---------------------------------------------
|
|
371
|
+
async evaluateAuthorization(action, opts) {
|
|
372
|
+
const layers = {
|
|
373
|
+
package_trust: { status: "allowed", reason: "signed kiwi-buyer-mcp package, version pinned" },
|
|
374
|
+
host_tool_policy: { status: "allowed", reason: "host invoked the tool within its policy" },
|
|
375
|
+
runtime_approval: { status: "allowed", reason: "no approval gate for this action" },
|
|
376
|
+
kiwi_delegation_policy: { status: "allowed" },
|
|
377
|
+
merchant_hard_policy: { status: "allowed", reason: "within merchant hard policy" },
|
|
378
|
+
};
|
|
379
|
+
// 第 4 层:DelegationPolicy
|
|
380
|
+
const mode = policyActionMode(this.policy, action);
|
|
381
|
+
if (mode === "never") {
|
|
382
|
+
layers.kiwi_delegation_policy = { status: "denied", reason: `action=${action} 委托=never` };
|
|
383
|
+
}
|
|
384
|
+
else if (mode === "ask") {
|
|
385
|
+
// ASK:必须有已批准的持久审批;approval 动作必须与请求动作一致。
|
|
386
|
+
const expectedAction = action === "accept_nonbinding" ? "accept_nonbinding" : "handoff";
|
|
387
|
+
const approval = opts.approvalId !== undefined ? this.store.getApproval(opts.approvalId) : undefined;
|
|
388
|
+
if (opts.approvalId !== undefined && approval === undefined) {
|
|
389
|
+
throw new McpError("approval_required", `approval ${opts.approvalId} 不存在`, {
|
|
390
|
+
approval_id: opts.approvalId,
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
if (approval === undefined) {
|
|
394
|
+
const created = this.requestApproval({
|
|
395
|
+
task_id: opts.taskId,
|
|
396
|
+
action: expectedAction,
|
|
397
|
+
candidate_digest: opts.candidateDigest,
|
|
398
|
+
});
|
|
399
|
+
throw new McpError("approval_required", `action=${action} 需要持久审批`, {
|
|
400
|
+
approval_id: created.approval_id,
|
|
401
|
+
});
|
|
402
|
+
}
|
|
403
|
+
if (approval.action !== expectedAction) {
|
|
404
|
+
layers.runtime_approval = {
|
|
405
|
+
status: "denied",
|
|
406
|
+
reason: `approval ${approval.approval_id} 动作=${approval.action} 与请求 ${action} 不一致`,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
else if (approval.status === "pending") {
|
|
410
|
+
throw new McpError("approval_required", `approval ${approval.approval_id} 待审批`, {
|
|
411
|
+
approval_id: approval.approval_id,
|
|
412
|
+
});
|
|
413
|
+
}
|
|
414
|
+
else if (approval.status === "denied" || approval.status === "expired") {
|
|
415
|
+
layers.runtime_approval = {
|
|
416
|
+
status: "denied",
|
|
417
|
+
reason: `approval ${approval.approval_id} 状态=${approval.status}`,
|
|
418
|
+
};
|
|
419
|
+
}
|
|
420
|
+
else {
|
|
421
|
+
layers.runtime_approval = {
|
|
422
|
+
status: "allowed",
|
|
423
|
+
reason: `persistent approval ${approval.approval_id} approved`,
|
|
424
|
+
};
|
|
425
|
+
}
|
|
426
|
+
// ASK 动作的 delegation 层只有在审批存在且有效时才允许。
|
|
427
|
+
if (layers.runtime_approval.status === "allowed") {
|
|
428
|
+
layers.kiwi_delegation_policy = { status: "allowed", reason: `action=${action} ask,审批已批` };
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
// AUTO:delegation 层默认 allowed。
|
|
432
|
+
// 硬约束(limits):只对已解析的约束做 deny。
|
|
433
|
+
const denyReason = this.limitViolation(action, opts);
|
|
434
|
+
if (denyReason !== undefined) {
|
|
435
|
+
layers.merchant_hard_policy = { status: "denied", reason: denyReason };
|
|
436
|
+
}
|
|
437
|
+
const denied = Object.values(layers).some((l) => l.status === "denied");
|
|
438
|
+
const authorization = {
|
|
439
|
+
authorization_id: `authz-${uuidv7()}`,
|
|
440
|
+
action,
|
|
441
|
+
subject: {
|
|
442
|
+
buyer_agent_id: this.buyerAgentId,
|
|
443
|
+
session_id: this.sessionId,
|
|
444
|
+
delegation_id: this.policy.policy_id,
|
|
445
|
+
expires_at: this.policy.expires_at,
|
|
446
|
+
},
|
|
447
|
+
layers,
|
|
448
|
+
effective_decision: denied ? "denied" : "granted",
|
|
449
|
+
...(opts.approvalId !== undefined ? { approval_id: opts.approvalId } : {}),
|
|
450
|
+
expires_at: this.policy.expires_at,
|
|
451
|
+
decided_at: this.now(),
|
|
452
|
+
};
|
|
453
|
+
// 冻结 schema 强制 deny-wins 不变量;非法即内部错误。
|
|
454
|
+
const errors = validateEffectiveAuthorization(authorization);
|
|
455
|
+
if (errors.length > 0) {
|
|
456
|
+
throw new McpError("internal_error", `EffectiveAuthorization 违反冻结契约:${errors.join("; ")}`, { authorization, errors });
|
|
457
|
+
}
|
|
458
|
+
return authorization;
|
|
459
|
+
}
|
|
460
|
+
limitViolation(action, _opts) {
|
|
461
|
+
const limits = this.policy.limits;
|
|
462
|
+
if (limits === undefined)
|
|
463
|
+
return undefined;
|
|
464
|
+
if (limits.deadline !== undefined &&
|
|
465
|
+
Date.parse(limits.deadline) < Date.parse(this.now())) {
|
|
466
|
+
return `delegation deadline ${limits.deadline} 已过期`;
|
|
467
|
+
}
|
|
468
|
+
if (action === "payment")
|
|
469
|
+
return "payment 恒为 never";
|
|
470
|
+
return undefined;
|
|
471
|
+
}
|
|
472
|
+
firstQuery(intent) {
|
|
473
|
+
const items = Array.isArray(intent.items) ? intent.items : [];
|
|
474
|
+
const first = items[0] ?? {};
|
|
475
|
+
if (typeof first.query === "string" && first.query !== "")
|
|
476
|
+
return first.query;
|
|
477
|
+
if (typeof first.sku === "string" && first.sku !== "")
|
|
478
|
+
return first.sku;
|
|
479
|
+
return "";
|
|
480
|
+
}
|
|
481
|
+
currentRounds(task) {
|
|
482
|
+
const decoded = this.decodeTask(task);
|
|
483
|
+
return Array.isArray(decoded.steps) ? decoded.steps.length : 0;
|
|
484
|
+
}
|
|
485
|
+
decodeTask(task) {
|
|
486
|
+
const parsed = this.parsePayload(task.payload);
|
|
487
|
+
return {
|
|
488
|
+
...parsed,
|
|
489
|
+
task_id: task.task_id,
|
|
490
|
+
task_kind: task.task_kind,
|
|
491
|
+
status: task.status,
|
|
492
|
+
idempotency_key: task.idempotency_key,
|
|
493
|
+
created_at: task.created_at,
|
|
494
|
+
updated_at: task.updated_at,
|
|
495
|
+
expires_at: task.expires_at,
|
|
496
|
+
resumable: task.resumable,
|
|
497
|
+
candidates: this.store.listCandidates(task.task_id),
|
|
498
|
+
approval: this.store.listApprovalsByTask(task.task_id)[0],
|
|
499
|
+
};
|
|
500
|
+
}
|
|
501
|
+
parsePayload(json) {
|
|
502
|
+
try {
|
|
503
|
+
return JSON.parse(json);
|
|
504
|
+
}
|
|
505
|
+
catch {
|
|
506
|
+
throw new McpError("store_corrupted", "stored payload is not parseable");
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
//# sourceMappingURL=service.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"service.js","sourceRoot":"","sources":["../../src/buyer-core/service.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright 2026 harrylabsj
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
export interface TaskApprovalStoreOptions {
|
|
17
|
+
/** SQLite 文件路径;`:memory:` 用于测试。目录不存在时创建(0700)。 */
|
|
18
|
+
dbPath: string;
|
|
19
|
+
now?: () => string;
|
|
20
|
+
}
|
|
21
|
+
export interface StoredTask {
|
|
22
|
+
task_id: string;
|
|
23
|
+
task_kind: string;
|
|
24
|
+
status: string;
|
|
25
|
+
idempotency_key: string;
|
|
26
|
+
intent_id?: string;
|
|
27
|
+
delegation_policy_id?: string;
|
|
28
|
+
created_at: string;
|
|
29
|
+
updated_at: string;
|
|
30
|
+
expires_at?: string;
|
|
31
|
+
resumable: boolean;
|
|
32
|
+
/** 完整 task 记录(持久 Task 契约的权威 JSON)。 */
|
|
33
|
+
payload: string;
|
|
34
|
+
}
|
|
35
|
+
export interface StoredApproval {
|
|
36
|
+
approval_id: string;
|
|
37
|
+
task_id: string;
|
|
38
|
+
action: string;
|
|
39
|
+
status: string;
|
|
40
|
+
candidate_digest?: string;
|
|
41
|
+
expires_at?: string;
|
|
42
|
+
decided_at?: string;
|
|
43
|
+
authorization_json?: string;
|
|
44
|
+
}
|
|
45
|
+
export interface StoredAgreement {
|
|
46
|
+
agreement_id: string;
|
|
47
|
+
task_id: string;
|
|
48
|
+
negotiation_id?: string;
|
|
49
|
+
terms_digest?: string;
|
|
50
|
+
created_at: string;
|
|
51
|
+
expires_at?: string;
|
|
52
|
+
payload: string;
|
|
53
|
+
}
|
|
54
|
+
export declare class TaskApprovalStore {
|
|
55
|
+
private readonly db;
|
|
56
|
+
private readonly now;
|
|
57
|
+
constructor(options: TaskApprovalStoreOptions);
|
|
58
|
+
private migrate;
|
|
59
|
+
/** 幂等创建任务:相同 idempotency_key 返回已有任务(不抛错、不重复写入)。 */
|
|
60
|
+
createTask(task: StoredTask): {
|
|
61
|
+
task: StoredTask;
|
|
62
|
+
created: boolean;
|
|
63
|
+
};
|
|
64
|
+
getTask(taskId: string): StoredTask | undefined;
|
|
65
|
+
/** 按 task_id 更新任务(乐观并发:payload 整体覆盖)。 */
|
|
66
|
+
updateTask(taskId: string, patch: Partial<StoredTask>): StoredTask;
|
|
67
|
+
addCandidate(taskId: string, candidate: {
|
|
68
|
+
candidate_id: string;
|
|
69
|
+
merchant_id: string;
|
|
70
|
+
status: string;
|
|
71
|
+
provenance?: Record<string, unknown>;
|
|
72
|
+
failure?: Record<string, unknown>;
|
|
73
|
+
expires_at?: string;
|
|
74
|
+
retryable: boolean;
|
|
75
|
+
}): void;
|
|
76
|
+
listCandidates(taskId: string): Array<Record<string, unknown>>;
|
|
77
|
+
setApproval(taskId: string, approval: StoredApproval): void;
|
|
78
|
+
getApproval(approvalId: string): StoredApproval | undefined;
|
|
79
|
+
listApprovalsByTask(taskId: string): StoredApproval[];
|
|
80
|
+
createAgreement(agreement: StoredAgreement): void;
|
|
81
|
+
getAgreement(agreementId: string): StoredAgreement | undefined;
|
|
82
|
+
close(): void;
|
|
83
|
+
private parse;
|
|
84
|
+
}
|