feat: sync intake context on project changes
This commit is contained in:
@@ -17,6 +17,12 @@
|
|||||||
- `导入 URL 配置` 现在会在切换平台时实时刷新说明文案和样例配置,抖音/快手两种场景可以直接在同一张表单里切换预设。
|
- `导入 URL 配置` 现在会在切换平台时实时刷新说明文案和样例配置,抖音/快手两种场景可以直接在同一张表单里切换预设。
|
||||||
- 这套联动同样保留“手动改过就不再覆盖”的原则,避免自动推荐把用户已经输入的内容冲掉。
|
- 这套联动同样保留“手动改过就不再覆盖”的原则,避免自动推荐把用户已经输入的内容冲掉。
|
||||||
|
|
||||||
|
### 输入型表单切项目时会同步刷新 Agent 和上下文
|
||||||
|
|
||||||
|
- `导入主页 / 导入当前对标 / 加入跟踪 / 导入作品链接 / 导入文本 / 上传本地视频` 这几张输入型表单,现在在切换项目后会一起刷新可选 Agent 列表和顶部“当前上下文”摘要。
|
||||||
|
- 这样不会再出现“项目已经换了,但表单里还是上一项目的 Agent 和上下文”的错位。
|
||||||
|
- `加入跟踪` 虽然没有项目切换,但现在在切换负责 Agent 时,顶部上下文摘要也会实时更新。
|
||||||
|
|
||||||
## 2026-04-06
|
## 2026-04-06
|
||||||
|
|
||||||
### 主 Agent 高注意图动作统一切到直执行入口
|
### 主 Agent 高注意图动作统一切到直执行入口
|
||||||
|
|||||||
@@ -503,6 +503,38 @@ function bindManualIntakeTitleRecommendation(fields, kind, options = {}) {
|
|||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function bindActionContextRecommendation(fields, options = {}) {
|
||||||
|
const contextHtml = fields.querySelector('[data-action-field="context"] .sheet-html');
|
||||||
|
const assistantSelect = fields.querySelector('[data-action-field="assistantId"]');
|
||||||
|
const projectField = options.projectField === undefined ? "projectId" : options.projectField;
|
||||||
|
const projectSelect = projectField ? fields.querySelector(`[data-action-field="${projectField}"]`) : null;
|
||||||
|
const defaultAssistantId = options.defaultAssistantId || "";
|
||||||
|
const syncAssistantOptions = () => {
|
||||||
|
if (!(assistantSelect instanceof HTMLSelectElement) || !(projectSelect instanceof HTMLSelectElement)) return;
|
||||||
|
const assistants = getAssistantOptions(projectSelect.value || "");
|
||||||
|
const currentValue = assistantSelect.value || "";
|
||||||
|
const fallbackValue = assistants.some((item) => item.value === currentValue)
|
||||||
|
? currentValue
|
||||||
|
: assistants.some((item) => item.value === defaultAssistantId)
|
||||||
|
? defaultAssistantId
|
||||||
|
: assistants[0]?.value || "";
|
||||||
|
assistantSelect.innerHTML = [{ value: "", label: "暂不绑定" }, ...assistants].map((item) => `
|
||||||
|
<option value="${escapeHtml(item.value)}">${escapeHtml(item.label)}</option>
|
||||||
|
`).join("");
|
||||||
|
assistantSelect.value = fallbackValue;
|
||||||
|
};
|
||||||
|
const sync = () => {
|
||||||
|
syncAssistantOptions();
|
||||||
|
if (!(contextHtml instanceof HTMLElement)) return;
|
||||||
|
const projectId = projectSelect instanceof HTMLSelectElement ? projectSelect.value : getSelectedProject()?.id || "";
|
||||||
|
const assistantId = assistantSelect instanceof HTMLSelectElement ? assistantSelect.value : defaultAssistantId;
|
||||||
|
contextHtml.innerHTML = renderIntakeActionContextHtml(projectId, assistantId);
|
||||||
|
};
|
||||||
|
projectSelect?.addEventListener("change", sync);
|
||||||
|
assistantSelect?.addEventListener("change", sync);
|
||||||
|
sync();
|
||||||
|
}
|
||||||
|
|
||||||
function getCompletedJobById(jobId = "") {
|
function getCompletedJobById(jobId = "") {
|
||||||
const normalizedId = String(jobId || "").trim();
|
const normalizedId = String(jobId || "").trim();
|
||||||
if (!normalizedId) return null;
|
if (!normalizedId) return null;
|
||||||
@@ -9534,6 +9566,7 @@ function openImportHomepageAction() {
|
|||||||
submitLabel: "开始同步",
|
submitLabel: "开始同步",
|
||||||
onOpen: ({ fields }) => {
|
onOpen: ({ fields }) => {
|
||||||
bindManualIntakeTitleRecommendation(fields, "主页对标", { defaultPlatform: "douyin" });
|
bindManualIntakeTitleRecommendation(fields, "主页对标", { defaultPlatform: "douyin" });
|
||||||
|
bindActionContextRecommendation(fields, { defaultAssistantId });
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
||||||
@@ -9596,6 +9629,9 @@ function openImportSelectedAccountAction() {
|
|||||||
{ name: "skipExisting", label: "跳过已存在作品", type: "checkbox", value: true },
|
{ name: "skipExisting", label: "跳过已存在作品", type: "checkbox", value: true },
|
||||||
{ name: "autoAnalyze", label: "同步后自动分析", type: "checkbox", value: true }
|
{ name: "autoAnalyze", label: "同步后自动分析", type: "checkbox", value: true }
|
||||||
],
|
],
|
||||||
|
onOpen: ({ fields }) => {
|
||||||
|
bindActionContextRecommendation(fields, { defaultAssistantId });
|
||||||
|
},
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
if (!values.sourceUrl?.trim()) throw new Error("请先填写主页链接");
|
if (!values.sourceUrl?.trim()) throw new Error("请先填写主页链接");
|
||||||
const projectId = values.projectId || project.id;
|
const projectId = values.projectId || project.id;
|
||||||
@@ -9638,6 +9674,9 @@ function openTrackSelectedAccountAction() {
|
|||||||
{ name: "assistantId", label: "负责 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "先不绑定" }, ...assistants] },
|
{ name: "assistantId", label: "负责 Agent", type: "select", value: defaultAssistantId, options: [{ value: "", label: "先不绑定" }, ...assistants] },
|
||||||
{ name: "note", label: "跟踪备注", value: trackedItem?.note || "", placeholder: "例如:重点观察开头结构、成交句式和更新频率" }
|
{ name: "note", label: "跟踪备注", value: trackedItem?.note || "", placeholder: "例如:重点观察开头结构、成交句式和更新频率" }
|
||||||
],
|
],
|
||||||
|
onOpen: ({ fields }) => {
|
||||||
|
bindActionContextRecommendation(fields, { defaultAssistantId, projectField: "" });
|
||||||
|
},
|
||||||
onSubmit: async (values) => {
|
onSubmit: async (values) => {
|
||||||
await runDirectDiscoveryAction("track-account", {
|
await runDirectDiscoveryAction("track-account", {
|
||||||
target_account_id: account.id,
|
target_account_id: account.id,
|
||||||
@@ -9666,6 +9705,7 @@ function openImportVideoLinkAction() {
|
|||||||
submitLabel: "开始分析",
|
submitLabel: "开始分析",
|
||||||
onOpen: ({ fields }) => {
|
onOpen: ({ fields }) => {
|
||||||
bindManualIntakeTitleRecommendation(fields, "单条作品", { defaultPlatform: "douyin" });
|
bindManualIntakeTitleRecommendation(fields, "单条作品", { defaultPlatform: "douyin" });
|
||||||
|
bindActionContextRecommendation(fields, { defaultAssistantId });
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
||||||
@@ -9706,6 +9746,7 @@ function openImportTextAction() {
|
|||||||
submitLabel: "开始分析",
|
submitLabel: "开始分析",
|
||||||
onOpen: ({ fields }) => {
|
onOpen: ({ fields }) => {
|
||||||
bindManualIntakeTitleRecommendation(fields, "文本素材", { defaultPlatform: "douyin" });
|
bindManualIntakeTitleRecommendation(fields, "文本素材", { defaultPlatform: "douyin" });
|
||||||
|
bindActionContextRecommendation(fields, { defaultAssistantId });
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
||||||
@@ -9745,6 +9786,7 @@ function openUploadVideoAction() {
|
|||||||
submitLabel: "上传并分析",
|
submitLabel: "上传并分析",
|
||||||
onOpen: ({ fields }) => {
|
onOpen: ({ fields }) => {
|
||||||
bindManualIntakeTitleRecommendation(fields, "本地视频", { defaultPlatform: "douyin" });
|
bindManualIntakeTitleRecommendation(fields, "本地视频", { defaultPlatform: "douyin" });
|
||||||
|
bindActionContextRecommendation(fields, { defaultAssistantId });
|
||||||
},
|
},
|
||||||
fields: [
|
fields: [
|
||||||
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
{ name: "context", label: "当前上下文", type: "html", html: renderIntakeActionContextHtml(project.id, defaultAssistantId) },
|
||||||
|
|||||||
@@ -1196,6 +1196,7 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
|
|||||||
assert.match(APP, /function recommendLiveRecorderImportSamples\(platform\)/);
|
assert.match(APP, /function recommendLiveRecorderImportSamples\(platform\)/);
|
||||||
assert.match(APP, /function recommendManualIntakeTitle\(project, platform, kind\)/);
|
assert.match(APP, /function recommendManualIntakeTitle\(project, platform, kind\)/);
|
||||||
assert.match(APP, /function bindManualIntakeTitleRecommendation\(fields, kind, options = \{\}\)/);
|
assert.match(APP, /function bindManualIntakeTitleRecommendation\(fields, kind, options = \{\}\)/);
|
||||||
|
assert.match(APP, /function bindActionContextRecommendation\(fields, options = \{\}\)/);
|
||||||
assert.match(APP, /function bindCreativeSourceJobRecommendations\(fields, options = \{\}\)/);
|
assert.match(APP, /function bindCreativeSourceJobRecommendations\(fields, options = \{\}\)/);
|
||||||
assert.match(APP, /function bindLiveRecorderSheetRecommendations\(fields, options = \{\}\)/);
|
assert.match(APP, /function bindLiveRecorderSheetRecommendations\(fields, options = \{\}\)/);
|
||||||
assert.match(importHomepage, /label: "当前上下文", type: "html"/);
|
assert.match(importHomepage, /label: "当前上下文", type: "html"/);
|
||||||
@@ -1205,19 +1206,23 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
|
|||||||
assert.match(importHomepage, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
assert.match(importHomepage, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||||||
assert.match(importHomepage, /value: defaultPlatform/);
|
assert.match(importHomepage, /value: defaultPlatform/);
|
||||||
assert.match(importHomepage, /placeholder: titlePlaceholder/);
|
assert.match(importHomepage, /placeholder: titlePlaceholder/);
|
||||||
|
assert.match(importHomepage, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||||||
assert.match(importHomepage, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "主页对标", \{ defaultPlatform: "douyin" \}\);/);
|
assert.match(importHomepage, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "主页对标", \{ defaultPlatform: "douyin" \}\);/);
|
||||||
assert.match(importSelected, /label: "当前上下文", type: "html"/);
|
assert.match(importSelected, /label: "当前上下文", type: "html"/);
|
||||||
assert.match(importSelected, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
assert.match(importSelected, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||||||
assert.match(importSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
assert.match(importSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||||||
|
assert.match(importSelected, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||||||
assert.match(trackSelected, /label: "当前上下文", type: "html"/);
|
assert.match(trackSelected, /label: "当前上下文", type: "html"/);
|
||||||
assert.match(trackSelected, /const defaultAssistantId = trackedItem\?\.assistant_id \|\| getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
assert.match(trackSelected, /const defaultAssistantId = trackedItem\?\.assistant_id \|\| getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||||||
assert.match(trackSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
assert.match(trackSelected, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||||||
|
assert.match(trackSelected, /bindActionContextRecommendation\(fields, \{ defaultAssistantId, projectField: "" \}\);/);
|
||||||
assert.match(importVideo, /label: "当前上下文", type: "html"/);
|
assert.match(importVideo, /label: "当前上下文", type: "html"/);
|
||||||
assert.match(importVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
assert.match(importVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||||||
assert.match(importVideo, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
|
assert.match(importVideo, /const defaultPlatform = normalizePlatformValue\(getPreferredPlatform\(\), "douyin"\)/);
|
||||||
assert.match(importVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "单条作品"\)/);
|
assert.match(importVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "单条作品"\)/);
|
||||||
assert.match(importVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
assert.match(importVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||||||
assert.match(importVideo, /placeholder: titlePlaceholder/);
|
assert.match(importVideo, /placeholder: titlePlaceholder/);
|
||||||
|
assert.match(importVideo, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||||||
assert.match(importVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "单条作品", \{ defaultPlatform: "douyin" \}\);/);
|
assert.match(importVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "单条作品", \{ defaultPlatform: "douyin" \}\);/);
|
||||||
assert.match(importText, /label: "当前上下文", type: "html"/);
|
assert.match(importText, /label: "当前上下文", type: "html"/);
|
||||||
assert.match(importText, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
assert.match(importText, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||||||
@@ -1225,6 +1230,7 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
|
|||||||
assert.match(importText, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "文本素材"\)/);
|
assert.match(importText, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "文本素材"\)/);
|
||||||
assert.match(importText, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
assert.match(importText, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||||||
assert.match(importText, /placeholder: titlePlaceholder/);
|
assert.match(importText, /placeholder: titlePlaceholder/);
|
||||||
|
assert.match(importText, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||||||
assert.match(importText, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "文本素材", \{ defaultPlatform: "douyin" \}\);/);
|
assert.match(importText, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "文本素材", \{ defaultPlatform: "douyin" \}\);/);
|
||||||
assert.match(uploadVideo, /label: "当前上下文", type: "html"/);
|
assert.match(uploadVideo, /label: "当前上下文", type: "html"/);
|
||||||
assert.match(uploadVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
assert.match(uploadVideo, /const defaultAssistantId = getSelectedAssistant\(\)\?\.id \|\| assistants\[0\]\?\.value \|\| ""/);
|
||||||
@@ -1232,6 +1238,7 @@ test("input-heavy intake sheets surface current context and smarter defaults", (
|
|||||||
assert.match(uploadVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "本地视频"\)/);
|
assert.match(uploadVideo, /const titlePlaceholder = recommendManualIntakeTitle\(project, defaultPlatform, "本地视频"\)/);
|
||||||
assert.match(uploadVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
assert.match(uploadVideo, /renderIntakeActionContextHtml\(project\.id, defaultAssistantId\)/);
|
||||||
assert.match(uploadVideo, /placeholder: titlePlaceholder/);
|
assert.match(uploadVideo, /placeholder: titlePlaceholder/);
|
||||||
|
assert.match(uploadVideo, /bindActionContextRecommendation\(fields, \{ defaultAssistantId \}\);/);
|
||||||
assert.match(uploadVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "本地视频", \{ defaultPlatform: "douyin" \}\);/);
|
assert.match(uploadVideo, /onOpen:\s*\(\{ fields \}\) => \{\s*bindManualIntakeTitleRecommendation\(fields, "本地视频", \{ defaultPlatform: "douyin" \}\);/);
|
||||||
assert.match(generateCopy, /label: "当前上下文", type: "html"/);
|
assert.match(generateCopy, /label: "当前上下文", type: "html"/);
|
||||||
assert.match(generateCopy, /renderIntakeActionContextHtml\(project\?\.id \|\| "", assistant\.id\)/);
|
assert.match(generateCopy, /renderIntakeActionContextHtml\(project\?\.id \|\| "", assistant\.id\)/);
|
||||||
|
|||||||
Reference in New Issue
Block a user