@harrylabsj/kiwi 0.7.22 → 0.9.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/negotiate.d.ts +6 -2
- package/dist/a2a/negotiate.js +10 -3
- package/dist/a2a/negotiate.js.map +1 -1
- package/dist/a2a/node.d.ts +4 -1
- package/dist/a2a/node.js +57 -4
- package/dist/a2a/node.js.map +1 -1
- package/dist/a2a/server/merchant-handler.d.ts +11 -3
- package/dist/a2a/server/merchant-handler.js +84 -26
- package/dist/a2a/server/merchant-handler.js.map +1 -1
- package/dist/agent/buyer/buyer-tools.js +17 -10
- package/dist/agent/buyer/buyer-tools.js.map +1 -1
- package/dist/agent/buyer/scheduler.d.ts +1 -0
- package/dist/agent/buyer/scheduler.js +5 -1
- package/dist/agent/buyer/scheduler.js.map +1 -1
- package/dist/agent/buyer/task-store.js +5 -2
- 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 +20 -1
- package/dist/agent/kernel.js +255 -14
- package/dist/agent/kernel.js.map +1 -1
- package/dist/agent/memory/schema.d.ts +1 -1
- package/dist/agent/memory/schema.js +9 -1
- package/dist/agent/memory/schema.js.map +1 -1
- package/dist/agent/merchant/action-candidate.d.ts +18 -0
- package/dist/agent/merchant/action-candidate.js +51 -0
- package/dist/agent/merchant/action-candidate.js.map +1 -1
- package/dist/agent/merchant/fake-merchant-client.js +6 -1
- package/dist/agent/merchant/fake-merchant-client.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 +477 -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-client.d.ts +50 -1
- package/dist/agent/merchant/merchant-client.js +157 -8
- package/dist/agent/merchant/merchant-client.js.map +1 -1
- 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 +207 -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 +291 -178
- package/dist/agent/merchant/merchant-tools.js.map +1 -1
- package/dist/agent/merchant/types.d.ts +6 -2
- package/dist/agent/merchant/types.js +45 -0
- package/dist/agent/merchant/types.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 +2 -0
- package/dist/agent/supplier/scheduler.js +101 -22
- package/dist/agent/supplier/scheduler.js.map +1 -1
- package/dist/agent/supplier/store.d.ts +2 -0
- package/dist/agent/supplier/store.js +44 -0
- package/dist/agent/supplier/store.js.map +1 -1
- 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/auth/merchant-authorization.d.ts +49 -0
- package/dist/auth/merchant-authorization.js +61 -0
- package/dist/auth/merchant-authorization.js.map +1 -0
- package/dist/auth/merchant-oauth.d.ts +255 -0
- package/dist/auth/merchant-oauth.js +764 -0
- package/dist/auth/merchant-oauth.js.map +1 -0
- package/dist/auth/merchant-pairing.d.ts +62 -0
- package/dist/auth/merchant-pairing.js +199 -0
- package/dist/auth/merchant-pairing.js.map +1 -0
- package/dist/auth/merchant-sessions.d.ts +71 -0
- package/dist/auth/merchant-sessions.js +168 -0
- package/dist/auth/merchant-sessions.js.map +1 -0
- package/dist/buyer-core/build-service.d.ts +5 -0
- package/dist/buyer-core/build-service.js +12 -0
- package/dist/buyer-core/build-service.js.map +1 -1
- package/dist/buyer-core/errors.d.ts +1 -1
- package/dist/buyer-core/errors.js +2 -0
- package/dist/buyer-core/errors.js.map +1 -1
- package/dist/buyer-core/merchant-index.d.ts +19 -4
- package/dist/buyer-core/merchant-index.js +137 -16
- package/dist/buyer-core/merchant-index.js.map +1 -1
- package/dist/buyer-core/negotiator.d.ts +0 -10
- package/dist/buyer-core/negotiator.js +12 -1
- package/dist/buyer-core/negotiator.js.map +1 -1
- package/dist/buyer-core/quote-fetcher.js +2 -1
- package/dist/buyer-core/quote-fetcher.js.map +1 -1
- package/dist/buyer-core/service.d.ts +104 -0
- package/dist/buyer-core/service.js +105 -1
- package/dist/buyer-core/service.js.map +1 -1
- package/dist/cli.d.ts +4 -2
- package/dist/cli.js +644 -32
- package/dist/cli.js.map +1 -1
- package/dist/config/profile.d.ts +51 -0
- package/dist/config/profile.js +185 -61
- package/dist/config/profile.js.map +1 -1
- package/dist/demo/demo-runner.js +12 -9
- package/dist/demo/demo-runner.js.map +1 -1
- package/dist/discovery/catalog-source/buyer-follows.d.ts +82 -0
- package/dist/discovery/catalog-source/buyer-follows.js +228 -0
- package/dist/discovery/catalog-source/buyer-follows.js.map +1 -0
- package/dist/discovery/catalog-source/connector-identity.d.ts +75 -0
- package/dist/discovery/catalog-source/connector-identity.js +175 -0
- package/dist/discovery/catalog-source/connector-identity.js.map +1 -0
- package/dist/discovery/catalog-source/errors.d.ts +1 -1
- package/dist/discovery/catalog-source/errors.js +2 -0
- package/dist/discovery/catalog-source/errors.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/discovery/catalog-source/merchant-publications.d.ts +65 -0
- package/dist/discovery/catalog-source/merchant-publications.js +207 -0
- package/dist/discovery/catalog-source/merchant-publications.js.map +1 -0
- package/dist/discovery/catalog-source/register.d.ts +24 -0
- package/dist/discovery/catalog-source/register.js +46 -0
- package/dist/discovery/catalog-source/register.js.map +1 -1
- package/dist/discovery/catalog-source/source.js +2 -1
- package/dist/discovery/catalog-source/source.js.map +1 -1
- package/dist/fs/atomic-write.d.ts +18 -0
- package/dist/fs/atomic-write.js +29 -0
- package/dist/fs/atomic-write.js.map +1 -0
- 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/http/server.js +4 -1
- package/dist/http/server.js.map +1 -1
- package/dist/mcp/cli.d.ts +2 -0
- package/dist/mcp/cli.js +7 -6
- package/dist/mcp/cli.js.map +1 -1
- package/dist/mcp/merchant-auth.d.ts +78 -0
- package/dist/mcp/merchant-auth.js +146 -0
- package/dist/mcp/merchant-auth.js.map +1 -0
- package/dist/mcp/merchant-dirs.d.ts +26 -0
- package/dist/mcp/merchant-dirs.js +44 -0
- package/dist/mcp/merchant-dirs.js.map +1 -0
- package/dist/mcp/merchant-resources.d.ts +38 -0
- package/dist/mcp/merchant-resources.js +146 -0
- package/dist/mcp/merchant-resources.js.map +1 -0
- package/dist/mcp/merchant-server.d.ts +106 -0
- package/dist/mcp/merchant-server.js +615 -0
- package/dist/mcp/merchant-server.js.map +1 -0
- package/dist/mcp/merchant-tools.d.ts +103 -0
- package/dist/mcp/merchant-tools.js +517 -0
- package/dist/mcp/merchant-tools.js.map +1 -0
- package/dist/mcp/server.js +4 -3
- package/dist/mcp/server.js.map +1 -1
- package/dist/mcp/tools.d.ts +5 -3
- package/dist/mcp/tools.js +102 -5
- package/dist/mcp/tools.js.map +1 -1
- package/dist/mcp/types.d.ts +1 -1
- package/dist/mcp/types.js +4 -0
- package/dist/mcp/types.js.map +1 -1
- package/dist/merchant/ops.d.ts +0 -11
- package/dist/merchant/ops.js +13 -1
- package/dist/merchant/ops.js.map +1 -1
- 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/merchant/workbench-service.d.ts +189 -0
- package/dist/merchant/workbench-service.js +417 -0
- package/dist/merchant/workbench-service.js.map +1 -0
- package/dist/merchant-admin/pending-page.d.ts +35 -0
- package/dist/merchant-admin/pending-page.js +69 -0
- package/dist/merchant-admin/pending-page.js.map +1 -0
- package/dist/merchant-core/commands.d.ts +99 -0
- package/dist/merchant-core/commands.js +179 -0
- package/dist/merchant-core/commands.js.map +1 -0
- package/dist/merchant-core/executor.d.ts +69 -0
- package/dist/merchant-core/executor.js +218 -0
- package/dist/merchant-core/executor.js.map +1 -0
- package/dist/merchant-core/negotiation-adapters.d.ts +55 -0
- package/dist/merchant-core/negotiation-adapters.js +55 -0
- package/dist/merchant-core/negotiation-adapters.js.map +1 -0
- package/dist/merchant-core/network-checks.d.ts +65 -0
- package/dist/merchant-core/network-checks.js +111 -0
- package/dist/merchant-core/network-checks.js.map +1 -0
- package/dist/merchant-core/operations.d.ts +64 -0
- package/dist/merchant-core/operations.js +136 -0
- package/dist/merchant-core/operations.js.map +1 -0
- package/dist/merchant-core/policy-runtime.d.ts +70 -0
- package/dist/merchant-core/policy-runtime.js +181 -0
- package/dist/merchant-core/policy-runtime.js.map +1 -0
- package/dist/merchant-core/product-import.d.ts +67 -0
- package/dist/merchant-core/product-import.js +160 -0
- package/dist/merchant-core/product-import.js.map +1 -0
- package/dist/merchant-core/service.d.ts +203 -0
- package/dist/merchant-core/service.js +402 -0
- package/dist/merchant-core/service.js.map +1 -0
- package/dist/merchant-gateway/catalog-publications.d.ts +71 -0
- package/dist/merchant-gateway/catalog-publications.js +175 -0
- package/dist/merchant-gateway/catalog-publications.js.map +1 -0
- package/dist/merchant-gateway/catalog-tools.d.ts +46 -0
- package/dist/merchant-gateway/catalog-tools.js +277 -0
- package/dist/merchant-gateway/catalog-tools.js.map +1 -0
- package/dist/merchant-gateway/cli.d.ts +75 -0
- package/dist/merchant-gateway/cli.js +458 -0
- package/dist/merchant-gateway/cli.js.map +1 -0
- package/dist/merchant-gateway/credential-vault.d.ts +44 -0
- package/dist/merchant-gateway/credential-vault.js +111 -0
- package/dist/merchant-gateway/credential-vault.js.map +1 -0
- package/dist/merchant-gateway/entry-server.d.ts +117 -0
- package/dist/merchant-gateway/entry-server.js +710 -0
- package/dist/merchant-gateway/entry-server.js.map +1 -0
- package/dist/merchant-gateway/instance-registration.d.ts +143 -0
- package/dist/merchant-gateway/instance-registration.js +382 -0
- package/dist/merchant-gateway/instance-registration.js.map +1 -0
- package/dist/merchant-gateway/instance-tools.d.ts +58 -0
- package/dist/merchant-gateway/instance-tools.js +184 -0
- package/dist/merchant-gateway/instance-tools.js.map +1 -0
- package/dist/merchant-gateway/mcp-proxy.d.ts +25 -0
- package/dist/merchant-gateway/mcp-proxy.js +192 -0
- package/dist/merchant-gateway/mcp-proxy.js.map +1 -0
- package/dist/merchant-gateway/pinned-fetch.d.ts +52 -0
- package/dist/merchant-gateway/pinned-fetch.js +212 -0
- package/dist/merchant-gateway/pinned-fetch.js.map +1 -0
- package/dist/merchant-gateway/tenant-registry.d.ts +82 -0
- package/dist/merchant-gateway/tenant-registry.js +190 -0
- package/dist/merchant-gateway/tenant-registry.js.map +1 -0
- package/dist/merchant-gateway/tool-bundle.d.ts +26 -0
- package/dist/merchant-gateway/tool-bundle.js +56 -0
- package/dist/merchant-gateway/tool-bundle.js.map +1 -0
- package/dist/merchant-runtime/backup.d.ts +48 -0
- package/dist/merchant-runtime/backup.js +226 -0
- package/dist/merchant-runtime/backup.js.map +1 -0
- package/dist/merchant-runtime/health.d.ts +99 -0
- package/dist/merchant-runtime/health.js +206 -0
- package/dist/merchant-runtime/health.js.map +1 -0
- package/dist/merchant-runtime/jobs.d.ts +64 -0
- package/dist/merchant-runtime/jobs.js +107 -0
- package/dist/merchant-runtime/jobs.js.map +1 -0
- package/dist/merchant-runtime/manager.d.ts +94 -0
- package/dist/merchant-runtime/manager.js +305 -0
- package/dist/merchant-runtime/manager.js.map +1 -0
- package/dist/merchant-runtime/services.d.ts +30 -0
- package/dist/merchant-runtime/services.js +51 -0
- package/dist/merchant-runtime/services.js.map +1 -0
- package/dist/negotiation/action-candidate.js +1 -1
- package/dist/net/url.d.ts +26 -0
- package/dist/net/url.js +32 -0
- package/dist/net/url.js.map +1 -0
- package/dist/operator/types.d.ts +1 -1
- package/dist/product-cli.d.ts +2 -2
- package/dist/product-cli.js +27 -6
- package/dist/product-cli.js.map +1 -1
- package/dist/product-compat.d.ts +9 -1
- package/dist/product-compat.js +12 -1
- package/dist/product-compat.js.map +1 -1
- package/dist/product-init.js +17 -5
- package/dist/product-init.js.map +1 -1
- package/dist/product-publish.js +2 -1
- package/dist/product-publish.js.map +1 -1
- package/dist/product-supplier.d.ts +73 -0
- package/dist/product-supplier.js +224 -5
- package/dist/product-supplier.js.map +1 -1
- 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 +9 -7
- package/skills/kiwi-buyer/SKILL.md +68 -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
|
@@ -13,16 +13,27 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
16
|
+
import { fenceModelPayload } from "../context/fencing.js";
|
|
17
|
+
import { MerchantWorkbenchError, MerchantWorkbenchService, parseProductPatch, publicProductView, } from "../../merchant/workbench-service.js";
|
|
18
18
|
import { buildNegotiationChatTools, writeGateText } from "../negotiation-chat.js";
|
|
19
19
|
import { requireScopeCredential } from "./credential-broker.js";
|
|
20
20
|
import { MerchantClientError } from "./types.js";
|
|
21
21
|
import { routeWriteCandidate } from "../write-gate.js";
|
|
22
|
+
import { createMerchantPresentationRegistry } from "./merchant-presentations.js";
|
|
23
|
+
import { runPresentation } from "../presentation/runner.js";
|
|
22
24
|
function textResult(text, details) {
|
|
23
25
|
return { content: [{ type: "text", text }], details };
|
|
24
26
|
}
|
|
25
27
|
function errorText(err) {
|
|
28
|
+
if (err instanceof MerchantWorkbenchError) {
|
|
29
|
+
const kindLabel = {
|
|
30
|
+
auth: "凭据被拒或缺失",
|
|
31
|
+
not_found: "未找到",
|
|
32
|
+
validation: "参数或服务校验失败",
|
|
33
|
+
unavailable: "暂时性错误",
|
|
34
|
+
};
|
|
35
|
+
return `商家操作失败(${kindLabel[err.kind] ?? err.kind}):${err.message}`;
|
|
36
|
+
}
|
|
26
37
|
if (err instanceof MerchantClientError) {
|
|
27
38
|
const kindLabel = {
|
|
28
39
|
auth: "凭据被拒或缺失",
|
|
@@ -37,6 +48,13 @@ function errorText(err) {
|
|
|
37
48
|
function optString(value) {
|
|
38
49
|
return typeof value === "string" && value !== "" ? value : undefined;
|
|
39
50
|
}
|
|
51
|
+
function experienceEnabled(profile, capability) {
|
|
52
|
+
const config = profile.merchant_experience;
|
|
53
|
+
return config?.enabled === true && config[capability] !== false;
|
|
54
|
+
}
|
|
55
|
+
function experienceMaxChars(profile) {
|
|
56
|
+
return profile.merchant_experience?.max_external_context_chars ?? 12_000;
|
|
57
|
+
}
|
|
40
58
|
function parseProductInput(value) {
|
|
41
59
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
42
60
|
throw new MerchantClientError("validation", "product 必须是对象");
|
|
@@ -65,43 +83,6 @@ function parseProductInput(value) {
|
|
|
65
83
|
: {}),
|
|
66
84
|
};
|
|
67
85
|
}
|
|
68
|
-
function parseChanges(value) {
|
|
69
|
-
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
70
|
-
throw new MerchantClientError("validation", "changes 必须是对象");
|
|
71
|
-
}
|
|
72
|
-
const v = value;
|
|
73
|
-
const patch = {};
|
|
74
|
-
if (typeof v.title === "string")
|
|
75
|
-
patch.title = v.title;
|
|
76
|
-
if (typeof v.price === "number" && Number.isFinite(v.price))
|
|
77
|
-
patch.price = v.price;
|
|
78
|
-
if (typeof v.stock === "number" && Number.isInteger(v.stock))
|
|
79
|
-
patch.stock = v.stock;
|
|
80
|
-
if (typeof v.currency === "string")
|
|
81
|
-
patch.currency = v.currency;
|
|
82
|
-
if (typeof v.category === "string")
|
|
83
|
-
patch.category = v.category;
|
|
84
|
-
if (Array.isArray(v.tags))
|
|
85
|
-
patch.tags = v.tags.map(String);
|
|
86
|
-
if (typeof v.description === "string")
|
|
87
|
-
patch.description = v.description;
|
|
88
|
-
if (Array.isArray(v.delivery_attributes))
|
|
89
|
-
patch.delivery_attributes = v.delivery_attributes.map(String);
|
|
90
|
-
if (typeof v.paused === "boolean")
|
|
91
|
-
patch.paused = v.paused;
|
|
92
|
-
return patch;
|
|
93
|
-
}
|
|
94
|
-
/** Public precondition snapshot of a product (no private values). */
|
|
95
|
-
function productPreconditions(product) {
|
|
96
|
-
return {
|
|
97
|
-
sku: product.sku,
|
|
98
|
-
merchant_id: product.merchant_id,
|
|
99
|
-
title: product.title,
|
|
100
|
-
price: product.price,
|
|
101
|
-
stock: product.stock,
|
|
102
|
-
paused: product.paused,
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
86
|
/**
|
|
106
87
|
* Autopilot escalation for catalog/inventory writes: anything outside the
|
|
107
88
|
* profile HardPolicy (private floor, max auto discount) needs a human. The
|
|
@@ -130,6 +111,19 @@ export function buildMerchantTools(deps) {
|
|
|
130
111
|
const { profile, merchantClient, broker, approvals, mode, now } = deps;
|
|
131
112
|
const ownerId = profile.owner_id;
|
|
132
113
|
const writeGateDeps = { mode, approvals, profile, now, registerPending: deps.registerPending };
|
|
114
|
+
// Merchant Workbench Facade(WorkBuddy 计划阶段一):只读工具与草稿写工具的
|
|
115
|
+
// 业务逻辑下沉到不依赖 Pi Agent Core 的服务层;工具层只负责 fencing、文案与 details。
|
|
116
|
+
const workbench = new MerchantWorkbenchService({
|
|
117
|
+
profile,
|
|
118
|
+
merchantClient,
|
|
119
|
+
approvals,
|
|
120
|
+
mode,
|
|
121
|
+
now,
|
|
122
|
+
...(deps.dataSource !== undefined ? { dataSource: deps.dataSource } : {}),
|
|
123
|
+
...(deps.registerPending !== undefined ? { registerPending: deps.registerPending } : {}),
|
|
124
|
+
...(deps.a2aLedgerDir !== undefined ? { a2aLedgerDir: deps.a2aLedgerDir } : {}),
|
|
125
|
+
...(deps.intelligence !== undefined ? { intelligence: deps.intelligence } : {}),
|
|
126
|
+
});
|
|
133
127
|
// ---- read-only tools -------------------------------------------------------
|
|
134
128
|
const listProducts = {
|
|
135
129
|
name: "list_catalog_products",
|
|
@@ -143,29 +137,22 @@ export function buildMerchantTools(deps) {
|
|
|
143
137
|
execute: async (_id, _params) => {
|
|
144
138
|
try {
|
|
145
139
|
// Always the merchant's own catalog — never an arbitrary merchant_id.
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
const rows = facts.map((p) => ({
|
|
149
|
-
sku: p.sku,
|
|
150
|
-
title: p.title ?? "",
|
|
151
|
-
price: p.price_minor ?? 0,
|
|
152
|
-
stock: p.stock ?? null,
|
|
153
|
-
paused: false,
|
|
154
|
-
}));
|
|
155
|
-
return textResult(rows.length === 0 ? "目录为空。" : JSON.stringify(rows), {
|
|
156
|
-
count: rows.length,
|
|
157
|
-
source: "data-source",
|
|
158
|
-
});
|
|
159
|
-
}
|
|
160
|
-
const products = await merchantClient.listProducts(ownerId);
|
|
161
|
-
const rows = products.map((p) => ({
|
|
140
|
+
const { items, source } = await workbench.listPublicProducts();
|
|
141
|
+
const rows = items.map((p) => ({
|
|
162
142
|
sku: p.sku,
|
|
163
143
|
title: p.title,
|
|
164
144
|
price: p.price,
|
|
165
145
|
stock: p.stock,
|
|
166
146
|
paused: p.paused,
|
|
167
147
|
}));
|
|
168
|
-
return textResult(rows.length === 0
|
|
148
|
+
return textResult(rows.length === 0
|
|
149
|
+
? "目录为空。"
|
|
150
|
+
: fenceModelPayload("merchant_api", rows, { maxChars: experienceMaxChars(profile) }), source === "data_source"
|
|
151
|
+
? {
|
|
152
|
+
count: rows.length,
|
|
153
|
+
source: "data-source",
|
|
154
|
+
}
|
|
155
|
+
: { count: rows.length });
|
|
169
156
|
}
|
|
170
157
|
catch (err) {
|
|
171
158
|
return textResult(errorText(err));
|
|
@@ -185,8 +172,8 @@ export function buildMerchantTools(deps) {
|
|
|
185
172
|
execute: async (_id, params) => {
|
|
186
173
|
try {
|
|
187
174
|
const { sku } = params;
|
|
188
|
-
const product = await
|
|
189
|
-
return textResult(
|
|
175
|
+
const product = await workbench.getPublicProduct(sku);
|
|
176
|
+
return textResult(fenceModelPayload("merchant_api", product, { maxChars: experienceMaxChars(profile) }));
|
|
190
177
|
}
|
|
191
178
|
catch (err) {
|
|
192
179
|
return textResult(errorText(err));
|
|
@@ -206,8 +193,8 @@ export function buildMerchantTools(deps) {
|
|
|
206
193
|
execute: async (_id, params) => {
|
|
207
194
|
try {
|
|
208
195
|
const { sku } = params;
|
|
209
|
-
const snapshot = await
|
|
210
|
-
return textResult(
|
|
196
|
+
const snapshot = await workbench.getInventorySnapshot(sku);
|
|
197
|
+
return textResult(fenceModelPayload("merchant_api", snapshot, { maxChars: experienceMaxChars(profile) }));
|
|
211
198
|
}
|
|
212
199
|
catch (err) {
|
|
213
200
|
return textResult(errorText(err));
|
|
@@ -226,49 +213,27 @@ export function buildMerchantTools(deps) {
|
|
|
226
213
|
additionalProperties: false,
|
|
227
214
|
},
|
|
228
215
|
execute: async (_id, _params) => {
|
|
229
|
-
|
|
230
|
-
if (ledgerDir === undefined) {
|
|
216
|
+
if (deps.a2aLedgerDir === undefined) {
|
|
231
217
|
return textResult("未配置 A2A ledger 目录,无法读取磋商记录。");
|
|
232
218
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
if (e.event_kind === "message_sent") {
|
|
247
|
-
const wp = e.wire_payload;
|
|
248
|
-
const item = wp?.payload?.terms?.items?.[0];
|
|
249
|
-
if (item?.sku !== undefined && item.sku !== "")
|
|
250
|
-
sku = item.sku;
|
|
251
|
-
if (item?.quantity?.value !== undefined)
|
|
252
|
-
qty = item.quantity.value;
|
|
253
|
-
if (item?.unit_price?.amount_minor !== undefined)
|
|
254
|
-
priceMinor = item.unit_price.amount_minor;
|
|
255
|
-
}
|
|
256
|
-
}
|
|
257
|
-
// 已到终态(AGREEMENT_REACHED/DECLINED/WITHDRAWN/CANCELLED/EXPIRED)不算进行中
|
|
258
|
-
if (TERMINAL_PHASES.includes(phase))
|
|
259
|
-
continue;
|
|
260
|
-
const price = priceMinor !== undefined ? `,价 ${(priceMinor / 100).toFixed(2)} 元/件` : "";
|
|
261
|
-
rows.push({
|
|
262
|
-
at,
|
|
263
|
-
line: `· ${negotiationId}(${phase})SKU=${sku || "-"} 数量=${qty ?? "-"}${price} ${at}`,
|
|
219
|
+
try {
|
|
220
|
+
const rows = await workbench.listActiveConsultations();
|
|
221
|
+
const lines = rows.map((r) => {
|
|
222
|
+
const price = r.price_minor !== undefined ? `,价 ${(r.price_minor / 100).toFixed(2)} 元/件` : "";
|
|
223
|
+
return `· ${r.negotiation_id}(${r.phase})SKU=${r.sku || "-"} 数量=${r.quantity ?? "-"}${price} ${r.recorded_at}`;
|
|
224
|
+
});
|
|
225
|
+
if (lines.length === 0)
|
|
226
|
+
return textResult("当前没有进行中的磋商。", { count: 0 });
|
|
227
|
+
return textResult(fenceModelPayload("a2a_message", {
|
|
228
|
+
total: lines.length,
|
|
229
|
+
items: lines,
|
|
230
|
+
}, { maxChars: experienceMaxChars(profile) }), {
|
|
231
|
+
count: lines.length,
|
|
264
232
|
});
|
|
265
233
|
}
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
return textResult(`共 ${rows.length} 笔进行中磋商:\n${rows.map((r) => r.line).join("\n")}`, {
|
|
270
|
-
count: rows.length,
|
|
271
|
-
});
|
|
234
|
+
catch (err) {
|
|
235
|
+
return textResult(errorText(err));
|
|
236
|
+
}
|
|
272
237
|
},
|
|
273
238
|
};
|
|
274
239
|
const humanReviewQueue = {
|
|
@@ -282,12 +247,10 @@ export function buildMerchantTools(deps) {
|
|
|
282
247
|
},
|
|
283
248
|
execute: async (_id, _params) => {
|
|
284
249
|
try {
|
|
285
|
-
const reviews = await
|
|
250
|
+
const reviews = await workbench.listHumanReviews();
|
|
286
251
|
if (reviews.length === 0)
|
|
287
252
|
return textResult("人工处理队列为空。");
|
|
288
|
-
return textResult(reviews
|
|
289
|
-
.map((r) => `· #${String(r.review_id)} ${r.sku} [${r.severity}] ${r.reason}(${r.conversation_id})`)
|
|
290
|
-
.join("\n"), { count: reviews.length });
|
|
253
|
+
return textResult(fenceModelPayload("human_review", reviews, { maxChars: experienceMaxChars(profile) }), { count: reviews.length });
|
|
291
254
|
}
|
|
292
255
|
catch (err) {
|
|
293
256
|
return textResult(errorText(err));
|
|
@@ -373,7 +336,7 @@ export function buildMerchantTools(deps) {
|
|
|
373
336
|
return textResult(credential.reason);
|
|
374
337
|
try {
|
|
375
338
|
const p = params;
|
|
376
|
-
const patch =
|
|
339
|
+
const patch = parseProductPatch(p.changes);
|
|
377
340
|
if (Object.keys(patch).length === 0) {
|
|
378
341
|
return textResult("changes 没有任何可修改字段。");
|
|
379
342
|
}
|
|
@@ -385,7 +348,7 @@ export function buildMerchantTools(deps) {
|
|
|
385
348
|
return textResult(`商品 ${p.sku} 不存在。`);
|
|
386
349
|
}
|
|
387
350
|
const args = { sku: p.sku, changes: { ...patch } };
|
|
388
|
-
const preconditions =
|
|
351
|
+
const preconditions = publicProductView(current);
|
|
389
352
|
const escalation = catalogEscalation(profile, args, current);
|
|
390
353
|
const outcome = await routeWriteCandidate(writeGateDeps, {
|
|
391
354
|
tool: "update_product",
|
|
@@ -398,7 +361,7 @@ export function buildMerchantTools(deps) {
|
|
|
398
361
|
},
|
|
399
362
|
readPreconditions: async () => {
|
|
400
363
|
const fresh = await merchantClient.getProduct(p.sku);
|
|
401
|
-
return
|
|
364
|
+
return publicProductView(fresh);
|
|
402
365
|
},
|
|
403
366
|
autopilotEscalation: () => escalation,
|
|
404
367
|
});
|
|
@@ -440,7 +403,7 @@ export function buildMerchantTools(deps) {
|
|
|
440
403
|
return textResult(`商品 ${p.sku} 不存在。`);
|
|
441
404
|
}
|
|
442
405
|
const args = { sku: p.sku, stock: p.stock };
|
|
443
|
-
const preconditions =
|
|
406
|
+
const preconditions = publicProductView(current);
|
|
444
407
|
const outcome = await routeWriteCandidate(writeGateDeps, {
|
|
445
408
|
tool: "update_inventory",
|
|
446
409
|
arguments: args,
|
|
@@ -452,7 +415,7 @@ export function buildMerchantTools(deps) {
|
|
|
452
415
|
},
|
|
453
416
|
readPreconditions: async () => {
|
|
454
417
|
const fresh = await merchantClient.getProduct(p.sku);
|
|
455
|
-
return
|
|
418
|
+
return publicProductView(fresh);
|
|
456
419
|
},
|
|
457
420
|
});
|
|
458
421
|
return writeGateText(outcome);
|
|
@@ -491,7 +454,7 @@ export function buildMerchantTools(deps) {
|
|
|
491
454
|
return textResult(`商品 ${p.sku} 不存在。`);
|
|
492
455
|
}
|
|
493
456
|
const args = { sku: p.sku, paused: p.paused };
|
|
494
|
-
const preconditions =
|
|
457
|
+
const preconditions = publicProductView(current);
|
|
495
458
|
const outcome = await routeWriteCandidate(writeGateDeps, {
|
|
496
459
|
tool: "pause_or_resume_listing",
|
|
497
460
|
arguments: args,
|
|
@@ -503,7 +466,7 @@ export function buildMerchantTools(deps) {
|
|
|
503
466
|
},
|
|
504
467
|
readPreconditions: async () => {
|
|
505
468
|
const fresh = await merchantClient.getProduct(p.sku);
|
|
506
|
-
return
|
|
469
|
+
return publicProductView(fresh);
|
|
507
470
|
},
|
|
508
471
|
});
|
|
509
472
|
return writeGateText(outcome);
|
|
@@ -521,7 +484,10 @@ export function buildMerchantTools(deps) {
|
|
|
521
484
|
type: "object",
|
|
522
485
|
properties: {
|
|
523
486
|
sku: { type: "string" },
|
|
524
|
-
changes: {
|
|
487
|
+
changes: {
|
|
488
|
+
type: "object",
|
|
489
|
+
description: "计划修改的字段(title/price/stock/description 等)",
|
|
490
|
+
},
|
|
525
491
|
reason: { type: "string" },
|
|
526
492
|
},
|
|
527
493
|
required: ["sku", "changes"],
|
|
@@ -533,45 +499,214 @@ export function buildMerchantTools(deps) {
|
|
|
533
499
|
return textResult(credential.reason);
|
|
534
500
|
try {
|
|
535
501
|
const p = params;
|
|
536
|
-
|
|
502
|
+
// 保持工具层既有文案:空 patch / 商品不存在的提示在调用 Facade 前拦截。
|
|
503
|
+
const patch = parseProductPatch(p.changes);
|
|
537
504
|
if (Object.keys(patch).length === 0) {
|
|
538
505
|
return textResult("changes 没有任何可修改字段。");
|
|
539
506
|
}
|
|
540
|
-
let current;
|
|
541
507
|
try {
|
|
542
|
-
|
|
508
|
+
await merchantClient.getProduct(p.sku);
|
|
543
509
|
}
|
|
544
510
|
catch {
|
|
545
511
|
return textResult(`商品 ${p.sku} 不存在。`);
|
|
546
512
|
}
|
|
547
|
-
const
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
preconditions: productPreconditions(current),
|
|
552
|
-
risk: "write_catalog",
|
|
553
|
-
// Drafts are ALWAYS pending (never auto-execute), even in autopilot.
|
|
554
|
-
force_pending: true,
|
|
555
|
-
execute: (approvedArgs) => {
|
|
556
|
-
const a = approvedArgs;
|
|
557
|
-
return merchantClient.updateProduct(a.sku, a.changes);
|
|
558
|
-
},
|
|
559
|
-
readPreconditions: async () => {
|
|
560
|
-
const fresh = await merchantClient.getProduct(p.sku);
|
|
561
|
-
return productPreconditions(fresh);
|
|
562
|
-
},
|
|
513
|
+
const result = await workbench.draftProductChange({
|
|
514
|
+
sku: p.sku,
|
|
515
|
+
changes: patch,
|
|
516
|
+
reason: optString(p.reason) ?? "",
|
|
563
517
|
});
|
|
564
|
-
if (outcome.kind === "pending_approval") {
|
|
565
|
-
return textResult(`已生成变更草稿候选 ${outcome.candidate.candidate_id}(等待批准后才执行)。当前商品:` +
|
|
566
|
-
JSON.stringify(
|
|
518
|
+
if (result.outcome.kind === "pending_approval") {
|
|
519
|
+
return textResult(`已生成变更草稿候选 ${result.outcome.candidate.candidate_id}(等待批准后才执行)。当前商品:` +
|
|
520
|
+
JSON.stringify(result.product), { candidate_id: result.outcome.candidate.candidate_id, status: "pending_approval" });
|
|
567
521
|
}
|
|
568
|
-
return writeGateText(outcome);
|
|
522
|
+
return writeGateText(result.outcome);
|
|
569
523
|
}
|
|
570
524
|
catch (err) {
|
|
571
525
|
return textResult(errorText(err));
|
|
572
526
|
}
|
|
573
527
|
},
|
|
574
528
|
};
|
|
529
|
+
const experienceTools = [];
|
|
530
|
+
if (experienceEnabled(profile, "intelligence") && deps.intelligence !== undefined) {
|
|
531
|
+
const intelligence = deps.intelligence;
|
|
532
|
+
const getBusinessSnapshot = {
|
|
533
|
+
name: "get_business_snapshot",
|
|
534
|
+
label: "读取经营摘要",
|
|
535
|
+
description: "读取当前商家经营摘要、咨询/磋商和待处理事项。只读;指标由服务端计算并注明数据限制。",
|
|
536
|
+
parameters: {
|
|
537
|
+
type: "object",
|
|
538
|
+
properties: {
|
|
539
|
+
period: {
|
|
540
|
+
type: "string",
|
|
541
|
+
pattern: "^(?:[1-9]|[1-8][0-9]|90)d$",
|
|
542
|
+
description: "UTC 统计窗口,1d 到 90d,例如 7d、14d、30d",
|
|
543
|
+
},
|
|
544
|
+
},
|
|
545
|
+
additionalProperties: false,
|
|
546
|
+
},
|
|
547
|
+
execute: async (_id, params) => {
|
|
548
|
+
try {
|
|
549
|
+
const period = optString(params.period);
|
|
550
|
+
const snapshot = await intelligence.getBusinessSnapshot({
|
|
551
|
+
merchant_id: ownerId,
|
|
552
|
+
...(period === undefined ? {} : { period }),
|
|
553
|
+
});
|
|
554
|
+
return textResult(fenceModelPayload("metric", snapshot, { maxChars: experienceMaxChars(profile) }), {
|
|
555
|
+
status: "ok",
|
|
556
|
+
metric: "business_snapshot",
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
catch (err) {
|
|
560
|
+
return textResult(errorText(err));
|
|
561
|
+
}
|
|
562
|
+
},
|
|
563
|
+
};
|
|
564
|
+
const queryMetric = {
|
|
565
|
+
name: "query_merchant_metric",
|
|
566
|
+
label: "读取经营指标",
|
|
567
|
+
description: "读取一项按日/周/月聚合的商家指标。不可得的指标返回明确说明,不用零值代替。",
|
|
568
|
+
parameters: {
|
|
569
|
+
type: "object",
|
|
570
|
+
properties: {
|
|
571
|
+
metric: { type: "string", description: "指标名,例如 contact_events、negotiations" },
|
|
572
|
+
period: {
|
|
573
|
+
type: "string",
|
|
574
|
+
pattern: "^(?:[1-9]|[1-8][0-9]|90)d$",
|
|
575
|
+
description: "UTC 统计窗口,1d 到 90d,例如 7d、14d、30d",
|
|
576
|
+
},
|
|
577
|
+
granularity: { type: "string", enum: ["day", "week", "month"] },
|
|
578
|
+
},
|
|
579
|
+
required: ["metric"],
|
|
580
|
+
additionalProperties: false,
|
|
581
|
+
},
|
|
582
|
+
execute: async (_id, params) => {
|
|
583
|
+
try {
|
|
584
|
+
const p = params;
|
|
585
|
+
const metric = optString(p.metric);
|
|
586
|
+
if (metric === undefined)
|
|
587
|
+
return textResult("metric 必须是非空字符串。");
|
|
588
|
+
const granularity = p.granularity === "week" || p.granularity === "month" ? p.granularity : "day";
|
|
589
|
+
const series = await intelligence.queryMetric({
|
|
590
|
+
merchant_id: ownerId,
|
|
591
|
+
metric,
|
|
592
|
+
granularity,
|
|
593
|
+
...(optString(p.period) === undefined ? {} : { period: optString(p.period) }),
|
|
594
|
+
});
|
|
595
|
+
return textResult(fenceModelPayload("metric", series, { maxChars: experienceMaxChars(profile) }), {
|
|
596
|
+
status: "ok",
|
|
597
|
+
metric,
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
catch (err) {
|
|
601
|
+
return textResult(errorText(err));
|
|
602
|
+
}
|
|
603
|
+
},
|
|
604
|
+
};
|
|
605
|
+
const getNegotiationDigest = {
|
|
606
|
+
name: "get_negotiation_digest",
|
|
607
|
+
label: "读取磋商摘要",
|
|
608
|
+
description: "读取商家 A2A 磋商摘要。返回当前 phase、公开报价和是否需要人工;只读。",
|
|
609
|
+
parameters: {
|
|
610
|
+
type: "object",
|
|
611
|
+
properties: {
|
|
612
|
+
status: { type: "string", enum: ["active", "agreement", "all"] },
|
|
613
|
+
limit: { type: "integer", minimum: 1, maximum: 100 },
|
|
614
|
+
},
|
|
615
|
+
additionalProperties: false,
|
|
616
|
+
},
|
|
617
|
+
execute: async (_id, params) => {
|
|
618
|
+
try {
|
|
619
|
+
const p = params;
|
|
620
|
+
const status = p.status === "active" || p.status === "agreement" ? p.status : "all";
|
|
621
|
+
const rawLimit = typeof p.limit === "number" && Number.isFinite(p.limit) ? Math.trunc(p.limit) : 20;
|
|
622
|
+
const rows = await intelligence.getNegotiationDigest({
|
|
623
|
+
merchant_id: ownerId,
|
|
624
|
+
status,
|
|
625
|
+
limit: Math.max(1, Math.min(100, rawLimit)),
|
|
626
|
+
});
|
|
627
|
+
return textResult(fenceModelPayload("a2a_message", rows, { maxChars: experienceMaxChars(profile) }), {
|
|
628
|
+
status: "ok",
|
|
629
|
+
count: rows.length,
|
|
630
|
+
});
|
|
631
|
+
}
|
|
632
|
+
catch (err) {
|
|
633
|
+
return textResult(errorText(err));
|
|
634
|
+
}
|
|
635
|
+
},
|
|
636
|
+
};
|
|
637
|
+
const getCatalogHealth = {
|
|
638
|
+
name: "get_catalog_health",
|
|
639
|
+
label: "读取目录健康度",
|
|
640
|
+
description: "读取商品总量、上下架状态和缺货数量;精确库存不可得时返回 null 及限制说明。",
|
|
641
|
+
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
642
|
+
execute: async () => {
|
|
643
|
+
try {
|
|
644
|
+
const health = await intelligence.getCatalogHealth({ merchant_id: ownerId });
|
|
645
|
+
return textResult(fenceModelPayload("merchant_api", health, { maxChars: experienceMaxChars(profile) }), {
|
|
646
|
+
status: "ok",
|
|
647
|
+
});
|
|
648
|
+
}
|
|
649
|
+
catch (err) {
|
|
650
|
+
return textResult(errorText(err));
|
|
651
|
+
}
|
|
652
|
+
},
|
|
653
|
+
};
|
|
654
|
+
const getPendingActions = {
|
|
655
|
+
name: "get_pending_actions",
|
|
656
|
+
label: "读取待审批操作",
|
|
657
|
+
description: "读取当前 principal 的待审批写操作。返回候选元数据,不返回私有阈值或凭据。",
|
|
658
|
+
parameters: { type: "object", properties: {}, additionalProperties: false },
|
|
659
|
+
execute: async () => {
|
|
660
|
+
try {
|
|
661
|
+
const rows = await intelligence.getPendingActions();
|
|
662
|
+
return textResult(fenceModelPayload("merchant_api", rows, { maxChars: experienceMaxChars(profile) }), {
|
|
663
|
+
status: "ok",
|
|
664
|
+
count: rows.length,
|
|
665
|
+
});
|
|
666
|
+
}
|
|
667
|
+
catch (err) {
|
|
668
|
+
return textResult(errorText(err));
|
|
669
|
+
}
|
|
670
|
+
},
|
|
671
|
+
};
|
|
672
|
+
experienceTools.push(getBusinessSnapshot, queryMetric, getCatalogHealth, getNegotiationDigest, getPendingActions);
|
|
673
|
+
}
|
|
674
|
+
if (experienceEnabled(profile, "presentation") && deps.emitEvent !== undefined) {
|
|
675
|
+
const registry = createMerchantPresentationRegistry();
|
|
676
|
+
const emitUi = async (component, payload) => {
|
|
677
|
+
await deps.emitEvent?.("ui", { component, payload });
|
|
678
|
+
};
|
|
679
|
+
const presentationContext = {
|
|
680
|
+
profile,
|
|
681
|
+
// 口径修复(V2 阶段二遗留核查):enrich 以 principalId 作为商家读取键
|
|
682
|
+
// (intelligence.assertOwned / listProducts 都按 merchant_id 口径)——
|
|
683
|
+
// 必须用 owner_id;传 agent_id 会导致 digest/catalog 展示校验失败或读空。
|
|
684
|
+
principalId: ownerId,
|
|
685
|
+
merchantClient,
|
|
686
|
+
approvals,
|
|
687
|
+
...(deps.intelligence !== undefined ? { intelligence: deps.intelligence } : {}),
|
|
688
|
+
};
|
|
689
|
+
for (const component of registry.list()) {
|
|
690
|
+
const presentationTool = {
|
|
691
|
+
name: component.toolName,
|
|
692
|
+
label: component.label,
|
|
693
|
+
description: component.description,
|
|
694
|
+
parameters: component.inputSchema,
|
|
695
|
+
execute: async (_id, params) => {
|
|
696
|
+
try {
|
|
697
|
+
const result = await runPresentation(registry, component.toolName, params, presentationContext, emitUi);
|
|
698
|
+
return textResult(component.toolName === "present_change_preview"
|
|
699
|
+
? "已展示变更预览;尚未批准或执行。"
|
|
700
|
+
: `已展示${component.label.replace(/^展示/, "")}。`, { component: result.component });
|
|
701
|
+
}
|
|
702
|
+
catch (err) {
|
|
703
|
+
return textResult(errorText(err));
|
|
704
|
+
}
|
|
705
|
+
},
|
|
706
|
+
};
|
|
707
|
+
experienceTools.push(presentationTool);
|
|
708
|
+
}
|
|
709
|
+
}
|
|
575
710
|
const negotiationTools = deps.commerceClient !== undefined
|
|
576
711
|
? buildNegotiationChatTools({
|
|
577
712
|
profile,
|
|
@@ -596,7 +731,9 @@ export function buildMerchantTools(deps) {
|
|
|
596
731
|
const values = deps.privateValues();
|
|
597
732
|
if (values.length === 0)
|
|
598
733
|
return textResult("暂无私密阈值记忆。");
|
|
599
|
-
return textResult(values.map((v) => `· ${v.key} = ${v.value}`).join("\n"), {
|
|
734
|
+
return textResult(values.map((v) => `· ${v.key} = ${v.value}`).join("\n"), {
|
|
735
|
+
count: values.length,
|
|
736
|
+
});
|
|
600
737
|
},
|
|
601
738
|
};
|
|
602
739
|
// ── A2A 磋商记录(真实经 A2A 节点的磋商,读 merchant 节点 ledger)───────
|
|
@@ -614,53 +751,28 @@ export function buildMerchantTools(deps) {
|
|
|
614
751
|
additionalProperties: false,
|
|
615
752
|
},
|
|
616
753
|
execute: async (_id, params) => {
|
|
617
|
-
|
|
618
|
-
if (ledgerDir === undefined) {
|
|
754
|
+
if (deps.a2aLedgerDir === undefined) {
|
|
619
755
|
return textResult("未配置 A2A ledger 目录,无法读取磋商记录。");
|
|
620
756
|
}
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
if (e.event_kind === "message_sent") {
|
|
636
|
-
const wp = e.wire_payload;
|
|
637
|
-
if (wp?.action !== undefined)
|
|
638
|
-
lastAction = wp.action;
|
|
639
|
-
const item = wp?.payload?.terms?.items?.[0];
|
|
640
|
-
if (item?.sku !== undefined && item.sku !== "")
|
|
641
|
-
sku = item.sku;
|
|
642
|
-
if (item?.quantity?.value !== undefined)
|
|
643
|
-
qty = item.quantity.value;
|
|
644
|
-
if (item?.unit_price?.amount_minor !== undefined)
|
|
645
|
-
priceMinor = item.unit_price.amount_minor;
|
|
646
|
-
}
|
|
647
|
-
if (e.state_transition?.to_phase === "AGREEMENT_REACHED")
|
|
648
|
-
agreement = true;
|
|
649
|
-
}
|
|
650
|
-
const price = priceMinor !== undefined ? `,价 ${(priceMinor / 100).toFixed(2)} 元/件` : "";
|
|
651
|
-
rows.push({
|
|
652
|
-
at,
|
|
653
|
-
line: `· ${negotiationId}${agreement ? " ✅ 已达成协议" : `(${lastAction || "?"})`} ` +
|
|
654
|
-
`SKU=${sku || "-"} 数量=${qty ?? "-"}${price} ${at}`,
|
|
757
|
+
try {
|
|
758
|
+
const { total, items } = await workbench.listA2aNegotiations(params.limit);
|
|
759
|
+
const lines = items.map((r) => {
|
|
760
|
+
const price = r.price_minor !== undefined ? `,价 ${(r.price_minor / 100).toFixed(2)} 元/件` : "";
|
|
761
|
+
return (`· ${r.negotiation_id}${r.agreement ? " ✅ 已达成协议" : `(${r.last_action || "?"})`} ` +
|
|
762
|
+
`SKU=${r.sku || "-"} 数量=${r.quantity ?? "-"}${price} ${r.recorded_at}`);
|
|
763
|
+
});
|
|
764
|
+
if (lines.length === 0)
|
|
765
|
+
return textResult("暂无 A2A 磋商记录。", { count: 0 });
|
|
766
|
+
return textResult(fenceModelPayload("a2a_message", {
|
|
767
|
+
total,
|
|
768
|
+
items: lines,
|
|
769
|
+
}, { maxChars: experienceMaxChars(profile) }), {
|
|
770
|
+
count: lines.length,
|
|
655
771
|
});
|
|
656
772
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
return textResult("暂无 A2A 磋商记录。", { count: 0 });
|
|
661
|
-
return textResult(`共 ${rows.length} 笔 A2A 磋商(最近 ${recent.length} 笔):\n${recent.map((r) => r.line).join("\n")}`, {
|
|
662
|
-
count: recent.length,
|
|
663
|
-
});
|
|
773
|
+
catch (err) {
|
|
774
|
+
return textResult(errorText(err));
|
|
775
|
+
}
|
|
664
776
|
},
|
|
665
777
|
};
|
|
666
778
|
return [
|
|
@@ -670,6 +782,7 @@ export function buildMerchantTools(deps) {
|
|
|
670
782
|
listConsultations,
|
|
671
783
|
humanReviewQueue,
|
|
672
784
|
viewPrivateThresholds,
|
|
785
|
+
...experienceTools,
|
|
673
786
|
...negotiationTools,
|
|
674
787
|
createProduct,
|
|
675
788
|
updateProduct,
|