返回 oh-my-ppt
runtime-user.ts
根目录 / src / main / agent-runtime / prompt / composers / runtime-user.ts
1 import {
2 CONTENT_LANGUAGE_RULES,
3 SOURCE_MATERIAL_PLANNING_RULES,
4 STABLE_HTML_FRAGMENT_PROTOCOL
5 } from "./shared";
6 import type { DeckEditScope, SelectedElementRuntimeContext } from '@shared/generation'
7 import { INDEX_TRANSITION_TYPES } from "../../../../shared/index-transition";
8 import { formatSelectedElementRuntimeContext } from '../selected-element-context'
9
10 const hasSourceMaterialCue = (value: string): boolean =>
11 /参考文档|源文档|参考资料|源资料|解析.*大纲|建议大纲|每页要点|必须保留|reference[-\s]?document|source[-\s]?document|source[-\s]?material|recommended outline|per-page points|facts\/metrics/i.test(
12 value
13 );
14
15 export function buildPlanningUserPrompt(args: {
16 topic: string;
17 totalPages: number;
18 userMessage: string;
19 hasSourceMaterials?: boolean;
20 }): string {
21 const hasExplicitPageHint = /第\s*\d+\s*页|(?:page|slide)\s*\d+/i.test(args.userMessage);
22 const sourcePlanningRules = args.hasSourceMaterials || hasSourceMaterialCue(args.userMessage)
23 ? SOURCE_MATERIAL_PLANNING_RULES
24 : "";
25 return [
26 `Topic: ${args.topic}`,
27 `Target slide count: ${args.totalPages}`,
28 `Return exactly ${args.totalPages} slides, no more and no fewer.`,
29 hasExplicitPageHint ? "The user provided page/slide hints. Preserve that pagination intent when possible." : "",
30 "",
31 "Plan each slide title, key points, and layout intent. Use short phrases, not long paragraphs.",
32 sourcePlanningRules,
33 "Output must be a JSON array. Each item must be exactly { title, keyPoints, layoutIntent }; keyPoints must contain 1-10 strings.",
34 `The array length must be exactly ${args.totalPages}.`,
35 "User requirements:",
36 args.userMessage,
37 ].join("\n");
38 }
39
40 export function buildDesignContractUserPrompt(): string {
41 return [
42 "Generate the unified visual contract only from the style specification in the system prompt.",
43 "Do not use the topic, outline, or user requirements for content planning. The design contract is only for visual consistency.",
44 "The theme field must describe visual mood, such as calm academic editorial or organic biophilic report. Do not turn it into the deck topic or a slide title.",
45 ].join("\n");
46 }
47
48 export function buildEditUserPrompt(args: {
49 userMessage: string;
50 editScope?: DeckEditScope;
51 selectedPageId?: string;
52 selectedPageNumber?: number;
53 selectedSelector?: string;
54 elementTag?: string;
55 elementText?: string;
56 selectedElementContext?: SelectedElementRuntimeContext;
57 existingPageIds?: string[];
58 }): string {
59 const isContainerScope = args.editScope === "presentation-container";
60 const isDeckScope = args.editScope === "deck";
61 const selector = args.selectedSelector?.trim();
62
63 if (isContainerScope) {
64 return [
65 "Apply the following edit instruction only to the presentation container:",
66 "",
67 args.userMessage,
68 "",
69 CONTENT_LANGUAGE_RULES,
70 "",
71 "Edit scope: presentation-container",
72 "Target file: index.html",
73 "Do not modify any /<pageId>.html files.",
74 "Only set page transitions through set_index_transition(type, durationMs).",
75 `Allowed type values: ${INDEX_TRANSITION_TYPES.join(", ")}. durationMs range: 120-1200, except none uses 0.`,
76 args.existingPageIds?.length ? `Existing pages: ${args.existingPageIds.join(", ")}` : "",
77 ].join("\n");
78 }
79
80 const elementDesc =
81 args.elementTag
82 ? `Target element: <${args.elementTag}>${args.elementText ? `"${args.elementText}"` : ""}`
83 : "";
84
85 return [
86 isDeckScope
87 ? "Apply the following edit instruction to the relevant /<pageId>.html files. You may edit multiple pages, but must not modify index.html:"
88 : "Apply the following edit instruction only to the specified page content. Do not modify other pages:",
89 "",
90 args.userMessage,
91 "",
92 CONTENT_LANGUAGE_RULES,
93 "",
94 args.selectedPageId
95 ? `Target page: ${args.selectedPageId} (slide ${args.selectedPageNumber ?? "?"})`
96 : isDeckScope
97 ? "Target pages: all /<pageId>.html files relevant to the instruction"
98 : "Target page: all pages",
99 selector ? `Target element CSS selector: ${selector}` : "",
100 elementDesc ? `Target element description: ${elementDesc}` : "",
101 formatSelectedElementRuntimeContext(args.selectedElementContext),
102 selector || elementDesc
103 ? "Location and edit protocol:"
104 : "",
105 selector || elementDesc
106 ? "- First use read_file to inspect the target page HTML source."
107 : "",
108 selector
109 ? `- Search the source with grep for key selector parts such as classes or attributes: ${selector}`
110 : "",
111 elementDesc
112 ? `- Search the source with grep for the element text: ${elementDesc}`
113 : "",
114 selector || elementDesc
115 ? "- Use the selector and element text together to confirm the exact target node in the source."
116 : "",
117 selector || elementDesc
118 ? "- Use edit_file(old_string, new_string) to modify the target node's HTML string directly."
119 : "",
120 selector || elementDesc
121 ? "- old_string must be large enough to be unique in the file; new_string should contain only the modified portion."
122 : "",
123 selector || elementDesc
124 ? "- Modify only the target node's text, classes, or local styles. Do not change surrounding structure."
125 : "",
126 selector || elementDesc
127 ? "- Do not rewrite the whole page, drift unrelated styles, or perform broad global replacements."
128 : "",
129 !selector && !elementDesc
130 ? "Edit strategy:"
131 : "",
132 !selector && !elementDesc
133 ? "- If this is a local change, preserve the existing layout and update only the necessary local part."
134 : "",
135 !selector && !elementDesc
136 ? "- If the user asks for relayout/redesign/restructure, you may rewrite the whole page fragment."
137 : "",
138 !selector && !elementDesc
139 ? "- For full-page rewrites, follow the Stable HTML fragment protocol strictly. Do not rebuild the page shell."
140 : "",
141 !selector && !elementDesc ? STABLE_HTML_FRAGMENT_PROTOCOL : "",
142 args.existingPageIds?.length ? `Existing pages: ${args.existingPageIds.join(", ")}` : "",
143 ].join("\n");
144 }
145
145 lines TYPESCRIPT