Merge remote Agent workspace updates with message process rendering
Electron E2E / Electron E2E (macos-latest) (push) Canceled after 0s
Electron E2E / Electron E2E (ubuntu-latest) (push) Canceled after 0s
Electron E2E / Electron E2E (windows-latest) (push) Canceled after 0s

This commit is contained in:
brother7 committed 2026-10-13 11:01:05 +08:00
commit bf39f4071f
83 files changed
+8002 -1296

No files matched your search

+2
View File
@@ -43,6 +43,8 @@ export async function handleCloudAgentsRoutes(req: IncomingMessage, res: ServerR
data = await cloudAgents.resolvePending(await parseJsonBody(req));
} else if (path === '/avatars/pick' && req.method === 'POST') {
data = await cloudAgents.uploadAvatar();
} else if (path === '/avatars/preset' && req.method === 'POST') {
data = await cloudAgents.useAvatarPreset(await parseJsonBody(req));
} else if (path === '/attachments/pick' && req.method === 'POST') {
data = await cloudAgents.upload();
} else if (path === '/knowledge/pick' && req.method === 'POST') {
@@ -0,0 +1,20 @@
/// <reference types="vite/client" />
// Inline assets make the same allowlisted portraits available in development
// and packaged Main without accepting a path or image bytes from Renderer.
const portraits = import.meta.glob('../../src/assets/agent-avatars/avatar-*.png', {
eager: true,
import: 'default',
query: '?inline',
}) as Record<string, string>;
const presets = new Map(Array.from({ length: 16 }, (_, index) => {
const id = `avatar-${String(index + 1).padStart(2, '0')}`;
return [id, portraits[`../../src/assets/agent-avatars/${id}.png`]];
}));
export function cloudAgentAvatarPreset(id: string): { bytes: Uint8Array; fileName: string } | null {
const image = presets.get(id);
if (!image?.startsWith('data:image/png;base64,')) return null;
return { bytes: new Uint8Array(Buffer.from(image.slice('data:image/png;base64,'.length), 'base64')), fileName: `${id}.png` };
}
+14 -3
View File
@@ -1,5 +1,6 @@
import { EMPTY_CLOUD_CONFIGURATION, type CloudAgentConfiguration, type CloudAgentDraft, type CloudAgentPage, type CreateCloudAgent, type SaveCloudAgentDraft, type CloudUpload } from '../../shared/cloud-agents';
import { operationPlan } from './cloud-agent-operations';
import { cloudAgentAvatarPreset } from './cloud-agent-avatar-presets';
const retiredChannelOperations = new Set([
'channelPolicy',
@@ -107,7 +108,7 @@ function projectDraft(value: unknown): CloudAgentDraft {
slug: slug(textField(item.slug, 80)),
name: textField(item.name, 100),
icon: item.icon == null ? null : textField(item.icon, 255, false),
purpose: textField(item.purpose, 2000),
purpose: textField(item.purpose, 2000, false),
system_prompt: textField(item.system_prompt, 32000, false),
draft_revision: revision(item.draft_revision),
updated_at: textField(item.updated_at, 40),
@@ -202,7 +203,7 @@ export class CloudAgentsModule {
const body: CreateCloudAgent = {
operation_id: operationId,
name: textField(input.name, 100).trim(),
purpose: textField(input.purpose, 2000).trim(),
purpose: textField(input.purpose, 2000, false).trim(),
...(input.icon === undefined ? {} : { icon: input.icon === null ? null : textField(input.icon, 255, false) }),
};
return this.withRecovery('createAgent', { ...body }, () => this.request('/api/makelore/agents', 'POST', body).then(result => this.withAvatar(projectDraft(result))));
@@ -296,7 +297,7 @@ export class CloudAgentsModule {
const body: SaveCloudAgentDraft = {
expected_revision: revision(input.expected_revision),
name: textField(input.name, 100).trim(),
purpose: textField(input.purpose, 2000).trim(),
purpose: textField(input.purpose, 2000, false).trim(),
system_prompt: textField(input.system_prompt, 32000, false),
...(input.icon === undefined ? {} : { icon: input.icon === null ? null : textField(input.icon, 255, false) }),
...(input.configuration === undefined ? {} : { configuration: configuration(input.configuration) }),
@@ -397,6 +398,16 @@ export class CloudAgentsModule {
return this.withAvatar({ icon: textField(result.icon, 255) });
}
async useAvatarPreset(value: unknown): Promise<{ icon: string; icon_url: string | null }> {
const id = textField(record(value).id, 32);
const preset = cloudAgentAvatarPreset(id);
if (!preset) throw new CloudAgentsError(422, 'invalid_input');
const body = new FormData();
body.append('file', new Blob([preset.bytes], { type: 'image/png' }), preset.fileName);
const result = record(await this.request('/api/makelore/avatars', 'POST', body));
return this.withAvatar({ icon: textField(result.icon, 255) });
}
async upload(): Promise<CloudUpload | null> {
const body = await this.pickUpload();
if (!body) return null;