@harrylabsj/kiwi 0.7.21 → 0.8.0
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/README.md +45 -10
- package/dist/a2a/node.js +1 -1
- package/dist/a2a/node.js.map +1 -1
- package/dist/agent/buyer/buyer-tools.d.ts +7 -0
- package/dist/agent/buyer/buyer-tools.js +53 -0
- package/dist/agent/buyer/buyer-tools.js.map +1 -1
- package/dist/agent/buyer/scheduler.d.ts +4 -0
- package/dist/agent/buyer/scheduler.js +5 -1
- package/dist/agent/buyer/scheduler.js.map +1 -1
- package/dist/agent/buyer/task-store.d.ts +5 -0
- package/dist/agent/buyer/task-store.js +13 -0
- package/dist/agent/buyer/task-store.js.map +1 -1
- package/dist/agent/chat-tools.js +10 -3
- package/dist/agent/chat-tools.js.map +1 -1
- package/dist/agent/context/fencing.d.ts +27 -0
- package/dist/agent/context/fencing.js +126 -0
- package/dist/agent/context/fencing.js.map +1 -0
- package/dist/agent/context/grounding.d.ts +18 -0
- package/dist/agent/context/grounding.js +22 -0
- package/dist/agent/context/grounding.js.map +1 -0
- package/dist/agent/host/events.d.ts +31 -0
- package/dist/agent/host/events.js +62 -0
- package/dist/agent/host/events.js.map +1 -0
- package/dist/agent/host/tui-renderer.d.ts +17 -0
- package/dist/agent/host/tui-renderer.js +125 -0
- package/dist/agent/host/tui-renderer.js.map +1 -0
- package/dist/agent/host/web-renderer.d.ts +71 -0
- package/dist/agent/host/web-renderer.js +185 -0
- package/dist/agent/host/web-renderer.js.map +1 -0
- package/dist/agent/kernel-builder.d.ts +3 -1
- package/dist/agent/kernel-builder.js +4 -1
- package/dist/agent/kernel-builder.js.map +1 -1
- package/dist/agent/kernel.d.ts +22 -1
- package/dist/agent/kernel.js +294 -22
- package/dist/agent/kernel.js.map +1 -1
- package/dist/agent/memory/schema.d.ts +1 -1
- package/dist/agent/memory/schema.js +67 -1
- package/dist/agent/memory/schema.js.map +1 -1
- package/dist/agent/merchant/intelligence/backend.d.ts +40 -0
- package/dist/agent/merchant/intelligence/backend.js +2 -0
- package/dist/agent/merchant/intelligence/backend.js.map +1 -0
- package/dist/agent/merchant/intelligence/default-backend.d.ts +38 -0
- package/dist/agent/merchant/intelligence/default-backend.js +454 -0
- package/dist/agent/merchant/intelligence/default-backend.js.map +1 -0
- package/dist/agent/merchant/intelligence/http-analytics-source.d.ts +55 -0
- package/dist/agent/merchant/intelligence/http-analytics-source.js +193 -0
- package/dist/agent/merchant/intelligence/http-analytics-source.js.map +1 -0
- package/dist/agent/merchant/intelligence/types.d.ts +109 -0
- package/dist/agent/merchant/intelligence/types.js +2 -0
- package/dist/agent/merchant/intelligence/types.js.map +1 -0
- package/dist/agent/merchant/merchant-enrichment.d.ts +10 -0
- package/dist/agent/merchant/merchant-enrichment.js +38 -0
- package/dist/agent/merchant/merchant-enrichment.js.map +1 -0
- package/dist/agent/merchant/merchant-grounding.d.ts +5 -0
- package/dist/agent/merchant/merchant-grounding.js +76 -0
- package/dist/agent/merchant/merchant-grounding.js.map +1 -0
- package/dist/agent/merchant/merchant-presentations.d.ts +8 -0
- package/dist/agent/merchant/merchant-presentations.js +184 -0
- package/dist/agent/merchant/merchant-presentations.js.map +1 -0
- package/dist/agent/merchant/merchant-tools.d.ts +8 -0
- package/dist/agent/merchant/merchant-tools.js +208 -9
- package/dist/agent/merchant/merchant-tools.js.map +1 -1
- package/dist/agent/presentation/registry.d.ts +14 -0
- package/dist/agent/presentation/registry.js +24 -0
- package/dist/agent/presentation/registry.js.map +1 -0
- package/dist/agent/presentation/runner.d.ts +11 -0
- package/dist/agent/presentation/runner.js +17 -0
- package/dist/agent/presentation/runner.js.map +1 -0
- package/dist/agent/presentation/sanitize.d.ts +16 -0
- package/dist/agent/presentation/sanitize.js +37 -0
- package/dist/agent/presentation/sanitize.js.map +1 -0
- package/dist/agent/presentation/types.d.ts +28 -0
- package/dist/agent/presentation/types.js +8 -0
- package/dist/agent/presentation/types.js.map +1 -0
- package/dist/agent/session.d.ts +1 -1
- package/dist/agent/session.js +2 -2
- package/dist/agent/session.js.map +1 -1
- package/dist/agent/skills/registry.d.ts +11 -0
- package/dist/agent/skills/registry.js +119 -0
- package/dist/agent/skills/registry.js.map +1 -0
- package/dist/agent/skills/tools.d.ts +6 -0
- package/dist/agent/skills/tools.js +36 -0
- package/dist/agent/skills/tools.js.map +1 -0
- package/dist/agent/skills/types.d.ts +9 -0
- package/dist/agent/skills/types.js +2 -0
- package/dist/agent/skills/types.js.map +1 -0
- package/dist/agent/supplier/scheduler.d.ts +86 -0
- package/dist/agent/supplier/scheduler.js +618 -0
- package/dist/agent/supplier/scheduler.js.map +1 -0
- package/dist/agent/supplier/store.d.ts +173 -0
- package/dist/agent/supplier/store.js +387 -0
- package/dist/agent/supplier/store.js.map +1 -0
- package/dist/agent/system-prompt.d.ts +5 -1
- package/dist/agent/system-prompt.js +20 -3
- package/dist/agent/system-prompt.js.map +1 -1
- package/dist/cli.d.ts +5 -0
- package/dist/cli.js +177 -12
- package/dist/cli.js.map +1 -1
- package/dist/config/profile.d.ts +21 -0
- package/dist/config/profile.js +59 -0
- package/dist/config/profile.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-record.d.ts +2 -0
- package/dist/discovery/catalog-source/kiwi-record.js.map +1 -1
- package/dist/discovery/catalog-source/kiwi-source.js +2 -0
- package/dist/discovery/catalog-source/kiwi-source.js.map +1 -1
- package/dist/handoff/authorization.js +1 -1
- package/dist/http/merchant-server.d.ts +65 -0
- package/dist/http/merchant-server.js +346 -0
- package/dist/http/merchant-server.js.map +1 -0
- package/dist/merchant/stats-store.d.ts +7 -0
- package/dist/merchant/stats-store.js +11 -0
- package/dist/merchant/stats-store.js.map +1 -1
- package/dist/negotiation/action-candidate.js +1 -1
- package/dist/operator/types.d.ts +1 -1
- package/dist/product-cli.d.ts +2 -2
- package/dist/product-cli.js +14 -2
- package/dist/product-cli.js.map +1 -1
- package/dist/product-supplier.d.ts +148 -0
- package/dist/product-supplier.js +452 -0
- package/dist/product-supplier.js.map +1 -0
- package/dist/runtime/fake-model.d.ts +1 -1
- package/dist/trust/identity/jwk.d.ts +11 -0
- package/dist/trust/identity/jwk.js +2 -0
- package/dist/trust/identity/jwk.js.map +1 -0
- package/dist/trust/identity/jws.d.ts +2 -1
- package/dist/trust/identity/jws.js.map +1 -1
- package/dist/trust/identity/keys.d.ts +2 -1
- package/dist/trust/identity/keys.js.map +1 -1
- package/dist/trust/identity/message-signature.d.ts +1 -14
- package/dist/trust/identity/message-signature.js.map +1 -1
- package/dist/weixin/channel.d.ts +3 -0
- package/dist/weixin/channel.js +18 -2
- package/dist/weixin/channel.js.map +1 -1
- package/examples/profiles/merchant.deepseek.yaml +6 -0
- package/examples/profiles/merchant.fake.yaml +6 -0
- package/examples/profiles/merchant.local.yaml +6 -0
- package/package.json +7 -6
- package/skills/kiwi-buyer/SKILL.md +66 -0
- package/skills/merchant/catalog-operations/SKILL.md +17 -0
- package/skills/merchant/change-approval/SKILL.md +16 -0
- package/skills/merchant/human-review/SKILL.md +17 -0
- package/skills/merchant/inventory-operations/SKILL.md +17 -0
- package/skills/merchant/negotiation-review/SKILL.md +18 -0
- package/skills/merchant/performance-insights/SKILL.md +19 -0
- package/contracts/candidate-agent-dto-1.0.README.md +0 -43
- package/contracts/conformance/python-service/README.md +0 -19
|
@@ -0,0 +1,184 @@
|
|
|
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
|
+
*/
|
|
7
|
+
import { sanitizeModelText } from "../context/fencing.js";
|
|
8
|
+
import { publicCandidatePreview } from "./merchant-enrichment.js";
|
|
9
|
+
import { PresentationRegistry } from "../presentation/registry.js";
|
|
10
|
+
const MAX_PERIOD = /^(?:[1-9]|[1-8][0-9]|90)d$/;
|
|
11
|
+
function objectInput(value) {
|
|
12
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
13
|
+
throw new Error("presentation input must be an object");
|
|
14
|
+
}
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
function optionalText(value, field, maxChars) {
|
|
18
|
+
if (value === undefined)
|
|
19
|
+
return undefined;
|
|
20
|
+
if (typeof value !== "string" || value.length > maxChars)
|
|
21
|
+
throw new Error(`${field} must be a string of at most ${maxChars} characters`);
|
|
22
|
+
return sanitizeModelText(value, { maxChars });
|
|
23
|
+
}
|
|
24
|
+
function requireText(value, field, maxChars) {
|
|
25
|
+
const text = optionalText(value, field, maxChars);
|
|
26
|
+
if (text === undefined || text === "")
|
|
27
|
+
throw new Error(`${field} must be a non-empty string`);
|
|
28
|
+
return text;
|
|
29
|
+
}
|
|
30
|
+
function intelligence(context) {
|
|
31
|
+
if (context.intelligence === undefined)
|
|
32
|
+
throw new Error("merchant intelligence is unavailable");
|
|
33
|
+
return context.intelligence;
|
|
34
|
+
}
|
|
35
|
+
function boundedLimit(value, defaultValue) {
|
|
36
|
+
if (value === undefined)
|
|
37
|
+
return defaultValue;
|
|
38
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 1 || value > 50) {
|
|
39
|
+
throw new Error("limit must be an integer between 1 and 50");
|
|
40
|
+
}
|
|
41
|
+
return value;
|
|
42
|
+
}
|
|
43
|
+
function parseDigest(value) {
|
|
44
|
+
const v = objectInput(value);
|
|
45
|
+
const period = optionalText(v.period, "period", 20);
|
|
46
|
+
if (period !== undefined && !MAX_PERIOD.test(period))
|
|
47
|
+
throw new Error("period must use 1d–90d syntax");
|
|
48
|
+
return { ...(optionalText(v.title, "title", 80) ? { title: optionalText(v.title, "title", 80) } : {}), ...(period ? { period } : {}) };
|
|
49
|
+
}
|
|
50
|
+
function parseMetrics(value) {
|
|
51
|
+
const v = objectInput(value);
|
|
52
|
+
const metric = requireText(v.metric, "metric", 80);
|
|
53
|
+
const period = optionalText(v.period, "period", 20);
|
|
54
|
+
if (period !== undefined && !MAX_PERIOD.test(period))
|
|
55
|
+
throw new Error("period must use 1d–90d syntax");
|
|
56
|
+
const granularity = v.granularity === undefined ? "day" : v.granularity;
|
|
57
|
+
if (granularity !== "day" && granularity !== "week" && granularity !== "month")
|
|
58
|
+
throw new Error("invalid granularity");
|
|
59
|
+
return { metric, ...(period ? { period } : {}), granularity };
|
|
60
|
+
}
|
|
61
|
+
function parseCatalog(value) {
|
|
62
|
+
return { limit: boundedLimit(objectInput(value).limit, 20) };
|
|
63
|
+
}
|
|
64
|
+
function parseNegotiations(value) {
|
|
65
|
+
const v = objectInput(value);
|
|
66
|
+
const status = v.status === undefined ? "all" : v.status;
|
|
67
|
+
if (status !== "active" && status !== "agreement" && status !== "all")
|
|
68
|
+
throw new Error("invalid negotiation status");
|
|
69
|
+
return { status, limit: boundedLimit(v.limit, 20) };
|
|
70
|
+
}
|
|
71
|
+
function parseHumanReview(value) {
|
|
72
|
+
return { limit: boundedLimit(objectInput(value).limit, 20) };
|
|
73
|
+
}
|
|
74
|
+
function parseChangePreview(value) {
|
|
75
|
+
const v = objectInput(value);
|
|
76
|
+
return {
|
|
77
|
+
candidate_id: requireText(v.candidate_id, "candidate_id", 200),
|
|
78
|
+
...(optionalText(v.headline, "headline", 120) ? { headline: optionalText(v.headline, "headline", 120) } : {}),
|
|
79
|
+
...(optionalText(v.note, "note", 200) ? { note: optionalText(v.note, "note", 200) } : {}),
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
function parseSuggestions(value) {
|
|
83
|
+
const raw = objectInput(value).suggestions;
|
|
84
|
+
if (!Array.isArray(raw) || raw.length < 1 || raw.length > 4)
|
|
85
|
+
throw new Error("suggestions must contain 1 to 4 items");
|
|
86
|
+
return { suggestions: raw.map((item) => requireText(item, "suggestion", 80)) };
|
|
87
|
+
}
|
|
88
|
+
function component(input) {
|
|
89
|
+
return input;
|
|
90
|
+
}
|
|
91
|
+
export function createMerchantPresentationRegistry() {
|
|
92
|
+
const registry = new PresentationRegistry();
|
|
93
|
+
registry
|
|
94
|
+
.register(component({
|
|
95
|
+
toolName: "present_merchant_digest",
|
|
96
|
+
component: "merchant_digest",
|
|
97
|
+
label: "展示经营摘要",
|
|
98
|
+
description: "展示商家经营摘要、告警、A2A 磋商和待审批事项。真实数据由服务端读取和补全。",
|
|
99
|
+
inputSchema: { type: "object", properties: { title: { type: "string", maxLength: 80 }, period: { type: "string", pattern: "^(?:[1-9]|[1-8][0-9]|90)d$" } }, additionalProperties: false },
|
|
100
|
+
validate: parseDigest,
|
|
101
|
+
enrich: async (input, context) => {
|
|
102
|
+
const backend = intelligence(context);
|
|
103
|
+
const max = context.profile.merchant_experience?.max_presentation_items ?? 12;
|
|
104
|
+
const [snapshot, negotiations, pending] = await Promise.all([
|
|
105
|
+
backend.getBusinessSnapshot({ merchant_id: context.principalId, ...(input.period ? { period: input.period } : {}) }),
|
|
106
|
+
backend.getNegotiationDigest({ merchant_id: context.principalId, status: "active", limit: max }),
|
|
107
|
+
backend.getPendingActions(),
|
|
108
|
+
]);
|
|
109
|
+
return { title: input.title ?? "经营摘要", snapshot, negotiations: negotiations.slice(0, max), pending_actions: pending.slice(0, max) };
|
|
110
|
+
},
|
|
111
|
+
}))
|
|
112
|
+
.register(component({
|
|
113
|
+
toolName: "present_metrics",
|
|
114
|
+
component: "metrics",
|
|
115
|
+
label: "展示经营指标",
|
|
116
|
+
description: "展示一项按日、周或月聚合的经营指标;数据和限制说明由服务端补全。",
|
|
117
|
+
inputSchema: { type: "object", properties: { metric: { type: "string", maxLength: 80 }, period: { type: "string", pattern: "^(?:[1-9]|[1-8][0-9]|90)d$" }, granularity: { type: "string", enum: ["day", "week", "month"] } }, required: ["metric"], additionalProperties: false },
|
|
118
|
+
validate: parseMetrics,
|
|
119
|
+
enrich: (input, context) => intelligence(context).queryMetric({ merchant_id: context.principalId, ...input }),
|
|
120
|
+
}))
|
|
121
|
+
.register(component({
|
|
122
|
+
toolName: "present_catalog",
|
|
123
|
+
component: "catalog",
|
|
124
|
+
label: "展示商品目录",
|
|
125
|
+
description: "展示商家商品目录及库存健康摘要;真实商品数据由服务端读取和补全。",
|
|
126
|
+
inputSchema: { type: "object", properties: { limit: { type: "integer", minimum: 1, maximum: 50 } }, additionalProperties: false },
|
|
127
|
+
validate: parseCatalog,
|
|
128
|
+
enrich: async (input, context) => {
|
|
129
|
+
const [products, health] = await Promise.all([
|
|
130
|
+
context.merchantClient.listProducts(context.principalId),
|
|
131
|
+
intelligence(context).getCatalogHealth({ merchant_id: context.principalId }),
|
|
132
|
+
]);
|
|
133
|
+
return { health, products: products.slice(0, input.limit) };
|
|
134
|
+
},
|
|
135
|
+
}))
|
|
136
|
+
.register(component({
|
|
137
|
+
toolName: "present_negotiations",
|
|
138
|
+
component: "negotiations",
|
|
139
|
+
label: "展示磋商列表",
|
|
140
|
+
description: "展示当前 A2A 磋商列表;状态、报价和时间由 Ledger 服务端补全。",
|
|
141
|
+
inputSchema: { type: "object", properties: { status: { type: "string", enum: ["active", "agreement", "all"] }, limit: { type: "integer", minimum: 1, maximum: 50 } }, additionalProperties: false },
|
|
142
|
+
validate: parseNegotiations,
|
|
143
|
+
enrich: (input, context) => intelligence(context).getNegotiationDigest({ merchant_id: context.principalId, ...input }),
|
|
144
|
+
}))
|
|
145
|
+
.register(component({
|
|
146
|
+
toolName: "present_human_review",
|
|
147
|
+
component: "human_review",
|
|
148
|
+
label: "展示人工审核",
|
|
149
|
+
description: "展示需要人工处理的事项;审核原因和实体由服务端读取和补全。",
|
|
150
|
+
inputSchema: { type: "object", properties: { limit: { type: "integer", minimum: 1, maximum: 50 } }, additionalProperties: false },
|
|
151
|
+
validate: parseHumanReview,
|
|
152
|
+
enrich: async (input, context) => ({ reviews: (await context.merchantClient.getHumanReviewQueue(context.principalId)).slice(0, input.limit) }),
|
|
153
|
+
}))
|
|
154
|
+
.register(component({
|
|
155
|
+
toolName: "present_change_preview",
|
|
156
|
+
component: "change_preview",
|
|
157
|
+
label: "展示变更预览",
|
|
158
|
+
description: "展示一个 WriteApprovalCandidate 的前后差异。展示不会批准或执行变更。",
|
|
159
|
+
inputSchema: { type: "object", properties: { candidate_id: { type: "string" }, headline: { type: "string", maxLength: 120 }, note: { type: "string", maxLength: 200 } }, required: ["candidate_id"], additionalProperties: false },
|
|
160
|
+
validate: parseChangePreview,
|
|
161
|
+
enrich: async (input, context) => {
|
|
162
|
+
const preview = context.intelligence === undefined
|
|
163
|
+
? publicCandidatePreview(context.approvals.get(input.candidate_id))
|
|
164
|
+
: await context.intelligence.getCandidatePreview({
|
|
165
|
+
principal_id: context.principalId,
|
|
166
|
+
candidate_id: input.candidate_id,
|
|
167
|
+
});
|
|
168
|
+
if (preview === undefined)
|
|
169
|
+
throw new Error("未找到当前 principal 的候选操作");
|
|
170
|
+
return { ...preview, headline: input.headline ?? "变更预览", note: input.note ?? "" };
|
|
171
|
+
},
|
|
172
|
+
}))
|
|
173
|
+
.register(component({
|
|
174
|
+
toolName: "present_suggestions",
|
|
175
|
+
component: "suggestions",
|
|
176
|
+
label: "展示下一步建议",
|
|
177
|
+
description: "展示 1–4 个下一步建议。建议只影响 UI,不改变权限或业务状态。",
|
|
178
|
+
inputSchema: { type: "object", properties: { suggestions: { type: "array", minItems: 1, maxItems: 4, items: { type: "string", maxLength: 80 } } }, required: ["suggestions"], additionalProperties: false },
|
|
179
|
+
validate: parseSuggestions,
|
|
180
|
+
enrich: async (input) => ({ suggestions: input.suggestions }),
|
|
181
|
+
}));
|
|
182
|
+
return registry;
|
|
183
|
+
}
|
|
184
|
+
//# sourceMappingURL=merchant-presentations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"merchant-presentations.js","sourceRoot":"","sources":["../../../src/agent/merchant/merchant-presentations.ts"],"names":[],"mappings":"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"}
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
*/
|
|
31
31
|
import type { AgentHarnessTool } from "@earendil-works/pi-agent-core";
|
|
32
32
|
import type { AgentProfile } from "../../config/profile.js";
|
|
33
|
+
import type { AgentHostEventType } from "../host/events.js";
|
|
33
34
|
import type { CommerceDataSource } from "../../commerce/data-source.js";
|
|
34
35
|
import type { CommerceClient } from "../../commerce/types.js";
|
|
35
36
|
import type { AgentMode } from "../mode.js";
|
|
@@ -37,6 +38,7 @@ import type { WriteApprovalCandidateStore } from "./action-candidate.js";
|
|
|
37
38
|
import type { CredentialBroker } from "./credential-broker.js";
|
|
38
39
|
import type { MerchantClient } from "./types.js";
|
|
39
40
|
import type { WriteGateDeps, WriteGateResult } from "../write-gate.js";
|
|
41
|
+
import type { MerchantIntelligenceBackend } from "./intelligence/backend.js";
|
|
40
42
|
type Tool = AgentHarnessTool<undefined>;
|
|
41
43
|
export interface MerchantToolDeps {
|
|
42
44
|
profile: AgentProfile;
|
|
@@ -72,6 +74,12 @@ export interface MerchantToolDeps {
|
|
|
72
74
|
/** 商家 A2A 节点 ledger 目录(`<dataDir>/a2a/ledger`);提供时挂载
|
|
73
75
|
* `list_a2a_negotiations` 工具,让运营者查看真实发生的 A2A 磋商记录。 */
|
|
74
76
|
a2aLedgerDir?: string;
|
|
77
|
+
/** Optional commerce-agents-style merchant application layer. */
|
|
78
|
+
intelligence?: MerchantIntelligenceBackend;
|
|
79
|
+
/** Optional host event projection; business state never depends on it. */
|
|
80
|
+
emitEvent?: (type: AgentHostEventType, data: unknown) => Promise<void>;
|
|
81
|
+
/** Process-bound principal id used by server enrichment. */
|
|
82
|
+
principalId?: string;
|
|
75
83
|
}
|
|
76
84
|
export declare function buildMerchantTools(deps: MerchantToolDeps): Tool[];
|
|
77
85
|
export type { WriteGateResult };
|
|
@@ -13,12 +13,15 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
+
import { fenceModelPayload } from "../context/fencing.js";
|
|
16
17
|
import { LedgerStore } from "../../negotiation/ledger/index.js";
|
|
17
18
|
import { TERMINAL_PHASES } from "../../negotiation/state/phase.js";
|
|
18
19
|
import { buildNegotiationChatTools, writeGateText } from "../negotiation-chat.js";
|
|
19
20
|
import { requireScopeCredential } from "./credential-broker.js";
|
|
20
21
|
import { MerchantClientError } from "./types.js";
|
|
21
22
|
import { routeWriteCandidate } from "../write-gate.js";
|
|
23
|
+
import { createMerchantPresentationRegistry } from "./merchant-presentations.js";
|
|
24
|
+
import { runPresentation } from "../presentation/runner.js";
|
|
22
25
|
function textResult(text, details) {
|
|
23
26
|
return { content: [{ type: "text", text }], details };
|
|
24
27
|
}
|
|
@@ -37,6 +40,13 @@ function errorText(err) {
|
|
|
37
40
|
function optString(value) {
|
|
38
41
|
return typeof value === "string" && value !== "" ? value : undefined;
|
|
39
42
|
}
|
|
43
|
+
function experienceEnabled(profile, capability) {
|
|
44
|
+
const config = profile.merchant_experience;
|
|
45
|
+
return config?.enabled === true && config[capability] !== false;
|
|
46
|
+
}
|
|
47
|
+
function experienceMaxChars(profile) {
|
|
48
|
+
return profile.merchant_experience?.max_external_context_chars ?? 12_000;
|
|
49
|
+
}
|
|
40
50
|
function parseProductInput(value) {
|
|
41
51
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
42
52
|
throw new MerchantClientError("validation", "product 必须是对象");
|
|
@@ -152,7 +162,7 @@ export function buildMerchantTools(deps) {
|
|
|
152
162
|
stock: p.stock ?? null,
|
|
153
163
|
paused: false,
|
|
154
164
|
}));
|
|
155
|
-
return textResult(rows.length === 0 ? "目录为空。" :
|
|
165
|
+
return textResult(rows.length === 0 ? "目录为空。" : fenceModelPayload("merchant_api", rows, { maxChars: experienceMaxChars(profile) }), {
|
|
156
166
|
count: rows.length,
|
|
157
167
|
source: "data-source",
|
|
158
168
|
});
|
|
@@ -165,7 +175,7 @@ export function buildMerchantTools(deps) {
|
|
|
165
175
|
stock: p.stock,
|
|
166
176
|
paused: p.paused,
|
|
167
177
|
}));
|
|
168
|
-
return textResult(rows.length === 0 ? "目录为空。" :
|
|
178
|
+
return textResult(rows.length === 0 ? "目录为空。" : fenceModelPayload("merchant_api", rows, { maxChars: experienceMaxChars(profile) }), { count: rows.length });
|
|
169
179
|
}
|
|
170
180
|
catch (err) {
|
|
171
181
|
return textResult(errorText(err));
|
|
@@ -186,7 +196,7 @@ export function buildMerchantTools(deps) {
|
|
|
186
196
|
try {
|
|
187
197
|
const { sku } = params;
|
|
188
198
|
const product = await merchantClient.getProduct(sku);
|
|
189
|
-
return textResult(
|
|
199
|
+
return textResult(fenceModelPayload("merchant_api", productPreconditions(product), { maxChars: experienceMaxChars(profile) }));
|
|
190
200
|
}
|
|
191
201
|
catch (err) {
|
|
192
202
|
return textResult(errorText(err));
|
|
@@ -207,7 +217,7 @@ export function buildMerchantTools(deps) {
|
|
|
207
217
|
try {
|
|
208
218
|
const { sku } = params;
|
|
209
219
|
const snapshot = await merchantClient.getInventorySnapshot(sku);
|
|
210
|
-
return textResult(
|
|
220
|
+
return textResult(fenceModelPayload("merchant_api", snapshot, { maxChars: experienceMaxChars(profile) }));
|
|
211
221
|
}
|
|
212
222
|
catch (err) {
|
|
213
223
|
return textResult(errorText(err));
|
|
@@ -266,7 +276,10 @@ export function buildMerchantTools(deps) {
|
|
|
266
276
|
rows.sort((a, b) => (a.at > b.at ? -1 : a.at < b.at ? 1 : 0));
|
|
267
277
|
if (rows.length === 0)
|
|
268
278
|
return textResult("当前没有进行中的磋商。", { count: 0 });
|
|
269
|
-
return textResult(
|
|
279
|
+
return textResult(fenceModelPayload("a2a_message", {
|
|
280
|
+
total: rows.length,
|
|
281
|
+
items: rows.map((r) => r.line),
|
|
282
|
+
}, { maxChars: experienceMaxChars(profile) }), {
|
|
270
283
|
count: rows.length,
|
|
271
284
|
});
|
|
272
285
|
},
|
|
@@ -285,9 +298,13 @@ export function buildMerchantTools(deps) {
|
|
|
285
298
|
const reviews = await merchantClient.getHumanReviewQueue(ownerId);
|
|
286
299
|
if (reviews.length === 0)
|
|
287
300
|
return textResult("人工处理队列为空。");
|
|
288
|
-
return textResult(reviews
|
|
289
|
-
|
|
290
|
-
|
|
301
|
+
return textResult(fenceModelPayload("human_review", reviews.map((r) => ({
|
|
302
|
+
review_id: r.review_id,
|
|
303
|
+
conversation_id: r.conversation_id,
|
|
304
|
+
sku: r.sku,
|
|
305
|
+
severity: r.severity,
|
|
306
|
+
reason: r.reason,
|
|
307
|
+
})), { maxChars: experienceMaxChars(profile) }), { count: reviews.length });
|
|
291
308
|
}
|
|
292
309
|
catch (err) {
|
|
293
310
|
return textResult(errorText(err));
|
|
@@ -572,6 +589,184 @@ export function buildMerchantTools(deps) {
|
|
|
572
589
|
}
|
|
573
590
|
},
|
|
574
591
|
};
|
|
592
|
+
const experienceTools = [];
|
|
593
|
+
if (experienceEnabled(profile, "intelligence") && deps.intelligence !== undefined) {
|
|
594
|
+
const intelligence = deps.intelligence;
|
|
595
|
+
const getBusinessSnapshot = {
|
|
596
|
+
name: "get_business_snapshot",
|
|
597
|
+
label: "读取经营摘要",
|
|
598
|
+
description: "读取当前商家经营摘要、咨询/磋商和待处理事项。只读;指标由服务端计算并注明数据限制。",
|
|
599
|
+
parameters: {
|
|
600
|
+
type: "object",
|
|
601
|
+
properties: {
|
|
602
|
+
period: {
|
|
603
|
+
type: "string",
|
|
604
|
+
pattern: "^(?:[1-9]|[1-8][0-9]|90)d$",
|
|
605
|
+
description: "UTC 统计窗口,1d 到 90d,例如 7d、14d、30d",
|
|
606
|
+
},
|
|
607
|
+
},
|
|
608
|
+
additionalProperties: false,
|
|
609
|
+
},
|
|
610
|
+
execute: async (_id, params) => {
|
|
611
|
+
try {
|
|
612
|
+
const period = optString(params.period);
|
|
613
|
+
const snapshot = await intelligence.getBusinessSnapshot({
|
|
614
|
+
merchant_id: ownerId,
|
|
615
|
+
...(period === undefined ? {} : { period }),
|
|
616
|
+
});
|
|
617
|
+
return textResult(fenceModelPayload("metric", snapshot, { maxChars: experienceMaxChars(profile) }), {
|
|
618
|
+
status: "ok",
|
|
619
|
+
metric: "business_snapshot",
|
|
620
|
+
});
|
|
621
|
+
}
|
|
622
|
+
catch (err) {
|
|
623
|
+
return textResult(errorText(err));
|
|
624
|
+
}
|
|
625
|
+
},
|
|
626
|
+
};
|
|
627
|
+
const queryMetric = {
|
|
628
|
+
name: "query_merchant_metric",
|
|
629
|
+
label: "读取经营指标",
|
|
630
|
+
description: "读取一项按日/周/月聚合的商家指标。不可得的指标返回明确说明,不用零值代替。",
|
|
631
|
+
parameters: {
|
|
632
|
+
type: "object",
|
|
633
|
+
properties: {
|
|
634
|
+
metric: { type: "string", description: "指标名,例如 contact_events、negotiations" },
|
|
635
|
+
period: {
|
|
636
|
+
type: "string",
|
|
637
|
+
pattern: "^(?:[1-9]|[1-8][0-9]|90)d$",
|
|
638
|
+
description: "UTC 统计窗口,1d 到 90d,例如 7d、14d、30d",
|
|
639
|
+
},
|
|
640
|
+
granularity: { type: "string", enum: ["day", "week", "month"] },
|
|
641
|
+
},
|
|
642
|
+
required: ["metric"],
|
|
643
|
+
additionalProperties: false,
|
|
644
|
+
},
|
|
645
|
+
execute: async (_id, params) => {
|
|
646
|
+
try {
|
|
647
|
+
const p = params;
|
|
648
|
+
const metric = optString(p.metric);
|
|
649
|
+
if (metric === undefined)
|
|
650
|
+
return textResult("metric 必须是非空字符串。");
|
|
651
|
+
const granularity = p.granularity === "week" || p.granularity === "month" ? p.granularity : "day";
|
|
652
|
+
const series = await intelligence.queryMetric({
|
|
653
|
+
merchant_id: ownerId,
|
|
654
|
+
metric,
|
|
655
|
+
granularity,
|
|
656
|
+
...(optString(p.period) === undefined ? {} : { period: optString(p.period) }),
|
|
657
|
+
});
|
|
658
|
+
return textResult(fenceModelPayload("metric", series, { maxChars: experienceMaxChars(profile) }), {
|
|
659
|
+
status: "ok",
|
|
660
|
+
metric,
|
|
661
|
+
});
|
|
662
|
+
}
|
|
663
|
+
catch (err) {
|
|
664
|
+
return textResult(errorText(err));
|
|
665
|
+
}
|
|
666
|
+
},
|
|
667
|
+
};
|
|
668
|
+
const getNegotiationDigest = {
|
|
669
|
+
name: "get_negotiation_digest",
|
|
670
|
+
label: "读取磋商摘要",
|
|
671
|
+
description: "读取商家 A2A 磋商摘要。返回当前 phase、公开报价和是否需要人工;只读。",
|
|
672
|
+
parameters: {
|
|
673
|
+
type: "object",
|
|
674
|
+
properties: {
|
|
675
|
+
status: { type: "string", enum: ["active", "agreement", "all"] },
|
|
676
|
+
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
677
|
+
},
|
|
678
|
+
additionalProperties: false,
|
|
679
|
+
},
|
|
680
|
+
execute: async (_id, params) => {
|
|
681
|
+
try {
|
|
682
|
+
const p = params;
|
|
683
|
+
const status = p.status === "active" || p.status === "agreement" ? p.status : "all";
|
|
684
|
+
const rawLimit = typeof p.limit === "number" && Number.isFinite(p.limit) ? Math.trunc(p.limit) : 20;
|
|
685
|
+
const rows = await intelligence.getNegotiationDigest({
|
|
686
|
+
merchant_id: ownerId,
|
|
687
|
+
status,
|
|
688
|
+
limit: Math.max(1, Math.min(100, rawLimit)),
|
|
689
|
+
});
|
|
690
|
+
return textResult(fenceModelPayload("a2a_message", rows, { maxChars: experienceMaxChars(profile) }), {
|
|
691
|
+
status: "ok",
|
|
692
|
+
count: rows.length,
|
|
693
|
+
});
|
|
694
|
+
}
|
|
695
|
+
catch (err) {
|
|
696
|
+
return textResult(errorText(err));
|
|
697
|
+
}
|
|
698
|
+
},
|
|
699
|
+
};
|
|
700
|
+
const getCatalogHealth = {
|
|
701
|
+
name: "get_catalog_health",
|
|
702
|
+
label: "读取目录健康度",
|
|
703
|
+
description: "读取商品总量、上下架状态和缺货数量;精确库存不可得时返回 null 及限制说明。",
|
|
704
|
+
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
705
|
+
execute: async () => {
|
|
706
|
+
try {
|
|
707
|
+
const health = await intelligence.getCatalogHealth({ merchant_id: ownerId });
|
|
708
|
+
return textResult(fenceModelPayload("merchant_api", health, { maxChars: experienceMaxChars(profile) }), {
|
|
709
|
+
status: "ok",
|
|
710
|
+
});
|
|
711
|
+
}
|
|
712
|
+
catch (err) {
|
|
713
|
+
return textResult(errorText(err));
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
};
|
|
717
|
+
const getPendingActions = {
|
|
718
|
+
name: "get_pending_actions",
|
|
719
|
+
label: "读取待审批操作",
|
|
720
|
+
description: "读取当前 principal 的待审批写操作。返回候选元数据,不返回私有阈值或凭据。",
|
|
721
|
+
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
722
|
+
execute: async () => {
|
|
723
|
+
try {
|
|
724
|
+
const rows = await intelligence.getPendingActions();
|
|
725
|
+
return textResult(fenceModelPayload("merchant_api", rows, { maxChars: experienceMaxChars(profile) }), {
|
|
726
|
+
status: "ok",
|
|
727
|
+
count: rows.length,
|
|
728
|
+
});
|
|
729
|
+
}
|
|
730
|
+
catch (err) {
|
|
731
|
+
return textResult(errorText(err));
|
|
732
|
+
}
|
|
733
|
+
},
|
|
734
|
+
};
|
|
735
|
+
experienceTools.push(getBusinessSnapshot, queryMetric, getCatalogHealth, getNegotiationDigest, getPendingActions);
|
|
736
|
+
}
|
|
737
|
+
if (experienceEnabled(profile, "presentation") && deps.emitEvent !== undefined) {
|
|
738
|
+
const registry = createMerchantPresentationRegistry();
|
|
739
|
+
const emitUi = async (component, payload) => {
|
|
740
|
+
await deps.emitEvent?.("ui", { component, payload });
|
|
741
|
+
};
|
|
742
|
+
const presentationContext = {
|
|
743
|
+
profile,
|
|
744
|
+
principalId: deps.principalId ?? ownerId,
|
|
745
|
+
merchantClient,
|
|
746
|
+
approvals,
|
|
747
|
+
...(deps.intelligence !== undefined ? { intelligence: deps.intelligence } : {}),
|
|
748
|
+
};
|
|
749
|
+
for (const component of registry.list()) {
|
|
750
|
+
const presentationTool = {
|
|
751
|
+
name: component.toolName,
|
|
752
|
+
label: component.label,
|
|
753
|
+
description: component.description,
|
|
754
|
+
parameters: component.inputSchema,
|
|
755
|
+
execute: async (_id, params) => {
|
|
756
|
+
try {
|
|
757
|
+
const result = await runPresentation(registry, component.toolName, params, presentationContext, emitUi);
|
|
758
|
+
return textResult(component.toolName === "present_change_preview"
|
|
759
|
+
? "已展示变更预览;尚未批准或执行。"
|
|
760
|
+
: `已展示${component.label.replace(/^展示/, "")}。`, { component: result.component });
|
|
761
|
+
}
|
|
762
|
+
catch (err) {
|
|
763
|
+
return textResult(errorText(err));
|
|
764
|
+
}
|
|
765
|
+
},
|
|
766
|
+
};
|
|
767
|
+
experienceTools.push(presentationTool);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
575
770
|
const negotiationTools = deps.commerceClient !== undefined
|
|
576
771
|
? buildNegotiationChatTools({
|
|
577
772
|
profile,
|
|
@@ -658,7 +853,10 @@ export function buildMerchantTools(deps) {
|
|
|
658
853
|
const recent = rows.slice(0, limit);
|
|
659
854
|
if (recent.length === 0)
|
|
660
855
|
return textResult("暂无 A2A 磋商记录。", { count: 0 });
|
|
661
|
-
return textResult(
|
|
856
|
+
return textResult(fenceModelPayload("a2a_message", {
|
|
857
|
+
total: rows.length,
|
|
858
|
+
items: recent.map((r) => r.line),
|
|
859
|
+
}, { maxChars: experienceMaxChars(profile) }), {
|
|
662
860
|
count: recent.length,
|
|
663
861
|
});
|
|
664
862
|
},
|
|
@@ -670,6 +868,7 @@ export function buildMerchantTools(deps) {
|
|
|
670
868
|
listConsultations,
|
|
671
869
|
humanReviewQueue,
|
|
672
870
|
viewPrivateThresholds,
|
|
871
|
+
...experienceTools,
|
|
673
872
|
...negotiationTools,
|
|
674
873
|
createProduct,
|
|
675
874
|
updateProduct,
|