@harrylabsj/kiwi 0.7.8 → 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.
Files changed (81) hide show
  1. package/contracts/commerce-intent/1.0/schema.json +124 -0
  2. package/contracts/delegation-policy/1.0/schema.json +143 -0
  3. package/contracts/effective-authorization/1.0/schema.json +167 -0
  4. package/contracts/kiwi-contracts.lock.json +1 -1
  5. package/contracts/manifest.json +25 -1
  6. package/contracts/persistent-task/1.0/schema.json +191 -0
  7. package/contracts/vectors/commerce-intent.invalid-no-items.json +7 -0
  8. package/contracts/vectors/commerce-intent.valid.json +32 -0
  9. package/contracts/vectors/delegation-policy.invalid-payment-auto.json +15 -0
  10. package/contracts/vectors/delegation-policy.valid.json +25 -0
  11. package/contracts/vectors/effective-authorization.invalid-deny-wins.json +20 -0
  12. package/contracts/vectors/effective-authorization.valid.json +23 -0
  13. package/contracts/vectors/persistent-task.invalid-no-idempotency.json +7 -0
  14. package/contracts/vectors/persistent-task.valid.json +45 -0
  15. package/dist/a2a/client/url-policy.js +52 -14
  16. package/dist/a2a/client/url-policy.js.map +1 -1
  17. package/dist/a2a/node.js +4 -1
  18. package/dist/a2a/node.js.map +1 -1
  19. package/dist/a2a/signing-key.js +18 -0
  20. package/dist/a2a/signing-key.js.map +1 -1
  21. package/dist/buyer-core/build-service.d.ts +28 -0
  22. package/dist/buyer-core/build-service.js +58 -0
  23. package/dist/buyer-core/build-service.js.map +1 -0
  24. package/dist/buyer-core/errors.d.ts +31 -0
  25. package/dist/buyer-core/errors.js +52 -0
  26. package/dist/buyer-core/errors.js.map +1 -0
  27. package/dist/buyer-core/merchant-index.d.ts +53 -0
  28. package/dist/buyer-core/merchant-index.js +138 -0
  29. package/dist/buyer-core/merchant-index.js.map +1 -0
  30. package/dist/buyer-core/negotiator.d.ts +51 -0
  31. package/dist/buyer-core/negotiator.js +181 -0
  32. package/dist/buyer-core/negotiator.js.map +1 -0
  33. package/dist/buyer-core/quote-fetcher.d.ts +46 -0
  34. package/dist/buyer-core/quote-fetcher.js +166 -0
  35. package/dist/buyer-core/quote-fetcher.js.map +1 -0
  36. package/dist/buyer-core/service.d.ts +192 -0
  37. package/dist/buyer-core/service.js +510 -0
  38. package/dist/buyer-core/service.js.map +1 -0
  39. package/dist/buyer-core/store.d.ts +84 -0
  40. package/dist/buyer-core/store.js +256 -0
  41. package/dist/buyer-core/store.js.map +1 -0
  42. package/dist/cli.js +25 -0
  43. package/dist/cli.js.map +1 -1
  44. package/dist/contracts/northbound-schema.d.ts +27 -0
  45. package/dist/contracts/northbound-schema.js +102 -0
  46. package/dist/contracts/northbound-schema.js.map +1 -0
  47. package/dist/handoff/destination.js +16 -5
  48. package/dist/handoff/destination.js.map +1 -1
  49. package/dist/http/cli.d.ts +16 -0
  50. package/dist/http/cli.js +111 -0
  51. package/dist/http/cli.js.map +1 -0
  52. package/dist/http/server.d.ts +39 -0
  53. package/dist/http/server.js +297 -0
  54. package/dist/http/server.js.map +1 -0
  55. package/dist/mcp/cli.d.ts +61 -0
  56. package/dist/mcp/cli.js +125 -0
  57. package/dist/mcp/cli.js.map +1 -0
  58. package/dist/mcp/server.d.ts +41 -0
  59. package/dist/mcp/server.js +141 -0
  60. package/dist/mcp/server.js.map +1 -0
  61. package/dist/mcp/tools.d.ts +28 -0
  62. package/dist/mcp/tools.js +230 -0
  63. package/dist/mcp/tools.js.map +1 -0
  64. package/dist/mcp/types.d.ts +107 -0
  65. package/dist/mcp/types.js +50 -0
  66. package/dist/mcp/types.js.map +1 -0
  67. package/dist/merchant/ops.d.ts +80 -0
  68. package/dist/merchant/ops.js +75 -0
  69. package/dist/merchant/ops.js.map +1 -0
  70. package/dist/merchant/ucp-profile.d.ts +39 -0
  71. package/dist/merchant/ucp-profile.js +55 -0
  72. package/dist/merchant/ucp-profile.js.map +1 -0
  73. package/dist/product-cli.d.ts +1 -1
  74. package/dist/product-cli.js +1 -1
  75. package/dist/product-cli.js.map +1 -1
  76. package/dist/trust/identity/auth-verifier.d.ts +2 -0
  77. package/dist/trust/identity/auth-verifier.js +30 -2
  78. package/dist/trust/identity/auth-verifier.js.map +1 -1
  79. package/dist/trust/identity/message-signature.js +14 -8
  80. package/dist/trust/identity/message-signature.js.map +1 -1
  81. package/package.json +4 -2
@@ -0,0 +1,52 @@
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
+ const CODE_TO_JSON_RPC = {
17
+ invalid_request: -32600,
18
+ invalid_params: -32602,
19
+ method_not_found: -32601,
20
+ not_initialized: -32002,
21
+ tool_not_found: -32002,
22
+ contract_violation: -32602,
23
+ idempotency_conflict: -32602,
24
+ delegation_denied: -32000,
25
+ authorization_denied: -32000,
26
+ approval_required: -32000,
27
+ approval_denied: -32000,
28
+ task_not_found: -32602,
29
+ task_expired: -32000,
30
+ agreement_not_found: -32602,
31
+ store_corrupted: -32603,
32
+ internal_error: -32603,
33
+ };
34
+ export class McpError extends Error {
35
+ code;
36
+ detail;
37
+ constructor(code, message, detail) {
38
+ super(message);
39
+ this.name = "McpError";
40
+ this.code = code;
41
+ this.detail = detail;
42
+ }
43
+ /** 映射为 JSON-RPC 错误负载(§6.10 错误分类语义)。 */
44
+ toJsonRpc() {
45
+ return {
46
+ code: CODE_TO_JSON_RPC[this.code],
47
+ message: `${this.code}: ${this.message}`,
48
+ data: this.detail,
49
+ };
50
+ }
51
+ }
52
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../../src/buyer-core/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAyBH,MAAM,gBAAgB,GAAiC;IACrD,eAAe,EAAE,CAAC,KAAK;IACvB,cAAc,EAAE,CAAC,KAAK;IACtB,gBAAgB,EAAE,CAAC,KAAK;IACxB,eAAe,EAAE,CAAC,KAAK;IACvB,cAAc,EAAE,CAAC,KAAK;IACtB,kBAAkB,EAAE,CAAC,KAAK;IAC1B,oBAAoB,EAAE,CAAC,KAAK;IAC5B,iBAAiB,EAAE,CAAC,KAAK;IACzB,oBAAoB,EAAE,CAAC,KAAK;IAC5B,iBAAiB,EAAE,CAAC,KAAK;IACzB,eAAe,EAAE,CAAC,KAAK;IACvB,cAAc,EAAE,CAAC,KAAK;IACtB,YAAY,EAAE,CAAC,KAAK;IACpB,mBAAmB,EAAE,CAAC,KAAK;IAC3B,eAAe,EAAE,CAAC,KAAK;IACvB,cAAc,EAAE,CAAC,KAAK;CACvB,CAAC;AAEF,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAe;IACnB,MAAM,CAAW;IAE1B,YAAY,IAAkB,EAAE,OAAe,EAAE,MAAgB;QAC/D,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;IAED,uCAAuC;IACvC,SAAS;QACP,OAAO;YACL,IAAI,EAAE,gBAAgB,CAAC,IAAI,CAAC,IAAI,CAAC;YACjC,OAAO,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,OAAO,EAAE;YACxC,IAAI,EAAE,IAAI,CAAC,MAAM;SAClB,CAAC;IACJ,CAAC;CACF"}
@@ -0,0 +1,53 @@
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
+ import type { MerchantRecord } from "./service.js";
17
+ export interface KiwiCatalogMerchantIndexOptions {
18
+ baseUrl: string;
19
+ authToken?: string;
20
+ timeoutMs?: number;
21
+ fetchImpl?: typeof fetch;
22
+ }
23
+ export declare class KiwiCatalogMerchantIndex {
24
+ private readonly source;
25
+ constructor(options: KiwiCatalogMerchantIndexOptions);
26
+ search(query: string, opts?: {
27
+ category?: string;
28
+ region?: string;
29
+ }): Promise<MerchantRecord[]>;
30
+ }
31
+ export interface MarketplaceMerchantIndexOptions {
32
+ baseUrl: string;
33
+ timeoutMs?: number;
34
+ fetchImpl?: typeof fetch;
35
+ }
36
+ /**
37
+ * MarketplaceMerchantIndex —— 基于 marketplace 真实商品 FTS 的 MerchantIndex。
38
+ *
39
+ * 商品查询 → /search/products 找"能供应该商品的商家"(真实商品/库存事实),
40
+ * 去重返回可路由 MerchantRecord。这解决 kiwi_search 对"谁有货"的意图(§3.2:
41
+ * 需要真实商品信息时访问 Merchant 的权威 endpoint;本索引用 marketplace 的
42
+ * 真实商品数据做路由,不拥有/不编造商品 truth)。
43
+ */
44
+ export declare class MarketplaceMerchantIndex {
45
+ private readonly baseUrl;
46
+ private readonly timeoutMs;
47
+ private readonly fetchImpl;
48
+ constructor(options: MarketplaceMerchantIndexOptions);
49
+ search(query: string, _opts?: {
50
+ category?: string;
51
+ region?: string;
52
+ }): Promise<MerchantRecord[]>;
53
+ }
@@ -0,0 +1,138 @@
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
+ * KiwiCatalogMerchantIndex —— kiwi-catalog 驱动的 MerchantIndex(战略 v2.5 §3.2)。
18
+ *
19
+ * kiwi-catalog 收缩为 Merchant Discovery & Routing Index:保存 Merchant
20
+ * Identity、Verification、Freshness、Category/Region、RFQ/KNP 支持、UCP Profile
21
+ * URL 与 A2A Agent Card。真实商品信息由 Buyer 访问 Merchant 的 UCP Catalog /
22
+ * 声明的权威 endpoint,kiwi-catalog 不是商品 truth source。
23
+ *
24
+ * 本实现包装现有 KiwiCatalogSource(/v1/agents);search 失败(catalog 不可达)
25
+ * 时由上层 service 降级为可解释 note,不编造商家。
26
+ */
27
+ import { KiwiCatalogSource } from "../discovery/catalog-source/kiwi-source.js";
28
+ const VERIFIED_LEVELS = new Set(["domain_verified", "agent_verified", "commerce_verified"]);
29
+ export class KiwiCatalogMerchantIndex {
30
+ source;
31
+ constructor(options) {
32
+ const deps = {
33
+ baseUrl: options.baseUrl,
34
+ ...(options.authToken !== undefined ? { authToken: options.authToken } : {}),
35
+ ...(options.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
36
+ ...(options.fetchImpl !== undefined ? { fetchImpl: options.fetchImpl } : {}),
37
+ };
38
+ this.source = new KiwiCatalogSource(deps);
39
+ }
40
+ async search(query, opts) {
41
+ const records = await this.source.searchRecords({ q: query });
42
+ const merchants = records
43
+ .filter((r) => r.principal_type === "merchant")
44
+ .filter((r) => r.merchant_id !== undefined)
45
+ .filter((r) => {
46
+ if (opts?.category !== undefined && !r.display_name.toLowerCase().includes(opts.category.toLowerCase())) {
47
+ return false;
48
+ }
49
+ if (opts?.region !== undefined && !r.display_name.toLowerCase().includes(opts.region.toLowerCase())) {
50
+ return false;
51
+ }
52
+ return true;
53
+ })
54
+ .map((r) => mapRecord(r));
55
+ return merchants;
56
+ }
57
+ }
58
+ function mapRecord(record) {
59
+ return {
60
+ merchant_id: record.merchant_id ?? record.catalog_agent_id,
61
+ name: record.display_name,
62
+ verified: record.verification_level !== undefined
63
+ ? VERIFIED_LEVELS.has(record.verification_level)
64
+ : false,
65
+ category: record.capabilities?.some((c) => c.includes("catalog")) ? "catalog" : undefined,
66
+ region: undefined,
67
+ ucp_profile_url: record.ucp_profile_url,
68
+ agent_card_url: record.agent_card_url,
69
+ capabilities: record.capabilities ? [...record.capabilities] : [],
70
+ };
71
+ }
72
+ /**
73
+ * MarketplaceMerchantIndex —— 基于 marketplace 真实商品 FTS 的 MerchantIndex。
74
+ *
75
+ * 商品查询 → /search/products 找"能供应该商品的商家"(真实商品/库存事实),
76
+ * 去重返回可路由 MerchantRecord。这解决 kiwi_search 对"谁有货"的意图(§3.2:
77
+ * 需要真实商品信息时访问 Merchant 的权威 endpoint;本索引用 marketplace 的
78
+ * 真实商品数据做路由,不拥有/不编造商品 truth)。
79
+ */
80
+ export class MarketplaceMerchantIndex {
81
+ baseUrl;
82
+ timeoutMs;
83
+ fetchImpl;
84
+ constructor(options) {
85
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
86
+ this.timeoutMs = options.timeoutMs ?? 5000;
87
+ this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
88
+ }
89
+ async search(query, _opts) {
90
+ const url = `${this.baseUrl}/search/products?query=${encodeURIComponent(query)}`;
91
+ const res = await this.fetchImpl(url, {
92
+ headers: { accept: "application/json" },
93
+ signal: AbortSignal.timeout(this.timeoutMs),
94
+ });
95
+ if (!res.ok)
96
+ throw new Error(`marketplace /search/products ${res.status}`);
97
+ const data = (await res.json());
98
+ const rows = data.results ?? [];
99
+ const terms = cjkTerms(query);
100
+ const seen = new Map();
101
+ for (const row of rows) {
102
+ const merchantId = row.merchant_id;
103
+ if (merchantId === undefined || merchantId === "")
104
+ continue;
105
+ const title = row.title ?? "";
106
+ // 相关度:标题命中的查询中文词数(≥2 字词)。FTS 对中文噪声大,
107
+ // 只保留标题含查询关键词的商品,避免把"长尾夹"当"扩展坞"的匹配。
108
+ const relevance = terms.reduce((n, term) => (title.includes(term) ? n + 1 : n), 0);
109
+ if (relevance === 0 || row.sku === undefined || row.sku === "")
110
+ continue;
111
+ const entry = seen.get(merchantId);
112
+ if (entry === undefined) {
113
+ seen.set(merchantId, {
114
+ record: {
115
+ merchant_id: merchantId,
116
+ name: row.merchant_name ?? merchantId,
117
+ verified: true,
118
+ category: row.category,
119
+ region: undefined,
120
+ capabilities: ["com.harrylabsj.kiwi.shopping.negotiation"],
121
+ },
122
+ skus: new Map(),
123
+ });
124
+ }
125
+ seen.get(merchantId)?.skus.set(row.sku, Math.max(relevance, seen.get(merchantId)?.skus.get(row.sku) ?? 0));
126
+ }
127
+ return [...seen.values()].map(({ record, skus }) => ({
128
+ ...record,
129
+ matching_skus: skus.size > 0 ? [...skus.entries()].sort((a, b) => b[1] - a[1]).map(([sku]) => sku) : undefined,
130
+ }));
131
+ }
132
+ }
133
+ /** 提取查询里的中文词(连续 CJK 长度≥2),用于标题相关度过滤。 */
134
+ function cjkTerms(query) {
135
+ const matches = query.match(/[一-鿿]{2,}/g);
136
+ return matches ?? [];
137
+ }
138
+ //# sourceMappingURL=merchant-index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merchant-index.js","sourceRoot":"","sources":["../../src/buyer-core/merchant-index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,51 @@
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
+ * MarketplaceNegotiator —— 真实磋商(CounterOffer)经 shopping-cli marketplace。
18
+ *
19
+ * 复用电报会话:买家 claim 商家最新回复 → 提交 counter 决策(结构化 proposal,
20
+ * 目标价来自 intent constraints 或当前报价折扣)→ complete claim → 轮询商家
21
+ * (kiwi merchant runtime)对还价的回复。所有回复为真实商家文本,不编造。
22
+ *
23
+ * 前置:报价阶段(MarketplaceQuoteFetcher)把 conversation 的 buyer_token 存入
24
+ * candidate provenance;本实现从 task candidates 读取磋商上下文。
25
+ */
26
+ import type { NegotiationStep, Negotiator } from "./service.js";
27
+ export interface MarketplaceNegotiatorOptions {
28
+ baseUrl: string;
29
+ pollIntervalMs?: number;
30
+ timeoutMs?: number;
31
+ fetchImpl?: typeof fetch;
32
+ /** 还价目标单价(minor/元);缺省从意图 constraints.target_unit_price 或
33
+ * 商家当前报价折扣(10%)推导。 */
34
+ defaultDiscountRate?: number;
35
+ }
36
+ export declare class MarketplaceNegotiator implements Negotiator {
37
+ private readonly baseUrl;
38
+ private readonly pollIntervalMs;
39
+ private readonly timeoutMs;
40
+ private readonly defaultDiscountRate;
41
+ private readonly fetchImpl;
42
+ constructor(options: MarketplaceNegotiatorOptions);
43
+ negotiate(_taskId: string, intent: Record<string, unknown>, current: NegotiationStep, candidates: Array<Record<string, unknown>>): Promise<NegotiationStep>;
44
+ /** 目标单价:intent.constraints.target_unit_price → 当前报价×(1-discount)。 */
45
+ private targetPrice;
46
+ private claimMessage;
47
+ private submitCounter;
48
+ private completeClaim;
49
+ /** 轮询会话直到出现 merchant 对还价的新回复(晚于被还价消息)或超时。 */
50
+ private pollMerchantReply;
51
+ }
@@ -0,0 +1,181 @@
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
+ const DEFAULT_POLL_MS = 1500;
17
+ const DEFAULT_TIMEOUT_MS = 15_000;
18
+ export class MarketplaceNegotiator {
19
+ baseUrl;
20
+ pollIntervalMs;
21
+ timeoutMs;
22
+ defaultDiscountRate;
23
+ fetchImpl;
24
+ constructor(options) {
25
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
26
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;
27
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
28
+ this.defaultDiscountRate = options.defaultDiscountRate ?? 0.1;
29
+ this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
30
+ }
31
+ async negotiate(_taskId, intent, current, candidates) {
32
+ const candidate = candidates.find((c) => c.provenance?.negotiation_id !== undefined);
33
+ if (candidate === undefined) {
34
+ return { ...current, summary: `${current.summary}(无会话上下文,无法真实还价)` };
35
+ }
36
+ const { negotiation_id: convId, merchant_reply_id, buyer_token, sku } = candidate.provenance ?? {};
37
+ if (convId === undefined || buyer_token === undefined || merchant_reply_id === undefined) {
38
+ return { ...current, summary: `${current.summary}(会话上下文不完整,无法真实还价)` };
39
+ }
40
+ const messageId = Number(merchant_reply_id);
41
+ if (!Number.isInteger(messageId)) {
42
+ return { ...current, summary: `${current.summary}(商家回复引用无效)` };
43
+ }
44
+ try {
45
+ const targetPrice = this.targetPrice(intent, candidate.provenance?.reply_text);
46
+ const stockQty = parseStock(candidate.provenance?.reply_text);
47
+ const claim = await this.claimMessage(buyer_token, convId, messageId);
48
+ if (claim !== true) {
49
+ return { ...current, summary: `${current.summary}(商家消息 ${messageId} 不可 claim)` };
50
+ }
51
+ const decisionOk = await this.submitCounter(buyer_token, convId, messageId, targetPrice, current.summary, sku, stockQty);
52
+ if (decisionOk !== true) {
53
+ return { ...current, summary: `${current.summary}(还价决策被拒)` };
54
+ }
55
+ await this.completeClaim(buyer_token, messageId);
56
+ const reply = await this.pollMerchantReply(buyer_token, convId, messageId);
57
+ if (reply !== undefined) {
58
+ return { ...current, reply };
59
+ }
60
+ return { ...current, summary: `${current.summary}(商家处理中,未回还价)` };
61
+ }
62
+ catch (error) {
63
+ return {
64
+ ...current,
65
+ summary: `${current.summary}(还价失败:${error instanceof Error ? error.message : String(error)})`,
66
+ };
67
+ }
68
+ }
69
+ /** 目标单价:intent.constraints.target_unit_price → 当前报价×(1-discount)。 */
70
+ targetPrice(intent, replyText) {
71
+ const constraints = (intent.constraints ?? {});
72
+ const explicit = constraints.target_unit_price;
73
+ if (typeof explicit === "number" && explicit > 0)
74
+ return explicit;
75
+ if (typeof explicit === "string" && Number(explicit) > 0)
76
+ return Number(explicit);
77
+ const current = parseCurrentPrice(replyText);
78
+ if (current !== undefined)
79
+ return Number((current * (1 - this.defaultDiscountRate)).toFixed(2));
80
+ return 0;
81
+ }
82
+ async claimMessage(buyerToken, convId, messageId) {
83
+ const res = await this.fetchImpl(`${this.baseUrl}/negotiation/claims`, {
84
+ method: "POST",
85
+ headers: { authorization: `Bearer ${buyerToken}`, "content-type": "application/json" },
86
+ body: JSON.stringify({ conversation_id: convId, message_id: messageId, idempotency_key: `nc-${messageId}-${Date.now()}` }),
87
+ signal: AbortSignal.timeout(8000),
88
+ });
89
+ if (!res.ok)
90
+ return false;
91
+ const data = (await res.json());
92
+ return data.claim?.claimed === true;
93
+ }
94
+ async submitCounter(buyerToken, convId, messageId, targetPrice, summary, sku, stockQty) {
95
+ const now = new Date().toISOString();
96
+ const proposal = {
97
+ sku: sku ?? "pilot-sku",
98
+ quantity: 10,
99
+ unit_price: targetPrice,
100
+ currency: "CNY",
101
+ // 库存快照须与服务端最新一致(stale_inventory 拒绝),从商家回复解析。
102
+ stock: { status: "available", quantity: stockQty, observed_at: now, reserved: false },
103
+ delivery: { eta_start: now, eta_end: now, fee: 0 },
104
+ after_sales_policy_refs: [],
105
+ valid_until: "2099-12-31T23:59:59Z",
106
+ };
107
+ const res = await this.fetchImpl(`${this.baseUrl}/negotiation/decisions`, {
108
+ method: "POST",
109
+ headers: { authorization: `Bearer ${buyerToken}`, "content-type": "application/json" },
110
+ body: JSON.stringify({
111
+ idempotency_key: `nd-${messageId}-${Date.now()}`,
112
+ decision: {
113
+ protocol_version: "shopping.negotiation/0.1",
114
+ conversation_id: convId,
115
+ in_reply_to_message_id: messageId,
116
+ action: "counter",
117
+ open_issues: [],
118
+ public_message: summary,
119
+ reason_codes: ["price"],
120
+ request_human_review: false,
121
+ proposal,
122
+ },
123
+ }),
124
+ signal: AbortSignal.timeout(8000),
125
+ });
126
+ if (!res.ok)
127
+ return false;
128
+ const data = (await res.json());
129
+ return data.policy_result?.result === "accepted";
130
+ }
131
+ async completeClaim(buyerToken, messageId) {
132
+ await this.fetchImpl(`${this.baseUrl}/negotiation/claims/complete`, {
133
+ method: "POST",
134
+ headers: { authorization: `Bearer ${buyerToken}`, "content-type": "application/json" },
135
+ body: JSON.stringify({ message_id: messageId, idempotency_key: `nc-${messageId}-${Date.now()}` }),
136
+ signal: AbortSignal.timeout(8000),
137
+ });
138
+ }
139
+ /** 轮询会话直到出现 merchant 对还价的新回复(晚于被还价消息)或超时。 */
140
+ async pollMerchantReply(buyerToken, convId, counterMessageId) {
141
+ const deadline = Date.now() + this.timeoutMs;
142
+ for (;;) {
143
+ const res = await this.fetchImpl(`${this.baseUrl}/conversations/${convId}`, {
144
+ headers: { authorization: `Bearer ${buyerToken}` },
145
+ signal: AbortSignal.timeout(8000),
146
+ });
147
+ if (res.ok) {
148
+ const data = (await res.json());
149
+ const reply = [...(data.conversation?.messages ?? [])]
150
+ .reverse()
151
+ .find((m) => m.sender === "merchant_agent" && (m.id ?? 0) > counterMessageId);
152
+ if (reply !== undefined && reply.text !== undefined)
153
+ return reply.text;
154
+ }
155
+ if (Date.now() >= deadline)
156
+ return undefined;
157
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
158
+ }
159
+ }
160
+ }
161
+ /** 从回复文本解析当前单价(如 "current price 189.00 CNY" / "单价 189")。 */
162
+ function parseCurrentPrice(text) {
163
+ if (text === undefined)
164
+ return undefined;
165
+ const match = text.match(/current price ([\d.]+) CNY/i) ?? text.match(/单价 ([\d.]+)/);
166
+ if (match === null)
167
+ return undefined;
168
+ const value = Number(match[1]);
169
+ return Number.isFinite(value) ? value : undefined;
170
+ }
171
+ /** 从回复文本解析库存(如 "stock 180" / "库存 180"),供 proposal 快照对齐。 */
172
+ function parseStock(text) {
173
+ if (text === undefined)
174
+ return 0;
175
+ const match = text.match(/\b(?:stock|库存)\s+(\d+)/i);
176
+ if (match === null)
177
+ return 0;
178
+ const value = Number(match[1]);
179
+ return Number.isFinite(value) ? value : 0;
180
+ }
181
+ //# sourceMappingURL=negotiator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"negotiator.js","sourceRoot":"","sources":["../../src/buyer-core/negotiator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAsCH,MAAM,eAAe,GAAG,IAAI,CAAC;AAC7B,MAAM,kBAAkB,GAAG,MAAM,CAAC;AAElC,MAAM,OAAO,qBAAqB;IACf,OAAO,CAAS;IAChB,cAAc,CAAS;IACvB,SAAS,CAAS;IAClB,mBAAmB,CAAS;IAC5B,SAAS,CAAe;IAEzC,YAAY,OAAqC;QAC/C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,eAAe,CAAC;QAChE,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,kBAAkB,CAAC;QACzD,IAAI,CAAC,mBAAmB,GAAG,OAAO,CAAC,mBAAmB,IAAI,GAAG,CAAC;QAC9D,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IACzD,CAAC;IAED,KAAK,CAAC,SAAS,CACb,OAAe,EACf,MAA+B,EAC/B,OAAwB,EACxB,UAA0C;QAE1C,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAC/B,CAAC,CAAC,EAAE,EAAE,CAAE,CAAmB,CAAC,UAAU,EAAE,cAAc,KAAK,SAAS,CACxC,CAAC;QAC/B,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;YAC5B,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,iBAAiB,EAAE,CAAC;QACtE,CAAC;QACD,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,iBAAiB,EAAE,WAAW,EAAE,GAAG,EAAE,GAAG,SAAS,CAAC,UAAU,IAAI,EAAE,CAAC;QACnG,IAAI,MAAM,KAAK,SAAS,IAAI,WAAW,KAAK,SAAS,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACzF,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,mBAAmB,EAAE,CAAC;QACxE,CAAC;QACD,MAAM,SAAS,GAAG,MAAM,CAAC,iBAAiB,CAAC,CAAC;QAC5C,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,SAAS,CAAC,EAAE,CAAC;YACjC,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,YAAY,EAAE,CAAC;QACjE,CAAC;QAED,IAAI,CAAC;YACH,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,MAAM,EAAE,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAC/E,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YAC9D,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,YAAY,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;YACtE,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;gBACnB,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,SAAS,SAAS,YAAY,EAAE,CAAC;YACnF,CAAC;YACD,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,CAAC,OAAO,EAAE,GAAG,EAAE,QAAQ,CAAC,CAAC;YACzH,IAAI,UAAU,KAAK,IAAI,EAAE,CAAC;gBACxB,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,UAAU,EAAE,CAAC;YAC/D,CAAC;YACD,MAAM,IAAI,CAAC,aAAa,CAAC,WAAW,EAAE,SAAS,CAAC,CAAC;YACjD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,iBAAiB,CAAC,WAAW,EAAE,MAAM,EAAE,SAAS,CAAC,CAAC;YAC3E,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,OAAO,EAAE,GAAG,OAAO,EAAE,KAAK,EAAE,CAAC;YAC/B,CAAC;YACD,OAAO,EAAE,GAAG,OAAO,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,cAAc,EAAE,CAAC;QACnE,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,OAAO;gBACL,GAAG,OAAO;gBACV,OAAO,EAAE,GAAG,OAAO,CAAC,OAAO,SAAS,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG;aAC9F,CAAC;QACJ,CAAC;IACH,CAAC;IAED,qEAAqE;IAC7D,WAAW,CAAC,MAA+B,EAAE,SAA6B;QAChF,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,WAAW,IAAI,EAAE,CAA4B,CAAC;QAC1E,MAAM,QAAQ,GAAG,WAAW,CAAC,iBAAiB,CAAC;QAC/C,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,GAAG,CAAC;YAAE,OAAO,QAAQ,CAAC;QAClE,IAAI,OAAO,QAAQ,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC;QAClF,MAAM,OAAO,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC7C,IAAI,OAAO,KAAK,SAAS;YAAE,OAAO,MAAM,CAAC,CAAC,OAAO,GAAG,CAAC,CAAC,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;QAChG,OAAO,CAAC,CAAC;IACX,CAAC;IAEO,KAAK,CAAC,YAAY,CAAC,UAAkB,EAAE,MAAc,EAAE,SAAiB;QAC9E,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,qBAAqB,EAAE;YACrE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACtF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,eAAe,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC;YAC1H,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAsC,CAAC;QACrE,OAAO,IAAI,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,aAAa,CACzB,UAAkB,EAClB,MAAc,EACd,SAAiB,EACjB,WAAmB,EACnB,OAAe,EACf,GAAuB,EACvB,QAAgB;QAEhB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;QACrC,MAAM,QAAQ,GAAG;YACf,GAAG,EAAE,GAAG,IAAI,WAAW;YACvB,QAAQ,EAAE,EAAE;YACZ,UAAU,EAAE,WAAW;YACvB,QAAQ,EAAE,KAAK;YACf,6CAA6C;YAC7C,KAAK,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE;YACrF,QAAQ,EAAE,EAAE,SAAS,EAAE,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC,EAAE;YAClD,uBAAuB,EAAE,EAAE;YAC3B,WAAW,EAAE,sBAAsB;SACpC,CAAC;QACF,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,wBAAwB,EAAE;YACxE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACtF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,eAAe,EAAE,MAAM,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE;gBAChD,QAAQ,EAAE;oBACR,gBAAgB,EAAE,0BAA0B;oBAC5C,eAAe,EAAE,MAAM;oBACvB,sBAAsB,EAAE,SAAS;oBACjC,MAAM,EAAE,SAAS;oBACjB,WAAW,EAAE,EAAE;oBACf,cAAc,EAAE,OAAO;oBACvB,YAAY,EAAE,CAAC,OAAO,CAAC;oBACvB,oBAAoB,EAAE,KAAK;oBAC3B,QAAQ;iBACT;aACF,CAAC;YACF,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;QACH,IAAI,CAAC,GAAG,CAAC,EAAE;YAAE,OAAO,KAAK,CAAC;QAC1B,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAA4C,CAAC;QAC3E,OAAO,IAAI,CAAC,aAAa,EAAE,MAAM,KAAK,UAAU,CAAC;IACnD,CAAC;IAEO,KAAK,CAAC,aAAa,CAAC,UAAkB,EAAE,SAAiB;QAC/D,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,8BAA8B,EAAE;YAClE,MAAM,EAAE,MAAM;YACd,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YACtF,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,UAAU,EAAE,SAAS,EAAE,eAAe,EAAE,MAAM,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE,EAAE,EAAE,CAAC;YACjG,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;SAClC,CAAC,CAAC;IACL,CAAC;IAED,6CAA6C;IACrC,KAAK,CAAC,iBAAiB,CAC7B,UAAkB,EAClB,MAAc,EACd,gBAAwB;QAExB,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC;QAC7C,SAAS,CAAC;YACR,MAAM,GAAG,GAAG,MAAM,IAAI,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC,OAAO,kBAAkB,MAAM,EAAE,EAAE;gBAC1E,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,UAAU,EAAE,EAAE;gBAClD,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,IAAI,CAAC;aAClC,CAAC,CAAC;YACH,IAAI,GAAG,CAAC,EAAE,EAAE,CAAC;gBACX,MAAM,IAAI,GAAG,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,CAAuB,CAAC;gBACtD,MAAM,KAAK,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,QAAQ,IAAI,EAAE,CAAC,CAAC;qBACnD,OAAO,EAAE;qBACT,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,gBAAgB,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,GAAG,gBAAgB,CAAC,CAAC;gBAChF,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,CAAC,IAAI,KAAK,SAAS;oBAAE,OAAO,KAAK,CAAC,IAAI,CAAC;YACzE,CAAC;YACD,IAAI,IAAI,CAAC,GAAG,EAAE,IAAI,QAAQ;gBAAE,OAAO,SAAS,CAAC;YAC7C,MAAM,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,IAAI,CAAC,cAAc,CAAC,CAAC,CAAC;QAC3E,CAAC;IACH,CAAC;CACF;AAED,4DAA4D;AAC5D,SAAS,iBAAiB,CAAC,IAAwB;IACjD,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACzC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,6BAA6B,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;IACrF,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC;AACpD,CAAC;AAED,2DAA2D;AAC3D,SAAS,UAAU,CAAC,IAAwB;IAC1C,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,CAAC,CAAC;IACjC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACpD,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,CAAC,CAAC;IAC7B,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/B,OAAO,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AAC5C,CAAC"}
@@ -0,0 +1,46 @@
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
+ import type { QuoteCandidateInput, QuoteFetcher, MerchantRecord } from "./service.js";
17
+ export interface MarketplaceQuoteFetcherOptions {
18
+ /** shopping-cli marketplace 根 URL(如 http://127.0.0.1:8765)。 */
19
+ baseUrl: string;
20
+ /** buyer bootstrap token(SHOPPING_BUYER_BOOTSTRAP_TOKEN)。 */
21
+ buyerBootstrapToken: string;
22
+ pollIntervalMs?: number;
23
+ timeoutMs?: number;
24
+ fetchImpl?: typeof fetch;
25
+ }
26
+ export declare class MarketplaceQuoteFetcher implements QuoteFetcher {
27
+ private readonly baseUrl;
28
+ private readonly buyerBootstrapToken;
29
+ private readonly pollIntervalMs;
30
+ private readonly timeoutMs;
31
+ private readonly fetchImpl;
32
+ constructor(options: MarketplaceQuoteFetcherOptions);
33
+ /** 对每个 Merchant 独立发起真实 RFQ 并收集回复(部分失败语义)。 */
34
+ requestQuotes(intent: Record<string, unknown>, merchants: MerchantRecord[]): Promise<QuoteCandidateInput[]>;
35
+ private requestQuote;
36
+ /**
37
+ * 从 CommerceIntent 提取 sku 与 RFQ 文本(真实商品语义,不做虚构)。
38
+ * 商家有 matching_skus(marketplace 商品 FTS 路由)时优先用商家自有 SKU——
39
+ * 否则商家 agent 无法按文本匹配到自己的商品(SKU 是会话匹配键)。
40
+ */
41
+ private buildRfq;
42
+ private createConversation;
43
+ /** 轮询会话直到 merchant_agent 回复出现或超时。 */
44
+ private pollMerchantReply;
45
+ private readConversation;
46
+ }