dsh-data-cleaning-agent 0.7.0 → 0.8.1
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 +34 -0
- package/README.en.md +20 -2
- package/README.md +18 -3
- package/docs/COMPATIBILITY.md +22 -0
- package/docs/RELEASE-0.8.0.md +60 -0
- package/docs/RELEASE-0.8.1.md +75 -0
- package/docs/UI-WORKFLOW-V2.md +2 -2
- package/docs/USER-GUIDE.md +29 -3
- package/lib/client.js +367 -37
- package/lib/image-intake.js +581 -0
- package/lib/index.js +1 -0
- package/lib/web.js +77 -0
- package/package.json +4 -2
package/lib/web.js
CHANGED
|
@@ -16,6 +16,13 @@ import { PHASE3_BATCH_LIMITS, Phase3BatchService, Phase3RunStore } from './qcc-p
|
|
|
16
16
|
import { publicWorkflowContract } from './workflow-contract.js';
|
|
17
17
|
import { DataCleaningWorkflowStore, WorkflowError } from './workflow.js';
|
|
18
18
|
import { ArtifactError, WorkflowArtifactStore } from './artifacts.js';
|
|
19
|
+
import {
|
|
20
|
+
ImageIntakeError,
|
|
21
|
+
ImageIntakeStore,
|
|
22
|
+
registerImageIntakeTool,
|
|
23
|
+
serializeImageExtractionPrompt,
|
|
24
|
+
TOOL_IMAGE_EXTRACT,
|
|
25
|
+
} from './image-intake.js';
|
|
19
26
|
|
|
20
27
|
const MAX_BODY = 16 * 1024 * 1024; // 16 MiB 上传上限(MVP)
|
|
21
28
|
|
|
@@ -119,6 +126,17 @@ function writeWorkflowError(res, error) {
|
|
|
119
126
|
});
|
|
120
127
|
}
|
|
121
128
|
|
|
129
|
+
function writeImageError(res, error) {
|
|
130
|
+
if (error instanceof ImageIntakeError) {
|
|
131
|
+
return writeJson(res, error.status, { ok: false, code: error.code, message: error.message });
|
|
132
|
+
}
|
|
133
|
+
return writeJson(res, 500, {
|
|
134
|
+
ok: false,
|
|
135
|
+
code: 'DC_IMAGE_INTERNAL',
|
|
136
|
+
message: '图片名单接入请求失败。',
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
|
|
122
140
|
/** 从 JSON 协议解析上传:{ filename, content }。content 为字符串;xlsx 时为 base64。 */
|
|
123
141
|
async function parseUpload(body) {
|
|
124
142
|
let payload;
|
|
@@ -285,13 +303,17 @@ export function mountWebRoutes(wctx, { logger, report, TOOL_NAME, SKILL_NAME })
|
|
|
285
303
|
const skills = wctx.skills;
|
|
286
304
|
const disposers = [];
|
|
287
305
|
const qccBridge = new QccHostBridge({ tools, logger });
|
|
306
|
+
const imageIntake = new ImageIntakeStore({ tools });
|
|
288
307
|
const g5Runs = new G5RunStore();
|
|
289
308
|
const qccCommands = new QccCommandStore({ bridge: qccBridge, runs: g5Runs });
|
|
290
309
|
if (typeof tools?.register === 'function') {
|
|
291
310
|
disposers.push(registerQccCommandTool(tools, qccCommands));
|
|
311
|
+
disposers.push(registerImageIntakeTool(tools, imageIntake));
|
|
292
312
|
report.qccCommandToolRegistered = true;
|
|
313
|
+
report.imageIntakeToolRegistered = true;
|
|
293
314
|
} else {
|
|
294
315
|
report.qccCommandToolRegistered = false;
|
|
316
|
+
report.imageIntakeToolRegistered = false;
|
|
295
317
|
}
|
|
296
318
|
const phase3Service = new Phase3BatchService(qccBridge);
|
|
297
319
|
const phase3Runs = new Phase3RunStore();
|
|
@@ -347,11 +369,65 @@ export function mountWebRoutes(wctx, { logger, report, TOOL_NAME, SKILL_NAME })
|
|
|
347
369
|
workflowV2: Boolean(wctx.storageDomain),
|
|
348
370
|
durableArtifacts: Boolean(artifactStore),
|
|
349
371
|
artifactBinaryStrategy: artifactStore ? 'xlsx-base64-over-writeText' : 'unavailable',
|
|
372
|
+
imageIntake: imageIntake.capabilities(),
|
|
350
373
|
qccBridge: qccBridge.capabilities(),
|
|
351
374
|
},
|
|
352
375
|
});
|
|
353
376
|
});
|
|
354
377
|
|
|
378
|
+
register('/data-cleaning/api/images/capabilities', (req, res) => {
|
|
379
|
+
if (!isTrusted(req)) return writeJson(res, 403, { ok: false, error: 'untrusted origin' });
|
|
380
|
+
if (req.method !== 'GET') return writeJson(res, 405, { ok: false, code: 'DC_METHOD', message: 'GET required' });
|
|
381
|
+
writeJson(res, 200, {
|
|
382
|
+
ok: true,
|
|
383
|
+
marker: 'data-cleaning-image-intake-v1',
|
|
384
|
+
tool: TOOL_IMAGE_EXTRACT,
|
|
385
|
+
toolRegistered: report.imageIntakeToolRegistered === true,
|
|
386
|
+
capabilities: imageIntake.capabilities(),
|
|
387
|
+
qccCalls: true,
|
|
388
|
+
billing: 'current-user-qcc-document-account',
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
register('/data-cleaning/api/images/commands', async (req, res) => {
|
|
393
|
+
if (!isTrusted(req)) return writeJson(res, 403, { ok: false, error: 'untrusted origin' });
|
|
394
|
+
try {
|
|
395
|
+
const pathname = new URL(req.url ?? '/data-cleaning/api/images/commands', 'http://127.0.0.1').pathname;
|
|
396
|
+
const segments = pathname.split('/').filter(Boolean);
|
|
397
|
+
const commandsIndex = segments.indexOf('commands');
|
|
398
|
+
const rest = commandsIndex >= 0 ? segments.slice(commandsIndex + 1) : [];
|
|
399
|
+
if (rest.length === 0 && req.method === 'POST') {
|
|
400
|
+
if (report.imageIntakeToolRegistered !== true) {
|
|
401
|
+
throw new ImageIntakeError('DC_IMAGE_TOOL_UNAVAILABLE', '当前 DSH Host 无法注册图片名单高层工具。', 503);
|
|
402
|
+
}
|
|
403
|
+
const payload = JSON.parse((await readBody(req)).toString('utf8'));
|
|
404
|
+
const command = await imageIntake.prepare(payload);
|
|
405
|
+
return writeJson(res, 201, {
|
|
406
|
+
ok: true,
|
|
407
|
+
marker: 'data-cleaning-image-intake-v1',
|
|
408
|
+
command: { ...command, prompt: serializeImageExtractionPrompt(command) },
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
if (rest.length === 1 && req.method === 'GET') {
|
|
412
|
+
return writeJson(res, 200, {
|
|
413
|
+
ok: true,
|
|
414
|
+
marker: 'data-cleaning-image-intake-v1',
|
|
415
|
+
command: imageIntake.status(decodeURIComponent(rest[0])),
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
if (rest.length === 1 && req.method === 'DELETE') {
|
|
419
|
+
await imageIntake.remove(decodeURIComponent(rest[0]));
|
|
420
|
+
return writeJson(res, 200, { ok: true, marker: 'data-cleaning-image-intake-v1', removed: true });
|
|
421
|
+
}
|
|
422
|
+
return writeJson(res, 405, { ok: false, code: 'DC_METHOD', message: 'POST a command, GET its status, or DELETE it.' });
|
|
423
|
+
} catch (error) {
|
|
424
|
+
if (error instanceof SyntaxError) {
|
|
425
|
+
return writeJson(res, 400, { ok: false, code: 'DC_BAD_JSON', message: 'Request body must be valid JSON.' });
|
|
426
|
+
}
|
|
427
|
+
return writeImageError(res, error);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
|
|
355
431
|
register('/data-cleaning/api/workflow/contract', (req, res) => {
|
|
356
432
|
if (!isTrusted(req)) return writeJson(res, 403, { ok: false, error: 'untrusted origin' });
|
|
357
433
|
if (req.method !== 'GET') {
|
|
@@ -955,6 +1031,7 @@ export function mountWebRoutes(wctx, { logger, report, TOOL_NAME, SKILL_NAME })
|
|
|
955
1031
|
return () => {
|
|
956
1032
|
if (state) { state.dispose().catch(() => {}); }
|
|
957
1033
|
if (workflow) { workflow.dispose().catch(() => {}); }
|
|
1034
|
+
imageIntake.dispose().catch(() => {});
|
|
958
1035
|
for (const dispose of disposers) dispose();
|
|
959
1036
|
};
|
|
960
1037
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-data-cleaning-agent",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.1",
|
|
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",
|
|
@@ -36,6 +36,8 @@
|
|
|
36
36
|
"docs/RELEASE-0.6.2.md",
|
|
37
37
|
"docs/RELEASE-0.6.3.md",
|
|
38
38
|
"docs/RELEASE-0.7.0.md",
|
|
39
|
+
"docs/RELEASE-0.8.0.md",
|
|
40
|
+
"docs/RELEASE-0.8.1.md",
|
|
39
41
|
"docs/UI-WORKFLOW-V2.md",
|
|
40
42
|
"docs/UI-WORKFLOW-V2-MIGRATION.md",
|
|
41
43
|
"docs/UI-WORKFLOW-V2-ACCEPTANCE.md",
|
|
@@ -44,7 +46,7 @@
|
|
|
44
46
|
],
|
|
45
47
|
"scripts": {
|
|
46
48
|
"test": "node --test",
|
|
47
|
-
"lint": "node --check lib/index.js && node --check lib/engine.js && node --check lib/artifacts.js && node --check lib/tools.js && node --check lib/skill.js && node --check lib/qcc-field-catalog.js && node --check lib/qcc-phase2.js && node --check lib/qcc-phase3.js && node --check lib/qcc-phase3-batch.js && node --check lib/qcc-phase2-acceptance.js && node --check lib/skill-enrich.js && node --check lib/jobs.js && node --check lib/workflow-contract.js && node --check lib/workflow.js && node --check lib/qcc-safety.js && node --check lib/qcc.js && node --check lib/qcc-command.js && node --check lib/qcc-runs.js && node --check lib/web.js && node --check lib/client.js && node --check scripts/check-readme-version.mjs && node --check scripts/check-market-registration.mjs && node --check scripts/g5-e2e.mjs && node --check scripts/phase3-e2e.mjs && node --check scripts/phase2-acceptance.mjs",
|
|
49
|
+
"lint": "node --check lib/index.js && node --check lib/engine.js && node --check lib/artifacts.js && node --check lib/image-intake.js && node --check lib/tools.js && node --check lib/skill.js && node --check lib/qcc-field-catalog.js && node --check lib/qcc-phase2.js && node --check lib/qcc-phase3.js && node --check lib/qcc-phase3-batch.js && node --check lib/qcc-phase2-acceptance.js && node --check lib/skill-enrich.js && node --check lib/jobs.js && node --check lib/workflow-contract.js && node --check lib/workflow.js && node --check lib/qcc-safety.js && node --check lib/qcc.js && node --check lib/qcc-command.js && node --check lib/qcc-runs.js && node --check lib/web.js && node --check lib/client.js && node --check scripts/check-readme-version.mjs && node --check scripts/check-market-registration.mjs && node --check scripts/g5-e2e.mjs && node --check scripts/phase3-e2e.mjs && node --check scripts/phase2-acceptance.mjs",
|
|
48
50
|
"docs:check": "node scripts/check-readme-version.mjs",
|
|
49
51
|
"marketing:check": "node scripts/check-marketing.mjs",
|
|
50
52
|
"verify-pack": "node scripts/verify-pack.mjs",
|