@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.
Files changed (332) hide show
  1. package/README.md +45 -10
  2. package/dist/a2a/negotiate.d.ts +6 -2
  3. package/dist/a2a/negotiate.js +10 -3
  4. package/dist/a2a/negotiate.js.map +1 -1
  5. package/dist/a2a/node.d.ts +4 -1
  6. package/dist/a2a/node.js +57 -4
  7. package/dist/a2a/node.js.map +1 -1
  8. package/dist/a2a/server/merchant-handler.d.ts +11 -3
  9. package/dist/a2a/server/merchant-handler.js +84 -26
  10. package/dist/a2a/server/merchant-handler.js.map +1 -1
  11. package/dist/agent/buyer/buyer-tools.js +17 -10
  12. package/dist/agent/buyer/buyer-tools.js.map +1 -1
  13. package/dist/agent/buyer/scheduler.d.ts +1 -0
  14. package/dist/agent/buyer/scheduler.js +5 -1
  15. package/dist/agent/buyer/scheduler.js.map +1 -1
  16. package/dist/agent/buyer/task-store.js +5 -2
  17. package/dist/agent/buyer/task-store.js.map +1 -1
  18. package/dist/agent/chat-tools.js +10 -3
  19. package/dist/agent/chat-tools.js.map +1 -1
  20. package/dist/agent/context/fencing.d.ts +27 -0
  21. package/dist/agent/context/fencing.js +126 -0
  22. package/dist/agent/context/fencing.js.map +1 -0
  23. package/dist/agent/context/grounding.d.ts +18 -0
  24. package/dist/agent/context/grounding.js +22 -0
  25. package/dist/agent/context/grounding.js.map +1 -0
  26. package/dist/agent/host/events.d.ts +31 -0
  27. package/dist/agent/host/events.js +62 -0
  28. package/dist/agent/host/events.js.map +1 -0
  29. package/dist/agent/host/tui-renderer.d.ts +17 -0
  30. package/dist/agent/host/tui-renderer.js +125 -0
  31. package/dist/agent/host/tui-renderer.js.map +1 -0
  32. package/dist/agent/host/web-renderer.d.ts +71 -0
  33. package/dist/agent/host/web-renderer.js +185 -0
  34. package/dist/agent/host/web-renderer.js.map +1 -0
  35. package/dist/agent/kernel-builder.d.ts +3 -1
  36. package/dist/agent/kernel-builder.js +4 -1
  37. package/dist/agent/kernel-builder.js.map +1 -1
  38. package/dist/agent/kernel.d.ts +20 -1
  39. package/dist/agent/kernel.js +255 -14
  40. package/dist/agent/kernel.js.map +1 -1
  41. package/dist/agent/memory/schema.d.ts +1 -1
  42. package/dist/agent/memory/schema.js +9 -1
  43. package/dist/agent/memory/schema.js.map +1 -1
  44. package/dist/agent/merchant/action-candidate.d.ts +18 -0
  45. package/dist/agent/merchant/action-candidate.js +51 -0
  46. package/dist/agent/merchant/action-candidate.js.map +1 -1
  47. package/dist/agent/merchant/fake-merchant-client.js +6 -1
  48. package/dist/agent/merchant/fake-merchant-client.js.map +1 -1
  49. package/dist/agent/merchant/intelligence/backend.d.ts +40 -0
  50. package/dist/agent/merchant/intelligence/backend.js +2 -0
  51. package/dist/agent/merchant/intelligence/backend.js.map +1 -0
  52. package/dist/agent/merchant/intelligence/default-backend.d.ts +38 -0
  53. package/dist/agent/merchant/intelligence/default-backend.js +477 -0
  54. package/dist/agent/merchant/intelligence/default-backend.js.map +1 -0
  55. package/dist/agent/merchant/intelligence/http-analytics-source.d.ts +55 -0
  56. package/dist/agent/merchant/intelligence/http-analytics-source.js +193 -0
  57. package/dist/agent/merchant/intelligence/http-analytics-source.js.map +1 -0
  58. package/dist/agent/merchant/intelligence/types.d.ts +109 -0
  59. package/dist/agent/merchant/intelligence/types.js +2 -0
  60. package/dist/agent/merchant/intelligence/types.js.map +1 -0
  61. package/dist/agent/merchant/merchant-client.d.ts +50 -1
  62. package/dist/agent/merchant/merchant-client.js +157 -8
  63. package/dist/agent/merchant/merchant-client.js.map +1 -1
  64. package/dist/agent/merchant/merchant-enrichment.d.ts +10 -0
  65. package/dist/agent/merchant/merchant-enrichment.js +38 -0
  66. package/dist/agent/merchant/merchant-enrichment.js.map +1 -0
  67. package/dist/agent/merchant/merchant-grounding.d.ts +5 -0
  68. package/dist/agent/merchant/merchant-grounding.js +76 -0
  69. package/dist/agent/merchant/merchant-grounding.js.map +1 -0
  70. package/dist/agent/merchant/merchant-presentations.d.ts +8 -0
  71. package/dist/agent/merchant/merchant-presentations.js +207 -0
  72. package/dist/agent/merchant/merchant-presentations.js.map +1 -0
  73. package/dist/agent/merchant/merchant-tools.d.ts +8 -0
  74. package/dist/agent/merchant/merchant-tools.js +291 -178
  75. package/dist/agent/merchant/merchant-tools.js.map +1 -1
  76. package/dist/agent/merchant/types.d.ts +6 -2
  77. package/dist/agent/merchant/types.js +45 -0
  78. package/dist/agent/merchant/types.js.map +1 -1
  79. package/dist/agent/presentation/registry.d.ts +14 -0
  80. package/dist/agent/presentation/registry.js +24 -0
  81. package/dist/agent/presentation/registry.js.map +1 -0
  82. package/dist/agent/presentation/runner.d.ts +11 -0
  83. package/dist/agent/presentation/runner.js +17 -0
  84. package/dist/agent/presentation/runner.js.map +1 -0
  85. package/dist/agent/presentation/sanitize.d.ts +16 -0
  86. package/dist/agent/presentation/sanitize.js +37 -0
  87. package/dist/agent/presentation/sanitize.js.map +1 -0
  88. package/dist/agent/presentation/types.d.ts +28 -0
  89. package/dist/agent/presentation/types.js +8 -0
  90. package/dist/agent/presentation/types.js.map +1 -0
  91. package/dist/agent/session.d.ts +1 -1
  92. package/dist/agent/session.js +2 -2
  93. package/dist/agent/session.js.map +1 -1
  94. package/dist/agent/skills/registry.d.ts +11 -0
  95. package/dist/agent/skills/registry.js +119 -0
  96. package/dist/agent/skills/registry.js.map +1 -0
  97. package/dist/agent/skills/tools.d.ts +6 -0
  98. package/dist/agent/skills/tools.js +36 -0
  99. package/dist/agent/skills/tools.js.map +1 -0
  100. package/dist/agent/skills/types.d.ts +9 -0
  101. package/dist/agent/skills/types.js +2 -0
  102. package/dist/agent/skills/types.js.map +1 -0
  103. package/dist/agent/supplier/scheduler.d.ts +2 -0
  104. package/dist/agent/supplier/scheduler.js +101 -22
  105. package/dist/agent/supplier/scheduler.js.map +1 -1
  106. package/dist/agent/supplier/store.d.ts +2 -0
  107. package/dist/agent/supplier/store.js +44 -0
  108. package/dist/agent/supplier/store.js.map +1 -1
  109. package/dist/agent/system-prompt.d.ts +5 -1
  110. package/dist/agent/system-prompt.js +20 -3
  111. package/dist/agent/system-prompt.js.map +1 -1
  112. package/dist/auth/merchant-authorization.d.ts +49 -0
  113. package/dist/auth/merchant-authorization.js +61 -0
  114. package/dist/auth/merchant-authorization.js.map +1 -0
  115. package/dist/auth/merchant-oauth.d.ts +255 -0
  116. package/dist/auth/merchant-oauth.js +764 -0
  117. package/dist/auth/merchant-oauth.js.map +1 -0
  118. package/dist/auth/merchant-pairing.d.ts +62 -0
  119. package/dist/auth/merchant-pairing.js +199 -0
  120. package/dist/auth/merchant-pairing.js.map +1 -0
  121. package/dist/auth/merchant-sessions.d.ts +71 -0
  122. package/dist/auth/merchant-sessions.js +168 -0
  123. package/dist/auth/merchant-sessions.js.map +1 -0
  124. package/dist/buyer-core/build-service.d.ts +5 -0
  125. package/dist/buyer-core/build-service.js +12 -0
  126. package/dist/buyer-core/build-service.js.map +1 -1
  127. package/dist/buyer-core/errors.d.ts +1 -1
  128. package/dist/buyer-core/errors.js +2 -0
  129. package/dist/buyer-core/errors.js.map +1 -1
  130. package/dist/buyer-core/merchant-index.d.ts +19 -4
  131. package/dist/buyer-core/merchant-index.js +137 -16
  132. package/dist/buyer-core/merchant-index.js.map +1 -1
  133. package/dist/buyer-core/negotiator.d.ts +0 -10
  134. package/dist/buyer-core/negotiator.js +12 -1
  135. package/dist/buyer-core/negotiator.js.map +1 -1
  136. package/dist/buyer-core/quote-fetcher.js +2 -1
  137. package/dist/buyer-core/quote-fetcher.js.map +1 -1
  138. package/dist/buyer-core/service.d.ts +104 -0
  139. package/dist/buyer-core/service.js +105 -1
  140. package/dist/buyer-core/service.js.map +1 -1
  141. package/dist/cli.d.ts +4 -2
  142. package/dist/cli.js +644 -32
  143. package/dist/cli.js.map +1 -1
  144. package/dist/config/profile.d.ts +51 -0
  145. package/dist/config/profile.js +185 -61
  146. package/dist/config/profile.js.map +1 -1
  147. package/dist/demo/demo-runner.js +12 -9
  148. package/dist/demo/demo-runner.js.map +1 -1
  149. package/dist/discovery/catalog-source/buyer-follows.d.ts +82 -0
  150. package/dist/discovery/catalog-source/buyer-follows.js +228 -0
  151. package/dist/discovery/catalog-source/buyer-follows.js.map +1 -0
  152. package/dist/discovery/catalog-source/connector-identity.d.ts +75 -0
  153. package/dist/discovery/catalog-source/connector-identity.js +175 -0
  154. package/dist/discovery/catalog-source/connector-identity.js.map +1 -0
  155. package/dist/discovery/catalog-source/errors.d.ts +1 -1
  156. package/dist/discovery/catalog-source/errors.js +2 -0
  157. package/dist/discovery/catalog-source/errors.js.map +1 -1
  158. package/dist/discovery/catalog-source/kiwi-record.d.ts +2 -0
  159. package/dist/discovery/catalog-source/kiwi-record.js.map +1 -1
  160. package/dist/discovery/catalog-source/kiwi-source.js +2 -0
  161. package/dist/discovery/catalog-source/kiwi-source.js.map +1 -1
  162. package/dist/discovery/catalog-source/merchant-publications.d.ts +65 -0
  163. package/dist/discovery/catalog-source/merchant-publications.js +207 -0
  164. package/dist/discovery/catalog-source/merchant-publications.js.map +1 -0
  165. package/dist/discovery/catalog-source/register.d.ts +24 -0
  166. package/dist/discovery/catalog-source/register.js +46 -0
  167. package/dist/discovery/catalog-source/register.js.map +1 -1
  168. package/dist/discovery/catalog-source/source.js +2 -1
  169. package/dist/discovery/catalog-source/source.js.map +1 -1
  170. package/dist/fs/atomic-write.d.ts +18 -0
  171. package/dist/fs/atomic-write.js +29 -0
  172. package/dist/fs/atomic-write.js.map +1 -0
  173. package/dist/handoff/authorization.js +1 -1
  174. package/dist/http/merchant-server.d.ts +65 -0
  175. package/dist/http/merchant-server.js +346 -0
  176. package/dist/http/merchant-server.js.map +1 -0
  177. package/dist/http/server.js +4 -1
  178. package/dist/http/server.js.map +1 -1
  179. package/dist/mcp/cli.d.ts +2 -0
  180. package/dist/mcp/cli.js +7 -6
  181. package/dist/mcp/cli.js.map +1 -1
  182. package/dist/mcp/merchant-auth.d.ts +78 -0
  183. package/dist/mcp/merchant-auth.js +146 -0
  184. package/dist/mcp/merchant-auth.js.map +1 -0
  185. package/dist/mcp/merchant-dirs.d.ts +26 -0
  186. package/dist/mcp/merchant-dirs.js +44 -0
  187. package/dist/mcp/merchant-dirs.js.map +1 -0
  188. package/dist/mcp/merchant-resources.d.ts +38 -0
  189. package/dist/mcp/merchant-resources.js +146 -0
  190. package/dist/mcp/merchant-resources.js.map +1 -0
  191. package/dist/mcp/merchant-server.d.ts +106 -0
  192. package/dist/mcp/merchant-server.js +615 -0
  193. package/dist/mcp/merchant-server.js.map +1 -0
  194. package/dist/mcp/merchant-tools.d.ts +103 -0
  195. package/dist/mcp/merchant-tools.js +517 -0
  196. package/dist/mcp/merchant-tools.js.map +1 -0
  197. package/dist/mcp/server.js +4 -3
  198. package/dist/mcp/server.js.map +1 -1
  199. package/dist/mcp/tools.d.ts +5 -3
  200. package/dist/mcp/tools.js +102 -5
  201. package/dist/mcp/tools.js.map +1 -1
  202. package/dist/mcp/types.d.ts +1 -1
  203. package/dist/mcp/types.js +4 -0
  204. package/dist/mcp/types.js.map +1 -1
  205. package/dist/merchant/ops.d.ts +0 -11
  206. package/dist/merchant/ops.js +13 -1
  207. package/dist/merchant/ops.js.map +1 -1
  208. package/dist/merchant/stats-store.d.ts +7 -0
  209. package/dist/merchant/stats-store.js +11 -0
  210. package/dist/merchant/stats-store.js.map +1 -1
  211. package/dist/merchant/workbench-service.d.ts +189 -0
  212. package/dist/merchant/workbench-service.js +417 -0
  213. package/dist/merchant/workbench-service.js.map +1 -0
  214. package/dist/merchant-admin/pending-page.d.ts +35 -0
  215. package/dist/merchant-admin/pending-page.js +69 -0
  216. package/dist/merchant-admin/pending-page.js.map +1 -0
  217. package/dist/merchant-core/commands.d.ts +99 -0
  218. package/dist/merchant-core/commands.js +179 -0
  219. package/dist/merchant-core/commands.js.map +1 -0
  220. package/dist/merchant-core/executor.d.ts +69 -0
  221. package/dist/merchant-core/executor.js +218 -0
  222. package/dist/merchant-core/executor.js.map +1 -0
  223. package/dist/merchant-core/negotiation-adapters.d.ts +55 -0
  224. package/dist/merchant-core/negotiation-adapters.js +55 -0
  225. package/dist/merchant-core/negotiation-adapters.js.map +1 -0
  226. package/dist/merchant-core/network-checks.d.ts +65 -0
  227. package/dist/merchant-core/network-checks.js +111 -0
  228. package/dist/merchant-core/network-checks.js.map +1 -0
  229. package/dist/merchant-core/operations.d.ts +64 -0
  230. package/dist/merchant-core/operations.js +136 -0
  231. package/dist/merchant-core/operations.js.map +1 -0
  232. package/dist/merchant-core/policy-runtime.d.ts +70 -0
  233. package/dist/merchant-core/policy-runtime.js +181 -0
  234. package/dist/merchant-core/policy-runtime.js.map +1 -0
  235. package/dist/merchant-core/product-import.d.ts +67 -0
  236. package/dist/merchant-core/product-import.js +160 -0
  237. package/dist/merchant-core/product-import.js.map +1 -0
  238. package/dist/merchant-core/service.d.ts +203 -0
  239. package/dist/merchant-core/service.js +402 -0
  240. package/dist/merchant-core/service.js.map +1 -0
  241. package/dist/merchant-gateway/catalog-publications.d.ts +71 -0
  242. package/dist/merchant-gateway/catalog-publications.js +175 -0
  243. package/dist/merchant-gateway/catalog-publications.js.map +1 -0
  244. package/dist/merchant-gateway/catalog-tools.d.ts +46 -0
  245. package/dist/merchant-gateway/catalog-tools.js +277 -0
  246. package/dist/merchant-gateway/catalog-tools.js.map +1 -0
  247. package/dist/merchant-gateway/cli.d.ts +75 -0
  248. package/dist/merchant-gateway/cli.js +458 -0
  249. package/dist/merchant-gateway/cli.js.map +1 -0
  250. package/dist/merchant-gateway/credential-vault.d.ts +44 -0
  251. package/dist/merchant-gateway/credential-vault.js +111 -0
  252. package/dist/merchant-gateway/credential-vault.js.map +1 -0
  253. package/dist/merchant-gateway/entry-server.d.ts +117 -0
  254. package/dist/merchant-gateway/entry-server.js +710 -0
  255. package/dist/merchant-gateway/entry-server.js.map +1 -0
  256. package/dist/merchant-gateway/instance-registration.d.ts +143 -0
  257. package/dist/merchant-gateway/instance-registration.js +382 -0
  258. package/dist/merchant-gateway/instance-registration.js.map +1 -0
  259. package/dist/merchant-gateway/instance-tools.d.ts +58 -0
  260. package/dist/merchant-gateway/instance-tools.js +184 -0
  261. package/dist/merchant-gateway/instance-tools.js.map +1 -0
  262. package/dist/merchant-gateway/mcp-proxy.d.ts +25 -0
  263. package/dist/merchant-gateway/mcp-proxy.js +192 -0
  264. package/dist/merchant-gateway/mcp-proxy.js.map +1 -0
  265. package/dist/merchant-gateway/pinned-fetch.d.ts +52 -0
  266. package/dist/merchant-gateway/pinned-fetch.js +212 -0
  267. package/dist/merchant-gateway/pinned-fetch.js.map +1 -0
  268. package/dist/merchant-gateway/tenant-registry.d.ts +82 -0
  269. package/dist/merchant-gateway/tenant-registry.js +190 -0
  270. package/dist/merchant-gateway/tenant-registry.js.map +1 -0
  271. package/dist/merchant-gateway/tool-bundle.d.ts +26 -0
  272. package/dist/merchant-gateway/tool-bundle.js +56 -0
  273. package/dist/merchant-gateway/tool-bundle.js.map +1 -0
  274. package/dist/merchant-runtime/backup.d.ts +48 -0
  275. package/dist/merchant-runtime/backup.js +226 -0
  276. package/dist/merchant-runtime/backup.js.map +1 -0
  277. package/dist/merchant-runtime/health.d.ts +99 -0
  278. package/dist/merchant-runtime/health.js +206 -0
  279. package/dist/merchant-runtime/health.js.map +1 -0
  280. package/dist/merchant-runtime/jobs.d.ts +64 -0
  281. package/dist/merchant-runtime/jobs.js +107 -0
  282. package/dist/merchant-runtime/jobs.js.map +1 -0
  283. package/dist/merchant-runtime/manager.d.ts +94 -0
  284. package/dist/merchant-runtime/manager.js +305 -0
  285. package/dist/merchant-runtime/manager.js.map +1 -0
  286. package/dist/merchant-runtime/services.d.ts +30 -0
  287. package/dist/merchant-runtime/services.js +51 -0
  288. package/dist/merchant-runtime/services.js.map +1 -0
  289. package/dist/negotiation/action-candidate.js +1 -1
  290. package/dist/net/url.d.ts +26 -0
  291. package/dist/net/url.js +32 -0
  292. package/dist/net/url.js.map +1 -0
  293. package/dist/operator/types.d.ts +1 -1
  294. package/dist/product-cli.d.ts +2 -2
  295. package/dist/product-cli.js +27 -6
  296. package/dist/product-cli.js.map +1 -1
  297. package/dist/product-compat.d.ts +9 -1
  298. package/dist/product-compat.js +12 -1
  299. package/dist/product-compat.js.map +1 -1
  300. package/dist/product-init.js +17 -5
  301. package/dist/product-init.js.map +1 -1
  302. package/dist/product-publish.js +2 -1
  303. package/dist/product-publish.js.map +1 -1
  304. package/dist/product-supplier.d.ts +73 -0
  305. package/dist/product-supplier.js +224 -5
  306. package/dist/product-supplier.js.map +1 -1
  307. package/dist/runtime/fake-model.d.ts +1 -1
  308. package/dist/trust/identity/jwk.d.ts +11 -0
  309. package/dist/trust/identity/jwk.js +2 -0
  310. package/dist/trust/identity/jwk.js.map +1 -0
  311. package/dist/trust/identity/jws.d.ts +2 -1
  312. package/dist/trust/identity/jws.js.map +1 -1
  313. package/dist/trust/identity/keys.d.ts +2 -1
  314. package/dist/trust/identity/keys.js.map +1 -1
  315. package/dist/trust/identity/message-signature.d.ts +1 -14
  316. package/dist/trust/identity/message-signature.js.map +1 -1
  317. package/dist/weixin/channel.d.ts +3 -0
  318. package/dist/weixin/channel.js +18 -2
  319. package/dist/weixin/channel.js.map +1 -1
  320. package/examples/profiles/merchant.deepseek.yaml +6 -0
  321. package/examples/profiles/merchant.fake.yaml +6 -0
  322. package/examples/profiles/merchant.local.yaml +6 -0
  323. package/package.json +9 -7
  324. package/skills/kiwi-buyer/SKILL.md +68 -0
  325. package/skills/merchant/catalog-operations/SKILL.md +17 -0
  326. package/skills/merchant/change-approval/SKILL.md +16 -0
  327. package/skills/merchant/human-review/SKILL.md +17 -0
  328. package/skills/merchant/inventory-operations/SKILL.md +17 -0
  329. package/skills/merchant/negotiation-review/SKILL.md +18 -0
  330. package/skills/merchant/performance-insights/SKILL.md +19 -0
  331. package/contracts/candidate-agent-dto-1.0.README.md +0 -43
  332. 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 { LedgerStore } from "../../negotiation/ledger/index.js";
17
- import { TERMINAL_PHASES } from "../../negotiation/state/phase.js";
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
- if (deps.dataSource !== undefined) {
147
- const facts = await deps.dataSource.getProducts({ limit: 100 });
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 ? "目录为空。" : JSON.stringify(rows), { count: rows.length });
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 merchantClient.getProduct(sku);
189
- return textResult(JSON.stringify(productPreconditions(product)));
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 merchantClient.getInventorySnapshot(sku);
210
- return textResult(JSON.stringify(snapshot));
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
- const ledgerDir = deps.a2aLedgerDir;
230
- if (ledgerDir === undefined) {
216
+ if (deps.a2aLedgerDir === undefined) {
231
217
  return textResult("未配置 A2A ledger 目录,无法读取磋商记录。");
232
218
  }
233
- const ledger = new LedgerStore({ dir: ledgerDir, now: deps.now });
234
- const rows = [];
235
- for (const negotiationId of ledger.listNegotiations()) {
236
- let phase = "OPEN";
237
- let at = "";
238
- let sku = "";
239
- let qty;
240
- let priceMinor;
241
- for (const e of ledger.events(negotiationId)) {
242
- if (e.recorded_at > at)
243
- at = e.recorded_at;
244
- if (e.state_transition?.to_phase !== undefined)
245
- phase = e.state_transition.to_phase;
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
- rows.sort((a, b) => (a.at > b.at ? -1 : a.at < b.at ? 1 : 0));
267
- if (rows.length === 0)
268
- return textResult("当前没有进行中的磋商。", { count: 0 });
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 merchantClient.getHumanReviewQueue(ownerId);
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 = parseChanges(p.changes);
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 = productPreconditions(current);
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 productPreconditions(fresh);
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 = productPreconditions(current);
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 productPreconditions(fresh);
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 = productPreconditions(current);
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 productPreconditions(fresh);
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: { type: "object", description: "计划修改的字段(title/price/stock/description 等)" },
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
- const patch = parseChanges(p.changes);
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
- current = await merchantClient.getProduct(p.sku);
508
+ await merchantClient.getProduct(p.sku);
543
509
  }
544
510
  catch {
545
511
  return textResult(`商品 ${p.sku} 不存在。`);
546
512
  }
547
- const args = { sku: p.sku, changes: { ...patch }, reason: optString(p.reason) ?? "" };
548
- const outcome = await routeWriteCandidate(writeGateDeps, {
549
- tool: "draft_product_change",
550
- arguments: args,
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(productPreconditions(current)), { candidate_id: outcome.candidate.candidate_id, status: "pending_approval" });
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"), { count: values.length });
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
- const ledgerDir = deps.a2aLedgerDir;
618
- if (ledgerDir === undefined) {
754
+ if (deps.a2aLedgerDir === undefined) {
619
755
  return textResult("未配置 A2A ledger 目录,无法读取磋商记录。");
620
756
  }
621
- const ledger = new LedgerStore({ dir: ledgerDir, now: deps.now });
622
- const limit = Math.min(Math.max(Number(params.limit ?? 20) || 20, 1), 100);
623
- const rows = [];
624
- for (const negotiationId of ledger.listNegotiations()) {
625
- const events = ledger.events(negotiationId);
626
- let at = "";
627
- let lastAction = "";
628
- let sku = "";
629
- let qty;
630
- let priceMinor;
631
- let agreement = false;
632
- for (const e of events) {
633
- if (e.recorded_at > at)
634
- at = e.recorded_at;
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
- rows.sort((a, b) => (a.at > b.at ? -1 : a.at < b.at ? 1 : 0));
658
- const recent = rows.slice(0, limit);
659
- if (recent.length === 0)
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,