Files
Genarrative/packages/shared/src/contracts/editorAgent.ts
T
kdletters 071faa482c 统一 Rust 与 TypeScript 格式化门禁
纳入 AGC Cargo workspace 的统一 rustfmt 检查与格式化入口

完成项目 TypeScript/Prettier 与 Rust 全量格式化

修复 Pingora expected executable 门禁的空白敏感误报

同步开发运维文档与 AGC skill pack 格式化忽略规则
2026-09-01 16:28:34 +08:00

221 lines
5.9 KiB
TypeScript
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.
// 画布Agent对话契约:会话元数据存 SpacetimeDB,消息正文整体存 OSSeditor-agent/{conversationId}.json)。
export const EDITOR_AGENT_MAX_ATTACHMENTS = 9;
export const EDITOR_AGENT_ATTACHMENT_LABEL_MAX_CODE_POINTS = 24;
export const EDITOR_AGENT_ERROR_MESSAGE_PREFIX = 'ERROR ';
export type EditorAgentMessageRole = 'user' | 'assistant' | 'system';
export type EditorAgentToolCallStatus =
| 'not_completed'
| 'completed'
| 'failed'
| 'cancelled';
export type EditorAgentAttachmentSource = 'canvas_resource' | 'library_asset';
function isUnsafeEditorAgentAttachmentLabelCharacter(character: string) {
const codePoint = character.codePointAt(0) ?? 0;
const isControlCharacter =
codePoint <= 0x1f || (codePoint >= 0x7f && codePoint <= 0x9f);
const isAsciiPunctuation =
(codePoint >= 0x21 && codePoint <= 0x2f) ||
(codePoint >= 0x3a && codePoint <= 0x40) ||
(codePoint >= 0x5b && codePoint <= 0x60) ||
(codePoint >= 0x7b && codePoint <= 0x7e);
const isUnsafeAsciiPunctuation =
isAsciiPunctuation &&
character !== '-' &&
character !== '_' &&
character !== '.';
return isControlCharacter || isUnsafeAsciiPunctuation;
}
function normalizeEditorAgentAttachmentLabel(
label: string | null | undefined,
fallback: string,
) {
const normalizeCandidate = (candidate: string | null | undefined) => {
const normalized: string[] = [];
let codePoints = 0;
let pendingSpace = false;
for (const character of candidate?.trim() ?? '') {
if (isUnsafeEditorAgentAttachmentLabelCharacter(character)) {
continue;
}
if (/\s/u.test(character)) {
pendingSpace = normalized.length > 0;
continue;
}
if (
pendingSpace &&
codePoints + 1 < EDITOR_AGENT_ATTACHMENT_LABEL_MAX_CODE_POINTS
) {
normalized.push(' ');
codePoints += 1;
}
pendingSpace = false;
if (codePoints >= EDITOR_AGENT_ATTACHMENT_LABEL_MAX_CODE_POINTS) {
break;
}
normalized.push(character);
codePoints += 1;
}
return normalized.join('').trim();
};
return normalizeCandidate(label) || normalizeCandidate(fallback) || '图片';
}
export interface EditorAgentAttachmentRef {
source: EditorAgentAttachmentSource;
referenceId: string;
objectKey?: string | null;
imageSrc: string;
thumbnailSrc?: string | null;
label?: string | null;
width?: number | null;
height?: number | null;
}
export function createEditorAgentAttachmentRef(
input: EditorAgentAttachmentRef,
fallbackLabel: string = input.referenceId,
) {
return {
...input,
label: normalizeEditorAgentAttachmentLabel(input.label, fallbackLabel),
};
}
export interface EditorAgentGeneratedImage {
resourceId?: string | null;
objectKey?: string | null;
assetObjectId?: string | null;
imageSrc: string;
thumbnailSrc?: string | null;
width?: number | null;
height?: number | null;
}
export interface EditorAgentGeneratedVideo {
resourceId?: string | null;
objectKey?: string | null;
assetObjectId?: string | null;
videoSrc: string;
thumbnailSrc?: string | null;
width?: number | null;
height?: number | null;
}
export interface EditorAgentGeneratedAudio {
resourceId?: string | null;
objectKey?: string | null;
assetObjectId?: string | null;
audioSrc: string;
}
export interface EditorAgentToolCallStringArg {
name: string;
label: string;
value: string;
}
export interface EditorAgentToolCallImageRef {
imageId: string;
imageSrc: string;
objectKey?: string | null;
thumbnailSrc?: string | null;
label?: string | null;
width?: number | null;
height?: number | null;
}
export interface EditorAgentToolCallImageArg {
name: string;
label: string;
refs: EditorAgentToolCallImageRef[];
}
export interface EditorAgentToolCallDisplayExtras {
priceMudPoints: number;
}
export interface EditorAgentToolCallDisplayArgs {
stringArgs: EditorAgentToolCallStringArg[];
imageArgs: EditorAgentToolCallImageArg[];
extras: EditorAgentToolCallDisplayExtras;
}
export interface EditorAgentToolCall {
toolName: string;
status: EditorAgentToolCallStatus;
args: unknown;
displayArgs: EditorAgentToolCallDisplayArgs;
externalJobId?: string | null;
images: EditorAgentGeneratedImage[];
// Older persisted conversation documents do not contain these media fields.
videos?: EditorAgentGeneratedVideo[];
audios?: EditorAgentGeneratedAudio[];
error?: string | null;
}
export interface EditorAgentMessage {
// Frontend must not use this to organize messages.
// It is an opaque backend locator for pending tool-call operations.
id: number;
// Present only on user messages created from a client send request.
clientMessageId?: string | null;
role: EditorAgentMessageRole;
text: string;
attachments: EditorAgentAttachmentRef[];
toolCall: EditorAgentToolCall | null;
createdAt: string;
}
export interface EditorAgentConversationSummary {
conversationId: string;
projectId: string;
title: string;
updatedAt: string;
}
export interface EditorAgentConversationDetail {
conversationId: string;
projectId: string;
title: string;
createdAt: string;
updatedAt: string;
messages: EditorAgentMessage[];
}
export interface EditorAgentConversationMessagesDocument {
version: number;
conversationId: string;
messages: EditorAgentMessage[];
}
export interface CreateEditorAgentConversationRequest {
title?: string | null;
}
export interface EditorAgentConversationListResponse {
conversations: EditorAgentConversationSummary[];
}
export interface EditorAgentConversationResponse {
conversation: EditorAgentConversationDetail;
}
export interface EditorAgentMessageRequest {
clientMessageId: string;
text: string;
attachments?: EditorAgentAttachmentRef[];
}
export interface EditorAgentMessageResponse {
conversation: EditorAgentConversationSummary;
deltaMessages: EditorAgentMessage[];
errorMessage: string | null;
}