@chenchaolong/plugin-trade-compliance-workbench 0.1.73 → 1.0.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 (180) hide show
  1. package/README.md +41 -22
  2. package/dist/assets/templates/CI.xlsx +0 -0
  3. package/dist/assets/templates/CUSTOMS_DECLARATION.xlsx +0 -0
  4. package/dist/assets/templates/PI.xlsx +0 -0
  5. package/dist/assets/templates/PL.xlsx +0 -0
  6. package/dist/index.d.ts +115 -228
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +19 -108
  9. package/dist/index.js.map +1 -1
  10. package/dist/lib/{document-text-extractor.d.ts → adapters/document-text-extractor.d.ts} +2 -2
  11. package/dist/lib/adapters/document-text-extractor.d.ts.map +1 -0
  12. package/dist/lib/{document-text-extractor.js → adapters/document-text-extractor.js} +8 -2
  13. package/dist/lib/adapters/document-text-extractor.js.map +1 -0
  14. package/dist/lib/adapters/file-storage.d.ts +9 -0
  15. package/dist/lib/adapters/file-storage.d.ts.map +1 -0
  16. package/dist/lib/adapters/file-storage.js +37 -0
  17. package/dist/lib/adapters/file-storage.js.map +1 -0
  18. package/dist/lib/{trade-compliance.enrichment.d.ts → adapters/hsbianma.provider.d.ts} +6 -6
  19. package/dist/lib/adapters/hsbianma.provider.d.ts.map +1 -0
  20. package/dist/lib/{trade-compliance.enrichment.js → adapters/hsbianma.provider.js} +1 -1
  21. package/dist/lib/adapters/hsbianma.provider.js.map +1 -0
  22. package/dist/lib/adapters/translation.provider.d.ts +4 -0
  23. package/dist/lib/adapters/translation.provider.d.ts.map +1 -0
  24. package/dist/lib/adapters/translation.provider.js +35 -0
  25. package/dist/lib/adapters/translation.provider.js.map +1 -0
  26. package/dist/lib/constants.d.ts +17 -11
  27. package/dist/lib/constants.d.ts.map +1 -1
  28. package/dist/lib/constants.js +17 -21
  29. package/dist/lib/constants.js.map +1 -1
  30. package/dist/lib/domain/contract-number.d.ts +14 -0
  31. package/dist/lib/domain/contract-number.d.ts.map +1 -0
  32. package/dist/lib/domain/contract-number.js +36 -0
  33. package/dist/lib/domain/contract-number.js.map +1 -0
  34. package/dist/lib/domain/default-settings.d.ts +28 -0
  35. package/dist/lib/domain/default-settings.d.ts.map +1 -0
  36. package/dist/lib/domain/default-settings.js +16 -0
  37. package/dist/lib/domain/default-settings.js.map +1 -0
  38. package/dist/lib/domain/finance.d.ts +37 -0
  39. package/dist/lib/domain/finance.d.ts.map +1 -0
  40. package/dist/lib/domain/finance.js +60 -0
  41. package/dist/lib/domain/finance.js.map +1 -0
  42. package/dist/lib/domain/import-issues.d.ts +10 -0
  43. package/dist/lib/domain/import-issues.d.ts.map +1 -0
  44. package/dist/lib/domain/import-issues.js +23 -0
  45. package/dist/lib/domain/import-issues.js.map +1 -0
  46. package/dist/lib/domain/normalization.d.ts +8 -0
  47. package/dist/lib/domain/normalization.d.ts.map +1 -0
  48. package/dist/lib/domain/normalization.js +50 -0
  49. package/dist/lib/domain/normalization.js.map +1 -0
  50. package/dist/lib/domain/workflow.d.ts +4 -0
  51. package/dist/lib/domain/workflow.d.ts.map +1 -0
  52. package/dist/lib/domain/workflow.js +14 -0
  53. package/dist/lib/domain/workflow.js.map +1 -0
  54. package/dist/lib/entities/base.d.ts +20 -0
  55. package/dist/lib/entities/base.d.ts.map +1 -0
  56. package/dist/lib/entities/base.js +51 -0
  57. package/dist/lib/entities/base.js.map +1 -0
  58. package/dist/lib/entities/catalog.entity.d.ts +80 -0
  59. package/dist/lib/entities/catalog.entity.d.ts.map +1 -0
  60. package/dist/lib/entities/catalog.entity.js +308 -0
  61. package/dist/lib/entities/catalog.entity.js.map +1 -0
  62. package/dist/lib/entities/customer.entity.d.ts +72 -0
  63. package/dist/lib/entities/customer.entity.d.ts.map +1 -0
  64. package/dist/lib/entities/customer.entity.js +276 -0
  65. package/dist/lib/entities/customer.entity.js.map +1 -0
  66. package/dist/lib/entities/index.d.ts +12 -6
  67. package/dist/lib/entities/index.d.ts.map +1 -1
  68. package/dist/lib/entities/index.js +20 -7
  69. package/dist/lib/entities/index.js.map +1 -1
  70. package/dist/lib/entities/procurement.entity.d.ts +99 -0
  71. package/dist/lib/entities/procurement.entity.d.ts.map +1 -0
  72. package/dist/lib/entities/procurement.entity.js +386 -0
  73. package/dist/lib/entities/procurement.entity.js.map +1 -0
  74. package/dist/lib/entities/settings.entity.d.ts +64 -0
  75. package/dist/lib/entities/settings.entity.d.ts.map +1 -0
  76. package/dist/lib/entities/settings.entity.js +243 -0
  77. package/dist/lib/entities/settings.entity.js.map +1 -0
  78. package/dist/lib/entities/shared.entity.d.ts +40 -0
  79. package/dist/lib/entities/shared.entity.d.ts.map +1 -0
  80. package/dist/lib/entities/shared.entity.js +149 -0
  81. package/dist/lib/entities/shared.entity.js.map +1 -0
  82. package/dist/lib/remote-components/trade-compliance-workbench/app.js +245 -2677
  83. package/dist/lib/remote-components/trade-compliance-workbench/editor-source.mjs +53 -0
  84. package/dist/lib/remote-components/trade-compliance-workbench/editor.css +1 -0
  85. package/dist/lib/remote-components/trade-compliance-workbench/editor.js +533 -0
  86. package/dist/lib/sales-file.service.d.ts +29 -0
  87. package/dist/lib/sales-file.service.d.ts.map +1 -0
  88. package/dist/lib/sales-file.service.js +300 -0
  89. package/dist/lib/sales-file.service.js.map +1 -0
  90. package/dist/lib/trade-compliance.config.d.ts +94 -187
  91. package/dist/lib/trade-compliance.config.d.ts.map +1 -1
  92. package/dist/lib/trade-compliance.config.js +12 -96
  93. package/dist/lib/trade-compliance.config.js.map +1 -1
  94. package/dist/lib/types.d.ts +104 -1
  95. package/dist/lib/types.d.ts.map +1 -1
  96. package/dist/lib/types.js +47 -1
  97. package/dist/lib/types.js.map +1 -1
  98. package/dist/lib/workbench-view.provider.d.ts +276 -0
  99. package/dist/lib/workbench-view.provider.d.ts.map +1 -0
  100. package/dist/lib/workbench-view.provider.js +222 -0
  101. package/dist/lib/workbench-view.provider.js.map +1 -0
  102. package/dist/lib/workbench.middleware.d.ts +351 -0
  103. package/dist/lib/workbench.middleware.d.ts.map +1 -0
  104. package/dist/lib/workbench.middleware.js +48 -0
  105. package/dist/lib/workbench.middleware.js.map +1 -0
  106. package/dist/lib/workbench.plugin.d.ts +5 -0
  107. package/dist/lib/workbench.plugin.d.ts.map +1 -0
  108. package/dist/lib/workbench.plugin.js +24 -0
  109. package/dist/lib/workbench.plugin.js.map +1 -0
  110. package/dist/lib/workbench.service.d.ts +257 -0
  111. package/dist/lib/workbench.service.d.ts.map +1 -0
  112. package/dist/lib/workbench.service.js +755 -0
  113. package/dist/lib/workbench.service.js.map +1 -0
  114. package/package.json +19 -25
  115. package/dist/assets/customs-workbook-template.xls +0 -0
  116. package/dist/lib/controlled-goods-extracted-text-store.d.ts +0 -29
  117. package/dist/lib/controlled-goods-extracted-text-store.d.ts.map +0 -1
  118. package/dist/lib/controlled-goods-extracted-text-store.js +0 -42
  119. package/dist/lib/controlled-goods-extracted-text-store.js.map +0 -1
  120. package/dist/lib/controlled-goods-file-parser.d.ts +0 -9
  121. package/dist/lib/controlled-goods-file-parser.d.ts.map +0 -1
  122. package/dist/lib/controlled-goods-file-parser.js +0 -298
  123. package/dist/lib/controlled-goods-file-parser.js.map +0 -1
  124. package/dist/lib/document-text-extractor.d.ts.map +0 -1
  125. package/dist/lib/document-text-extractor.js.map +0 -1
  126. package/dist/lib/entities/controlled-goods-record.entity.d.ts +0 -5
  127. package/dist/lib/entities/controlled-goods-record.entity.d.ts.map +0 -1
  128. package/dist/lib/entities/controlled-goods-record.entity.js +0 -68
  129. package/dist/lib/entities/controlled-goods-record.entity.js.map +0 -1
  130. package/dist/lib/entities/customs-workbook-generation.entity.d.ts +0 -5
  131. package/dist/lib/entities/customs-workbook-generation.entity.d.ts.map +0 -1
  132. package/dist/lib/entities/customs-workbook-generation.entity.js +0 -72
  133. package/dist/lib/entities/customs-workbook-generation.entity.js.map +0 -1
  134. package/dist/lib/entities/trade-compliance-import-batch.entity.d.ts +0 -5
  135. package/dist/lib/entities/trade-compliance-import-batch.entity.d.ts.map +0 -1
  136. package/dist/lib/entities/trade-compliance-import-batch.entity.js +0 -60
  137. package/dist/lib/entities/trade-compliance-import-batch.entity.js.map +0 -1
  138. package/dist/lib/entities/trade-compliance-review-item.entity.d.ts +0 -5
  139. package/dist/lib/entities/trade-compliance-review-item.entity.d.ts.map +0 -1
  140. package/dist/lib/entities/trade-compliance-review-item.entity.js +0 -84
  141. package/dist/lib/entities/trade-compliance-review-item.entity.js.map +0 -1
  142. package/dist/lib/entities/trade-product.entity.d.ts +0 -5
  143. package/dist/lib/entities/trade-product.entity.d.ts.map +0 -1
  144. package/dist/lib/entities/trade-product.entity.js +0 -105
  145. package/dist/lib/entities/trade-product.entity.js.map +0 -1
  146. package/dist/lib/entities/trade-supplier.entity.d.ts +0 -5
  147. package/dist/lib/entities/trade-supplier.entity.d.ts.map +0 -1
  148. package/dist/lib/entities/trade-supplier.entity.js +0 -55
  149. package/dist/lib/entities/trade-supplier.entity.js.map +0 -1
  150. package/dist/lib/trade-compliance-workbench-view.provider.d.ts +0 -129
  151. package/dist/lib/trade-compliance-workbench-view.provider.d.ts.map +0 -1
  152. package/dist/lib/trade-compliance-workbench-view.provider.js +0 -863
  153. package/dist/lib/trade-compliance-workbench-view.provider.js.map +0 -1
  154. package/dist/lib/trade-compliance-workbench.middleware.d.ts +0 -485
  155. package/dist/lib/trade-compliance-workbench.middleware.d.ts.map +0 -1
  156. package/dist/lib/trade-compliance-workbench.middleware.js +0 -494
  157. package/dist/lib/trade-compliance-workbench.middleware.js.map +0 -1
  158. package/dist/lib/trade-compliance-workbench.plugin.d.ts +0 -11
  159. package/dist/lib/trade-compliance-workbench.plugin.d.ts.map +0 -1
  160. package/dist/lib/trade-compliance-workbench.plugin.js +0 -39
  161. package/dist/lib/trade-compliance-workbench.plugin.js.map +0 -1
  162. package/dist/lib/trade-compliance-workbench.service.d.ts +0 -33
  163. package/dist/lib/trade-compliance-workbench.service.d.ts.map +0 -1
  164. package/dist/lib/trade-compliance-workbench.service.js +0 -369
  165. package/dist/lib/trade-compliance-workbench.service.js.map +0 -1
  166. package/dist/lib/trade-compliance-workbench.templates.d.ts +0 -31
  167. package/dist/lib/trade-compliance-workbench.templates.d.ts.map +0 -1
  168. package/dist/lib/trade-compliance-workbench.templates.js +0 -60
  169. package/dist/lib/trade-compliance-workbench.templates.js.map +0 -1
  170. package/dist/lib/trade-compliance-workbook.d.ts +0 -28
  171. package/dist/lib/trade-compliance-workbook.d.ts.map +0 -1
  172. package/dist/lib/trade-compliance-workbook.js +0 -635
  173. package/dist/lib/trade-compliance-workbook.js.map +0 -1
  174. package/dist/lib/trade-compliance.enrichment.d.ts.map +0 -1
  175. package/dist/lib/trade-compliance.enrichment.js.map +0 -1
  176. package/dist/lib/trade-compliance.matching.d.ts +0 -10
  177. package/dist/lib/trade-compliance.matching.d.ts.map +0 -1
  178. package/dist/lib/trade-compliance.matching.js +0 -63
  179. package/dist/lib/trade-compliance.matching.js.map +0 -1
  180. package/dist/xpert-trade-compliance-workbench-assistant.yaml +0 -27
@@ -1,863 +0,0 @@
1
- // @ts-nocheck
2
- import { __decorate, __metadata } from "tslib";
3
- import { Injectable } from '@nestjs/common';
4
- import { readFile } from 'fs/promises';
5
- import { createRequire } from 'module';
6
- import { dirname, join } from 'path';
7
- import { fileURLToPath } from 'url';
8
- import { renderRemoteReactIframeHtml, ViewExtensionProvider } from '@xpert-ai/plugin-sdk';
9
- import { AGENT_WORKBENCH_FIXED_SLOT, AGENT_WORKBENCH_MAIN_SLOT, TRADE_COMPLIANCE_FEATURE, TRADE_COMPLIANCE_ICON, TRADE_COMPLIANCE_PLUGIN_NAME, TRADE_COMPLIANCE_PROVIDER_KEY, TRADE_COMPLIANCE_REMOTE_ENTRY_KEY, TRADE_COMPLIANCE_VIEW_KEY } from './constants.js';
10
- import { TradeComplianceWorkbenchService } from './trade-compliance-workbench.service.js';
11
- import { buildCustomsWorkbookModel, buildCustomsWorkbookTemplateFileName, createCustomsWorkbookFromTemplateBuffer, readCustomsWorkbookTemplateSheetNames } from './trade-compliance-workbook.js';
12
- import { getHsBianmaCodeDetail, searchHsBianmaCodes } from './trade-compliance.enrichment.js';
13
- import { extractDocumentText } from './document-text-extractor.js';
14
- import { storeControlledGoodsExtractedText } from './controlled-goods-extracted-text-store.js';
15
- const __filename = fileURLToPath(import.meta.url);
16
- const __dirname = dirname(__filename);
17
- const requireFromHere = createRequire(__filename);
18
- const text = (en_US, zh_Hans) => ({ en_US, zh_Hans });
19
- let TradeComplianceWorkbenchViewProvider = class TradeComplianceWorkbenchViewProvider {
20
- constructor(service) {
21
- this.service = service;
22
- }
23
- supports(context) {
24
- return context.hostType === 'agent';
25
- }
26
- getViewManifests(_context, slot) {
27
- if (slot !== AGENT_WORKBENCH_MAIN_SLOT && slot !== AGENT_WORKBENCH_FIXED_SLOT) {
28
- return [];
29
- }
30
- return [
31
- {
32
- key: TRADE_COMPLIANCE_VIEW_KEY,
33
- title: text('Trade Compliance Workbench', '外贸合规工作台'),
34
- description: text('Manage controlled goods, supplier products, and generated customs workbooks.', '管理管控商品、供应商商品和生成的报关资料。'),
35
- icon: {
36
- type: 'svg',
37
- value: TRADE_COMPLIANCE_ICON
38
- },
39
- hostType: 'agent',
40
- slot,
41
- order: 40,
42
- refreshable: true,
43
- activation: {
44
- requiredFeatures: [TRADE_COMPLIANCE_FEATURE]
45
- },
46
- source: {
47
- provider: TRADE_COMPLIANCE_PROVIDER_KEY,
48
- plugin: TRADE_COMPLIANCE_PLUGIN_NAME
49
- },
50
- view: {
51
- type: 'remote_component',
52
- runtime: 'react',
53
- protocolVersion: 1,
54
- component: {
55
- isolation: 'iframe',
56
- entry: TRADE_COMPLIANCE_REMOTE_ENTRY_KEY
57
- },
58
- dataSource: {
59
- mode: 'platform'
60
- }
61
- },
62
- dataSource: {
63
- mode: 'platform',
64
- querySchema: {
65
- supportsPagination: true,
66
- supportsSearch: true,
67
- supportsParameters: true,
68
- defaultPageSize: 20
69
- },
70
- cache: {
71
- enabled: false
72
- }
73
- },
74
- clientCommands: [
75
- {
76
- key: 'assistant.chat.send_message',
77
- label: text('Send to Assistant Chat', '发送到 Assistant 对话')
78
- }
79
- ],
80
- actions: [
81
- { key: 'refresh', label: text('Refresh', '刷新'), icon: 'ri-refresh-line', placement: 'toolbar', actionType: 'refresh' },
82
- {
83
- key: 'upload_controlled_goods_file',
84
- label: text('Upload Controlled Goods File', '上传管控商品文件'),
85
- icon: 'ri-upload-cloud-line',
86
- placement: 'toolbar',
87
- actionType: 'invoke',
88
- transport: 'file'
89
- },
90
- {
91
- key: 'upload_supplier_contract',
92
- label: text('Upload Supplier Contract', '上传供应商合同'),
93
- icon: 'ri-file-list-3-line',
94
- placement: 'toolbar',
95
- actionType: 'invoke',
96
- transport: 'file'
97
- },
98
- {
99
- key: 'upload_sales_contract',
100
- label: text('Upload Sales Contract', '上传购销合同'),
101
- icon: 'ri-file-excel-2-line',
102
- placement: 'toolbar',
103
- actionType: 'invoke',
104
- transport: 'file'
105
- },
106
- { key: 'confirm_review_item', label: text('Confirm Item', '确认单条'), icon: 'ri-check-line', actionType: 'invoke' },
107
- { key: 'confirm_review_items', label: text('Confirm Selected', '批量确认'), icon: 'ri-check-double-line', actionType: 'invoke' },
108
- { key: 'reject_review_item', label: text('Reject Item', '驳回单条'), icon: 'ri-close-line', actionType: 'invoke' },
109
- { key: 'reject_review_items', label: text('Reject Selected', '批量驳回'), icon: 'ri-close-circle-line', actionType: 'invoke' },
110
- { key: 'save_controlled_goods', label: text('Save Controlled Goods', '保存管控商品'), icon: 'ri-save-line', actionType: 'invoke' },
111
- { key: 'save_supplier_product', label: text('Save Supplier Product', '保存供应商商品'), icon: 'ri-save-line', actionType: 'invoke' },
112
- { key: 'update_review_item', label: text('Update Review Item', '更新审核项'), icon: 'ri-edit-line', actionType: 'invoke' },
113
- { key: 'delete_review_item', label: text('Delete Review Item', '删除审核项'), icon: 'ri-delete-bin-line', actionType: 'invoke' },
114
- { key: 'update_controlled_goods', label: text('Update Controlled Goods', '更新管控商品'), icon: 'ri-edit-line', actionType: 'invoke' },
115
- { key: 'delete_controlled_goods', label: text('Delete Controlled Goods', '删除管控商品'), icon: 'ri-delete-bin-line', actionType: 'invoke' },
116
- { key: 'update_supplier_product', label: text('Update Supplier Product', '更新供应商商品'), icon: 'ri-edit-line', actionType: 'invoke' },
117
- { key: 'delete_supplier_product', label: text('Delete Supplier Product', '删除供应商商品'), icon: 'ri-delete-bin-line', actionType: 'invoke' },
118
- { key: 'delete_customs_workbook', label: text('Delete Workbook', '删除销售发票'), icon: 'ri-delete-bin-line', actionType: 'invoke' },
119
- { key: 'download_customs_workbook', label: text('Download Workbook', '下载销售发票'), icon: 'ri-download-line', actionType: 'invoke' },
120
- { key: 'search_hs_code', label: text('Search HS Code', '查询海关编码'), icon: 'ri-search-line', actionType: 'invoke' },
121
- { key: 'get_hs_code_detail', label: text('Get HS Code Detail', '查看海关编码详情'), icon: 'ri-file-search-line', actionType: 'invoke' },
122
- { key: 'generate_customs_workbook', label: text('Generate Workbook', '生成报关资料'), icon: 'ri-file-excel-line', actionType: 'invoke' }
123
- ]
124
- }
125
- ];
126
- }
127
- async getRemoteComponentEntry(_context, viewKey, component) {
128
- if (viewKey !== TRADE_COMPLIANCE_VIEW_KEY || component.entry !== TRADE_COMPLIANCE_REMOTE_ENTRY_KEY) {
129
- return {
130
- html: '<!doctype html><html><body>Unsupported trade compliance component.</body></html>',
131
- contentType: 'text/html; charset=utf-8'
132
- };
133
- }
134
- const appScript = await readFile(join(__dirname, 'remote-components', TRADE_COMPLIANCE_REMOTE_ENTRY_KEY, 'app.js'), 'utf8');
135
- const reactUmd = await readPackageFile('react', 'umd/react.production.min.js');
136
- const reactDomUmd = await readPackageFile('react-dom', 'umd/react-dom.production.min.js');
137
- return {
138
- html: renderRemoteReactIframeHtml({
139
- title: 'Trade Compliance Workbench',
140
- lang: 'zh-Hans',
141
- reactUmd,
142
- reactDomUmd,
143
- appScript
144
- }),
145
- contentType: 'text/html; charset=utf-8'
146
- };
147
- }
148
- async getViewData(context, _viewKey, _query) {
149
- const scope = scopeFromContext(context);
150
- const [reviewItems, controlledGoods, products, workbookGenerations] = await Promise.all([
151
- this.service.listReviewItems(scope),
152
- this.service.listControlledGoods(scope),
153
- this.service.listProducts(scope),
154
- this.service.listWorkbookGenerations(scope)
155
- ]);
156
- return {
157
- items: reviewItems,
158
- total: reviewItems.length,
159
- summary: {
160
- reviewItems,
161
- controlledGoods,
162
- products,
163
- workbookGenerations
164
- }
165
- };
166
- }
167
- async executeViewAction(context, _viewKey, actionKey, request) {
168
- const scope = scopeFromContext(context);
169
- if (actionKey === 'confirm_review_item') {
170
- const itemId = readString(request.input, 'itemId');
171
- if (!itemId) {
172
- return failure('itemId is required', '缺少 itemId');
173
- }
174
- const item = await this.service.confirmReviewItem(scope, itemId, readRecord(request.input, 'confirmedData'));
175
- return success(await this.materializeConfirmedReviewItem(scope, item));
176
- }
177
- if (actionKey === 'confirm_review_items') {
178
- const itemIds = readStringArray(request.input, 'itemIds');
179
- const items = await this.service.confirmReviewItems(scope, itemIds);
180
- return success(await Promise.all(items.map((item) => this.materializeConfirmedReviewItem(scope, item))));
181
- }
182
- if (actionKey === 'reject_review_item') {
183
- const itemId = readString(request.input, 'itemId');
184
- if (!itemId) {
185
- return failure('itemId is required', '缺少 itemId');
186
- }
187
- return success(await this.service.rejectReviewItem(scope, itemId));
188
- }
189
- if (actionKey === 'reject_review_items') {
190
- const itemIds = readStringArray(request.input, 'itemIds');
191
- return success(await this.service.rejectReviewItems(scope, itemIds));
192
- }
193
- if (actionKey === 'update_review_item') {
194
- const itemId = readString(request.input, 'itemId');
195
- const confirmedData = readRecord(request.input, 'confirmedData');
196
- if (!itemId || !confirmedData)
197
- return failure('itemId and confirmedData are required', '缺少 itemId 或更新数据');
198
- return success(await this.service.updateReviewItem(scope, itemId, confirmedData));
199
- }
200
- if (actionKey === 'delete_review_item') {
201
- const itemId = readString(request.input, 'itemId');
202
- if (!itemId)
203
- return failure('itemId is required', '缺少 itemId');
204
- return success(await this.service.deleteReviewItem(scope, itemId));
205
- }
206
- if (actionKey === 'refresh') {
207
- return { success: true, message: text('Refreshed', '已刷新'), refresh: true };
208
- }
209
- if (actionKey === 'search_hs_code') {
210
- const keywords = readString(request.input, 'keywords');
211
- if (!keywords) {
212
- return failure('keywords is required', '请输入商品名称或海关编码');
213
- }
214
- const result = await searchHsBianmaCodes({
215
- keywords,
216
- page: readNumber(request.input, 'page') ?? 1,
217
- filterFailureCode: true,
218
- displayChapter: false,
219
- displayEnName: true
220
- });
221
- return success(result);
222
- }
223
- if (actionKey === 'get_hs_code_detail') {
224
- const code = readString(request.input, 'code');
225
- const detailUrl = readString(request.input, 'detailUrl');
226
- if (!code && !detailUrl) {
227
- return failure('code or detailUrl is required', '缺少海关编码');
228
- }
229
- return success(await getHsBianmaCodeDetail({ code, detailUrl }));
230
- }
231
- if (actionKey === 'save_controlled_goods') {
232
- const productName = readString(request.input, 'productName');
233
- if (!productName) {
234
- return failure('productName is required', '缺少商品名称');
235
- }
236
- return success(await this.service.saveControlledGoods(scope, {
237
- productName,
238
- hsCode: readString(request.input, 'hsCode'),
239
- keywords: readStringArray(request.input, 'keywords'),
240
- controlNote: readString(request.input, 'controlNote'),
241
- enabled: readBoolean(request.input, 'enabled') ?? true,
242
- sourceFileName: readString(request.input, 'sourceFileName'),
243
- sourceLocation: readString(request.input, 'sourceLocation')
244
- }));
245
- }
246
- if (actionKey === 'save_supplier_product') {
247
- const supplierName = readString(request.input, 'supplierName');
248
- const productName = readString(request.input, 'productName');
249
- if (!supplierName || !productName) {
250
- return failure('supplierName and productName are required', '缺少供应商或商品名称');
251
- }
252
- return success(await this.service.saveSupplierProduct(scope, {
253
- supplierName,
254
- supplierCreditCode: readString(request.input, 'supplierCreditCode'),
255
- supplierAddress: readString(request.input, 'supplierAddress'),
256
- productName,
257
- model: readString(request.input, 'model'),
258
- description: readString(request.input, 'description'),
259
- quantity: readNumber(request.input, 'quantity'),
260
- unit: readString(request.input, 'unit'),
261
- taxInclusiveUnitPrice: readNumber(request.input, 'taxInclusiveUnitPrice'),
262
- taxInclusiveTotalAmount: readNumber(request.input, 'taxInclusiveTotalAmount'),
263
- contractHsCode: readString(request.input, 'contractHsCode'),
264
- enrichedHsCode: readString(request.input, 'enrichedHsCode'),
265
- taxRefundRate: readString(request.input, 'taxRefundRate'),
266
- englishName: readString(request.input, 'englishName'),
267
- controlledStatus: readControlledGoodsStatus(request.input, 'controlledStatus'),
268
- controlNote: readString(request.input, 'controlNote')
269
- }));
270
- }
271
- if (actionKey === 'update_controlled_goods') {
272
- const id = readString(request.input, 'id');
273
- if (!id)
274
- return failure('id is required', '缺少 id');
275
- return success(await this.service.updateControlledGoods(scope, id, {
276
- productName: readString(request.input, 'productName'),
277
- hsCode: readString(request.input, 'hsCode'),
278
- keywords: readStringArray(request.input, 'keywords'),
279
- controlNote: readString(request.input, 'controlNote'),
280
- enabled: readBoolean(request.input, 'enabled'),
281
- sourceFileName: readString(request.input, 'sourceFileName'),
282
- sourceLocation: readString(request.input, 'sourceLocation')
283
- }));
284
- }
285
- if (actionKey === 'delete_controlled_goods') {
286
- const id = readString(request.input, 'id');
287
- if (!id)
288
- return failure('id is required', '缺少 id');
289
- return success(await this.service.deleteControlledGoods(scope, id));
290
- }
291
- if (actionKey === 'update_supplier_product') {
292
- const id = readString(request.input, 'id');
293
- if (!id)
294
- return failure('id is required', '缺少 id');
295
- return success(await this.service.updateSupplierProduct(scope, id, {
296
- supplierName: readString(request.input, 'supplierName'),
297
- productName: readString(request.input, 'productName'),
298
- model: readString(request.input, 'model'),
299
- description: readString(request.input, 'description'),
300
- quantity: readNumber(request.input, 'quantity'),
301
- unit: readString(request.input, 'unit'),
302
- contractHsCode: readString(request.input, 'contractHsCode'),
303
- enrichedHsCode: readString(request.input, 'enrichedHsCode'),
304
- taxRefundRate: readString(request.input, 'taxRefundRate'),
305
- englishName: readString(request.input, 'englishName'),
306
- controlledStatus: readControlledGoodsStatus(request.input, 'controlledStatus'),
307
- controlNote: readString(request.input, 'controlNote')
308
- }));
309
- }
310
- if (actionKey === 'delete_supplier_product') {
311
- const id = readString(request.input, 'id');
312
- if (!id)
313
- return failure('id is required', '缺少 id');
314
- return success(await this.service.deleteSupplierProduct(scope, id));
315
- }
316
- if (actionKey === 'delete_customs_workbook') {
317
- const id = readString(request.input, 'id');
318
- if (!id)
319
- return failure('id is required', '缺少 id');
320
- return success(await this.service.deleteWorkbookGeneration(scope, id));
321
- }
322
- if (actionKey === 'download_customs_workbook') {
323
- const id = readString(request.input, 'id');
324
- if (!id)
325
- return failure('id is required', '缺少 id');
326
- const item = await this.service.getWorkbookGeneration(scope, id);
327
- const template = await readFile(join(__dirname, '..', 'assets', 'customs-workbook-template.xls'));
328
- const source = normalizeWorkbookSource({
329
- ...(item.workbookData || {}),
330
- invoiceNo: item.invoiceNo,
331
- contractNo: item.contractNo,
332
- sourceFileName: item.sourceFileName
333
- });
334
- const workbook = await createCustomsWorkbookFromTemplateBuffer(buildCustomsWorkbookModel(source, {}), template);
335
- return success({
336
- fileName: workbook.fileName || item.fileName,
337
- mimeType: workbook.mimeType,
338
- bookType: workbook.bookType,
339
- base64: workbook.buffer.toString('base64')
340
- });
341
- }
342
- if (actionKey === 'generate_customs_workbook') {
343
- const now = new Date();
344
- const invoiceNo = readString(request.input, 'invoiceNo') ?? `INV-${now.toISOString().slice(0, 10).replace(/-/g, '')}`;
345
- const template = await readFile(join(__dirname, '..', 'assets', 'customs-workbook-template.xls'));
346
- const result = await this.service.recordWorkbookGeneration(scope, {
347
- sourceFileName: readString(request.input, 'sourceFileName') ?? readString(request.input, 'contractName'),
348
- invoiceNo,
349
- contractNo: readString(request.input, 'contractNo'),
350
- fileName: buildCustomsWorkbookTemplateFileName(invoiceNo),
351
- sheetNames: readCustomsWorkbookTemplateSheetNames(template),
352
- workbookData: readRecord(request.input, 'workbookData') ?? {
353
- invoiceNo,
354
- contractNo: readString(request.input, 'contractNo'),
355
- generatedFrom: 'trade-compliance-workbench'
356
- }
357
- });
358
- return success(result);
359
- }
360
- return {
361
- success: true,
362
- message: text('Action accepted', '操作已接收'),
363
- refresh: true
364
- };
365
- }
366
- async executeViewFileAction(context, viewKey, actionKey, request, file) {
367
- if (viewKey !== TRADE_COMPLIANCE_VIEW_KEY) {
368
- return failure('Unsupported view', '不支持的视图');
369
- }
370
- const scope = scopeFromContext(context);
371
- const fileName = getFileDisplayName(file, request.input);
372
- const assistantFile = viewFileToAssistantFile(file, fileName, roleForUploadAction(actionKey) ?? 'source_file', request.input);
373
- if (actionKey === 'upload_controlled_goods_file') {
374
- const buffer = getFileBuffer(file) ?? await readWorkspaceFileBuffer(assistantFile);
375
- if (!buffer?.length) {
376
- return failure('Uploaded file content is not readable.', '无法读取上传文件内容,请重新上传后再解析。');
377
- }
378
- const extractedText = await extractDocumentText({
379
- buffer,
380
- fileName,
381
- mimeType: getFileMimeType(file),
382
- maxChars: 30000
383
- });
384
- const result = await this.service.createReviewBatch(scope, {
385
- type: 'controlled_goods_file',
386
- sourceFileName: fileName,
387
- metadata: {
388
- fileName,
389
- size: getFileSize(file),
390
- mimeType: getFileMimeType(file),
391
- parser: 'document-text-to-llm',
392
- extractedTextKind: extractedText.kind,
393
- extractedTextLength: extractedText.originalLength,
394
- extractedTextTruncated: extractedText.truncated,
395
- extractedTextChunked: extractedText.chunked,
396
- extractedTextChunkCount: extractedText.chunkCount
397
- },
398
- items: []
399
- });
400
- storeControlledGoodsExtractedText(result.batch.id, {
401
- sourceFileName: fileName,
402
- kind: extractedText.kind,
403
- originalLength: extractedText.originalLength,
404
- chunks: extractedText.chunks
405
- });
406
- return parsingStarted(buildAssistantCommand({
407
- action: 'parse_controlled_goods_file',
408
- file: assistantFile,
409
- fileName,
410
- role: 'controlled_goods_file',
411
- batchId: result.batch.id,
412
- extractedText,
413
- text: buildControlledGoodsParsePrompt(fileName, result.batch.id, extractedText)
414
- }));
415
- }
416
- if (!hasAssistantReadableFileHandle(assistantFile)) {
417
- return failure('Uploaded file was not registered as an assistant-readable workspace file.', '文件未写入智能体工作空间,请重新上传后再解析。');
418
- }
419
- if (actionKey === 'upload_supplier_contract') {
420
- const result = await this.service.createReviewBatch(scope, {
421
- type: 'supplier_contract',
422
- sourceFileName: fileName,
423
- metadata: { fileName, size: getFileSize(file), mimeType: getFileMimeType(file) },
424
- items: []
425
- });
426
- return parsingStarted(buildAssistantCommand({
427
- action: 'parse_supplier_contract',
428
- file: assistantFile,
429
- fileName,
430
- role: 'supplier_contract',
431
- batchId: result.batch.id,
432
- text: buildSupplierContractParsePrompt(fileName, result.batch.id)
433
- }));
434
- }
435
- if (actionKey === 'upload_sales_contract') {
436
- const result = await this.service.createReviewBatch(scope, {
437
- type: 'sales_contract',
438
- sourceFileName: fileName,
439
- metadata: { fileName, size: getFileSize(file), mimeType: getFileMimeType(file) },
440
- items: []
441
- });
442
- return parsingStarted(buildAssistantCommand({
443
- action: 'parse_sales_contract',
444
- file: assistantFile,
445
- fileName,
446
- role: 'sales_contract',
447
- batchId: result.batch.id,
448
- text: buildSalesContractParsePrompt(fileName, result.batch.id)
449
- }));
450
- }
451
- return failure('Unsupported file action', '不支持的文件操作');
452
- }
453
- async materializeConfirmedReviewItem(scope, item) {
454
- const data = mergeReviewData(item.defaultData, item.extractedData, item.confirmedData);
455
- if (item.type === 'controlled_goods') {
456
- const productName = readString(data, 'productName') ?? item.title;
457
- return {
458
- item,
459
- materialized: await this.service.saveControlledGoods(scope, {
460
- productName,
461
- hsCode: readString(data, 'hsCode'),
462
- keywords: readStringArray(data, 'keywords'),
463
- controlNote: readString(data, 'controlNote'),
464
- enabled: readBoolean(data, 'enabled') ?? true,
465
- sourceFileName: readString(data, 'sourceFileName'),
466
- sourceLocation: item.sourceLocation ?? readString(data, 'sourceLocation')
467
- })
468
- };
469
- }
470
- if (item.type === 'supplier_product') {
471
- const supplierName = readString(data, 'supplierName') ?? '未识别供应商';
472
- const productName = readString(data, 'productName') ?? item.title;
473
- return {
474
- item,
475
- materialized: await this.service.saveSupplierProduct(scope, {
476
- supplierName,
477
- supplierCreditCode: readString(data, 'supplierCreditCode'),
478
- supplierAddress: readString(data, 'supplierAddress'),
479
- productName,
480
- model: readString(data, 'model'),
481
- description: readString(data, 'description'),
482
- quantity: readNumber(data, 'quantity'),
483
- unit: readString(data, 'unit'),
484
- taxInclusiveUnitPrice: readNumber(data, 'taxInclusiveUnitPrice'),
485
- taxInclusiveTotalAmount: readNumber(data, 'taxInclusiveTotalAmount'),
486
- contractHsCode: readString(data, 'contractHsCode'),
487
- enrichedHsCode: readString(data, 'enrichedHsCode'),
488
- taxRefundRate: readString(data, 'taxRefundRate'),
489
- englishName: readString(data, 'englishName'),
490
- controlledStatus: readControlledGoodsStatus(data, 'controlledStatus'),
491
- controlNote: readString(data, 'controlNote'),
492
- matchedControlledGoods: readRecordArray(data, 'matchedControlledGoods')
493
- })
494
- };
495
- }
496
- return { item, materialized: null };
497
- }
498
- };
499
- TradeComplianceWorkbenchViewProvider = __decorate([
500
- Injectable(),
501
- ViewExtensionProvider(TRADE_COMPLIANCE_PROVIDER_KEY),
502
- __metadata("design:paramtypes", [TradeComplianceWorkbenchService])
503
- ], TradeComplianceWorkbenchViewProvider);
504
- export { TradeComplianceWorkbenchViewProvider };
505
- async function readPackageFile(packageName, filePath) {
506
- const packageRoot = dirname(requireFromHere.resolve(`${packageName}/package.json`));
507
- return readFile(join(packageRoot, filePath), 'utf8');
508
- }
509
- function scopeFromContext(context) {
510
- return {
511
- tenantId: context.tenantId,
512
- organizationId: context.organizationId,
513
- workspaceId: context.workspaceId ?? null,
514
- assistantId: context.hostType === 'agent' ? context.hostId : null,
515
- userId: context.userId
516
- };
517
- }
518
- function success(data) {
519
- return {
520
- success: true,
521
- message: text('Saved', '已保存'),
522
- data,
523
- refresh: true
524
- };
525
- }
526
- function parsingStarted(data) {
527
- return {
528
- success: true,
529
- message: text('Parsing request sent to assistant', '已发送给智能体解析'),
530
- data,
531
- refresh: false
532
- };
533
- }
534
- function failure(en_US, zh_Hans) {
535
- return {
536
- success: false,
537
- message: text(en_US, zh_Hans),
538
- refresh: false
539
- };
540
- }
541
- function readString(input, key) {
542
- return typeof input === 'object' && input != null && typeof Reflect.get(input, key) === 'string'
543
- ? String(Reflect.get(input, key))
544
- : undefined;
545
- }
546
- function readRecord(input, key) {
547
- const value = typeof input === 'object' && input != null ? Reflect.get(input, key) : undefined;
548
- return typeof value === 'object' && value != null && !Array.isArray(value) ? value : undefined;
549
- }
550
- function readStringArray(input, key) {
551
- const value = typeof input === 'object' && input != null ? Reflect.get(input, key) : undefined;
552
- return Array.isArray(value) ? value.filter((item) => typeof item === 'string') : [];
553
- }
554
- function readBoolean(input, key) {
555
- const value = typeof input === 'object' && input != null ? Reflect.get(input, key) : undefined;
556
- return typeof value === 'boolean' ? value : undefined;
557
- }
558
- function readNumber(input, key) {
559
- const value = typeof input === 'object' && input != null ? Reflect.get(input, key) : undefined;
560
- if (typeof value === 'number' && Number.isFinite(value))
561
- return value;
562
- if (typeof value === 'string' && value.trim()) {
563
- const parsed = Number(value.replace(/,/g, ''));
564
- return Number.isFinite(parsed) ? parsed : undefined;
565
- }
566
- return undefined;
567
- }
568
- function readRecordArray(input, key) {
569
- const value = typeof input === 'object' && input != null ? Reflect.get(input, key) : undefined;
570
- return Array.isArray(value)
571
- ? value.filter((item) => typeof item === 'object' && item != null && !Array.isArray(item))
572
- : undefined;
573
- }
574
- function readControlledGoodsStatus(input, key) {
575
- const value = readString(input, key);
576
- return value === 'unchecked' || value === 'not_controlled' || value === 'suspected' || value === 'controlled'
577
- ? value
578
- : undefined;
579
- }
580
- function roleForUploadAction(actionKey) {
581
- if (actionKey === 'upload_controlled_goods_file')
582
- return 'controlled_goods_file';
583
- if (actionKey === 'upload_supplier_contract')
584
- return 'supplier_contract';
585
- if (actionKey === 'upload_sales_contract')
586
- return 'sales_contract';
587
- return null;
588
- }
589
- function normalizeWorkbookSource(input) {
590
- const itemsValue = Array.isArray(input.items) ? input.items : [];
591
- return {
592
- invoiceNo: stringValue(input.invoiceNo),
593
- contractNo: stringValue(input.contractNo),
594
- date: stringValue(input.date),
595
- buyerName: stringValue(input.buyerName),
596
- buyerAddress: stringValue(input.buyerAddress),
597
- sellerName: stringValue(input.sellerName),
598
- sellerEnglishName: stringValue(input.sellerEnglishName) ?? stringValue(input.sellerName),
599
- sellerEnglishAddress: stringValue(input.sellerEnglishAddress),
600
- paymentTerm: stringValue(input.paymentTerm),
601
- tradeTerm: stringValue(input.tradeTerm),
602
- origin: stringValue(input.origin),
603
- destination: stringValue(input.destination),
604
- currency: stringValue(input.currency) ?? '人民币',
605
- exchangeRate: numberValue(input.exchangeRate),
606
- packageType: stringValue(input.packageType),
607
- supervisionMode: stringValue(input.supervisionMode),
608
- taxExemptionNature: stringValue(input.taxExemptionNature ?? input.taxNature),
609
- domesticSourceLocation: stringValue(input.domesticSourceLocation),
610
- bankBeneficiary: stringValue(input.bankBeneficiary),
611
- bankName: stringValue(input.bankName),
612
- bankAddress: stringValue(input.bankAddress),
613
- bankAccountNo: stringValue(input.bankAccountNo),
614
- cnapsCode: stringValue(input.cnapsCode),
615
- swiftCode: stringValue(input.swiftCode),
616
- items: itemsValue
617
- .filter((item) => typeof item === 'object' && item != null && !Array.isArray(item))
618
- .map((item) => ({
619
- productName: stringValue(item.productName),
620
- englishName: stringValue(item.englishName),
621
- model: stringValue(item.model),
622
- description: stringValue(item.description),
623
- quantity: numberValue(item.quantity),
624
- unit: stringValue(item.unit),
625
- unitPrice: numberValue(item.unitPrice ?? item.taxInclusiveUnitPrice),
626
- amount: numberValue(item.amount ?? item.taxInclusiveTotalAmount),
627
- hsCode: stringValue(item.hsCode ?? item.contractHsCode ?? item.enrichedHsCode),
628
- cartonNo: stringValue(item.cartonNo),
629
- dimension: stringValue(item.dimension),
630
- netWeight: numberValue(item.netWeight),
631
- grossWeight: numberValue(item.grossWeight)
632
- }))
633
- };
634
- }
635
- function stringValue(value) {
636
- return value === undefined || value === null || value === '' ? undefined : String(value);
637
- }
638
- function numberValue(value) {
639
- if (typeof value === 'number' && Number.isFinite(value))
640
- return value;
641
- if (typeof value === 'string' && value.trim()) {
642
- const parsed = Number(value.replace(/,/g, ''));
643
- return Number.isFinite(parsed) ? parsed : undefined;
644
- }
645
- return undefined;
646
- }
647
- function mergeReviewData(...records) {
648
- return Object.assign({}, ...records.filter(Boolean));
649
- }
650
- function getFileDisplayName(file, input) {
651
- return readString(input, 'name') ?? readString(input, 'fileName') ?? getFileName(file) ?? 'uploaded-document';
652
- }
653
- function getFileName(file) {
654
- const record = file;
655
- return typeof record.name === 'string'
656
- ? record.name
657
- : typeof record.originalname === 'string'
658
- ? record.originalname
659
- : typeof record.originalName === 'string'
660
- ? record.originalName
661
- : undefined;
662
- }
663
- function getFileMimeType(file) {
664
- const record = file;
665
- return typeof record.mimetype === 'string'
666
- ? record.mimetype
667
- : typeof record.type === 'string'
668
- ? record.type
669
- : undefined;
670
- }
671
- function getFileSize(file) {
672
- const record = file;
673
- return typeof record.size === 'number' ? record.size : undefined;
674
- }
675
- function getFileBuffer(file) {
676
- const record = file;
677
- const buffer = record.buffer;
678
- if (Buffer.isBuffer(buffer))
679
- return buffer;
680
- if (buffer instanceof ArrayBuffer)
681
- return Buffer.from(buffer);
682
- if (ArrayBuffer.isView(buffer))
683
- return Buffer.from(buffer.buffer, buffer.byteOffset, buffer.byteLength);
684
- return undefined;
685
- }
686
- async function readWorkspaceFileBuffer(file) {
687
- const workspacePath = file?.workspacePath ?? file?.filePath;
688
- if (!workspacePath)
689
- return undefined;
690
- try {
691
- return await readFile(workspacePath);
692
- }
693
- catch {
694
- return undefined;
695
- }
696
- }
697
- function buildAssistantCommand(input) {
698
- const files = [input.file];
699
- const workspacePath = input.file.workspacePath ?? input.file.filePath;
700
- const references = files
701
- .map((file) => toChatReference(file, input.fileName, input.role))
702
- .filter((item) => Boolean(item));
703
- return {
704
- commandKey: 'assistant.chat.send_message',
705
- expectedChunkCount: input.extractedText?.chunkCount ?? 0,
706
- payload: {
707
- text: input.text,
708
- clientMessageId: input.messageId ?? `trade-compliance:${input.action}:${input.batchId ?? Date.now()}`,
709
- files,
710
- attachments: files.map(toChatAttachment).filter((item) => Boolean(item)),
711
- references,
712
- followUpMode: 'queue',
713
- state: {
714
- tradeComplianceWorkbench: {
715
- action: input.action,
716
- batchId: input.batchId,
717
- sourceFileName: input.fileName,
718
- workspacePath
719
- }
720
- }
721
- },
722
- batchId: input.batchId,
723
- role: input.role
724
- };
725
- }
726
- function hasAssistantReadableFileHandle(file) {
727
- return Boolean(file.fileAssetId || file.fileId || file.workspacePath || file.filePath);
728
- }
729
- function viewFileToAssistantFile(file, fileName, role, input) {
730
- const record = file;
731
- const inputRecord = typeof input === 'object' && input != null ? input : {};
732
- const workspaceFile = readRecord(inputRecord, 'workspaceFile') ?? {};
733
- const workspacePath = readOptionalFileString(workspaceFile, 'workspacePath') ??
734
- readOptionalFileString(workspaceFile, 'filePath') ??
735
- readOptionalFileString(inputRecord, 'workspacePath') ??
736
- readOptionalFileString(inputRecord, 'filePath');
737
- const fileAssetId = readOptionalFileString(inputRecord, 'fileAssetId') ??
738
- readOptionalFileString(inputRecord, 'fileId') ??
739
- readOptionalFileString(record, 'fileAssetId') ??
740
- readOptionalFileString(record, 'fileId');
741
- const fileId = fileAssetId;
742
- const storageFileId = readOptionalFileString(inputRecord, 'storageFileId') ?? readOptionalFileString(record, 'storageFileId');
743
- return {
744
- id: fileAssetId ?? storageFileId,
745
- fileId,
746
- fileAssetId,
747
- storageFileId,
748
- workspacePath,
749
- filePath: workspacePath,
750
- fileUrl: readOptionalFileString(workspaceFile, 'fileUrl') ?? readOptionalFileString(workspaceFile, 'url'),
751
- url: readOptionalFileString(workspaceFile, 'fileUrl') ?? readOptionalFileString(workspaceFile, 'url'),
752
- name: readOptionalFileString(workspaceFile, 'name') ?? readOptionalFileString(inputRecord, 'name') ?? fileName,
753
- originalName: readOptionalFileString(workspaceFile, 'originalName') ?? readOptionalFileString(inputRecord, 'originalName') ?? fileName,
754
- mimeType: readOptionalFileString(workspaceFile, 'mimeType') ?? readOptionalFileString(inputRecord, 'mimeType') ?? getFileMimeType(file),
755
- mimetype: readOptionalFileString(workspaceFile, 'mimeType') ?? readOptionalFileString(inputRecord, 'mimeType') ?? getFileMimeType(file),
756
- size: readNumber(workspaceFile, 'size') ?? readNumber(inputRecord, 'size') ?? getFileSize(file),
757
- role
758
- };
759
- }
760
- function readOptionalFileString(record, key) {
761
- const value = record[key];
762
- return typeof value === 'string' && value.trim() ? value.trim() : undefined;
763
- }
764
- function toChatAttachment(file) {
765
- const id = file.fileAssetId ?? file.fileId ?? file.id ?? file.storageFileId ?? file.workspacePath;
766
- if (!id)
767
- return null;
768
- return {
769
- type: 'file',
770
- id,
771
- name: file.name,
772
- mime_type: file.mimeType ?? 'application/octet-stream',
773
- workspacePath: file.workspacePath,
774
- filePath: file.filePath
775
- };
776
- }
777
- function toChatReference(file, fileName, role) {
778
- const fileId = file.fileAssetId ?? file.fileId;
779
- const workspacePath = file.workspacePath ?? file.filePath;
780
- if (!fileId && !workspacePath)
781
- return null;
782
- return {
783
- type: 'quote',
784
- label: fileName,
785
- source: 'Trade Compliance Workbench uploaded document',
786
- text: [
787
- `role=${role}`,
788
- `name=${fileName}`,
789
- `fileId=${fileId}`,
790
- `workspacePath=${workspacePath ?? '-'}`,
791
- `mimeType=${file.mimeType ?? '-'}`,
792
- `size=${file.size ?? '-'}`
793
- ].join('\n')
794
- };
795
- }
796
- function buildControlledGoodsParsePrompt(fileName, batchId, extractedText) {
797
- const chunkCount = extractedText?.chunkCount ?? 0;
798
- const isChunked = chunkCount > 1;
799
- const textBlock = extractedText?.text
800
- ? isChunked
801
- ? [
802
- '',
803
- `转换文本已无损分成 ${chunkCount} 块。为避免 chatkit 消息截断,初始消息不直接携带大块原文。`,
804
- `请先调用 trade_compliance_get_controlled_goods_extracted_text_chunk 读取第 1 块,参数 batchId=${batchId ?? '-'}、chunkIndex=1。`
805
- ]
806
- : [
807
- '',
808
- '以下是插件从上传文件中转换出的文本,请基于下方文本提取,不要重新读取附件:',
809
- '```text',
810
- extractedText.text,
811
- '```'
812
- ]
813
- : [
814
- '',
815
- '插件未能从上传文件中转换出文本;如确需处理,请再尝试读取附件内容。'
816
- ];
817
- return [
818
- `请解析我刚上传的管控商品文件《${fileName}》。`,
819
- '插件已经先把上传文件转换成纯文本/Markdown 表格,代码只做格式转换,不做业务字段提取。',
820
- isChunked
821
- ? `本次必须由大模型基于转换文本分块识别完整文件,不要调用代码解析工具,不要重新读取附件,不要生成 JSON 文件。保存时必须使用同一个 batchId:${batchId ?? '-'}。`
822
- : `本次必须由大模型基于下方文本一次性识别完整文件,不要调用代码解析工具,不要生成 JSON 文件,不要分批保存。保存时必须使用同一个 batchId:${batchId ?? '-'}。`,
823
- isChunked
824
- ? '当前消息不包含原文全文。请按块处理:先调用 trade_compliance_get_controlled_goods_extracted_text_chunk 获取当前块文本,再抽取并调用 trade_compliance_save_controlled_goods_extraction 保存该块 rows,然后继续获取下一块,直到工具返回 hasMore=false。'
825
- : '请一次性抽取文件中的全部管控商品明细,然后一次性调用 trade_compliance_save_controlled_goods_extraction 保存。为避免工具参数过大,管控商品优先使用 rows 紧凑入参,不要为每条记录手写完整 items 结构。',
826
- '禁止摘要、禁止概览、禁止使用“等”“主要包括”“大类结构”代替明细;凡是表格或正文中的每一行商品、技术、软件、设备、材料、子项,都要拆成独立待审核记录。',
827
- 'rows 中每条记录尽量包含 productName、hsCode、keywords、enabled、sequence、controlCode、sectionPath、rawText、sourcePage、sourceLocation、confidence;sourceLocation 必须写明页码、工作表行号或表格/章节位置。',
828
- 'controlNote 只在源文件当前行明确写有许可证要求、禁止/限制说明、管制依据或合规备注时填写;不要把章节名、类别名、商品名、HS Code 或“管控商品/管控章节”这类泛化判断写入 controlNote,没有明确说明就留空。',
829
- '如果转换文本是表格,rows 数量应尽量等于有效数据行数量,不要只保存前几行;不要因为聊天展示只列出部分数据而只传部分 rows。',
830
- '如果源文件没有海关商品编号,hsCode 留空,不要编造;如果一行有多个 HS Code,用换行或数组语义保留全部编码;技术、软件类没有 HS Code 也要保存。',
831
- isChunked
832
- ? '每块保存完成后继续下一块,不要提前总结;最终回复只用简短中文说明:总块数、已处理块数、实际保存数量、是否存在未处理块。'
833
- : '保存前请确认没有把文件后半部分压缩成摘要。最终回复只用简短中文说明:实际识别数量、工具实际保存数量;不要在聊天里贴完整明细。',
834
- isChunked
835
- ? `转换文本长度:${extractedText?.originalLength ?? 0} 字符,已无损分成 ${chunkCount} 块。必须调用 trade_compliance_get_controlled_goods_extracted_text_chunk 按 chunkIndex=1,2,3... 顺序读取。`
836
- : `转换文本长度:${extractedText?.originalLength ?? 0} 字符。`,
837
- ...textBlock
838
- ].join('\n');
839
- }
840
- function buildSupplierContractParsePrompt(fileName, batchId) {
841
- return [
842
- `请解析我刚上传的供应商合同《${fileName}》。`,
843
- '文件已写入智能体工作空间,请优先根据 state.tradeComplianceWorkbench.workspacePath 使用 SandboxFile 等沙箱文件工具按路径读取;如果同时存在附件能力,也可以使用 file_preview、file_search、file_read 等文件理解工具读取。',
844
- '目标:识别供应商信息和商品信息,商品信息包括商品名称、型号、描述、数量、单位、含税单价、含税金额、合同里的海关编码。',
845
- '如果文件自带有效合同海关编码(8-10 位数字),默认使用文件里的海关编码,并用该编码查询退税率、英文品名等信息补充到待审核商品;如果文件没有有效海关编码,或只识别到“未识别”等占位值,再结合商品名称、型号和描述查询并选择最可信的海关编码。插件会保留全部候选海关编码,编辑页面保留重新查询和确认入口。',
846
- '再结合已有管控商品记录调用 trade_compliance_match_controlled_goods 判断是否为管控商品。',
847
- `最后必须调用 trade_compliance_save_supplier_contract_extraction 保存待审核结果,batchId 必须传 ${batchId ?? '-'};只有调用该保存工具后,工作台左侧供应商商品列表才会出现记录。`,
848
- '每个 items 条目的 type 必须是 supplier_product;extractedData/defaultData 中请包含 supplierName、supplierCreditCode、supplierAddress、productName、model、description、quantity、unit、taxInclusiveUnitPrice、taxInclusiveTotalAmount、contractHsCode、controlledStatus、controlNote。',
849
- '不要只回复文字,必须调用工具把识别结果写入插件;回复中的识别数量必须等于本次工具实际保存的 items 数量。'
850
- ].join('\n');
851
- }
852
- function buildSalesContractParsePrompt(fileName, batchId) {
853
- return [
854
- `请解析我刚上传的购销合同《${fileName}》。`,
855
- '文件已写入智能体工作空间,请优先根据 state.tradeComplianceWorkbench.workspacePath 使用 SandboxFile 等沙箱文件工具按路径读取;如果同时存在附件能力,也可以使用 file_preview、file_search、file_read 等文件理解工具读取。',
856
- '目标:识别销售发票和报关资料所需字段,包括发票号、合同号、买方、卖方、币种、贸易术语、付款方式、商品明细、数量、单价、金额、包装、毛重、净重等。',
857
- `请调用 trade_compliance_save_sales_contract_extraction 保存待审核结果,batchId 可记录为 ${batchId ?? '-'}。`,
858
- '一个购销合同只保存 1 个 items 条目,type 必须是 customs_workbook;不要把每个商品明细拆成独立审核项,商品明细必须放到该条 extractedData.items 数组中。',
859
- '该 customs_workbook 条目的 extractedData 中请包含 invoiceNo、contractNo、buyerName、sellerName、currency、items 等字段。',
860
- '不要只回复文字,必须调用工具把识别结果写入插件。'
861
- ].join('\n');
862
- }
863
- //# sourceMappingURL=trade-compliance-workbench-view.provider.js.map