From 0b9998528f4010a5a0c9cccc1db4a1c6d1544160 Mon Sep 17 00:00:00 2001 From: hailin Date: Mon, 23 Jun 2025 13:21:43 +0800 Subject: [PATCH] . --- apps/blogai/app/[locale]/morphic/action.tsx | 175 ++++++++++---------- apps/blogai/app/[locale]/morphic/layout.tsx | 2 +- 2 files changed, 91 insertions(+), 86 deletions(-) diff --git a/apps/blogai/app/[locale]/morphic/action.tsx b/apps/blogai/app/[locale]/morphic/action.tsx index 9e9b9ab..06b419c 100644 --- a/apps/blogai/app/[locale]/morphic/action.tsx +++ b/apps/blogai/app/[locale]/morphic/action.tsx @@ -5,94 +5,18 @@ import { createStreamableValue, getMutableAIState } from 'ai/rsc' - import { ExperimentalMessage } from 'ai' import { Spinner } from '@/components/ui-v2/spinner' import { Section } from '@/components/mpv2/section' import { FollowupPanel } from '@/components/mpv2/followup-panel' import { inquire, researcher, taskManager, querySuggestor } from '@/lib/agents' -async function submit(formData?: FormData, skip?: boolean) { - 'use server' - - const aiState = getMutableAIState() - const uiStream = createStreamableUI() - const isGenerating = createStreamableValue(true) - - const messages: ExperimentalMessage[] = aiState.get() as any - const userInput = skip - ? `{"action": "skip"}` - : (formData?.get('input') as string) - const content = skip - ? userInput - : formData - ? JSON.stringify(Object.fromEntries(formData)) - : null - - if (content) { - const message = { role: 'user', content } - messages.push(message as ExperimentalMessage) - aiState.update([...(aiState.get() as any), message]) - } - - async function processEvents() { - uiStream.update() - - let action: any = { object: { next: 'proceed' } } - if (!skip) action = await taskManager(messages) - - if (action.object.next === 'inquire') { - const inquiry = await inquire(uiStream, messages) - uiStream.done() - isGenerating.done() - aiState.done([ - ...aiState.get(), - { role: 'assistant', content: `inquiry: ${inquiry?.question}` } - ]) - return - } - - let answer = '' - let errorOccurred = false - const streamText = createStreamableValue() - - while (answer.length === 0) { - const { fullResponse, hasError } = await researcher( - uiStream, - streamText, - messages - ) - answer = fullResponse - errorOccurred = hasError - } - - streamText.done() - - if (!errorOccurred) { - await querySuggestor(uiStream, messages) - - uiStream.append( -
- -
- ) - } - - isGenerating.done(false) - uiStream.done() - aiState.done([...aiState.get(), { role: 'assistant', content: answer }]) - } - - processEvents() - - return { - id: Date.now(), - isGenerating: isGenerating.value, - component: uiStream.value - } -} - -const initialAIState: ExperimentalMessage[] = [] +const initialAIState: { + role: 'user' | 'assistant' | 'system' | 'function' | 'tool' + content: string + id?: string + name?: string +}[] = [] const initialUIState: { id: number @@ -100,13 +24,94 @@ const initialUIState: { component: React.ReactNode }[] = [] +// ① 先声明 submit(不引用 AI) +let submit: any + +// ② 先生成 AI,再写 submit export const { AIProvider, useAIState, useUIState, useActions } = createAI({ - actions: { submit }, - initialAIState, - initialUIState + actions: { + submit: async function(formData?: FormData, skip?: boolean) { + 'use server' + + const aiState = getMutableAIState() // 这里用 AIProvider + const uiStream = createStreamableUI() + const isGenerating = createStreamableValue(true) + + const messages: ExperimentalMessage[] = aiState.get() as any + const userInput = skip + ? `{"action": "skip"}` + : (formData?.get('input') as string) + const content = skip + ? userInput + : formData + ? JSON.stringify(Object.fromEntries(formData)) + : null + + if (content) { + const message = { role: 'user', content } + messages.push(message as ExperimentalMessage) + aiState.update([...(aiState.get() as any), message]) + } + + async function processEvents() { + uiStream.update() + + let action: any = { object: { next: 'proceed' } } + if (!skip) action = await taskManager(messages) + + if (action.object.next === 'inquire') { + const inquiry = await inquire(uiStream, messages) + uiStream.done() + isGenerating.done() + aiState.done([ + ...aiState.get(), + { role: 'assistant', content: `inquiry: ${inquiry?.question}` } + ]) + return + } + + let answer = '' + let errorOccurred = false + const streamText = createStreamableValue() + while (answer.length === 0) { + const { fullResponse, hasError } = await researcher( + uiStream, + streamText, + messages + ) + answer = fullResponse + errorOccurred = hasError + } + streamText.done() + + if (!errorOccurred) { + await querySuggestor(uiStream, messages) + uiStream.append( +
+ +
+ ) + } + + isGenerating.done(false) + uiStream.done() + aiState.done([...aiState.get(), { role: 'assistant', content: answer }]) + } + + processEvents() + + return { + id: Date.now(), + isGenerating: isGenerating.value, + component: uiStream.value + } + } + }, + initialUIState, + initialAIState }) diff --git a/apps/blogai/app/[locale]/morphic/layout.tsx b/apps/blogai/app/[locale]/morphic/layout.tsx index 7a733f4..a9d6c1c 100644 --- a/apps/blogai/app/[locale]/morphic/layout.tsx +++ b/apps/blogai/app/[locale]/morphic/layout.tsx @@ -1,6 +1,6 @@ import type { Metadata, Viewport } from 'next' import { Inter as FontSans } from 'next/font/google' -import { AIProvider } from './action' // ⬅️ 正确导入 +import { AIProvider } from './action' import '../../globals.css' import { cn } from '@/lib/utils' import { ThemeProvider } from '@/components/mpv2/theme-provider'