dsh-data-cleaning-agent 0.8.4 → 0.8.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +18 -0
- package/README.en.md +1 -1
- package/README.md +1 -1
- package/lib/client.js +129 -26
- package/lib/image-intake.js +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
本文件记录 `dsh-data-cleaning-agent` 的版本变更。格式遵循 [Keep a Changelog](https://keepachangelog.com/zh-CN/1.1.0/),版本号遵循 [SemVer](https://semver.org/lang/zh-CN/)。
|
|
4
4
|
|
|
5
|
+
## [0.8.6] - 2026-09-06
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
- 上传/OCR 核验页使用完整原始清单,每页 20 行可翻页,显示序号与全列;不再把前 5 行摘要当成核验视图。
|
|
9
|
+
- 匹配结果共用全量分页和中文字段展示,不再截断为前 8 行/列。
|
|
10
|
+
- 核验阶段支持全量 CSV 和原值 JSON 下载,不触发 QCC 调用;CSV 对公式及长编号作文本保护。明细未完整载入时禁用核验下载。
|
|
11
|
+
- OCR 完成后的引导明确真实核验路径、规则/体检/匹配步骤及自动回填,无需人工复制 dcq- 凭证,不将识别清单误报为匹配结果。
|
|
12
|
+
|
|
13
|
+
## [0.8.5] - 2026-09-06
|
|
14
|
+
|
|
15
|
+
### Fixed
|
|
16
|
+
- 清洗入口恢复使用 workspaceId 创建独立会话,修复仅 cwd 导致 DSH 首页缺少工作区、图片任务回填后发送按钮和模型控件持续禁用的问题。
|
|
17
|
+
- 增加可卸载的新会话兼容 Bridge:仅在清洗业务激活期间通过原生 create/open 创建普通会话,避免复用空白清洗会话;普通会话仍使用原生动作。
|
|
18
|
+
- 创建失败保留原会话和草稿,连续点击合并;等待期间切换其它智能体不被迟到的创建结果抢回页面。
|
|
19
|
+
|
|
20
|
+
### Tests
|
|
21
|
+
- 增加 DSH 原生 Hero 工作区禁用表达式回归、工作区关联和新会话生命周期测试;这些为代码/契约测试,不等于真实 QCC OCR 已通过。
|
|
22
|
+
|
|
5
23
|
## [0.8.4] - 2026-09-06
|
|
6
24
|
|
|
7
25
|
### Fixed
|
package/README.en.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> A data cleaning & completion agent plugin for DeepSeek Harness: local CSV/XLSX/JSON engine plus optional Qichacha (QCC) MCP enterprise-data enrichment. Initiated and maintained by the Qichacha (QCC) team.
|
|
4
4
|
>
|
|
5
|
-
> Current source version / 当前源码版本: **0.8.
|
|
5
|
+
> Current source version / 当前源码版本: **0.8.6** (stable release)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/dsh-data-cleaning-agent)
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> 在 DeepSeek Harness 中清洗、补全、画像企业名单数据的智能体插件:本地 CSV/XLSX/JSON 引擎 + 可选企查查(Qichacha/QCC)MCP 企业数据补全,由企查查(Qichacha/QCC)团队发起并维护。
|
|
4
4
|
>
|
|
5
|
-
> 当前源码版本 / Current source version: **0.8.
|
|
5
|
+
> 当前源码版本 / Current source version: **0.8.6**(正式版本)
|
|
6
6
|
|
|
7
7
|
[](https://github.com/duhu2000/dsh-data-cleaning-agent/actions/workflows/ci.yml)
|
|
8
8
|
[](https://www.npmjs.com/package/dsh-data-cleaning-agent)
|
package/lib/client.js
CHANGED
|
@@ -887,6 +887,7 @@ window.__ModuleLoader__.load({
|
|
|
887
887
|
if (!from || !toId || String(fromId) === String(toId)) return runtimeFor(toId);
|
|
888
888
|
const target = runtimeFor(toId);
|
|
889
889
|
target.rows = from.rows;
|
|
890
|
+
target.sourceRows = from.sourceRows;
|
|
890
891
|
target.headers = from.headers;
|
|
891
892
|
target.source = from.source;
|
|
892
893
|
target.lastCsv = from.lastCsv;
|
|
@@ -1109,6 +1110,7 @@ window.__ModuleLoader__.load({
|
|
|
1109
1110
|
* 面板和用户草稿。新版本入口始终创建独立会话,不再依赖 DOM 文案推测导航。
|
|
1110
1111
|
*/
|
|
1111
1112
|
function installSessionOwnershipBridge(ctx) {
|
|
1113
|
+
const releaseNewSessionBridge = installNewSessionBridge(ctx);
|
|
1112
1114
|
let staleDraftObserver = null;
|
|
1113
1115
|
let staleDraftObserverTimer = null;
|
|
1114
1116
|
const clearStaleDefaultDraft = () => {
|
|
@@ -1156,6 +1158,7 @@ window.__ModuleLoader__.load({
|
|
|
1156
1158
|
}
|
|
1157
1159
|
});
|
|
1158
1160
|
return () => {
|
|
1161
|
+
releaseNewSessionBridge();
|
|
1159
1162
|
staleDraftObserver?.disconnect();
|
|
1160
1163
|
if (staleDraftObserverTimer !== null) clearTimeout(staleDraftObserverTimer);
|
|
1161
1164
|
if (typeof unsubscribe === 'function') unsubscribe();
|
|
@@ -1549,6 +1552,45 @@ window.__ModuleLoader__.load({
|
|
|
1549
1552
|
return mount;
|
|
1550
1553
|
}
|
|
1551
1554
|
|
|
1555
|
+
// rc/alpha 兼容边界:原生 startSession 会复用工作区内的空白会话。
|
|
1556
|
+
// 只在清洗会话激活时替换此动作,创建普通会话;不改 connectWorkspace 或全局点击。
|
|
1557
|
+
function installNewSessionBridge(ctx) {
|
|
1558
|
+
const workspaces = ctx.workspaces;
|
|
1559
|
+
const original = workspaces?.startSession;
|
|
1560
|
+
if (typeof original !== 'function' || typeof ctx.sessions?.create !== 'function') return () => {};
|
|
1561
|
+
const ownDescriptor = Object.getOwnPropertyDescriptor(workspaces, 'startSession');
|
|
1562
|
+
let pending = null;
|
|
1563
|
+
let disposed = false;
|
|
1564
|
+
const wrapped = function (workspaceId) {
|
|
1565
|
+
if (disposed) return original.call(this, workspaceId);
|
|
1566
|
+
const current = ctx.sessions.list.getSnapshot().current;
|
|
1567
|
+
if (!isCleaningSession(current)) return original.call(this, workspaceId);
|
|
1568
|
+
if (pending) return;
|
|
1569
|
+
const snapshot = workspaces.list.getSnapshot();
|
|
1570
|
+
const target = workspaceId
|
|
1571
|
+
?? snapshot.items.find((item) => item.sessionIds?.includes(current))?.workspaceId
|
|
1572
|
+
?? snapshot.recentWorkspaceId;
|
|
1573
|
+
if (!target) return original.call(this, workspaceId);
|
|
1574
|
+
pending = Promise.resolve().then(() => ctx.sessions.create({ workspaceId: target }))
|
|
1575
|
+
.then((sessionId) => {
|
|
1576
|
+
// 用户在等待期间转往其它智能体时不抢回页面;成功导航才撤销业务归属。
|
|
1577
|
+
if (!disposed && isCleaningSession(current) && ctx.sessions.list.getSnapshot().current === current) {
|
|
1578
|
+
ctx.sessions.open(sessionId);
|
|
1579
|
+
}
|
|
1580
|
+
}).catch((error) => {
|
|
1581
|
+
console.warn('[dc-agent] new session failed; current draft retained:', error instanceof Error ? error.message : String(error));
|
|
1582
|
+
}).finally(() => { pending = null; });
|
|
1583
|
+
};
|
|
1584
|
+
try { workspaces.startSession = wrapped; }
|
|
1585
|
+
catch (_error) { console.warn('[dc-agent] New Session compatibility bridge unavailable'); return () => {}; }
|
|
1586
|
+
return () => {
|
|
1587
|
+
disposed = true;
|
|
1588
|
+
if (workspaces.startSession !== wrapped) return;
|
|
1589
|
+
if (ownDescriptor) Object.defineProperty(workspaces, 'startSession', ownDescriptor);
|
|
1590
|
+
else delete workspaces.startSession;
|
|
1591
|
+
};
|
|
1592
|
+
}
|
|
1593
|
+
|
|
1552
1594
|
const CLEANING_SESSION_ID_PREFIX = 'session-dsh-data-cleaning-agent-';
|
|
1553
1595
|
const SESSION_UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/iu;
|
|
1554
1596
|
function createCleaningSessionId() {
|
|
@@ -1567,20 +1609,20 @@ window.__ModuleLoader__.load({
|
|
|
1567
1609
|
? undefined
|
|
1568
1610
|
: items.find((item) => Array.isArray(item.sessionIds) && item.sessionIds.includes(current));
|
|
1569
1611
|
const recentWorkspace = items.find((item) => item.workspaceId === workspace.recentWorkspaceId);
|
|
1570
|
-
const
|
|
1571
|
-
if (
|
|
1612
|
+
const targetWorkspace = currentWorkspace ?? recentWorkspace ?? items[0];
|
|
1613
|
+
if (!targetWorkspace?.workspaceId) {
|
|
1572
1614
|
throw new Error('请先选择一个工作空间,再打开数据清洗补全智能体');
|
|
1573
1615
|
}
|
|
1574
1616
|
// 单一会话所有权:与招投标入口一致,显式创建带前缀的独立原生会话,绝不复用空白会话。
|
|
1575
1617
|
// connectWorkspace 会把「招投标」尚为空白的工作台会话复用为清洗会话,
|
|
1576
1618
|
// 使同一会话同时被招投标与清洗两个插件认领,进而争夺 Hero 标题与右侧工作台面板。
|
|
1577
|
-
//
|
|
1578
|
-
//
|
|
1619
|
+
// 原生 Hero 通过 workspace.sessionIds 判断输入是否可用。仅 cwd 会导致
|
|
1620
|
+
// chipTitle 缺失、inert=true;必须关联工作区,空白复用由 New Session Bridge 隔离。
|
|
1579
1621
|
if (typeof ctx.sessions.create !== 'function') {
|
|
1580
1622
|
throw new Error('当前 DSH 版本没有可用的独立会话创建能力');
|
|
1581
1623
|
}
|
|
1582
1624
|
const requestedId = createCleaningSessionId();
|
|
1583
|
-
const sessionId = await ctx.sessions.create({
|
|
1625
|
+
const sessionId = await ctx.sessions.create({ workspaceId: targetWorkspace.workspaceId, sessionId: requestedId });
|
|
1584
1626
|
if (sessionId !== requestedId) {
|
|
1585
1627
|
throw new Error('当前 DSH 版本不支持独立会话创建,请升级 DSH 后再打开数据清洗补全智能体');
|
|
1586
1628
|
}
|
|
@@ -2640,6 +2682,7 @@ window.__ModuleLoader__.load({
|
|
|
2640
2682
|
function applyParsed(result, actions, taskId = 'unassigned', source = {}) {
|
|
2641
2683
|
const runtime = runtimeFor(taskId);
|
|
2642
2684
|
runtime.rows = Array.isArray(result.rows) ? result.rows : [];
|
|
2685
|
+
runtime.sourceRows = runtime.rows;
|
|
2643
2686
|
runtime.headers = Array.isArray(result.headers) ? result.headers : [];
|
|
2644
2687
|
runtime.source = {
|
|
2645
2688
|
type: source.type || result.fmt || 'csv',
|
|
@@ -2671,6 +2714,7 @@ window.__ModuleLoader__.load({
|
|
|
2671
2714
|
// 都以本次解析结果覆盖目标 runtime,避免复用已完成任务的一行旧数据。
|
|
2672
2715
|
const target = runtimeFor(current.id);
|
|
2673
2716
|
target.rows = Array.isArray(result.rows) ? result.rows : [];
|
|
2717
|
+
target.sourceRows = target.rows;
|
|
2674
2718
|
target.headers = Array.isArray(result.headers) ? result.headers : [];
|
|
2675
2719
|
target.source = {
|
|
2676
2720
|
type: source.type || result.fmt || 'csv',
|
|
@@ -2692,6 +2736,67 @@ window.__ModuleLoader__.load({
|
|
|
2692
2736
|
return current;
|
|
2693
2737
|
}
|
|
2694
2738
|
|
|
2739
|
+
function reviewColumns(rows, headers = []) {
|
|
2740
|
+
return [...new Set([...headers, ...rows.flatMap((row) => Object.keys(row || {}))])];
|
|
2741
|
+
}
|
|
2742
|
+
|
|
2743
|
+
function reviewCsv(rows, headers) {
|
|
2744
|
+
const cell = (value) => {
|
|
2745
|
+
let text = value == null ? '' : typeof value === 'object' ? JSON.stringify(value) : String(value);
|
|
2746
|
+
// 保留长编号的文本形式,阻止外部 OCR/企业字段成为 Excel 公式。
|
|
2747
|
+
if (/^[\s]*[=+@-]/.test(text) || /^\d{15,}$/.test(text) || /^0\d+/.test(text)) text = "'" + text;
|
|
2748
|
+
return '"' + text.replace(/"/g, '""') + '"';
|
|
2749
|
+
};
|
|
2750
|
+
return '\uFEFF' + [headers.map((key) => cell(resultFieldLabel(key))).join(','),
|
|
2751
|
+
...rows.map((row) => headers.map((key) => cell(row?.[key])).join(','))].join('\r\n');
|
|
2752
|
+
}
|
|
2753
|
+
|
|
2754
|
+
/** 页内查看和核验下载均使用完整 rows,不使用 store 的五行摘要。 */
|
|
2755
|
+
function DatasetReview({ rows, headers, title, expectedCount, onError }) {
|
|
2756
|
+
const [page, setPage] = react.useState(0);
|
|
2757
|
+
const pageSize = 20;
|
|
2758
|
+
const total = rows.length;
|
|
2759
|
+
const columns = reviewColumns(rows, headers);
|
|
2760
|
+
const currentPage = Math.min(page, Math.max(0, Math.ceil(total / pageSize) - 1));
|
|
2761
|
+
const start = currentPage * pageSize;
|
|
2762
|
+
const download = (format) => {
|
|
2763
|
+
try {
|
|
2764
|
+
const content = format === 'csv' ? reviewCsv(rows, columns) : JSON.stringify(rows, null, 2);
|
|
2765
|
+
const url = URL.createObjectURL(new Blob([content], { type: format === 'csv' ? 'text/csv;charset=utf-8' : 'application/json;charset=utf-8' }));
|
|
2766
|
+
const anchor = document.createElement('a');
|
|
2767
|
+
anchor.href = url;
|
|
2768
|
+
anchor.download = title + '.' + format;
|
|
2769
|
+
try { anchor.click(); } finally { setTimeout(() => URL.revokeObjectURL(url), 1000); }
|
|
2770
|
+
} catch (error) { onError?.(error instanceof Error ? error.message : String(error)); }
|
|
2771
|
+
};
|
|
2772
|
+
const complete = expectedCount == null || expectedCount === total;
|
|
2773
|
+
return h('section', { className: 'dcAgentSection', 'aria-label': title },
|
|
2774
|
+
h('h3', null, title),
|
|
2775
|
+
h('p', { className: 'dcAgentHint', role: 'status' }, complete
|
|
2776
|
+
? `共 ${total} 条,当前显示 ${total ? start + 1 : 0}–${Math.min(start + pageSize, total)} 条;共 ${columns.length} 列,可横向滚动。`
|
|
2777
|
+
: `完整清单尚未就绪:预期 ${expectedCount} 条,当前载入 ${total} 条。请等待同步;刷新后若仍缺失,请重新上传源文件。`),
|
|
2778
|
+
h('div', { className: 'dcAgentPreviewTable', style: { overflow: 'auto', maxHeight: '420px' } },
|
|
2779
|
+
h('table', { className: 'dcAgentTable' },
|
|
2780
|
+
h('thead', null, h('tr', null, h('th', null, '序号'), columns.map((key) => h('th', { key }, resultFieldLabel(key))))),
|
|
2781
|
+
h('tbody', null, rows.slice(start, start + pageSize).map((row, index) => h('tr', { key: start + index },
|
|
2782
|
+
h('td', null, String(start + index + 1)),
|
|
2783
|
+
columns.map((key) => h('td', { key }, row?.[key] == null ? '' : typeof row[key] === 'object' ? JSON.stringify(row[key]) : String(row[key]))),
|
|
2784
|
+
))),
|
|
2785
|
+
),
|
|
2786
|
+
),
|
|
2787
|
+
h('div', { className: 'dcAgentRow' },
|
|
2788
|
+
h('button', { type: 'button', className: 'dcAgentButton', disabled: currentPage === 0, onClick: () => setPage(currentPage - 1) }, '上一页'),
|
|
2789
|
+
h('span', null, `第 ${currentPage + 1} / ${Math.max(1, Math.ceil(total / pageSize))} 页`),
|
|
2790
|
+
h('button', { type: 'button', className: 'dcAgentButton', disabled: start + pageSize >= total, onClick: () => setPage(currentPage + 1) }, '下一页'),
|
|
2791
|
+
),
|
|
2792
|
+
h('div', { className: 'dcAgentRow' },
|
|
2793
|
+
h('button', { type: 'button', className: 'dcAgentButton', disabled: !complete || !total, onClick: () => download('csv') }, `下载全部 ${total} 条 CSV`),
|
|
2794
|
+
h('button', { type: 'button', className: 'dcAgentButton', disabled: !complete || !total, onClick: () => download('json') }, '下载原值 JSON'),
|
|
2795
|
+
),
|
|
2796
|
+
h('p', { className: 'dcAgentHint' }, '下载包含全部行,不受分页影响。CSV 对公式及长编号作文本保护;JSON 保留原值。仅导出当前清单,不触发企查查调用。'),
|
|
2797
|
+
);
|
|
2798
|
+
}
|
|
2799
|
+
|
|
2695
2800
|
/** 右侧非模态工作台:中央区域始终保留 DSH 原生会话。 */
|
|
2696
2801
|
function WorkbenchDrawer(props) {
|
|
2697
2802
|
const { useStore, actions } = props;
|
|
@@ -2847,10 +2952,9 @@ window.__ModuleLoader__.load({
|
|
|
2847
2952
|
const cachedTask = workflowTaskBySession.get(String(activeSessionId || 'unassigned')) ?? workflowTask;
|
|
2848
2953
|
const runtimeKey = cachedTask?.id ?? `session:${activeSessionId || 'unassigned'}`;
|
|
2849
2954
|
const runtime = runtimeFor(runtimeKey);
|
|
2955
|
+
const stagedSource = runtimeFor(`session:${activeSessionId || 'unassigned'}`, false);
|
|
2956
|
+
const sourceRows = stagedSource?.sourceRows ?? runtime.sourceRows ?? runtime.rows;
|
|
2850
2957
|
const lastCsv = runtime.lastCsv;
|
|
2851
|
-
const qccPreviewColumns = Array.isArray(qccRun?.rows) && qccRun.rows.length
|
|
2852
|
-
? Object.keys(qccRun.rows[0] || {}).slice(0, 8)
|
|
2853
|
-
: [];
|
|
2854
2958
|
const fieldByPattern = (pattern) => runtime.headers.find((field) => pattern.test(field)) ?? null;
|
|
2855
2959
|
const phoneField = fieldByPattern(/^(phone|mobile|tel|telephone|联系电话|手机号码|手机号)$/i);
|
|
2856
2960
|
const amountField = fieldByPattern(/^(amount|price|金额|注册资本)$/i);
|
|
@@ -3563,17 +3667,11 @@ window.__ModuleLoader__.load({
|
|
|
3563
3667
|
stat('未匹配', qccRun.summary?.unresolved ?? 0, (qccRun.summary?.unresolved ?? 0) > 0 ? 'warn' : null),
|
|
3564
3668
|
stat('失败', qccRun.summary?.failed ?? 0, (qccRun.summary?.failed ?? 0) > 0 ? 'bad' : null),
|
|
3565
3669
|
),
|
|
3566
|
-
Array.isArray(qccRun.rows) && qccRun.rows.length ? h(
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
h('tbody', null, qccRun.rows.slice(0, 8).map((row, index) => h('tr', { key: `${index}-${row?.qcc_credit_no || row?.credit_no || ''}` },
|
|
3572
|
-
qccPreviewColumns.map((key) => h('td', { key }, String(row?.[key] ?? ''))),
|
|
3573
|
-
))),
|
|
3574
|
-
),
|
|
3575
|
-
h('p', { className: 'dcAgentHint' }, `显示前 ${Math.min(8, qccRun.rows.length)} 行;完整结果在下载阶段生成耐久制品。`),
|
|
3576
|
-
) : null,
|
|
3670
|
+
Array.isArray(qccRun.rows) && qccRun.rows.length ? h(DatasetReview, {
|
|
3671
|
+
key: qccRun.runId, rows: qccRun.rows, headers: runtime.headers,
|
|
3672
|
+
title: '企查查匹配补全结果', expectedCount: qccRun.summary?.totalRows,
|
|
3673
|
+
onError: actions.setError,
|
|
3674
|
+
}) : null,
|
|
3577
3675
|
(qccRun.reviewQueue || []).map((item) => h('div', { key: item.companyName, className: 'dcAgentSection' },
|
|
3578
3676
|
h('h3', null, `待核验:${item.companyName}`),
|
|
3579
3677
|
item.candidates.map((candidate) => h('div', { key: candidate.creditNo, className: 'dcAgentCandidate' },
|
|
@@ -3675,15 +3773,16 @@ window.__ModuleLoader__.load({
|
|
|
3675
3773
|
(dataset.headers || []).slice(0, 12).map((name) => h('span', { key: name, className: 'dcAgentChip' }, name)),
|
|
3676
3774
|
(dataset.headers || []).length > 12 ? h('span', { className: 'dcAgentChip' }, `+${dataset.headers.length - 12} 列`) : null,
|
|
3677
3775
|
) : null,
|
|
3678
|
-
dataset ? h(
|
|
3679
|
-
|
|
3680
|
-
|
|
3681
|
-
|
|
3682
|
-
|
|
3683
|
-
) : null,
|
|
3776
|
+
dataset ? h(DatasetReview, {
|
|
3777
|
+
key: runtimeKey, rows: sourceRows, headers: dataset.headers || [],
|
|
3778
|
+
expectedCount: dataset.rowCount,
|
|
3779
|
+
title: runtime.source?.type === 'image' ? '图片识别原始名单(尚未匹配)' : '导入原始清单',
|
|
3780
|
+
onError: actions.setError,
|
|
3781
|
+
}) : null,
|
|
3782
|
+
hasData ? h('p', { className: 'dcAgentHint' }, '请核对完整名单。识别清单不代表已完成企查查匹配。核对后进入「字段映射与规则」,确认规则生成质量体检;再进入「数据匹配」估算调用量并确认账号额度,点击「生成可编辑任务说明」自动回填中央对话框,无需手工复制任务凭证。') : null,
|
|
3684
3783
|
h('div', { className: 'dcAgentRow' },
|
|
3685
3784
|
h('button', { type: 'button', className: 'dcAgentButton is-primary', disabled: busy, 'aria-label': '解析数据', onClick: handleParse }, busy ? '解析中…' : '解析数据'),
|
|
3686
|
-
hasData ? h('button', { type: 'button', className: 'dcAgentButton', onClick: () => actions.setStep('rules') }, '
|
|
3785
|
+
hasData ? h('button', { type: 'button', className: 'dcAgentButton', disabled: busy || sourceRows.length !== dataset.rowCount, onClick: () => actions.setStep('rules') }, '已核对清单,下一步:字段映射与规则') : null,
|
|
3687
3786
|
),
|
|
3688
3787
|
);
|
|
3689
3788
|
}
|
|
@@ -3856,6 +3955,9 @@ window.__ModuleLoader__.load({
|
|
|
3856
3955
|
// 测试用纯函数,不构成 Host / DSH 稳定 API。
|
|
3857
3956
|
exports.__testing = {
|
|
3858
3957
|
buildTaskPrompt,
|
|
3958
|
+
DatasetReview,
|
|
3959
|
+
reviewColumns,
|
|
3960
|
+
reviewCsv,
|
|
3859
3961
|
clearCleaningDraft,
|
|
3860
3962
|
entriesToDataset,
|
|
3861
3963
|
extractPromptEntries,
|
|
@@ -3865,6 +3967,7 @@ window.__ModuleLoader__.load({
|
|
|
3865
3967
|
guessMappings,
|
|
3866
3968
|
deactivateCleaningSession,
|
|
3867
3969
|
installSessionOwnershipBridge,
|
|
3970
|
+
installNewSessionBridge,
|
|
3868
3971
|
isCleaningSession,
|
|
3869
3972
|
isKnownCleaningDraft,
|
|
3870
3973
|
markCleaningSession,
|
package/lib/image-intake.js
CHANGED
|
@@ -580,7 +580,7 @@ export function registerImageIntakeTool(tools, store) {
|
|
|
580
580
|
},
|
|
581
581
|
render: (_args, value) => [{
|
|
582
582
|
type: 'text',
|
|
583
|
-
text: `企查查智能文档解析已识别图片企业名单:${value.entryCount}
|
|
583
|
+
text: `企查查智能文档解析已识别图片企业名单:${value.entryCount} 条,已同步回数据清洗补全工作台等待核验。请在「上传数据」查看原始清单全部行或下载全量 CSV/JSON,核对后进入「字段映射与规则」确认规则并生成质量体检,再到「数据匹配」估算调用量并确认账号额度,点击「生成可编辑任务说明」自动回填中央对话框。无需手工复制 dcq- 凭证或重新粘贴名单;识别名单不代表已匹配,尚未查询时不要编造匹配摘要。`,
|
|
584
584
|
}],
|
|
585
585
|
},
|
|
586
586
|
async execute(args, exec) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-data-cleaning-agent",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.6",
|
|
4
4
|
"description": "Clean, complete, and profile enterprise name lists in DeepSeek Harness — a data cleaning & completion agent plugin with local CSV/XLSX/JSON engine and optional Qichacha (QCC) MCP enrichment. Maintained by Qichacha/QCC.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "lib/index.js",
|