@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,166 @@
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
+ * MarketplaceQuoteFetcher —— 真实 RFQ fan-out(战略 v2.5 Phase 2 Supply 轨)。
18
+ *
19
+ * 对每个目标 Merchant,经 shopping-cli marketplace 创建定向会话(真实商品/
20
+ * 库存/交付数据 + resident merchant agent 确定性回复),轮询拿真实回复,映射为
21
+ * QuoteCandidateInput(含 provenance:merchant_reply_id / conversation_id)。
22
+ *
23
+ * 拒绝编造:Merchant 不可达 / 超时 / 协议错误 → failed + 可解释 failure
24
+ * classification;绝不返回虚构报价。
25
+ */
26
+ import { uuidv7 } from "@earendil-works/pi-ai";
27
+ const DEFAULT_POLL_MS = 2000;
28
+ const DEFAULT_TIMEOUT_MS = 20_000;
29
+ export class MarketplaceQuoteFetcher {
30
+ baseUrl;
31
+ buyerBootstrapToken;
32
+ pollIntervalMs;
33
+ timeoutMs;
34
+ fetchImpl;
35
+ constructor(options) {
36
+ this.baseUrl = options.baseUrl.replace(/\/+$/, "");
37
+ this.buyerBootstrapToken = options.buyerBootstrapToken;
38
+ this.pollIntervalMs = options.pollIntervalMs ?? DEFAULT_POLL_MS;
39
+ this.timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
40
+ this.fetchImpl = options.fetchImpl ?? globalThis.fetch;
41
+ }
42
+ /** 对每个 Merchant 独立发起真实 RFQ 并收集回复(部分失败语义)。 */
43
+ async requestQuotes(intent, merchants) {
44
+ const buyerId = `buyer-${uuidv7()}`;
45
+ const results = await Promise.all(merchants.map((merchant) => this.requestQuote(buyerId, intent, merchant)));
46
+ return results;
47
+ }
48
+ async requestQuote(buyerId, intent, merchant) {
49
+ const { sku, text } = this.buildRfq(intent, merchant);
50
+ try {
51
+ const conversation = await this.createConversation(buyerId, merchant.merchant_id, sku, text);
52
+ if (conversation.conversation?.id === undefined || conversation.buyer_token === undefined) {
53
+ throw new Error(`marketplace did not return conversation/buyer_token for ${merchant.merchant_id}`);
54
+ }
55
+ const convId = conversation.conversation.id;
56
+ const reply = await this.pollMerchantReply(convId, conversation.buyer_token);
57
+ if (reply === undefined) {
58
+ return {
59
+ merchant_id: merchant.merchant_id,
60
+ status: "failed",
61
+ failure: { classification: "timeout", retryable: true, detail: `no merchant reply within ${this.timeoutMs}ms` },
62
+ };
63
+ }
64
+ return {
65
+ merchant_id: merchant.merchant_id,
66
+ status: "succeeded",
67
+ provenance: {
68
+ merchant_reply_id: String(reply.messageId),
69
+ negotiation_id: convId,
70
+ source: "marketplace",
71
+ reply_text: reply.text,
72
+ // 会话 buyer_token:供后续磋商(claim→counter→complete)复用。
73
+ // 作用域仅限该会话,属最小披露。
74
+ buyer_token: conversation.buyer_token,
75
+ // 该商家实际报价的 SKU(RFQ 用商家自有 SKU),磋商 proposal 复用。
76
+ sku,
77
+ },
78
+ };
79
+ }
80
+ catch (error) {
81
+ return {
82
+ merchant_id: merchant.merchant_id,
83
+ status: "failed",
84
+ failure: {
85
+ classification: "protocol_error",
86
+ retryable: true,
87
+ detail: error instanceof Error ? error.message : String(error),
88
+ },
89
+ };
90
+ }
91
+ }
92
+ /**
93
+ * 从 CommerceIntent 提取 sku 与 RFQ 文本(真实商品语义,不做虚构)。
94
+ * 商家有 matching_skus(marketplace 商品 FTS 路由)时优先用商家自有 SKU——
95
+ * 否则商家 agent 无法按文本匹配到自己的商品(SKU 是会话匹配键)。
96
+ */
97
+ buildRfq(intent, merchant) {
98
+ const items = Array.isArray(intent.items) ? intent.items : [];
99
+ const first = items[0] ?? {};
100
+ const query = typeof first.query === "string" ? first.query : "";
101
+ const itemSku = typeof first.sku === "string" ? first.sku : "";
102
+ const sku = merchant.matching_skus?.[0] ?? itemSku;
103
+ const quantity = typeof first.quantity === "object" && first.quantity !== null
104
+ ? String(first.quantity.value ?? "")
105
+ : "";
106
+ const itemText = query !== "" ? query : sku;
107
+ const text = `采购 ${quantity} 个 ${itemText}(sku=${sku || "?"}),请报价与交期。`.trim();
108
+ return { sku, text };
109
+ }
110
+ async createConversation(buyerId, merchantId, sku, text) {
111
+ const res = await this.fetchImpl(`${this.baseUrl}/conversations`, {
112
+ method: "POST",
113
+ headers: {
114
+ authorization: `Bearer ${this.buyerBootstrapToken}`,
115
+ "content-type": "application/json",
116
+ },
117
+ body: JSON.stringify({
118
+ buyer_id: buyerId,
119
+ merchant_id: merchantId,
120
+ sku,
121
+ text,
122
+ intent: "ask_price",
123
+ }),
124
+ // 连接挂起不阻塞 worker:单次请求硬超时(fail-closed,同仓库 safe-http)。
125
+ signal: AbortSignal.timeout(this.pollIntervalMs + 8000),
126
+ });
127
+ if (!res.ok) {
128
+ throw new Error(`marketplace /conversations ${res.status}`);
129
+ }
130
+ const data = (await res.json());
131
+ if (data.ok !== true) {
132
+ throw new Error(`marketplace rejected conversation: ${JSON.stringify(data)}`);
133
+ }
134
+ return data;
135
+ }
136
+ /** 轮询会话直到 merchant_agent 回复出现或超时。 */
137
+ async pollMerchantReply(conversationId, buyerToken) {
138
+ const deadline = Date.now() + this.timeoutMs;
139
+ for (;;) {
140
+ const reply = await this.readConversation(conversationId, buyerToken);
141
+ if (reply !== undefined)
142
+ return reply;
143
+ if (Date.now() >= deadline)
144
+ return undefined;
145
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
146
+ }
147
+ }
148
+ async readConversation(conversationId, buyerToken) {
149
+ const res = await this.fetchImpl(`${this.baseUrl}/conversations/${conversationId}`, {
150
+ headers: { authorization: `Bearer ${buyerToken}` },
151
+ signal: AbortSignal.timeout(this.pollIntervalMs + 8000),
152
+ });
153
+ if (!res.ok) {
154
+ throw new Error(`marketplace /conversations/${conversationId} ${res.status}`);
155
+ }
156
+ const data = (await res.json());
157
+ const messages = data.conversation?.messages ?? [];
158
+ const reply = [...messages]
159
+ .reverse()
160
+ .find((m) => m.sender === "merchant_agent" && typeof m.id === "number");
161
+ if (reply === undefined)
162
+ return undefined;
163
+ return { messageId: reply.id, text: reply.text ?? "" };
164
+ }
165
+ }
166
+ //# sourceMappingURL=quote-fetcher.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"quote-fetcher.js","sourceRoot":"","sources":["../../src/buyer-core/quote-fetcher.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,192 @@
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 { TaskApprovalStore } from "./store.js";
17
+ export type BuyerAction = "discover" | "inquiry_rfq" | "compare_offers" | "counter_offer" | "accept_nonbinding" | "handoff" | "payment";
18
+ export interface MerchantRecord {
19
+ merchant_id: string;
20
+ name: string;
21
+ verified: boolean;
22
+ category?: string;
23
+ region?: string;
24
+ ucp_profile_url?: string;
25
+ agent_card_url?: string;
26
+ capabilities: string[];
27
+ /** 该商家匹配查询的商品 SKU(marketplace 商品 FTS 路由),供 RFQ 用商家自有 SKU。 */
28
+ matching_skus?: string[];
29
+ }
30
+ export interface MerchantIndex {
31
+ search(query: string, opts?: {
32
+ category?: string;
33
+ region?: string;
34
+ }): Promise<MerchantRecord[]>;
35
+ }
36
+ export interface QuoteCandidateInput {
37
+ merchant_id: string;
38
+ status: "succeeded" | "failed";
39
+ provenance?: {
40
+ merchant_reply_id?: string;
41
+ negotiation_id?: string;
42
+ offer_id?: string;
43
+ source?: string;
44
+ /** 商家原回复文本(真实报价/库存/交付事实),用于 kiwi_get_task 展示。 */
45
+ reply_text?: string;
46
+ /** 会话 buyer_token(作用域限该会话),供磋商复用;最小披露。 */
47
+ buyer_token?: string;
48
+ /** 该商家实际报价的 SKU(磋商 proposal 复用)。 */
49
+ sku?: string;
50
+ };
51
+ failure?: {
52
+ classification: string;
53
+ retryable: boolean;
54
+ detail?: string;
55
+ };
56
+ }
57
+ export interface QuoteFetcher {
58
+ requestQuotes(intent: Record<string, unknown>, merchants: MerchantRecord[]): Promise<QuoteCandidateInput[]>;
59
+ }
60
+ export interface NegotiationStep {
61
+ round: number;
62
+ action: "counter_offer" | "clarification";
63
+ summary: string;
64
+ /** 商家对本次还价的回复(真实文本),供 kiwi_get_task 展示。 */
65
+ reply?: string;
66
+ }
67
+ export interface Negotiator {
68
+ negotiate(taskId: string, intent: Record<string, unknown>, current: NegotiationStep, candidates: Array<Record<string, unknown>>): Promise<NegotiationStep>;
69
+ }
70
+ export interface KiwiBuyerServiceOptions {
71
+ store: TaskApprovalStore;
72
+ principal: string;
73
+ buyerAgentId: string;
74
+ sessionId: string;
75
+ /** 冻结的 DelegationPolicy(已通过 schema 校验)。 */
76
+ delegationPolicy: Record<string, unknown>;
77
+ merchantIndex?: MerchantIndex;
78
+ quoteFetcher?: QuoteFetcher;
79
+ negotiator?: Negotiator;
80
+ now?: () => string;
81
+ }
82
+ export interface AuthorizationRecord {
83
+ authorization_id: string;
84
+ action: BuyerAction;
85
+ subject: {
86
+ buyer_agent_id: string;
87
+ session_id: string;
88
+ delegation_id: string;
89
+ expires_at: string;
90
+ };
91
+ layers: Record<string, {
92
+ status: "allowed" | "denied";
93
+ reason?: string;
94
+ }>;
95
+ effective_decision: "granted" | "denied";
96
+ approval_id?: string;
97
+ expires_at: string;
98
+ decided_at: string;
99
+ }
100
+ export declare class KiwiBuyerService {
101
+ private readonly store;
102
+ private readonly principal;
103
+ private readonly buyerAgentId;
104
+ private readonly sessionId;
105
+ private readonly policy;
106
+ private readonly merchantIndex?;
107
+ private readonly quoteFetcher?;
108
+ private readonly negotiator?;
109
+ private readonly now;
110
+ constructor(options: KiwiBuyerServiceOptions);
111
+ search(input: {
112
+ query: string;
113
+ category?: string;
114
+ region?: string;
115
+ }): Promise<{
116
+ merchants: MerchantRecord[];
117
+ note?: string;
118
+ }>;
119
+ requestQuotes(input: {
120
+ intent: Record<string, unknown>;
121
+ idempotency_key?: string;
122
+ merchant_ids?: string[];
123
+ }): Promise<{
124
+ task: Record<string, unknown>;
125
+ created: boolean;
126
+ }>;
127
+ getTask(taskId: string): {
128
+ task: Record<string, unknown>;
129
+ };
130
+ negotiate(input: {
131
+ task_id: string;
132
+ action: "counter_offer" | "clarification";
133
+ summary: string;
134
+ }): Promise<{
135
+ task: Record<string, unknown>;
136
+ step: NegotiationStep;
137
+ }>;
138
+ acceptAgreement(input: {
139
+ task_id: string;
140
+ candidate_id: string;
141
+ approval_id?: string;
142
+ }): Promise<{
143
+ task: Record<string, unknown>;
144
+ agreement: Record<string, unknown>;
145
+ authorization: AuthorizationRecord;
146
+ }>;
147
+ getAgreement(agreementId: string): {
148
+ agreement: Record<string, unknown>;
149
+ };
150
+ handoff(input: {
151
+ agreement_id: string;
152
+ approval_id: string;
153
+ destination_type: string;
154
+ url?: string;
155
+ }): Promise<{
156
+ handoff_ref: {
157
+ handoff_id: string;
158
+ destination_type: string;
159
+ url?: string;
160
+ };
161
+ authorization: AuthorizationRecord;
162
+ }>;
163
+ /** 创建 pending 审批记录(ASK 动作触发)。返回持久 approval_id。 */
164
+ requestApproval(input: {
165
+ task_id: string;
166
+ action: "accept_nonbinding" | "handoff" | "sensitive_disclosure";
167
+ candidate_digest?: string;
168
+ }): {
169
+ approval_id: string;
170
+ };
171
+ /** 批准一个 pending 审批(绑定授权记录)。 */
172
+ approveApproval(input: {
173
+ approval_id: string;
174
+ authorization: AuthorizationRecord;
175
+ }): void;
176
+ /** 拒绝一个 pending 审批(deny 路径;deny 优先,§5.5)。 */
177
+ rejectApproval(input: {
178
+ approval_id: string;
179
+ reason?: string;
180
+ }): void;
181
+ evaluateAuthorization(action: BuyerAction, opts: {
182
+ taskId: string;
183
+ candidateId?: string;
184
+ candidateDigest?: string;
185
+ approvalId?: string;
186
+ }): Promise<AuthorizationRecord>;
187
+ private limitViolation;
188
+ private firstQuery;
189
+ private currentRounds;
190
+ private decodeTask;
191
+ private parsePayload;
192
+ }