From 251f5deab6135f966d2e52403e9bb107168eee46 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?F=C3=A9lix=20Malfait?= Date: Fri, 24 Apr 2026 16:58:26 +0200 Subject: [PATCH] [breaking, deploy server first] fix(ai-chat): persist providerExecuted flag on tool parts (#20030) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ## Summary Fixes Sentry errors of the form: > \`messages.3: \`tool_use\` ids were found without \`tool_result\` blocks immediately after: srvtoolu_…. Each \`tool_use\` block must have a corresponding \`tool_result\` block in the next message.\` ### Root cause When the model invokes a **provider-hosted tool** (e.g. Anthropic's native \`web_search\` — note the \`srvtoolu_\` ID prefix), the AI SDK marks the resulting \`UIMessagePart\` with \`providerExecuted: true\`. \`convertToModelMessages\` uses that flag to emit the tool_use/tool_result pair *inside the same assistant message* — the format Anthropic requires for server-side tools. Our \`AgentMessagePart\` persistence was dropping \`providerExecuted\` on the way to the DB (and re-hydration didn't know to set it). On the next turn, \`convertToModelMessages\` treated the rehydrated part as a client-side tool call, splitting it into \`assistant(tool_use)\` + \`user(tool_result)\` — which Anthropic then rejects with the error above. ### Fix - Add nullable \`providerExecuted BOOLEAN\` column on \`core.agentMessagePart\` via a fast instance command. - Surface the field on \`AgentMessagePartDTO\` (GraphQL). - Preserve it through \`mapUIMessagePartsToDBParts\` (server) and both \`mapDBPartToUIMessagePart\` mappers (server + frontend). - Include it in \`GET_CHAT_MESSAGES\` and \`GET_AGENT_TURNS\` selections. - Regenerate \`generated-metadata/graphql.ts\`. ### Backwards compatibility Existing rows have \`NULL providerExecuted\` and round-trip as the omitted flag — which is exactly the pre-fix behaviour for tool parts that were never provider-executed. Only *new* assistant messages using \`web_search\` (or other provider-hosted tools) will write \`true\`, and those are the only ones that were breaking. ## Test plan - [x] \`npx tsgo\` typecheck — server + front clean - [x] \`oxlint\` + \`prettier --check\` on all touched files — clean - [x] \`npx nx run twenty-server:database:migrate:prod\` runs the new instance command locally; \`providerExecuted\` column present on \`core.agentMessagePart\` - [x] Regenerated \`generated-metadata/graphql.ts\` — \`providerExecuted\` wired into both queries and \`AgentMessagePart\` type - [ ] Manual: start a chat with Anthropic web_search enabled, invoke the tool in turn 1, reply in turn 2 — should not throw the srvtoolu error 🤖 Generated with [Claude Code](https://claude.com/claude-code) --------- Co-authored-by: Claude Opus 4.7 (1M context) --- .../src/metadata/generated/schema.graphql | 1 + .../src/metadata/generated/schema.ts | 2 ++ .../src/metadata/generated/types.ts | 3 ++ .../src/generated-metadata/graphql.ts | 9 +++--- .../ai/graphql/queries/getAgentTurns.ts | 1 + .../ai/graphql/queries/getChatMessages.ts | 1 + .../ai/utils/mapDBPartToUIMessagePart.ts | 3 ++ ...ce-command-generation.service.spec.ts.snap | 28 +++++++++---------- ...provider-executed-to-agent-message-part.ts | 21 ++++++++++++++ .../2-2/2-2-upgrade-version-command.module.ts | 7 +++++ .../instance-commands.constant.ts | 2 ++ .../workspace-command-provider.module.ts | 2 ++ .../twenty-current-version.constant.ts | 2 +- .../twenty-next-versions.constant.ts | 2 +- .../twenty-previous-versions.constant.ts | 7 ++++- .../dtos/agent-message-part.dto.ts | 3 ++ .../entities/agent-message-part.entity.ts | 6 ++++ .../utils/mapDBPartToUIMessagePart.ts | 3 ++ .../utils/mapUIMessagePartsToDBParts.ts | 1 + ...g-sequence-runner.integration-spec.ts.snap | 2 +- 20 files changed, 84 insertions(+), 22 deletions(-) create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1777012800000-add-provider-executed-to-agent-message-part.ts create mode 100644 packages/twenty-server/src/database/commands/upgrade-version-command/2-2/2-2-upgrade-version-command.module.ts diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql index 864853139e..d124db6f1a 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.graphql +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.graphql @@ -2440,6 +2440,7 @@ type AgentMessagePart { toolInput: JSON toolOutput: JSON state: String + providerExecuted: Boolean errorMessage: String errorDetails: JSON sourceUrlSourceId: String diff --git a/packages/twenty-client-sdk/src/metadata/generated/schema.ts b/packages/twenty-client-sdk/src/metadata/generated/schema.ts index 2427a6d4f3..ea574410d5 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/schema.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/schema.ts @@ -2116,6 +2116,7 @@ export interface AgentMessagePart { toolInput?: Scalars['JSON'] toolOutput?: Scalars['JSON'] state?: Scalars['String'] + providerExecuted?: Scalars['Boolean'] errorMessage?: Scalars['String'] errorDetails?: Scalars['JSON'] sourceUrlSourceId?: Scalars['String'] @@ -5110,6 +5111,7 @@ export interface AgentMessagePartGenqlSelection{ toolInput?: boolean | number toolOutput?: boolean | number state?: boolean | number + providerExecuted?: boolean | number errorMessage?: boolean | number errorDetails?: boolean | number sourceUrlSourceId?: boolean | number diff --git a/packages/twenty-client-sdk/src/metadata/generated/types.ts b/packages/twenty-client-sdk/src/metadata/generated/types.ts index afaa0853b4..ba6a53d3e9 100644 --- a/packages/twenty-client-sdk/src/metadata/generated/types.ts +++ b/packages/twenty-client-sdk/src/metadata/generated/types.ts @@ -4809,6 +4809,9 @@ export default { "state": [ 1 ], + "providerExecuted": [ + 6 + ], "errorMessage": [ 1 ], diff --git a/packages/twenty-front/src/generated-metadata/graphql.ts b/packages/twenty-front/src/generated-metadata/graphql.ts index e14a7659d5..a64935f430 100644 --- a/packages/twenty-front/src/generated-metadata/graphql.ts +++ b/packages/twenty-front/src/generated-metadata/graphql.ts @@ -132,6 +132,7 @@ export type AgentMessagePart = { id: Scalars['UUID']; messageId: Scalars['UUID']; orderIndex: Scalars['Int']; + providerExecuted?: Maybe; providerMetadata?: Maybe; reasoningContent?: Maybe; sourceDocumentFilename?: Maybe; @@ -6103,14 +6104,14 @@ export type GetAgentTurnsQueryVariables = Exact<{ }>; -export type GetAgentTurnsQuery = { __typename?: 'Query', agentTurns: Array<{ __typename?: 'AgentTurn', id: string, threadId: string, agentId?: string | null, createdAt: string, evaluations: Array<{ __typename?: 'AgentTurnEvaluation', id: string, score: number, comment?: string | null, createdAt: string }>, messages: Array<{ __typename?: 'AgentMessage', id: string, role: string, createdAt: string, parts: Array<{ __typename?: 'AgentMessagePart', id: string, type: string, textContent?: string | null, reasoningContent?: string | null, toolName?: string | null, toolCallId?: string | null, toolInput?: any | null, toolOutput?: any | null, errorMessage?: string | null, state?: string | null, errorDetails?: any | null, sourceUrlSourceId?: string | null, sourceUrlUrl?: string | null, sourceUrlTitle?: string | null, sourceDocumentSourceId?: string | null, sourceDocumentMediaType?: string | null, sourceDocumentTitle?: string | null, sourceDocumentFilename?: string | null, fileMediaType?: string | null, fileFilename?: string | null, fileUrl?: string | null, providerMetadata?: any | null }> }> }> }; +export type GetAgentTurnsQuery = { __typename?: 'Query', agentTurns: Array<{ __typename?: 'AgentTurn', id: string, threadId: string, agentId?: string | null, createdAt: string, evaluations: Array<{ __typename?: 'AgentTurnEvaluation', id: string, score: number, comment?: string | null, createdAt: string }>, messages: Array<{ __typename?: 'AgentMessage', id: string, role: string, createdAt: string, parts: Array<{ __typename?: 'AgentMessagePart', id: string, type: string, textContent?: string | null, reasoningContent?: string | null, toolName?: string | null, toolCallId?: string | null, toolInput?: any | null, toolOutput?: any | null, errorMessage?: string | null, state?: string | null, providerExecuted?: boolean | null, errorDetails?: any | null, sourceUrlSourceId?: string | null, sourceUrlUrl?: string | null, sourceUrlTitle?: string | null, sourceDocumentSourceId?: string | null, sourceDocumentMediaType?: string | null, sourceDocumentTitle?: string | null, sourceDocumentFilename?: string | null, fileMediaType?: string | null, fileFilename?: string | null, fileUrl?: string | null, providerMetadata?: any | null }> }> }> }; export type GetChatMessagesQueryVariables = Exact<{ threadId: Scalars['UUID']; }>; -export type GetChatMessagesQuery = { __typename?: 'Query', chatMessages: Array<{ __typename?: 'AgentMessage', id: string, threadId: string, turnId?: string | null, role: string, status: string, createdAt: string, parts: Array<{ __typename?: 'AgentMessagePart', id: string, messageId: string, orderIndex: number, type: string, textContent?: string | null, reasoningContent?: string | null, toolName?: string | null, toolCallId?: string | null, toolInput?: any | null, toolOutput?: any | null, state?: string | null, errorMessage?: string | null, errorDetails?: any | null, sourceUrlSourceId?: string | null, sourceUrlUrl?: string | null, sourceUrlTitle?: string | null, sourceDocumentSourceId?: string | null, sourceDocumentMediaType?: string | null, sourceDocumentTitle?: string | null, sourceDocumentFilename?: string | null, fileMediaType?: string | null, fileFilename?: string | null, fileUrl?: string | null, fileId?: string | null, providerMetadata?: any | null, createdAt: string }> }>, chatStreamCatchupChunks: { __typename?: 'ChatStreamCatchupChunks', chunks: Array, maxSeq: number } }; +export type GetChatMessagesQuery = { __typename?: 'Query', chatMessages: Array<{ __typename?: 'AgentMessage', id: string, threadId: string, turnId?: string | null, role: string, status: string, createdAt: string, parts: Array<{ __typename?: 'AgentMessagePart', id: string, messageId: string, orderIndex: number, type: string, textContent?: string | null, reasoningContent?: string | null, toolName?: string | null, toolCallId?: string | null, toolInput?: any | null, toolOutput?: any | null, state?: string | null, providerExecuted?: boolean | null, errorMessage?: string | null, errorDetails?: any | null, sourceUrlSourceId?: string | null, sourceUrlUrl?: string | null, sourceUrlTitle?: string | null, sourceDocumentSourceId?: string | null, sourceDocumentMediaType?: string | null, sourceDocumentTitle?: string | null, sourceDocumentFilename?: string | null, fileMediaType?: string | null, fileFilename?: string | null, fileUrl?: string | null, fileId?: string | null, providerMetadata?: any | null, createdAt: string }> }>, chatStreamCatchupChunks: { __typename?: 'ChatStreamCatchupChunks', chunks: Array, maxSeq: number } }; export type GetChatThreadsQueryVariables = Exact<{ paging?: InputMaybe; @@ -7839,8 +7840,8 @@ export const FindManyAgentsDocument = {"kind":"Document","definitions":[{"kind": export const FindManySkillsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindManySkills"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"skills"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SkillFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SkillFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Skill"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const FindOneAgentDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneAgent"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"findOneAgent"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"input"},"value":{"kind":"ObjectValue","fields":[{"kind":"ObjectField","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}]}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"AgentFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"AgentFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Agent"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"prompt"}},{"kind":"Field","name":{"kind":"Name","value":"modelId"}},{"kind":"Field","name":{"kind":"Name","value":"responseFormat"}},{"kind":"Field","name":{"kind":"Name","value":"roleId"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"modelConfiguration"}},{"kind":"Field","name":{"kind":"Name","value":"evaluationInputs"}},{"kind":"Field","name":{"kind":"Name","value":"applicationId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; export const FindOneSkillDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"FindOneSkill"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"id"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"skill"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"id"},"value":{"kind":"Variable","name":{"kind":"Name","value":"id"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"FragmentSpread","name":{"kind":"Name","value":"SkillFields"}}]}}]}},{"kind":"FragmentDefinition","name":{"kind":"Name","value":"SkillFields"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"Skill"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"label"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}},{"kind":"Field","name":{"kind":"Name","value":"content"}},{"kind":"Field","name":{"kind":"Name","value":"isCustom"}},{"kind":"Field","name":{"kind":"Name","value":"isActive"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}}]} as unknown as DocumentNode; -export const GetAgentTurnsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAgentTurns"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agentTurns"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"threadId"}},{"kind":"Field","name":{"kind":"Name","value":"agentId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"evaluations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"messages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"parts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"reasoningContent"}},{"kind":"Field","name":{"kind":"Name","value":"toolName"}},{"kind":"Field","name":{"kind":"Name","value":"toolCallId"}},{"kind":"Field","name":{"kind":"Name","value":"toolInput"}},{"kind":"Field","name":{"kind":"Name","value":"toolOutput"}},{"kind":"Field","name":{"kind":"Name","value":"errorMessage"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"errorDetails"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlUrl"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"fileFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileUrl"}},{"kind":"Field","name":{"kind":"Name","value":"providerMetadata"}}]}}]}}]}}]}}]} as unknown as DocumentNode; -export const GetChatMessagesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChatMessages"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chatMessages"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"threadId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"threadId"}},{"kind":"Field","name":{"kind":"Name","value":"turnId"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"parts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"messageId"}},{"kind":"Field","name":{"kind":"Name","value":"orderIndex"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"reasoningContent"}},{"kind":"Field","name":{"kind":"Name","value":"toolName"}},{"kind":"Field","name":{"kind":"Name","value":"toolCallId"}},{"kind":"Field","name":{"kind":"Name","value":"toolInput"}},{"kind":"Field","name":{"kind":"Name","value":"toolOutput"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"errorMessage"}},{"kind":"Field","name":{"kind":"Name","value":"errorDetails"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlUrl"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"fileFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileUrl"}},{"kind":"Field","name":{"kind":"Name","value":"fileId"}},{"kind":"Field","name":{"kind":"Name","value":"providerMetadata"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"chatStreamCatchupChunks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"threadId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chunks"}},{"kind":"Field","name":{"kind":"Name","value":"maxSeq"}}]}}]}}]} as unknown as DocumentNode; +export const GetAgentTurnsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetAgentTurns"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"agentId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"agentTurns"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"agentId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"agentId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"threadId"}},{"kind":"Field","name":{"kind":"Name","value":"agentId"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"evaluations"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"score"}},{"kind":"Field","name":{"kind":"Name","value":"comment"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"messages"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"parts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"reasoningContent"}},{"kind":"Field","name":{"kind":"Name","value":"toolName"}},{"kind":"Field","name":{"kind":"Name","value":"toolCallId"}},{"kind":"Field","name":{"kind":"Name","value":"toolInput"}},{"kind":"Field","name":{"kind":"Name","value":"toolOutput"}},{"kind":"Field","name":{"kind":"Name","value":"errorMessage"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"providerExecuted"}},{"kind":"Field","name":{"kind":"Name","value":"errorDetails"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlUrl"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"fileFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileUrl"}},{"kind":"Field","name":{"kind":"Name","value":"providerMetadata"}}]}}]}}]}}]}}]} as unknown as DocumentNode; +export const GetChatMessagesDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChatMessages"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"UUID"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chatMessages"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"threadId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"threadId"}},{"kind":"Field","name":{"kind":"Name","value":"turnId"}},{"kind":"Field","name":{"kind":"Name","value":"role"}},{"kind":"Field","name":{"kind":"Name","value":"status"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"parts"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"messageId"}},{"kind":"Field","name":{"kind":"Name","value":"orderIndex"}},{"kind":"Field","name":{"kind":"Name","value":"type"}},{"kind":"Field","name":{"kind":"Name","value":"textContent"}},{"kind":"Field","name":{"kind":"Name","value":"reasoningContent"}},{"kind":"Field","name":{"kind":"Name","value":"toolName"}},{"kind":"Field","name":{"kind":"Name","value":"toolCallId"}},{"kind":"Field","name":{"kind":"Name","value":"toolInput"}},{"kind":"Field","name":{"kind":"Name","value":"toolOutput"}},{"kind":"Field","name":{"kind":"Name","value":"state"}},{"kind":"Field","name":{"kind":"Name","value":"providerExecuted"}},{"kind":"Field","name":{"kind":"Name","value":"errorMessage"}},{"kind":"Field","name":{"kind":"Name","value":"errorDetails"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlUrl"}},{"kind":"Field","name":{"kind":"Name","value":"sourceUrlTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentSourceId"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentTitle"}},{"kind":"Field","name":{"kind":"Name","value":"sourceDocumentFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileMediaType"}},{"kind":"Field","name":{"kind":"Name","value":"fileFilename"}},{"kind":"Field","name":{"kind":"Name","value":"fileUrl"}},{"kind":"Field","name":{"kind":"Name","value":"fileId"}},{"kind":"Field","name":{"kind":"Name","value":"providerMetadata"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}}]}}]}},{"kind":"Field","name":{"kind":"Name","value":"chatStreamCatchupChunks"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"threadId"},"value":{"kind":"Variable","name":{"kind":"Name","value":"threadId"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chunks"}},{"kind":"Field","name":{"kind":"Name","value":"maxSeq"}}]}}]}}]} as unknown as DocumentNode; export const GetChatThreadsDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetChatThreads"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"paging"}},"type":{"kind":"NamedType","name":{"kind":"Name","value":"CursorPaging"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"chatThreads"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"paging"},"value":{"kind":"Variable","name":{"kind":"Name","value":"paging"}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"edges"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"node"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"title"}},{"kind":"Field","name":{"kind":"Name","value":"totalInputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"totalOutputTokens"}},{"kind":"Field","name":{"kind":"Name","value":"contextWindowTokens"}},{"kind":"Field","name":{"kind":"Name","value":"conversationSize"}},{"kind":"Field","name":{"kind":"Name","value":"totalInputCredits"}},{"kind":"Field","name":{"kind":"Name","value":"totalOutputCredits"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"updatedAt"}}]}},{"kind":"Field","name":{"kind":"Name","value":"cursor"}}]}},{"kind":"Field","name":{"kind":"Name","value":"pageInfo"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"endCursor"}},{"kind":"Field","name":{"kind":"Name","value":"hasNextPage"}}]}}]}}]}}]} as unknown as DocumentNode; export const GetToolIndexDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetToolIndex"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getToolIndex"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"category"}},{"kind":"Field","name":{"kind":"Name","value":"objectName"}},{"kind":"Field","name":{"kind":"Name","value":"icon"}}]}}]}}]} as unknown as DocumentNode; export const GetToolInputSchemaDocument = {"kind":"Document","definitions":[{"kind":"OperationDefinition","operation":"query","name":{"kind":"Name","value":"GetToolInputSchema"},"variableDefinitions":[{"kind":"VariableDefinition","variable":{"kind":"Variable","name":{"kind":"Name","value":"toolName"}},"type":{"kind":"NonNullType","type":{"kind":"NamedType","name":{"kind":"Name","value":"String"}}}}],"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"getToolInputSchema"},"arguments":[{"kind":"Argument","name":{"kind":"Name","value":"toolName"},"value":{"kind":"Variable","name":{"kind":"Name","value":"toolName"}}}]}]}}]} as unknown as DocumentNode; diff --git a/packages/twenty-front/src/modules/ai/graphql/queries/getAgentTurns.ts b/packages/twenty-front/src/modules/ai/graphql/queries/getAgentTurns.ts index 39a63df8ee..42b0ff4af5 100644 --- a/packages/twenty-front/src/modules/ai/graphql/queries/getAgentTurns.ts +++ b/packages/twenty-front/src/modules/ai/graphql/queries/getAgentTurns.ts @@ -28,6 +28,7 @@ export const GET_AGENT_TURNS = gql` toolOutput errorMessage state + providerExecuted errorDetails sourceUrlSourceId sourceUrlUrl diff --git a/packages/twenty-front/src/modules/ai/graphql/queries/getChatMessages.ts b/packages/twenty-front/src/modules/ai/graphql/queries/getChatMessages.ts index 1b6e9d4715..f3b58464ff 100644 --- a/packages/twenty-front/src/modules/ai/graphql/queries/getChatMessages.ts +++ b/packages/twenty-front/src/modules/ai/graphql/queries/getChatMessages.ts @@ -21,6 +21,7 @@ export const GET_CHAT_MESSAGES = gql` toolInput toolOutput state + providerExecuted errorMessage errorDetails sourceUrlSourceId diff --git a/packages/twenty-front/src/modules/ai/utils/mapDBPartToUIMessagePart.ts b/packages/twenty-front/src/modules/ai/utils/mapDBPartToUIMessagePart.ts index 23ace1e82c..14ab20ca07 100644 --- a/packages/twenty-front/src/modules/ai/utils/mapDBPartToUIMessagePart.ts +++ b/packages/twenty-front/src/modules/ai/utils/mapDBPartToUIMessagePart.ts @@ -71,6 +71,9 @@ export const mapDBPartToUIMessagePart = ( output: part.toolOutput, errorText: part.errorMessage!, state: part.state, + ...(part.providerExecuted != null && { + providerExecuted: part.providerExecuted, + }), } as ToolUIPart; } } diff --git a/packages/twenty-server/src/database/commands/__tests__/__snapshots__/instance-command-generation.service.spec.ts.snap b/packages/twenty-server/src/database/commands/__tests__/__snapshots__/instance-command-generation.service.spec.ts.snap index 2e8e6d988b..668dd24838 100644 --- a/packages/twenty-server/src/database/commands/__tests__/__snapshots__/instance-command-generation.service.spec.ts.snap +++ b/packages/twenty-server/src/database/commands/__tests__/__snapshots__/instance-command-generation.service.spec.ts.snap @@ -26,13 +26,13 @@ export class TestFastInstanceCommand implements FastInstanceCommand { exports[`InstanceCommandGenerationService should escape backslashes in SQL queries 1`] = ` { "className": "UpdatePathFastInstanceCommand", - "fileName": "2-0-instance-command-fast-1775000000000-update-path.ts", + "fileName": "2-1-instance-command-fast-1775000000000-update-path.ts", "fileTemplate": "import { QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000) +@RegisteredInstanceCommand('2.1.0', 1775000000000) export class UpdatePathFastInstanceCommand implements FastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('UPDATE "core"."config" SET "value" = E\\'path\\\\\\\\to\\\\\\\\file\\''); @@ -49,13 +49,13 @@ export class UpdatePathFastInstanceCommand implements FastInstanceCommand { exports[`InstanceCommandGenerationService should escape single quotes in SQL queries 1`] = ` { "className": "UpdateConfigFastInstanceCommand", - "fileName": "2-0-instance-command-fast-1775000000000-update-config.ts", + "fileName": "2-1-instance-command-fast-1775000000000-update-config.ts", "fileTemplate": "import { QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000) +@RegisteredInstanceCommand('2.1.0', 1775000000000) export class UpdateConfigFastInstanceCommand implements FastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('UPDATE "core"."config" SET "value" = \\'it\\'\\'s done\\''); @@ -72,13 +72,13 @@ export class UpdateConfigFastInstanceCommand implements FastInstanceCommand { exports[`InstanceCommandGenerationService should generate a migration with a single up/down query 1`] = ` { "className": "AddFooColumnFastInstanceCommand", - "fileName": "2-0-instance-command-fast-1775000000000-add-foo-column.ts", + "fileName": "2-1-instance-command-fast-1775000000000-add-foo-column.ts", "fileTemplate": "import { QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000) +@RegisteredInstanceCommand('2.1.0', 1775000000000) export class AddFooColumnFastInstanceCommand implements FastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('ALTER TABLE "core"."user" ADD "foo" varchar'); @@ -95,13 +95,13 @@ export class AddFooColumnFastInstanceCommand implements FastInstanceCommand { exports[`InstanceCommandGenerationService should generate a migration with multiple queries 1`] = ` { "className": "CreateTaskTableFastInstanceCommand", - "fileName": "2-0-instance-command-fast-1775000000000-create-task-table.ts", + "fileName": "2-1-instance-command-fast-1775000000000-create-task-table.ts", "fileTemplate": "import { QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000) +@RegisteredInstanceCommand('2.1.0', 1775000000000) export class CreateTaskTableFastInstanceCommand implements FastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('CREATE TABLE "core"."task" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "name" varchar NOT NULL)'); @@ -120,13 +120,13 @@ export class CreateTaskTableFastInstanceCommand implements FastInstanceCommand { exports[`InstanceCommandGenerationService should generate a migration with query parameters 1`] = ` { "className": "SeedSettingFastInstanceCommand", - "fileName": "2-0-instance-command-fast-1775000000000-seed-setting.ts", + "fileName": "2-1-instance-command-fast-1775000000000-seed-setting.ts", "fileTemplate": "import { QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000) +@RegisteredInstanceCommand('2.1.0', 1775000000000) export class SeedSettingFastInstanceCommand implements FastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('INSERT INTO "core"."setting" ("key", "value") VALUES ($1, $2)', ["theme","dark"]); @@ -143,13 +143,13 @@ export class SeedSettingFastInstanceCommand implements FastInstanceCommand { exports[`InstanceCommandGenerationService should generate a slow instance command with populated up/down 1`] = ` { "className": "MakeColumnNotNullableSlowInstanceCommand", - "fileName": "2-0-instance-command-slow-1775000000000-make-column-not-nullable.ts", + "fileName": "2-1-instance-command-slow-1775000000000-make-column-not-nullable.ts", "fileTemplate": "import { DataSource, QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { SlowInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/slow-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000, { type: 'slow' }) +@RegisteredInstanceCommand('2.1.0', 1775000000000, { type: 'slow' }) export class MakeColumnNotNullableSlowInstanceCommand implements SlowInstanceCommand { async runDataMigration(dataSource: DataSource): Promise { // TODO: implement data backfill before the DDL migration @@ -170,13 +170,13 @@ export class MakeColumnNotNullableSlowInstanceCommand implements SlowInstanceCom exports[`InstanceCommandGenerationService should use default migration name in class and file names 1`] = ` { "className": "AutoGeneratedFastInstanceCommand", - "fileName": "2-0-instance-command-fast-1775000000000-auto-generated.ts", + "fileName": "2-1-instance-command-fast-1775000000000-auto-generated.ts", "fileTemplate": "import { QueryRunner } from 'typeorm'; import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; -@RegisteredInstanceCommand('2.0.0', 1775000000000) +@RegisteredInstanceCommand('2.1.0', 1775000000000) export class AutoGeneratedFastInstanceCommand implements FastInstanceCommand { public async up(queryRunner: QueryRunner): Promise { await queryRunner.query('ALTER TABLE "core"."user" ADD "bar" integer'); diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1777012800000-add-provider-executed-to-agent-message-part.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1777012800000-add-provider-executed-to-agent-message-part.ts new file mode 100644 index 0000000000..bc56898dc3 --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1777012800000-add-provider-executed-to-agent-message-part.ts @@ -0,0 +1,21 @@ +import { QueryRunner } from 'typeorm'; + +import { RegisteredInstanceCommand } from 'src/engine/core-modules/upgrade/decorators/registered-instance-command.decorator'; +import { FastInstanceCommand } from 'src/engine/core-modules/upgrade/interfaces/fast-instance-command.interface'; + +@RegisteredInstanceCommand('2.1.0', 1777012800000) +export class AddProviderExecutedToAgentMessagePartFastInstanceCommand + implements FastInstanceCommand +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "core"."agentMessagePart" ADD "providerExecuted" boolean', + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + 'ALTER TABLE "core"."agentMessagePart" DROP COLUMN "providerExecuted"', + ); + } +} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/2-2/2-2-upgrade-version-command.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/2-2/2-2-upgrade-version-command.module.ts new file mode 100644 index 0000000000..c5672d56ef --- /dev/null +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/2-2/2-2-upgrade-version-command.module.ts @@ -0,0 +1,7 @@ +import { Module } from '@nestjs/common'; + +@Module({ + imports: [], + providers: [], +}) +export class V2_2_UpgradeVersionCommandModule {} diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts index 6d5a4c6469..8ced21402c 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/instance-commands.constant.ts @@ -16,6 +16,7 @@ import { AddGlobalObjectContextToCommandMenuItemAvailabilityTypeFastInstanceComm import { AddPageLayoutIdToCommandMenuItemFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-23/1-23-instance-command-fast-1776168404836-add-page-layout-id-to-command-menu-item'; import { AddConditionalAvailabilityExpressionToPageLayoutWidgetFastInstanceCommand } from 'src/database/commands/upgrade-version-command/1-23/1-23-instance-command-fast-1775654781000-add-conditional-availability-expression-to-page-layout-widget'; import { AddIsPreInstalledToApplicationRegistrationFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-0/2-0-instance-command-fast-1776886452831-add-is-pre-installed-to-application-registration'; +import { AddProviderExecutedToAgentMessagePartFastInstanceCommand } from 'src/database/commands/upgrade-version-command/2-1/2-1-instance-command-fast-1777012800000-add-provider-executed-to-agent-message-part'; import { BackfillPageLayoutWidgetPositionSlowInstanceCommand } from 'src/database/commands/upgrade-version-command/2-1/2-1-instance-command-slow-1795000002000-backfill-page-layout-widget-position'; export const INSTANCE_COMMANDS = [ @@ -35,5 +36,6 @@ export const INSTANCE_COMMANDS = [ AddPageLayoutIdToCommandMenuItemFastInstanceCommand, AddConditionalAvailabilityExpressionToPageLayoutWidgetFastInstanceCommand, AddIsPreInstalledToApplicationRegistrationFastInstanceCommand, + AddProviderExecutedToAgentMessagePartFastInstanceCommand, BackfillPageLayoutWidgetPositionSlowInstanceCommand, ]; diff --git a/packages/twenty-server/src/database/commands/upgrade-version-command/workspace-command-provider.module.ts b/packages/twenty-server/src/database/commands/upgrade-version-command/workspace-command-provider.module.ts index b0b3762578..56620eb6c4 100644 --- a/packages/twenty-server/src/database/commands/upgrade-version-command/workspace-command-provider.module.ts +++ b/packages/twenty-server/src/database/commands/upgrade-version-command/workspace-command-provider.module.ts @@ -5,6 +5,7 @@ import { V1_22_UpgradeVersionCommandModule } from 'src/database/commands/upgrade import { V1_23_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/1-23/1-23-upgrade-version-command.module'; import { V2_0_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-0/2-0-upgrade-version-command.module'; import { V2_1_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-1/2-1-upgrade-version-command.module'; +import { V2_2_UpgradeVersionCommandModule } from 'src/database/commands/upgrade-version-command/2-2/2-2-upgrade-version-command.module'; @Module({ imports: [ @@ -13,6 +14,7 @@ import { V2_1_UpgradeVersionCommandModule } from 'src/database/commands/upgrade- V1_23_UpgradeVersionCommandModule, V2_0_UpgradeVersionCommandModule, V2_1_UpgradeVersionCommandModule, + V2_2_UpgradeVersionCommandModule, ], }) export class WorkspaceCommandProviderModule {} diff --git a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts index 9a5047b8cd..50788645f2 100644 --- a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts +++ b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-current-version.constant.ts @@ -1 +1 @@ -export const TWENTY_CURRENT_VERSION = '2.0.0' as const; +export const TWENTY_CURRENT_VERSION = '2.1.0' as const; diff --git a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts index 6b00bed5bb..83f2eaa8c5 100644 --- a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts +++ b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-next-versions.constant.ts @@ -1 +1 @@ -export const TWENTY_NEXT_VERSIONS = ['2.1.0'] as const; +export const TWENTY_NEXT_VERSIONS = ['2.2.0'] as const; diff --git a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts index 17710bfc74..c0c25c12cf 100644 --- a/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts +++ b/packages/twenty-server/src/engine/core-modules/upgrade/constants/twenty-previous-versions.constant.ts @@ -1 +1,6 @@ -export const TWENTY_PREVIOUS_VERSIONS = ['1.21.0', '1.22.0', '1.23.0'] as const; +export const TWENTY_PREVIOUS_VERSIONS = [ + '1.21.0', + '1.22.0', + '1.23.0', + '2.0.0', +] as const; diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/dtos/agent-message-part.dto.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/dtos/agent-message-part.dto.ts index 751d9195f7..326884a9c4 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/dtos/agent-message-part.dto.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/dtos/agent-message-part.dto.ts @@ -40,6 +40,9 @@ export class AgentMessagePartDTO { @Field(() => String, { nullable: true }) state: string | null; + @Field(() => Boolean, { nullable: true }) + providerExecuted: boolean | null; + @Field(() => String, { nullable: true }) errorMessage: string | null; diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/entities/agent-message-part.entity.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/entities/agent-message-part.entity.ts index 3f2b5e315f..cc0f6e7933 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/entities/agent-message-part.entity.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/entities/agent-message-part.entity.ts @@ -64,6 +64,12 @@ export class AgentMessagePartEntity { @Column({ type: 'varchar', nullable: true }) state: string | null; + // True when the tool was executed by the model provider itself + // (e.g. Anthropic's server-side web_search). convertToModelMessages + // relies on this to emit the correct server-tool wire format. + @Column({ type: 'boolean', nullable: true }) + providerExecuted: boolean | null; + @Column({ type: 'text', nullable: true }) errorMessage: string | null; diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapDBPartToUIMessagePart.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapDBPartToUIMessagePart.ts index b8437e8667..9523ba989a 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapDBPartToUIMessagePart.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapDBPartToUIMessagePart.ts @@ -64,6 +64,9 @@ export const mapDBPartToUIMessagePart = ( output: part.toolOutput, errorText: part.errorMessage ?? '', state: part.state, + ...(part.providerExecuted != null && { + providerExecuted: part.providerExecuted, + }), } as ExtendedUIMessagePart; } diff --git a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapUIMessagePartsToDBParts.ts b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapUIMessagePartsToDBParts.ts index 0ea11b4de7..73e1f51a9d 100644 --- a/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapUIMessagePartsToDBParts.ts +++ b/packages/twenty-server/src/engine/metadata-modules/ai/ai-agent-execution/utils/mapUIMessagePartsToDBParts.ts @@ -92,6 +92,7 @@ export const mapUIMessagePartsToDBParts = ( toolOutput: output, errorMessage: errorText, state, + providerExecuted: part.providerExecuted ?? null, }; } } diff --git a/packages/twenty-server/test/integration/upgrade/suites/sequence-runner/__snapshots__/failing-sequence-runner.integration-spec.ts.snap b/packages/twenty-server/test/integration/upgrade/suites/sequence-runner/__snapshots__/failing-sequence-runner.integration-spec.ts.snap index ac084923a4..6ddc9879f2 100644 --- a/packages/twenty-server/test/integration/upgrade/suites/sequence-runner/__snapshots__/failing-sequence-runner.integration-spec.ts.snap +++ b/packages/twenty-server/test/integration/upgrade/suites/sequence-runner/__snapshots__/failing-sequence-runner.integration-spec.ts.snap @@ -1,3 +1,3 @@ // Jest Snapshot v1, https://jestjs.io/docs/snapshot-testing -exports[`UpgradeSequenceRunnerService — failing sequence (integration) should throw when cursor command is not found in the sequence 1`] = `"Step "RemovedCommand" not found in upgrade sequence. The sequence only covers versions [1.21.0, 1.22.0, 1.23.0, 2.0.0]. Please upgrade to 1.21.0 first."`; +exports[`UpgradeSequenceRunnerService — failing sequence (integration) should throw when cursor command is not found in the sequence 1`] = `"Step "RemovedCommand" not found in upgrade sequence. The sequence only covers versions [1.21.0, 1.22.0, 1.23.0, 2.0.0, 2.1.0]. Please upgrade to 1.21.0 first."`;