Skip to content

Commit

Permalink
🐛 (dify) Fix conversation ID being overwritten randomly
Browse files Browse the repository at this point in the history
Closes #1452
  • Loading branch information
baptisteArno committed Apr 23, 2024
1 parent fadcd3a commit 7f39d5a
Show file tree
Hide file tree
Showing 9 changed files with 132 additions and 42 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,13 @@ export const ZodFieldLayout = ({
<DropdownList
currentItem={data ?? layout?.defaultValue}
onItemSelect={onDataChange}
items={innerSchema._def.values}
items={
layout?.hiddenItems
? innerSchema._def.values.filter(
(v: any) => !layout.hiddenItems.includes(v)
)
: innerSchema._def.values
}
label={layout?.label}
helperText={
layout?.helperText ? (
Expand Down
15 changes: 15 additions & 0 deletions apps/docs/editor/blocks/integrations/dify-ai.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
title: Dify.AI
---

This block allows you to integrate your Dify.AI's assistant in your typebot.

## Create Chat Message

This action sends a user message to your agent. Then you can save `Answer` to a variable and display it in your typebot.

You are expected to provide the following parameters:

- `Query`: The user message you want to send to your agent.
- `Conversation ID`: The conversation ID you want to use for this message. If you don't provide one, a new conversation will be created. This variable content will be updated automatically if a new conversation is created.
- `User`: The user email used to identify the user in the conversation.
3 changes: 2 additions & 1 deletion apps/docs/mint.json
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,8 @@
"editor/blocks/integrations/zemantic-ai",
"editor/blocks/integrations/mistral",
"editor/blocks/integrations/elevenlabs",
"editor/blocks/integrations/anthropic"
"editor/blocks/integrations/anthropic",
"editor/blocks/integrations/dify-ai"
]
}
]
Expand Down
6 changes: 5 additions & 1 deletion apps/docs/openapi/builder.json
Original file line number Diff line number Diff line change
Expand Up @@ -19591,7 +19591,7 @@
"query": {
"type": "string"
},
"conversation_id": {
"conversationVariableId": {
"type": "string"
},
"user": {
Expand Down Expand Up @@ -19629,6 +19629,10 @@
}
}
}
},
"conversation_id": {
"type": "string",
"description": "Deprecated, use `conversationVariableId` instead"
}
},
"required": [
Expand Down
6 changes: 5 additions & 1 deletion apps/docs/openapi/viewer.json
Original file line number Diff line number Diff line change
Expand Up @@ -10419,7 +10419,7 @@
"query": {
"type": "string"
},
"conversation_id": {
"conversationVariableId": {
"type": "string"
},
"user": {
Expand Down Expand Up @@ -10457,6 +10457,10 @@
}
}
}
},
"conversation_id": {
"type": "string",
"description": "Deprecated, use `conversationVariableId` instead"
}
},
"required": [
Expand Down
89 changes: 61 additions & 28 deletions packages/forge/blocks/difyAi/actions/createChatMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,45 +4,67 @@ import { auth } from '../auth'
import { defaultBaseUrl } from '../constants'
import { Chunk } from '../types'
import ky from 'ky'
import { deprecatedCreateChatMessageOptions } from '../deprecated'

export const createChatMessage = createAction({
auth,
name: 'Create Chat Message',
options: option.object({
query: option.string.layout({
label: 'Query',
placeholder: 'User input/question content',
inputType: 'textarea',
isRequired: true,
}),
conversation_id: option.string.layout({
label: 'Conversation ID',
moreInfoTooltip:
'Used to remember the conversation with the user. If empty, a new conversation id is created.',
}),
user: option.string.layout({
label: 'User',
moreInfoTooltip:
'The user identifier, defined by the developer, must ensure uniqueness within the app.',
}),
inputs: option.keyValueList.layout({
accordion: 'Inputs',
}),
responseMapping: option
.saveResponseArray(['Answer', 'Conversation ID', 'Total Tokens'] as const)
.layout({
accordion: 'Save response',
options: option
.object({
query: option.string.layout({
label: 'Query',
placeholder: 'User input/question content',
inputType: 'textarea',
isRequired: true,
}),
}),

conversationVariableId: option.string.layout({
label: 'Conversation ID',
moreInfoTooltip:
'Used to remember the conversation with the user. If empty, a new conversation ID is created.',
inputType: 'variableDropdown',
}),
user: option.string.layout({
label: 'User',
moreInfoTooltip:
'The user identifier, defined by the developer, must ensure uniqueness within the app.',
}),
inputs: option.keyValueList.layout({
accordion: 'Inputs',
}),
responseMapping: option
.saveResponseArray(
['Answer', 'Conversation ID', 'Total Tokens'] as const,
{
item: {
hiddenItems: ['Conversation ID'],
},
}
)
.layout({
accordion: 'Save response',
}),
})
.merge(deprecatedCreateChatMessageOptions),
getSetVariableIds: ({ responseMapping }) =>
responseMapping?.map((r) => r.variableId).filter(isDefined) ?? [],
run: {
server: async ({
credentials: { apiEndpoint, apiKey },
options: { conversation_id, query, user, inputs, responseMapping },
options: {
conversationVariableId,
conversation_id,
query,
user,
inputs,
responseMapping,
},
variables,
logs,
}) => {
const existingDifyConversationId = conversationVariableId
? variables.get(conversationVariableId)
: conversation_id
try {
const response = await ky(
(apiEndpoint ?? defaultBaseUrl) + '/v1/chat-messages',
Expand All @@ -63,7 +85,7 @@ export const createChatMessage = createAction({
}, {}) ?? {},
query,
response_mode: 'streaming',
conversation_id,
conversation_id: existingDifyConversationId,
user,
files: [],
}),
Expand Down Expand Up @@ -139,9 +161,20 @@ export const createChatMessage = createAction({
if (item === 'Answer')
variables.set(mapping.variableId, convertNonMarkdownLinks(answer))

if (item === 'Conversation ID' && isNotEmpty(conversationId))
if (
item === 'Conversation ID' &&
isNotEmpty(conversationId) &&
isEmpty(existingDifyConversationId?.toString())
)
variables.set(mapping.variableId, conversationId)

if (
conversationVariableId &&
isNotEmpty(conversationId) &&
isEmpty(existingDifyConversationId?.toString())
)
variables.set(conversationVariableId, conversationId)

if (item === 'Total Tokens')
variables.set(mapping.variableId, totalTokens)
})
Expand Down
12 changes: 12 additions & 0 deletions packages/forge/blocks/difyAi/deprecated.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { option } from '@typebot.io/forge'

export const deprecatedCreateChatMessageOptions = option.object({
conversation_id: option.string
.layout({
label: 'Conversation ID',
moreInfoTooltip:
'Used to remember the conversation with the user. If empty, a new conversation id is created.',
isHidden: true,
})
.describe('Deprecated, use `conversationVariableId` instead'),
})
34 changes: 24 additions & 10 deletions packages/forge/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { ZodRawShape } from 'zod'
import { ZodRawShape, ZodTypeAny } from 'zod'
import { AuthDefinition, BlockDefinition, ActionDefinition } from './types'
import { z } from './zod'
import { ZodLayoutMetadata, z } from './zod'

export const variableStringSchema = z.custom<`{{${string}}}`>((val) =>
/^{{.+}}$/g.test(val as string)
Expand Down Expand Up @@ -137,17 +137,31 @@ export const option = {
z.object({ [field]: z.undefined() }),
...schemas,
]),
saveResponseArray: <I extends readonly [string, ...string[]]>(items: I) =>
saveResponseArray: <I extends readonly [string, ...string[]]>(
items: I,
layouts?: {
item?: ZodLayoutMetadata<ZodTypeAny>
variableId?: ZodLayoutMetadata<ZodTypeAny>
}
) =>
z
.array(
z.object({
item: z.enum(items).optional().layout({
placeholder: 'Select a response',
defaultValue: items[0],
}),
variableId: z.string().optional().layout({
inputType: 'variableDropdown',
}),
item: z
.enum(items)
.optional()
.layout({
...(layouts?.item ?? {}),
placeholder: 'Select a response',
defaultValue: items[0],
}),
variableId: z
.string()
.optional()
.layout({
...(layouts?.variableId ?? {}),
inputType: 'variableDropdown',
}),
})
)
.optional(),
Expand Down
1 change: 1 addition & 0 deletions packages/forge/core/zod/extendWithTypebotLayout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ export interface ZodLayoutMetadata<
moreInfoTooltip?: string
isHidden?: boolean
isDebounceDisabled?: boolean
hiddenItems?: string[]
}

declare module 'zod' {
Expand Down

0 comments on commit 7f39d5a

Please sign in to comment.