mindspace: close authority boundaries
This commit is contained in:
+194
-94
@@ -7,7 +7,7 @@ import sharp from 'sharp';
|
||||
import {
|
||||
buildWechatAgentPrompt,
|
||||
buildWechatTextReply,
|
||||
createWechatMpService,
|
||||
createWechatMpService as createProductionWechatMpService,
|
||||
guardMissingPublicHtmlLinks,
|
||||
assertWechatAgentReplyIsSendable,
|
||||
findRecoverableWechatAgentErrorInReply,
|
||||
@@ -26,6 +26,10 @@ import {
|
||||
WECHAT_CUSTOMER_TEXT_MAX_BYTES,
|
||||
} from './wechat-mp.mjs';
|
||||
import { createChatIntentRouter } from './chat-intent-router.mjs';
|
||||
import {
|
||||
ensureWechatFreshPageThumbnailsAtWorkspace,
|
||||
prepareWechatHtmlDeliveryAtWorkspace,
|
||||
} from './mindspace-wechat-html-delivery.mjs';
|
||||
|
||||
function signatureFor(token, timestamp, nonce) {
|
||||
return crypto
|
||||
@@ -70,6 +74,82 @@ function previewReadyPageHtml({ title = 'Page', subtitle = '测试页面', cover
|
||||
return `<!doctype html><html><head><meta name="description" content="${subtitle}"><meta name="mindspace-cover" content='{"tag":"页面","accent":"#3366cc","accent2":"#112233","subtitle":"${subtitle}"${coverField}}'><title>${title}</title></head><body><main>${'x'.repeat(600)}</main><p data-mindspace-page-tag="platform-brand">TKMind · 智趣</p></body></html>`;
|
||||
}
|
||||
|
||||
function createWechatMpService(options) {
|
||||
const resolvePublishDir = async (userId) => {
|
||||
const layout =
|
||||
await options.userAuth
|
||||
?.getUserPublishLayout?.(userId);
|
||||
return (
|
||||
layout?.publishDir ??
|
||||
await options.userAuth
|
||||
?.resolveWorkingDir?.(userId)
|
||||
);
|
||||
};
|
||||
const buildCanonicalUrl = (
|
||||
userId,
|
||||
relativePath,
|
||||
) => {
|
||||
const base = String(
|
||||
options.config?.publicBaseUrl ??
|
||||
'https://example.com',
|
||||
).replace(/\/+$/, '');
|
||||
const normalized = String(relativePath)
|
||||
.replace(/^\/+/, '')
|
||||
.split('/')
|
||||
.map(encodeURIComponent)
|
||||
.join('/');
|
||||
return `${base}/MindSpace/${encodeURIComponent(userId)}/${normalized}`;
|
||||
};
|
||||
const htmlDeliveryAuthority =
|
||||
options.htmlDeliveryAuthority ?? {
|
||||
async prepareWechatHtmlDelivery(input) {
|
||||
const publishDir =
|
||||
await resolvePublishDir(input.userId);
|
||||
return prepareWechatHtmlDeliveryAtWorkspace({
|
||||
reply: input.reply,
|
||||
intent: input.intent,
|
||||
publishDir,
|
||||
requestStartedAt:
|
||||
input.requestStartedAt,
|
||||
allowRecentArtifacts:
|
||||
input.allowRecentArtifacts,
|
||||
buildCanonicalUrl: (relativePath) =>
|
||||
buildCanonicalUrl(
|
||||
input.userId,
|
||||
relativePath,
|
||||
),
|
||||
});
|
||||
},
|
||||
async ensureWechatFreshPageThumbnails(
|
||||
input,
|
||||
) {
|
||||
const publishDir =
|
||||
await resolvePublishDir(input.userId);
|
||||
return ensureWechatFreshPageThumbnailsAtWorkspace(
|
||||
{
|
||||
artifacts: input.artifacts,
|
||||
images: input.images,
|
||||
messages: input.messages,
|
||||
repairEnabled:
|
||||
input.repairEnabled,
|
||||
publishDir,
|
||||
buildCanonicalUrl: (
|
||||
relativePath,
|
||||
) =>
|
||||
buildCanonicalUrl(
|
||||
input.userId,
|
||||
relativePath,
|
||||
),
|
||||
},
|
||||
);
|
||||
},
|
||||
};
|
||||
return createProductionWechatMpService({
|
||||
...options,
|
||||
htmlDeliveryAuthority,
|
||||
});
|
||||
}
|
||||
|
||||
test('executeSessionReply converts a hanging event stream into a bounded timeout', async () => {
|
||||
let cancelled = false;
|
||||
const body = new ReadableStream({
|
||||
@@ -453,34 +533,39 @@ test('maybeAttachPublishedHtmlLink copies generated root html into public and re
|
||||
const workspaceRoot = fs.mkdtempSync('/tmp/wechat-mp-public-');
|
||||
const htmlPath = `${workspaceRoot}/hello.html`;
|
||||
fs.writeFileSync(htmlPath, '<!doctype html><title>Hello</title>');
|
||||
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
{
|
||||
text: '已完成',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'developer',
|
||||
arguments: {
|
||||
action: 'write',
|
||||
path: htmlPath,
|
||||
content: '<!doctype html><title>Hello</title>',
|
||||
},
|
||||
const reply = {
|
||||
text: '已完成',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'developer',
|
||||
arguments: {
|
||||
action: 'write',
|
||||
path: htmlPath,
|
||||
content: '<!doctype html><title>Hello</title>',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const prepared = prepareWechatHtmlDeliveryAtWorkspace({
|
||||
reply,
|
||||
publishDir: workspaceRoot,
|
||||
buildCanonicalUrl: (relativePath) =>
|
||||
`https://m.tkmind.cn/MindSpace/user-1/${relativePath}`,
|
||||
});
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
reply,
|
||||
{
|
||||
workingDir: workspaceRoot,
|
||||
publicBaseUrl: 'https://m.tkmind.cn',
|
||||
artifacts: prepared.confirmedArtifacts,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -496,33 +581,38 @@ test('maybeAttachPublishedHtmlLink recognizes sandbox-fs write_file html outputs
|
||||
const htmlPath = `${workspaceRoot}/public/codex-verify.html`;
|
||||
fs.mkdirSync(`${workspaceRoot}/public`, { recursive: true });
|
||||
fs.writeFileSync(htmlPath, '<!doctype html><title>Codex Verify</title>');
|
||||
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
{
|
||||
text: '页面已生成 ✅',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'sandbox-fs__write_file',
|
||||
arguments: {
|
||||
path: 'public/codex-verify.html',
|
||||
content: '<!doctype html><title>Codex Verify</title>',
|
||||
},
|
||||
const reply = {
|
||||
text: '页面已生成 ✅',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'sandbox-fs__write_file',
|
||||
arguments: {
|
||||
path: 'public/codex-verify.html',
|
||||
content: '<!doctype html><title>Codex Verify</title>',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const prepared = prepareWechatHtmlDeliveryAtWorkspace({
|
||||
reply,
|
||||
publishDir: workspaceRoot,
|
||||
buildCanonicalUrl: (relativePath) =>
|
||||
`https://m.tkmind.cn/MindSpace/user-1/${relativePath}`,
|
||||
});
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
reply,
|
||||
{
|
||||
workingDir: workspaceRoot,
|
||||
publicBaseUrl: 'https://m.tkmind.cn',
|
||||
artifacts: prepared.confirmedArtifacts,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -537,33 +627,38 @@ test('maybeAttachPublishedHtmlLink rewrites wrong public html links to the canon
|
||||
const htmlPath = `${workspaceRoot}/public/summer-breeze-journal.html`;
|
||||
fs.mkdirSync(`${workspaceRoot}/public`, { recursive: true });
|
||||
fs.writeFileSync(htmlPath, '<!doctype html><title>Summer</title>');
|
||||
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
{
|
||||
text: '页面已发布:https://m.tkmind.cn/public/summer-breeze-journal.html',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'sandbox-fs__write_file',
|
||||
arguments: {
|
||||
path: 'public/summer-breeze-journal.html',
|
||||
content: '<!doctype html><title>Summer</title>',
|
||||
},
|
||||
const reply = {
|
||||
text: '页面已发布:https://m.tkmind.cn/public/summer-breeze-journal.html',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'sandbox-fs__write_file',
|
||||
arguments: {
|
||||
path: 'public/summer-breeze-journal.html',
|
||||
content: '<!doctype html><title>Summer</title>',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const prepared = prepareWechatHtmlDeliveryAtWorkspace({
|
||||
reply,
|
||||
publishDir: workspaceRoot,
|
||||
buildCanonicalUrl: (relativePath) =>
|
||||
`https://m.tkmind.cn/MindSpace/user-1/${relativePath}`,
|
||||
});
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
reply,
|
||||
{
|
||||
workingDir: workspaceRoot,
|
||||
publicBaseUrl: 'https://m.tkmind.cn',
|
||||
artifacts: prepared.confirmedArtifacts,
|
||||
},
|
||||
);
|
||||
|
||||
@@ -579,33 +674,38 @@ test('maybeAttachPublishedHtmlLink rewrites tkmind domain variants to the canoni
|
||||
const htmlPath = `${workspaceRoot}/public/codex-prod-check-v6.html`;
|
||||
fs.mkdirSync(`${workspaceRoot}/public`, { recursive: true });
|
||||
fs.writeFileSync(htmlPath, '<!doctype html><title>Prod Check</title>');
|
||||
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
{
|
||||
text: '唯一可访问链接:https://mindspace.tkmind.cn/a70ff537-8908-486e-9b6c-042e07cc25db/codex-prod-check-v6.html',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'sandbox-fs__write_file',
|
||||
arguments: {
|
||||
path: 'public/codex-prod-check-v6.html',
|
||||
content: '<!doctype html><title>Prod Check</title>',
|
||||
},
|
||||
const reply = {
|
||||
text: '唯一可访问链接:https://mindspace.tkmind.cn/a70ff537-8908-486e-9b6c-042e07cc25db/codex-prod-check-v6.html',
|
||||
messages: [
|
||||
{
|
||||
role: 'assistant',
|
||||
content: [
|
||||
{
|
||||
type: 'toolRequest',
|
||||
toolCall: {
|
||||
value: {
|
||||
name: 'sandbox-fs__write_file',
|
||||
arguments: {
|
||||
path: 'public/codex-prod-check-v6.html',
|
||||
content: '<!doctype html><title>Prod Check</title>',
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
};
|
||||
const prepared = prepareWechatHtmlDeliveryAtWorkspace({
|
||||
reply,
|
||||
publishDir: workspaceRoot,
|
||||
buildCanonicalUrl: (relativePath) =>
|
||||
`https://m.tkmind.cn/MindSpace/user-1/${relativePath}`,
|
||||
});
|
||||
const text = await maybeAttachPublishedHtmlLink(
|
||||
reply,
|
||||
{
|
||||
workingDir: workspaceRoot,
|
||||
publicBaseUrl: 'https://m.tkmind.cn',
|
||||
artifacts: prepared.confirmedArtifacts,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user