feat: 完善智能体图片聊天与会话恢复
- 增加私有图片上传、绑定、历史回显与生命周期清理 - 支持输入草稿恢复、图片交互和模型图片能力约束 - 修复旧脏会话幂等删除与前端会话恢复
This commit is contained in:
@@ -42,6 +42,12 @@ const selectedKnowledge = computed(() => {
|
||||
|
||||
const activeBaseTab = ref<'basic' | 'interaction'>('basic');
|
||||
const interactionForm = ref<InstanceType<typeof AgentInteractionForm>>();
|
||||
const selectedModel = computed(() =>
|
||||
props.models.find((item) => item.value === String(props.state.agent.modelId)),
|
||||
);
|
||||
const tryoutImageEnabled = computed(() =>
|
||||
Boolean(selectedModel.value?.raw?.supportImage),
|
||||
);
|
||||
|
||||
function isInteractionIssue(issue?: AgentValidationIssue) {
|
||||
return issue?.field?.startsWith('interaction.');
|
||||
@@ -95,6 +101,7 @@ const selectedToolOptions = computed(() => {
|
||||
<template v-if="state.panelMode === 'tryout'">
|
||||
<AgentTryoutPanel
|
||||
:agent="state.agent"
|
||||
:image-enabled="tryoutImageEnabled"
|
||||
:tool-bindings="state.toolBindings"
|
||||
:knowledge-bindings="state.knowledgeBindings"
|
||||
@close="emit('closeTryout')"
|
||||
|
||||
@@ -18,6 +18,8 @@ import { BrushCleaning } from '@easyflow/icons';
|
||||
import { ElButton, ElMessage } from 'element-plus';
|
||||
|
||||
import AiChatPanel from '#/components/ai-chat/AiChatPanel.vue';
|
||||
import { loadAgentChatImage } from '#/components/ai-chat/mediaApi';
|
||||
import { useAgentComposerDraft } from '#/components/ai-chat/useAgentComposerDraft';
|
||||
|
||||
import { approveAgentRun, rejectAgentRun } from '../api';
|
||||
import { useAgentTryoutStream } from '../composables/useAgentTryoutStream';
|
||||
@@ -26,6 +28,7 @@ import AgentWelcomeState from './AgentWelcomeState.vue';
|
||||
|
||||
const props = defineProps<{
|
||||
agent: AgentInfo;
|
||||
imageEnabled?: boolean;
|
||||
knowledgeBindings: AgentKnowledgeBinding[];
|
||||
toolBindings: AgentToolBinding[];
|
||||
}>();
|
||||
@@ -45,6 +48,7 @@ const {
|
||||
stop,
|
||||
} = useAgentTryoutStream();
|
||||
const approvalLoading = ref(false);
|
||||
const composer = useAgentComposerDraft('DRAFT');
|
||||
const interactionDisplay = computed(() =>
|
||||
resolveInteractionDisplay(props.agent),
|
||||
);
|
||||
@@ -58,18 +62,27 @@ function getDraftContext() {
|
||||
}
|
||||
|
||||
function syncCurrentDraftContext(restore = false) {
|
||||
syncDraftContext(getDraftContext(), restore);
|
||||
syncDraftContext(getDraftContext(), restore, composer.sessionId.value);
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
syncCurrentDraftContext(true);
|
||||
});
|
||||
async function activateComposer() {
|
||||
const agentId = String(props.agent.id || '');
|
||||
if (!agentId) return;
|
||||
try {
|
||||
await composer.activate(agentId, `agent-draft-${agentId}`);
|
||||
syncCurrentDraftContext(true);
|
||||
} catch (error) {
|
||||
ElMessage.warning(
|
||||
error instanceof Error ? error.message : '输入草稿恢复失败',
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
onMounted(() => void activateComposer());
|
||||
|
||||
watch(
|
||||
() => [props.agent.id, props.agent.localId],
|
||||
() => {
|
||||
syncCurrentDraftContext(true);
|
||||
},
|
||||
() => void activateComposer(),
|
||||
);
|
||||
|
||||
watch(
|
||||
@@ -82,12 +95,35 @@ watch(
|
||||
|
||||
async function handleSend(prompt: string) {
|
||||
if (loading.value || approvalLoading.value) return;
|
||||
if (composer.images.uploading.value) {
|
||||
ElMessage.warning('图片上传完成后再发送');
|
||||
return;
|
||||
}
|
||||
const failedImage = composer.images.items.value.find(
|
||||
(item) => item.status === 'error',
|
||||
);
|
||||
if (failedImage) {
|
||||
ElMessage.error(failedImage.error || '请处理上传失败的图片');
|
||||
return;
|
||||
}
|
||||
await composer.flush();
|
||||
await sendDraft({
|
||||
...getDraftContext(),
|
||||
prompt,
|
||||
imageUploadIds: composer.images.uploadIds.value,
|
||||
images: composer.images.readyItems.value.map((item) => ({ ...item })),
|
||||
sessionId: composer.sessionId.value,
|
||||
onAccepted: () =>
|
||||
composer.markAccepted().catch(() => {
|
||||
ElMessage.warning('消息已发送,草稿将在过期后自动清理');
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
function handleDraftTextInput() {
|
||||
composer.scheduleSave();
|
||||
}
|
||||
|
||||
function handleSuggestedQuestion(question: string) {
|
||||
void handleSend(question);
|
||||
}
|
||||
@@ -137,12 +173,49 @@ function handleSelectNextVariant(item: ChatTimelineMessageItem) {
|
||||
async function handleClearSession() {
|
||||
try {
|
||||
await clearDraftSession();
|
||||
await composer.clear();
|
||||
await activateComposer();
|
||||
ElMessage.success('已清理会话');
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '清理会话失败');
|
||||
}
|
||||
}
|
||||
|
||||
async function handleAddFiles(files: File[]) {
|
||||
if (!props.agent.id) {
|
||||
ElMessage.warning('请先保存智能体');
|
||||
return;
|
||||
}
|
||||
await composer.ensureSession();
|
||||
const rejected = await composer.images.addFiles(files, {
|
||||
agentId: String(props.agent.id),
|
||||
mode: 'DRAFT',
|
||||
sessionId: composer.sessionId.value,
|
||||
});
|
||||
if (rejected > 0) {
|
||||
ElMessage.warning('每次最多添加 5 张图片');
|
||||
}
|
||||
composer.scheduleSave();
|
||||
}
|
||||
|
||||
async function handleRetryImage(item: any) {
|
||||
await composer.images.retry(item, {
|
||||
agentId: String(props.agent.id),
|
||||
mode: 'DRAFT',
|
||||
sessionId: composer.sessionId.value,
|
||||
});
|
||||
composer.scheduleSave();
|
||||
}
|
||||
|
||||
async function handleRemoveImage(item: any) {
|
||||
try {
|
||||
await composer.images.remove(item);
|
||||
composer.scheduleSave();
|
||||
} catch (error) {
|
||||
ElMessage.error(error instanceof Error ? error.message : '图片删除失败');
|
||||
}
|
||||
}
|
||||
|
||||
function handleStop() {
|
||||
if (!loading.value) {
|
||||
return;
|
||||
@@ -189,14 +262,22 @@ async function handleReject(payload: ChatTimelineToolApprovalPayload) {
|
||||
|
||||
<template>
|
||||
<AiChatPanel
|
||||
v-model="composer.text.value"
|
||||
:title="agent.name || '草稿试运行'"
|
||||
empty-text="输入问题试运行当前智能体"
|
||||
closable
|
||||
:messages="[]"
|
||||
:loading="loading"
|
||||
:images="composer.images.items.value"
|
||||
:image-enabled="imageEnabled"
|
||||
:image-loader="loadAgentChatImage"
|
||||
:placeholder="interactionDisplay.inputPlaceholder"
|
||||
:approval-loading="approvalLoading"
|
||||
@send="handleSend"
|
||||
@update:model-value="handleDraftTextInput"
|
||||
@add-files="handleAddFiles"
|
||||
@remove-image="handleRemoveImage"
|
||||
@retry-image="handleRetryImage"
|
||||
@stop="handleStop"
|
||||
@approve="handleApprove"
|
||||
@reject="handleReject"
|
||||
@@ -226,6 +307,7 @@ async function handleReject(payload: ChatTimelineToolApprovalPayload) {
|
||||
<ChatTimeline
|
||||
v-else
|
||||
:items="timelineItems"
|
||||
:image-loader="loadAgentChatImage"
|
||||
empty-text="输入问题试运行当前智能体"
|
||||
:approval-loading="approvalLoading"
|
||||
:copyable="canCopyMessage"
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
import type {
|
||||
ChatImageAttachment,
|
||||
ChatTimelineItem,
|
||||
ChatTimelineKnowledgeHit,
|
||||
ChatTimelineMessageItem,
|
||||
ChatTimelineToolStatus,
|
||||
} from '@easyflow/common-ui';
|
||||
import {ChatTimelineBuilder} from '@easyflow/common-ui';
|
||||
import { ChatTimelineBuilder } from '@easyflow/common-ui';
|
||||
|
||||
interface AgentTryoutRuntimeEvent {
|
||||
createdAt: number;
|
||||
@@ -25,6 +26,7 @@ interface AgentTryoutRawVariant {
|
||||
|
||||
interface AgentTryoutRawRound {
|
||||
createdAt: number;
|
||||
images?: ChatImageAttachment[];
|
||||
prompt: string;
|
||||
roundId: string;
|
||||
selectedVariantIndex: number;
|
||||
@@ -110,7 +112,9 @@ function createVariant(variantIndex: number): AgentTryoutRawVariant {
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeRuntimeEvent(value: any): AgentTryoutRuntimeEvent | undefined {
|
||||
function normalizeRuntimeEvent(
|
||||
value: any,
|
||||
): AgentTryoutRuntimeEvent | undefined {
|
||||
if (!value || typeof value !== 'object') {
|
||||
return undefined;
|
||||
}
|
||||
@@ -135,8 +139,9 @@ function normalizeVariant(value: any, index: number) {
|
||||
? value.runtimeEvents
|
||||
.map((item: any) => normalizeRuntimeEvent(item))
|
||||
.filter(
|
||||
(item: AgentTryoutRuntimeEvent | undefined): item is AgentTryoutRuntimeEvent =>
|
||||
Boolean(item),
|
||||
(
|
||||
item: AgentTryoutRuntimeEvent | undefined,
|
||||
): item is AgentTryoutRuntimeEvent => Boolean(item),
|
||||
)
|
||||
: [];
|
||||
return {
|
||||
@@ -157,7 +162,8 @@ function normalizeRound(value: any): AgentTryoutRawRound | undefined {
|
||||
}
|
||||
const prompt = asText(value.prompt);
|
||||
const roundId = asText(value.roundId);
|
||||
if (!prompt || !roundId) {
|
||||
const images = Array.isArray(value.images) ? value.images.slice(0, 5) : [];
|
||||
if ((!prompt && images.length === 0) || !roundId) {
|
||||
return undefined;
|
||||
}
|
||||
const variants = Array.isArray(value.variants)
|
||||
@@ -174,6 +180,7 @@ function normalizeRound(value: any): AgentTryoutRawRound | undefined {
|
||||
);
|
||||
return {
|
||||
createdAt: Number(value.createdAt || Date.now()),
|
||||
images,
|
||||
prompt,
|
||||
roundId,
|
||||
selectedVariantIndex,
|
||||
@@ -210,7 +217,10 @@ function restoreSession(mode: string, sessionId: string) {
|
||||
.map((item) => normalizeRound(item))
|
||||
.filter((item): item is AgentTryoutRawRound => Boolean(item))
|
||||
: [];
|
||||
memorySessions.set(key, rounds.map((item) => clone(item)));
|
||||
memorySessions.set(
|
||||
key,
|
||||
rounds.map((item) => clone(item)),
|
||||
);
|
||||
return rounds;
|
||||
} catch {
|
||||
return [];
|
||||
@@ -228,7 +238,10 @@ function persistSession(
|
||||
sessionId,
|
||||
version: STORAGE_VERSION,
|
||||
};
|
||||
memorySessions.set(key, snapshot.rounds.map((item) => clone(item)));
|
||||
memorySessions.set(
|
||||
key,
|
||||
snapshot.rounds.map((item) => clone(item)),
|
||||
);
|
||||
const storage = safeSessionStorage();
|
||||
if (!storage) {
|
||||
return;
|
||||
@@ -269,7 +282,9 @@ function visibleText(item: ChatTimelineMessageItem) {
|
||||
.join('');
|
||||
}
|
||||
|
||||
function isUserMessage(item: ChatTimelineItem): item is ChatTimelineMessageItem {
|
||||
function isUserMessage(
|
||||
item: ChatTimelineItem,
|
||||
): item is ChatTimelineMessageItem {
|
||||
return item.type === 'message' && item.role === 'user';
|
||||
}
|
||||
|
||||
@@ -326,7 +341,10 @@ function normalizeAssistantPartIds(
|
||||
const segment = assistantSegmentIndex(items, roundId);
|
||||
const latest = [...items]
|
||||
.reverse()
|
||||
.find((item): item is ChatTimelineMessageItem => isAssistantMessage(item) && item.roundId === roundId);
|
||||
.find(
|
||||
(item): item is ChatTimelineMessageItem =>
|
||||
isAssistantMessage(item) && item.roundId === roundId,
|
||||
);
|
||||
if (!latest) {
|
||||
return;
|
||||
}
|
||||
@@ -468,7 +486,9 @@ function projectEventToTimeline(
|
||||
metadata: payload.metadata,
|
||||
requestId: asText(payload.requestId),
|
||||
resumeToken: asText(payload.resumeToken),
|
||||
toolCallId: asText(payload.toolCallId ?? payload.tool_call_id ?? payload.id),
|
||||
toolCallId: asText(
|
||||
payload.toolCallId ?? payload.tool_call_id ?? payload.id,
|
||||
),
|
||||
toolDisplayName: asText(payload.toolDisplayName),
|
||||
toolName: asText(payload.toolName),
|
||||
toolType: asText(payload.toolType),
|
||||
@@ -482,7 +502,9 @@ function projectEventToTimeline(
|
||||
ChatTimelineBuilder.markToolApproving(items, {
|
||||
requestId: asText(payload.requestId),
|
||||
resumeToken: asText(payload.resumeToken),
|
||||
toolCallId: asText(payload.toolCallId ?? payload.tool_call_id ?? payload.id),
|
||||
toolCallId: asText(
|
||||
payload.toolCallId ?? payload.tool_call_id ?? payload.id,
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -491,7 +513,9 @@ function projectEventToTimeline(
|
||||
reason: asText(payload.reason),
|
||||
requestId: asText(payload.requestId),
|
||||
resumeToken: asText(payload.resumeToken),
|
||||
toolCallId: asText(payload.toolCallId ?? payload.tool_call_id ?? payload.id),
|
||||
toolCallId: asText(
|
||||
payload.toolCallId ?? payload.tool_call_id ?? payload.id,
|
||||
),
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -508,8 +532,12 @@ function projectEventToTimeline(
|
||||
ChatTimelineBuilder.upsertToolCall(items, {
|
||||
input: payload.input ?? payload.toolInput,
|
||||
output: asyncTool
|
||||
? payload.summary ?? payload.label ?? payload.output ?? payload.result ?? payload.text
|
||||
: payload.output ?? payload.result ?? payload.text,
|
||||
? (payload.summary ??
|
||||
payload.label ??
|
||||
payload.output ??
|
||||
payload.result ??
|
||||
payload.text)
|
||||
: (payload.output ?? payload.result ?? payload.text),
|
||||
status: asyncTool
|
||||
? asyncToolTimelineStatus(payload)
|
||||
: type === 'TOOL_RESULT'
|
||||
@@ -521,8 +549,17 @@ function projectEventToTimeline(
|
||||
variantIndex,
|
||||
'knowledge-retrieval',
|
||||
),
|
||||
toolCallId: asText(payload.toolCallId ?? payload.taskId ?? payload.tool_call_id ?? payload.id),
|
||||
toolName: asyncTool ? displayToolName : isHiddenToolName(rawToolName) ? rawToolName : displayToolName,
|
||||
toolCallId: asText(
|
||||
payload.toolCallId ??
|
||||
payload.taskId ??
|
||||
payload.tool_call_id ??
|
||||
payload.id,
|
||||
),
|
||||
toolName: asyncTool
|
||||
? displayToolName
|
||||
: isHiddenToolName(rawToolName)
|
||||
? rawToolName
|
||||
: displayToolName,
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -568,7 +605,9 @@ function projectEventToTimeline(
|
||||
}
|
||||
}
|
||||
|
||||
function asyncToolTimelineStatus(payload: Record<string, unknown>): ChatTimelineToolStatus {
|
||||
function asyncToolTimelineStatus(
|
||||
payload: Record<string, unknown>,
|
||||
): ChatTimelineToolStatus {
|
||||
const status = asText(payload.status).toUpperCase();
|
||||
if (status === 'SUCCEEDED') return 'success';
|
||||
if (status === 'FAILED' || status === 'TIMEOUT' || status === 'CANCELLED') {
|
||||
@@ -612,7 +651,10 @@ export function useAgentTryoutRawRounds(options: {
|
||||
|
||||
function schedulePersist() {
|
||||
const key = storageKey(options.mode, options.sessionId);
|
||||
memorySessions.set(key, [...rounds.values()].map((item) => clone(item)));
|
||||
memorySessions.set(
|
||||
key,
|
||||
[...rounds.values()].map((item) => clone(item)),
|
||||
);
|
||||
if (persistTimer) {
|
||||
return;
|
||||
}
|
||||
@@ -630,11 +672,12 @@ export function useAgentTryoutRawRounds(options: {
|
||||
removeStoredSession(options.mode, options.sessionId);
|
||||
}
|
||||
|
||||
function createRound(prompt: string) {
|
||||
function createRound(prompt: string, images: ChatImageAttachment[] = []) {
|
||||
const now = Date.now();
|
||||
const roundId = createRoundId();
|
||||
rounds.set(roundId, {
|
||||
createdAt: now,
|
||||
images: clone(images),
|
||||
prompt,
|
||||
roundId,
|
||||
selectedVariantIndex: 1,
|
||||
@@ -738,6 +781,7 @@ export function useAgentTryoutRawRounds(options: {
|
||||
for (const round of sortedRounds(rounds)) {
|
||||
ChatTimelineBuilder.appendUserMessage(items, round.prompt, {
|
||||
id: `user-${round.roundId}`,
|
||||
images: round.images,
|
||||
roundId: round.roundId,
|
||||
});
|
||||
const variant = selectedVariant(round);
|
||||
@@ -745,7 +789,12 @@ export function useAgentTryoutRawRounds(options: {
|
||||
continue;
|
||||
}
|
||||
for (const event of variant.runtimeEvents) {
|
||||
projectEventToTimeline(items, event, round.roundId, variant.variantIndex);
|
||||
projectEventToTimeline(
|
||||
items,
|
||||
event,
|
||||
round.roundId,
|
||||
variant.variantIndex,
|
||||
);
|
||||
}
|
||||
if (variant.status === 'completed' || variant.status === 'error') {
|
||||
ChatTimelineBuilder.finalize(items);
|
||||
@@ -761,10 +810,7 @@ export function useAgentTryoutRawRounds(options: {
|
||||
return items;
|
||||
}
|
||||
|
||||
function selectVariant(
|
||||
roundId: string,
|
||||
direction: 'next' | 'previous',
|
||||
) {
|
||||
function selectVariant(roundId: string, direction: 'next' | 'previous') {
|
||||
const round = rounds.get(roundId);
|
||||
if (!round) {
|
||||
return;
|
||||
|
||||
@@ -1,19 +1,24 @@
|
||||
import type {ServerSentEventMessage} from 'fetch-event-stream';
|
||||
import type { ServerSentEventMessage } from 'fetch-event-stream';
|
||||
|
||||
import type {
|
||||
ChatImageAttachment,
|
||||
ChatTimelineItem as ChatTimelineItemType,
|
||||
ChatTimelineMessageItem,
|
||||
} from '@easyflow/common-ui';
|
||||
import {ChatTimelineBuilder} from '@easyflow/common-ui';
|
||||
import { ChatTimelineBuilder } from '@easyflow/common-ui';
|
||||
|
||||
import type {AgentInfo, AgentKnowledgeBinding, AgentToolBinding,} from '../types';
|
||||
import type {
|
||||
AgentInfo,
|
||||
AgentKnowledgeBinding,
|
||||
AgentToolBinding,
|
||||
} from '../types';
|
||||
|
||||
import {ref} from 'vue';
|
||||
import { ref } from 'vue';
|
||||
|
||||
import {sseClient} from '#/api/request';
|
||||
import { sseClient } from '#/api/request';
|
||||
|
||||
import {clearAgentDraftSession} from '../api';
|
||||
import {useAgentTryoutRawRounds} from './useAgentTryoutRawRounds';
|
||||
import { clearAgentDraftSession } from '../api';
|
||||
import { useAgentTryoutRawRounds } from './useAgentTryoutRawRounds';
|
||||
|
||||
function resolveDraftSessionId(agent: AgentInfo) {
|
||||
return `agent-draft-${agent.id || agent.localId || 'unsaved'}`;
|
||||
@@ -99,8 +104,13 @@ export function useAgentTryoutStream() {
|
||||
timelineItems.value = rawRounds?.buildTimelineItems() || [];
|
||||
}
|
||||
|
||||
function syncDraftContext(payload: DraftRuntimeContext, restore = false) {
|
||||
const sessionId = resolveDraftSessionId(payload.agent);
|
||||
function syncDraftContext(
|
||||
payload: DraftRuntimeContext,
|
||||
restore = false,
|
||||
requestedSessionId?: string,
|
||||
) {
|
||||
const sessionId =
|
||||
requestedSessionId || resolveDraftSessionId(payload.agent);
|
||||
const sessionChanged = activeSessionId !== sessionId;
|
||||
activeSessionId = sessionId;
|
||||
if (!rawRounds || sessionChanged) {
|
||||
@@ -206,26 +216,44 @@ export function useAgentTryoutStream() {
|
||||
|
||||
async function runDraft(payload: {
|
||||
agent: AgentInfo;
|
||||
images?: ChatImageAttachment[];
|
||||
imageUploadIds?: string[];
|
||||
knowledgeBindings: AgentKnowledgeBinding[];
|
||||
onAccepted?: () => void | Promise<void>;
|
||||
prompt: string;
|
||||
sessionId?: string;
|
||||
toolBindings: AgentToolBinding[];
|
||||
}) {
|
||||
syncDraftContext(payload);
|
||||
syncDraftContext(payload, false, payload.sessionId);
|
||||
if (!rawRounds) {
|
||||
return;
|
||||
}
|
||||
activeRoundId = rawRounds.createRound(payload.prompt);
|
||||
activeRoundId = rawRounds.createRound(payload.prompt, payload.images);
|
||||
rebuildTimeline();
|
||||
loading.value = true;
|
||||
userStopped = false;
|
||||
let accepted = false;
|
||||
await sseClient.post(
|
||||
'/api/v1/agent/chat/draft',
|
||||
{
|
||||
...payload,
|
||||
agent: payload.agent,
|
||||
imageUploadIds: payload.imageUploadIds,
|
||||
knowledgeBindings: payload.knowledgeBindings,
|
||||
prompt: payload.prompt,
|
||||
sessionId: activeSessionId,
|
||||
toolBindings: payload.toolBindings,
|
||||
},
|
||||
{
|
||||
onMessage: handleMessage,
|
||||
onMessage: (message) => {
|
||||
const envelope = resolveEnvelope(parseEventData(message));
|
||||
const domain = String(envelope.domain || '').toUpperCase();
|
||||
const type = String(envelope.type || '').toUpperCase();
|
||||
if (!accepted && domain === 'SYSTEM' && type === 'INPUT_ACCEPTED') {
|
||||
accepted = true;
|
||||
void payload.onAccepted?.();
|
||||
}
|
||||
handleMessage(message);
|
||||
},
|
||||
onError: (error) => {
|
||||
if (shouldIgnoreStoppedError(error)) {
|
||||
return;
|
||||
@@ -257,8 +285,12 @@ export function useAgentTryoutStream() {
|
||||
|
||||
async function sendDraft(payload: {
|
||||
agent: AgentInfo;
|
||||
images?: ChatImageAttachment[];
|
||||
imageUploadIds?: string[];
|
||||
knowledgeBindings: AgentKnowledgeBinding[];
|
||||
onAccepted?: () => void | Promise<void>;
|
||||
prompt: string;
|
||||
sessionId?: string;
|
||||
toolBindings: AgentToolBinding[];
|
||||
}) {
|
||||
await runDraft(payload);
|
||||
|
||||
Reference in New Issue
Block a user