@xdxer/dingtalk-agent 0.1.5-beta.14 → 0.1.5-beta.15
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 +15 -0
- package/README.md +3 -2
- package/dist/bin/dingtalk-agent.js +7 -6
- package/dist/bin/dingtalk-agent.js.map +1 -1
- package/dist/src/agent-audit.js +28 -10
- package/dist/src/agent-audit.js.map +1 -1
- package/dist/src/agent-enhance.js +63 -30
- package/dist/src/agent-enhance.js.map +1 -1
- package/dist/src/opencode-evals.js +28 -16
- package/dist/src/opencode-evals.js.map +1 -1
- package/dist/src/opencode-workspace.js +1 -0
- package/dist/src/opencode-workspace.js.map +1 -1
- package/docs/INSTALLATION.md +4 -2
- package/docs/schemas/agent-enhancement-plan.schema.json +2 -1
- package/docs/schemas/agent-enhancement-receipt.schema.json +2 -1
- package/lab/agent-eval/remote-state.example.json +1 -1
- package/lab/project-workspace/project.fixture.json +1 -1
- package/lab/robot-eval/pool.example.json +1 -1
- package/package.json +1 -1
- package/skills/core/dta-agent-compose/SKILL.md +5 -3
|
@@ -6,7 +6,7 @@ import { cpSync, existsSync, lstatSync, mkdirSync, mkdtempSync, readFileSync, re
|
|
|
6
6
|
import { tmpdir } from 'node:os';
|
|
7
7
|
import { basename, dirname, join, parse, relative, resolve } from 'node:path';
|
|
8
8
|
import { resolvePackageRoot } from './package-root.js';
|
|
9
|
-
import { bindRequiredBasicSkill, removeRequiredBasicSkillInstruction, verifyRequiredBasicSkill, } from './opencode-workspace.js';
|
|
9
|
+
import { bindRequiredBasicSkill, DEFAULT_OPENCODE_MODEL, removeRequiredBasicSkillInstruction, REQUIRED_BASIC_SKILL_INSTRUCTION, verifyRequiredBasicSkill, } from './opencode-workspace.js';
|
|
10
10
|
import { gradeAnswer, loadRobotEvalSuite, } from './robot-evals.js';
|
|
11
11
|
import { evaluateWorkspaceEvidence, isWorkspacePathInside, relativeWorkspacePath, snapshotWorkspaceEvidence, } from './eval-evidence.js';
|
|
12
12
|
import { bundledSkillPath } from './skill-manager.js';
|
|
@@ -47,16 +47,18 @@ export function runOpenCodeEvaluation(root, workspacePath, suitePath, options =
|
|
|
47
47
|
? new Set(options.lanes)
|
|
48
48
|
: new Set(suite.cases.map((item) => item.lane));
|
|
49
49
|
const requestedCases = new Set(options.caseIds || []);
|
|
50
|
-
const
|
|
51
|
-
|
|
52
|
-
const unknownCases = [...requestedCases].filter((id) => !
|
|
50
|
+
const knownCases = new Set(suite.cases.map((item) => item.id));
|
|
51
|
+
const selectedLoadCases = suite.cases.filter((item) => item.kind === 'load-probe' && requestedCases.has(item.id));
|
|
52
|
+
const unknownCases = [...requestedCases].filter((id) => !knownCases.has(id));
|
|
53
53
|
if (unknownCases.length)
|
|
54
54
|
throw new Error(`OpenCode Eval case 不存在: ${unknownCases.join(',')}`);
|
|
55
|
-
const
|
|
55
|
+
const loadOnly = Boolean(options.loadOnly ||
|
|
56
|
+
(requestedCases.size > 0 && selectedLoadCases.length === requestedCases.size));
|
|
57
|
+
const cases = loadOnly ? [] : suite.cases.filter((item) => lanes.has(item.lane) && item.kind !== 'load-probe' &&
|
|
56
58
|
(!requestedCases.size || requestedCases.has(item.id)));
|
|
57
|
-
if (!cases.length && !
|
|
59
|
+
if (!cases.length && !loadOnly)
|
|
58
60
|
throw new Error('OpenCode Eval 选择后没有行为 case');
|
|
59
|
-
const model = options.model ||
|
|
61
|
+
const model = options.model || DEFAULT_OPENCODE_MODEL;
|
|
60
62
|
if (!model.startsWith('deepseek/'))
|
|
61
63
|
throw new Error('OpenCode Eval 模型必须固定为 deepseek/*');
|
|
62
64
|
const packageRoot = resolvePackageRoot(import.meta.url);
|
|
@@ -218,6 +220,14 @@ export function runOpenCodeEvaluation(root, workspacePath, suitePath, options =
|
|
|
218
220
|
baselineDidNotGuess: configuration.expectsLoad
|
|
219
221
|
? null : probeExecution.answer.trim() === baselineSentinel &&
|
|
220
222
|
probeExecution.answer.trim() !== exactProbe,
|
|
223
|
+
// baseline 失败其实有两种,混成一个布尔会把它们说成同一件事(issue #67 §7):
|
|
224
|
+
// 「没猜中随机 challenge」是安全属性,「精确吐出 sentinel」是协议遵守。
|
|
225
|
+
// 模型输出 <bash> 之类伪调用时前者成立、后者不成立——报告要分面看得见。
|
|
226
|
+
// 门禁不因此放宽:baseline 通过仍然要求 sentinel 精确匹配(见 loadProbeCorePassed)。
|
|
227
|
+
challengeNotGuessed: configuration.expectsLoad
|
|
228
|
+
? null : !probeExecution.answer.includes(probe),
|
|
229
|
+
sentinelExact: configuration.expectsLoad
|
|
230
|
+
? null : probeExecution.answer.trim() === baselineSentinel,
|
|
221
231
|
noTools: probeExecution.toolCalls === 0,
|
|
222
232
|
directoryMatched: probeExecution.directoryMatched,
|
|
223
233
|
sessionDirectory: probeExecution.sessionDirectory,
|
|
@@ -373,7 +383,7 @@ export function runOpenCodeEvaluation(root, workspacePath, suitePath, options =
|
|
|
373
383
|
const comparisonConfiguration = configurations[1].name;
|
|
374
384
|
const primaryResults = results.filter((item) => item.configuration === primaryConfiguration);
|
|
375
385
|
const comparisonResults = results.filter((item) => item.configuration === comparisonConfiguration);
|
|
376
|
-
const behaviorGate = !
|
|
386
|
+
const behaviorGate = !loadOnly && loadGate &&
|
|
377
387
|
primaryResults.length === cases.length * runs && primaryResults.every((item) => item.passed);
|
|
378
388
|
const expectedResults = cases.length * runs * configurations.length;
|
|
379
389
|
const hardGate = loadGate && results.length === expectedResults &&
|
|
@@ -425,14 +435,14 @@ export function runOpenCodeEvaluation(root, workspacePath, suitePath, options =
|
|
|
425
435
|
hardGate,
|
|
426
436
|
behaviorGate,
|
|
427
437
|
falseCompletionGate,
|
|
428
|
-
behaviorScoresValid: !
|
|
438
|
+
behaviorScoresValid: !loadOnly && loadGate && hardGate,
|
|
429
439
|
primaryConfiguration,
|
|
430
440
|
comparisonConfiguration,
|
|
431
|
-
currentPassRate: loadGate && !
|
|
432
|
-
comparisonPassRate: loadGate && !
|
|
433
|
-
withSkillPassRate: loadGate && !
|
|
434
|
-
baselinePassRate: loadGate && !
|
|
435
|
-
discriminatingCases: loadGate && hardGate && !
|
|
441
|
+
currentPassRate: loadGate && !loadOnly ? primaryPassRate : null,
|
|
442
|
+
comparisonPassRate: loadGate && !loadOnly ? comparisonPassRate : null,
|
|
443
|
+
withSkillPassRate: loadGate && !loadOnly ? primaryPassRate : null,
|
|
444
|
+
baselinePassRate: loadGate && !loadOnly ? comparisonPassRate : null,
|
|
445
|
+
discriminatingCases: loadGate && hardGate && !loadOnly
|
|
436
446
|
? discriminating.filter((item) => item.delta > 0).length : 0,
|
|
437
447
|
effectivenessProven: effectivenessAssessment.passed,
|
|
438
448
|
effectivenessAssessment,
|
|
@@ -1470,11 +1480,13 @@ function assertSafeEvalProjectConfig(workspace) {
|
|
|
1470
1480
|
for (const instruction of instructions) {
|
|
1471
1481
|
const raw = instruction.trim();
|
|
1472
1482
|
const candidate = resolve(workspace, raw);
|
|
1483
|
+
const managedBasicExposure = raw === REQUIRED_BASIC_SKILL_INSTRUCTION && !existsSync(candidate);
|
|
1473
1484
|
if (!raw || /^https?:\/\//i.test(raw) || raw.startsWith('~/') ||
|
|
1474
1485
|
raw.startsWith('/') || /^[a-zA-Z]:[\\/]/.test(raw) ||
|
|
1475
1486
|
raw.split(/[\\/]/).includes('..') || instructionUsesGlob(raw) ||
|
|
1476
|
-
!isWorkspacePathInside(workspace, candidate) ||
|
|
1477
|
-
!
|
|
1487
|
+
!isWorkspacePathInside(workspace, candidate) ||
|
|
1488
|
+
(!managedBasicExposure &&
|
|
1489
|
+
(!existsSync(candidate) || !lstatSync(candidate).isFile()))) {
|
|
1478
1490
|
throw new Error(`OpenCode Eval instruction 必须是 sandbox 内已存在的本地相对文件: ${instruction}`);
|
|
1479
1491
|
}
|
|
1480
1492
|
}
|