Files
tkmind_go/ui/h5/mindspace-agent-runner.test.mjs
john 4e21ca937a
Deploy Documentation / deploy (push) Has been cancelled
Canary / Prepare Version (push) Has been cancelled
Canary / build-cli (push) Has been cancelled
Canary / Upload Install Script (push) Has been cancelled
Canary / bundle-desktop (push) Has been cancelled
Canary / bundle-desktop-intel (push) Has been cancelled
Canary / bundle-desktop-linux (push) Has been cancelled
Canary / bundle-desktop-windows (push) Has been cancelled
Canary / bundle-desktop-windows-cuda (push) Has been cancelled
Canary / Release (push) Has been cancelled
Unused Dependencies / machete (push) Has been cancelled
CI / changes (push) Has been cancelled
CI / Check Rust Code Format (push) Has been cancelled
CI / Build and Test Rust Project (push) Has been cancelled
CI / Build Rust Project on Windows (push) Has been cancelled
CI / Check MSRV (push) Has been cancelled
CI / Lint Rust Code (push) Has been cancelled
CI / Check Generated Schemas are Up-to-Date (push) Has been cancelled
CI / Test and Lint Electron Desktop App (push) Has been cancelled
CI / H5 Plaza Tests and Build (push) Has been cancelled
Live Provider Tests / check-fork (push) Has been cancelled
Live Provider Tests / changes (push) Has been cancelled
Live Provider Tests / Build Binary (push) Has been cancelled
Live Provider Tests / Smoke Tests (push) Has been cancelled
Live Provider Tests / Smoke Tests (Code Execution) (push) Has been cancelled
Live Provider Tests / Compaction Tests (push) Has been cancelled
Live Provider Tests / goose server HTTP integration tests (push) Has been cancelled
Publish Ask AI Bot Docker Image / docker (push) Has been cancelled
Publish Docker Image / docker (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
Add TKMind platform extensions, H5/MindSpace stack, and deployment tooling.
Fork goose with custom MCP widgets, platform extensions (aider, git, web, search),
MindSpace H5 backend/frontend, Plaza/Ops UIs, and deploy scripts for tkmind.cn.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-14 21:30:20 +08:00

154 lines
5.4 KiB
JavaScript

import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import os from 'node:os';
import path from 'node:path';
import test from 'node:test';
import { agentRunnerInternals, createMindSpaceAgentRunner } from './mindspace-agent-runner.mjs';
test('buildAgentJobPrompt includes asset excerpts and strict JSON instructions', () => {
const prompt = agentRunnerInternals.buildAgentJobPrompt(
{ instruction: '根据资料生成周报' },
[
{
displayName: 'weekly.md',
mimeType: 'text/markdown',
excerpt: '# Weekly\nDone.',
},
],
);
assert.match(prompt, /合法 JSON 对象/);
assert.match(prompt, /weekly\.md/);
assert.match(prompt, /# Weekly/);
});
test('extractJsonObject and normalizeStructuredResult parse structured agent output', () => {
const payload = agentRunnerInternals.extractJsonObject(`
这里是结果
\`\`\`json
{"title":"项目周报","summary":"本周进展","content":"# 周报\\n\\n完成了任务","content_format":"markdown"}
\`\`\`
`);
const result = agentRunnerInternals.normalizeStructuredResult(payload);
assert.equal(result.title, '项目周报');
assert.equal(result.contentFormat, 'markdown');
});
test('extractJsonObject repairs multiline content and trailing commas', () => {
const multiline = agentRunnerInternals.extractJsonObject(`{
"title":"项目周报",
"summary":"本周进展",
"content":"# 周报
完成了任务",
"content_format":"markdown"
}`);
assert.equal(multiline.title, '项目周报');
assert.match(multiline.content, /完成了任务/);
const trailingComma = agentRunnerInternals.extractJsonObject(
'{"title":"页面","summary":"摘要","content":"正文","content_format":"markdown",}',
);
assert.equal(trailingComma.title, '页面');
});
test('extractJsonObject keeps braces inside content strings', () => {
const payload = agentRunnerInternals.extractJsonObject(
'{"title":"页面","summary":"摘要","content":"function demo() { return 1; }","content_format":"markdown"}',
);
assert.match(payload.content, /return 1/);
});
test('readAssetContext reads and truncates text assets', async () => {
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-agent-runner-'));
const file = path.join(dir, 'note.md');
await fs.writeFile(file, 'A'.repeat(64), 'utf8');
const context = await agentRunnerInternals.readAssetContext(
{ assetId: 'a1', displayName: 'note.md', mimeType: 'text/markdown', path: file },
16,
);
assert.equal(context.excerpt.length, 16);
assert.equal(context.truncated, true);
});
test('runner claims job, executes reply, bills usage, and completes job', async () => {
const calls = [];
const runner = createMindSpaceAgentRunner({
apiTarget: 'http://example.test',
apiSecret: 'secret',
userAuth: {
async canUseChat() {
return { ok: true };
},
async resolveWorkingDir() {
return '/tmp/user-space';
},
async getAgentSessionPolicy() {
return { enableContextMemory: false, unrestricted: true };
},
async registerAgentSession(userId, sessionId) {
calls.push(['registerAgentSession', userId, sessionId]);
},
async billSessionUsage(userId, sessionId, tokenState, requestId) {
calls.push(['billSessionUsage', userId, sessionId, tokenState, requestId]);
return { ok: true, costCents: 1 };
},
},
agentJobService: {
async claimJob(jobId) {
calls.push(['claimJob', jobId]);
return {
jobId,
userId: 'user-1',
jobToken: 'job-token',
instruction: '生成周报',
allowedAssets: [{ assetId: 'asset-1', displayName: 'weekly.md', mimeType: 'text/markdown' }],
};
},
async getAssetForJob(jobId, token, assetId) {
calls.push(['getAssetForJob', jobId, token, assetId]);
const dir = await fs.mkdtemp(path.join(os.tmpdir(), 'mindspace-agent-job-'));
const file = path.join(dir, 'weekly.md');
await fs.writeFile(file, '# Weekly\nAll good.', 'utf8');
return {
assetId,
displayName: 'weekly.md',
mimeType: 'text/markdown',
path: file,
};
},
async completeJob(jobId, token, payload) {
calls.push(['completeJob', jobId, token, payload]);
return { id: jobId, status: payload.status ?? 'completed', resultPageId: 'page-1' };
},
},
executeSessionReply: async (_apiFetch, sessionId, requestId, prompt) => {
calls.push(['executeSessionReply', sessionId, requestId, prompt]);
return {
text: '{"title":"项目周报","summary":"本周完成情况","content":"# 周报\\n\\n完成了全部任务","content_format":"markdown"}',
tokenState: {
inputTokens: 10,
outputTokens: 20,
totalTokens: 30,
accumulatedInputTokens: 10,
accumulatedOutputTokens: 20,
accumulatedTotalTokens: 30,
},
};
},
apiFetchImpl: async (_pathname, _init) => ({
ok: true,
async text() {
return JSON.stringify({ id: 'session-1' });
},
}),
});
const result = await runner.runJob('job-1');
assert.equal(result.status, 'completed');
assert.equal(calls.some((item) => item[0] === 'billSessionUsage'), true);
const completeCall = calls.find((item) => item[0] === 'completeJob');
assert.equal(completeCall[3].title, '项目周报');
});