dsh-im-ops/test/message-failure.test.mjs

107 lines
4 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import assert from 'node:assert/strict';
import test from 'node:test';
import {
classifyMessageFailure,
messageFailureText,
publicMessageFailure,
} from '../src/channels/shared/message-failure.mjs';
const options = { referenceId: 'MF-TEST01', at: 123 };
test('message failures distinguish stable Harness transport errors', () => {
assert.equal(classifyMessageFailure({
code: 'harness-connect-failed', method: 'host.describe',
}, options).code, 'HARNESS_CONNECT');
assert.equal(classifyMessageFailure({
code: 'harness-connect-failed', method: 'session.history',
}, options).code, 'HARNESS_RESULT_UNCERTAIN');
assert.equal(classifyMessageFailure({
code: 'harness-timeout', method: 'session.prompt',
}, options).code, 'HARNESS_RESULT_UNCERTAIN');
assert.equal(classifyMessageFailure({
code: 'harness-auth-required', method: 'host.describe',
}, options).code, 'HARNESS_ACCESS');
assert.equal(classifyMessageFailure({
code: 'harness-api-not-found', method: 'session.history',
}, options).code, 'HARNESS_PROTOCOL');
});
test('message failures use verified turn-end provider codes without exposing provider detail', () => {
for (const [providerCode, code] of [
['AUTH', 'MODEL_AUTH'],
['QUOTA', 'MODEL_QUOTA'],
['RATE_LIMIT', 'MODEL_RATE_LIMIT'],
['CONTEXT_WINDOW_EXCEEDED', 'MODEL_CONTEXT_LIMIT'],
['UNKNOWN_MODEL', 'MODEL_UNAVAILABLE'],
['TIMEOUT', 'MODEL_TIMEOUT'],
['TRANSPORT', 'MODEL_TRANSPORT'],
['SERVER', 'MODEL_SERVICE'],
['STREAM_CLOSED', 'MODEL_STREAM'],
['EMPTY_RESPONSE', 'MODEL_EMPTY_REPLY'],
['CONTENT_FILTER', 'MODEL_CONTENT_REJECTED'],
]) {
const failure = classifyMessageFailure({
code: 'harness-turn-failed',
providerCode,
message: 'provider-token /private/path',
reason: { error: { message: 'secret provider payload' } },
}, options);
assert.equal(failure.code, code);
assert.doesNotMatch(JSON.stringify(failure), /provider-token|private|secret provider/);
}
assert.equal(classifyMessageFailure({
code: 'channel-send-failed', providerCode: 'RATE_LIMIT', status: 429,
}, options).code, 'CHANNEL_RATE_LIMIT');
assert.equal(classifyMessageFailure({
code: 'harness-turn-failed', providerCode: 'PRIVATE_PROVIDER_CODE',
}, options).code, 'INTERNAL_UNKNOWN');
});
test('message failure text contains a safe code and traceable reference', () => {
const failure = classifyMessageFailure(new Error('secret-shaped internal detail'), options);
assert.deepEqual(failure, {
code: 'INTERNAL_UNKNOWN',
reason: 'INTERNAL_UNKNOWN',
message: '任务未完成,暂时无法确定原因。请重试;若持续发生,请将参考号提供给管理员。',
referenceId: 'MF-TEST01',
at: 123,
});
assert.match(messageFailureText(failure), /错误码:INTERNAL_UNKNOWN;参考号:MF-TEST01/);
assert.doesNotMatch(messageFailureText(failure), /secret-shaped/);
});
test('public message failure keeps only bounded safe fields', () => {
assert.deepEqual(publicMessageFailure({
...classifyMessageFailure({ code: 'agent-busy' }, options),
providerDetail: 'secret',
stack: '/private/path',
}), {
code: 'SESSION_BUSY',
reason: 'SESSION_BUSY',
message: '当前会话仍在处理上一项任务。请等待完成,或发送 /stop 后重试。',
referenceId: 'MF-TEST01',
at: 123,
});
});
test('artifact permission failures use the shared channel permission classification', () => {
const error = new Error('private provider permission detail');
error.code = 'artifact-permission-required';
const failure = classifyMessageFailure(error, {
userMessage: '结果文件已生成,但机器人没有文件发送权限。',
reason: error.code,
referenceId: 'MF-ART12345',
at: 123,
});
assert.deepEqual(failure, {
code: 'CHANNEL_PERMISSION',
reason: 'ARTIFACT_PERMISSION_REQUIRED',
message: '结果文件已生成,但机器人没有文件发送权限。',
referenceId: 'MF-ART12345',
at: 123,
});
});