dify/web/service/debug.ts
Crazywoola 0bfbd2061e
feat: enhance go to anything (#32130)
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-06-04 11:06:17 +00:00

192 lines
6.0 KiB
TypeScript

import type { Viewport } from 'reactflow'
import type { IOnCompleted, IOnData, IOnError, IOnMessageReplace } from './base'
import type { Edge, Node } from '@/app/components/workflow/types'
import type { ChatPromptConfig, CompletionPromptConfig } from '@/models/debug'
import type { AppModeEnum, ModelModeType } from '@/types/app'
import { get, post, ssePost } from './base'
type BasicAppFirstRes = {
prompt: string
variables: string[]
opening_statement: string
error?: string
}
export type GenRes = {
modified: string
message?: string // tip for human
variables?: string[] // only for basic app first time rule
opening_statement?: string // only for basic app first time rule
error?: string
}
export const stopChatMessageResponding = async (appId: string, taskId: string) => {
return post(`apps/${appId}/chat-messages/${taskId}/stop`)
}
export const sendCompletionMessage = async (appId: string, body: Record<string, any>, { onData, onCompleted, onError, onMessageReplace }: {
onData: IOnData
onCompleted: IOnCompleted
onError: IOnError
onMessageReplace: IOnMessageReplace
}) => {
return ssePost(`apps/${appId}/completion-messages`, {
body: {
...body,
response_mode: 'streaming',
},
}, { onData, onCompleted, onError, onMessageReplace })
}
export const fetchSuggestedQuestions = (appId: string, messageId: string, getAbortController?: any) => {
return get(
`apps/${appId}/chat-messages/${messageId}/suggested-questions`,
{},
{
getAbortController,
},
)
}
export const fetchConversationMessages = (appId: string, conversation_id: string, getAbortController?: any) => {
return get(`apps/${appId}/chat-messages`, {
params: {
conversation_id,
},
}, {
getAbortController,
})
}
export const generateBasicAppFirstTimeRule = (body: Record<string, any>) => {
return post<BasicAppFirstRes>('/rule-generate', {
body,
})
}
export const generateRule = (body: Record<string, any>) => {
return post<GenRes>('/instruction-generate', {
body,
})
}
/**
* One structured error from the workflow generator backend. ``code`` is a
* stable machine-readable identifier the frontend maps to localised copy
* via the ``workflowGenerator.errors.<code>`` i18n keys; ``detail`` is the
* raw English diagnostic; ``node_id`` is set when the error is tied to a
* specific node (the preview canvas can highlight it).
*
* Stable codes — adding a new one without updating the i18n map will fall
* back to ``detail`` and that's fine, but every value listed here MUST
* exist in both en-US and zh-Hans.
*/
// Not exported: knip flags unused exports and the modal looks codes up by
// string interpolation (``workflowGenerator.errors.${code}``) rather than
// importing the union. Kept here so the ``GenerateWorkflowResponse``
// definition below documents the contract in one place.
type GenerateWorkflowErrorCode
= | 'INVALID_JSON'
| 'INVALID_SCHEMA'
| 'EMPTY_INSTRUCTION'
| 'EMPTY_PLAN'
| 'UNKNOWN_NODE_REFERENCE'
| 'INVALID_CONTAINER'
| 'UNRESOLVED_REFERENCE'
| 'UNKNOWN_TOOL'
| 'MISSING_TERMINAL'
| 'MISSING_START'
| 'DANGLING_EDGE'
| 'MODEL_ERROR'
type GenerateWorkflowError = {
code: GenerateWorkflowErrorCode | string
detail: string
node_id?: string
}
export type GenerateWorkflowResponse = {
graph: {
nodes: Node[]
edges: Edge[]
viewport: Viewport
}
message?: string
/**
* Planner-picked product-style name (e.g. "URL Summarizer"). Empty when
* the planner omits it; the caller (applyToNewApp) supplies a fallback.
*/
app_name?: string
/**
* Planner-picked emoji that captures the workflow's purpose. Empty when
* the planner omits it; the caller supplies a 🤖 fallback.
*/
icon?: string
/** Human-readable concatenation of ``errors[].detail``. "" on success. */
error?: string
/** Structured errors with stable codes for FE-localised mapping. [] on success. */
errors?: GenerateWorkflowError[]
}
export type GenerateWorkflowBody = {
mode: 'workflow' | 'advanced-chat'
instruction: string
ideal_output?: string
model_config: { provider: string, name: string, mode: string, completion_params?: Record<string, unknown> }
/**
* Existing draft graph for the cmd+k `/refine` flow. When present the
* backend refines this graph instead of generating from scratch. Omitted
* for `/create`.
*/
current_graph?: {
nodes: Node[]
edges: Edge[]
viewport?: Viewport
}
}
export type GenerateWorkflowOptions = {
/**
* Callback receiving the ``AbortController`` for the in-flight request.
* The caller stores it and aborts on modal close / second submit / hard
* timeout. Pattern mirrors ``fetchSuggestedQuestions`` / ``fetchConversationMessages``
* which already thread this through ``base.ts``.
*/
getAbortController?: (controller: AbortController) => void
}
export const generateWorkflow = (body: GenerateWorkflowBody, options?: GenerateWorkflowOptions) => {
// Only pass the third argument when the caller actually supplied one —
// otherwise the shared ``post()`` wrapper sees ``undefined`` and that
// breaks tests asserting the 2-arg call shape, with no behaviour upside.
if (options?.getAbortController) {
return post<GenerateWorkflowResponse>('/workflow-generate', { body }, {
getAbortController: options.getAbortController,
})
}
return post<GenerateWorkflowResponse>('/workflow-generate', { body })
}
export const fetchPromptTemplate = ({
appMode,
mode,
modelName,
hasSetDataSet,
}: { appMode: AppModeEnum, mode: ModelModeType, modelName: string, hasSetDataSet: boolean }) => {
return get<Promise<{ chat_prompt_config: ChatPromptConfig, completion_prompt_config: CompletionPromptConfig, stop: [] }>>('/app/prompt-templates', {
params: {
app_mode: appMode,
model_mode: mode,
model_name: modelName,
has_context: hasSetDataSet,
},
})
}
export const fetchTextGenerationMessage = ({
appId,
messageId,
}: { appId: string, messageId: string }) => {
return get<Promise<any>>(`/apps/${appId}/messages/${messageId}`)
}