This commit is contained in:
marko-kraemer 2025-07-27 01:22:56 +02:00
parent ef087747ab
commit 3405c27ef6
11 changed files with 99 additions and 28 deletions

View File

@ -0,0 +1,31 @@
-- Migration: Move agent_id and agent_version_id from dedicated columns to metadata
-- This improves storage efficiency by only storing agent info for assistant messages where it's relevant
BEGIN;
-- Step 1: Update existing messages to move agent info to metadata
-- Only update messages that have agent_id or agent_version_id set
UPDATE messages
SET metadata = jsonb_set(
jsonb_set(
COALESCE(metadata, '{}'::jsonb),
'{agent_id}',
to_jsonb(agent_id)
),
'{agent_version_id}',
to_jsonb(agent_version_id)
)
WHERE agent_id IS NOT NULL OR agent_version_id IS NOT NULL;
-- Step 2: Drop indexes on the columns we're about to remove
DROP INDEX IF EXISTS idx_messages_agent_id;
DROP INDEX IF EXISTS idx_messages_agent_version_id;
-- Step 3: Drop the dedicated agent columns
ALTER TABLE messages DROP COLUMN IF EXISTS agent_id;
ALTER TABLE messages DROP COLUMN IF EXISTS agent_version_id;
-- Step 4: Add comment explaining the new structure
COMMENT ON COLUMN messages.metadata IS 'JSONB metadata including agent_id and agent_version_id for assistant messages, and other message-specific data';
COMMIT;

View File

@ -0,0 +1,36 @@
-- Reverse Migration: Move agent_id and agent_version_id back from metadata to dedicated columns
-- This reverses the changes made in 20250726223759_move_agent_fields_to_metadata.sql
BEGIN;
-- Step 1: Add back the dedicated agent columns with proper foreign key constraints
ALTER TABLE messages ADD COLUMN IF NOT EXISTS agent_id UUID REFERENCES agents(agent_id) ON DELETE SET NULL;
ALTER TABLE messages ADD COLUMN IF NOT EXISTS agent_version_id UUID REFERENCES agent_versions(version_id) ON DELETE SET NULL;
-- Step 2: Extract agent info from metadata and populate the dedicated columns
-- Only update messages that have agent info in metadata
UPDATE messages
SET
agent_id = CASE
WHEN metadata ? 'agent_id' THEN (metadata->>'agent_id')::UUID
ELSE NULL
END,
agent_version_id = CASE
WHEN metadata ? 'agent_version_id' THEN (metadata->>'agent_version_id')::UUID
ELSE NULL
END
WHERE metadata ? 'agent_id' OR metadata ? 'agent_version_id';
-- Step 3: Remove agent fields from metadata
UPDATE messages
SET metadata = metadata - 'agent_id' - 'agent_version_id'
WHERE metadata ? 'agent_id' OR metadata ? 'agent_version_id';
-- Step 4: Recreate the indexes on the agent columns
CREATE INDEX IF NOT EXISTS idx_messages_agent_id ON messages(agent_id);
CREATE INDEX IF NOT EXISTS idx_messages_agent_version_id ON messages(agent_version_id);
-- Step 5: Update the comment to reflect the original structure
COMMENT ON COLUMN messages.metadata IS 'JSONB metadata for message-specific data (agent info stored in dedicated columns)';
COMMIT;

View File

@ -1,9 +0,0 @@
NEXT_PUBLIC_ENV_MODE="LOCAL" #production, or staging
NEXT_PUBLIC_SUPABASE_URL=""
NEXT_PUBLIC_SUPABASE_ANON_KEY=""
NEXT_PUBLIC_BACKEND_URL=""
NEXT_PUBLIC_URL=""
NEXT_PUBLIC_GOOGLE_CLIENT_ID=""
OPENAI_API_KEY=""
EDGE_CONFIG="https://edge-config.vercel.com/REDACTED?token=REDACTED"

View File

@ -129,9 +129,9 @@ export default function ThreadPage({
const agent = threadAgentData?.agent;
const workflowId = threadQuery.data?.metadata?.workflow_id;
// Set initial selected agent from thread data (most recently used agent)
// Set initial selected agent from thread data
useEffect(() => {
if (threadAgentData?.agent && !selectedAgentId && threadAgentData.source === 'recent') {
if (threadAgentData?.agent && !selectedAgentId) {
setSelectedAgentId(threadAgentData.agent.agent_id);
}
}, [threadAgentData, selectedAgentId]);
@ -282,10 +282,10 @@ export default function ThreadPage({
const agentPromise = startAgentMutation.mutateAsync({
threadId,
options: selectedAgentId ? {
options: {
...options,
agent_id: selectedAgentId
} : options
}
});
const results = await Promise.allSettled([messagePromise, agentPromise]);

View File

@ -312,10 +312,7 @@ export const AgentBuilderChat = React.memo(function AgentBuilderChat({
const agentPromise = startAgentMutation.mutateAsync({
threadId,
options: {
...options,
agent_id: agentId
}
options
});
const results = await Promise.allSettled([messagePromise, agentPromise]);

View File

@ -213,10 +213,7 @@ export const AgentPreview = ({ agent, agentMetadata }: AgentPreviewProps) => {
try {
const agentResult = await startAgentMutation.mutateAsync({
threadId: result.thread_id,
options: {
...options,
agent_id: agent.agent_id
}
options
});
console.log('[PREVIEW] Agent started manually:', agentResult);
setAgentRunId(agentResult.agent_run_id);
@ -283,10 +280,7 @@ export const AgentPreview = ({ agent, agentMetadata }: AgentPreviewProps) => {
const agentPromise = startAgentMutation.mutateAsync({
threadId,
options: {
...options,
agent_id: agent.agent_id
}
options
});
const results = await Promise.allSettled([messagePromise, agentPromise]);

View File

@ -74,7 +74,7 @@ export type AgentsParams = {
export type ThreadAgentResponse = {
agent: Agent | null;
source: 'recent' | 'none' | 'missing';
source: 'thread' | 'default' | 'none' | 'missing';
message: string;
};

View File

@ -77,6 +77,28 @@ export function useKnowledgeBaseEntry(entryId: string) {
});
}
export function useKnowledgeBaseContext(threadId: string, maxTokens = 4000) {
const { getHeaders } = useAuthHeaders();
return useQuery({
queryKey: knowledgeBaseKeys.context(threadId),
queryFn: async () => {
const headers = await getHeaders();
const url = new URL(`${API_URL}/knowledge-base/threads/${threadId}/context`);
url.searchParams.set('max_tokens', maxTokens.toString());
const response = await fetch(url.toString(), { headers });
if (!response.ok) {
const error = await response.text();
throw new Error(error || 'Failed to fetch knowledge base context');
}
return await response.json();
},
enabled: !!threadId,
});
}
export function useCreateKnowledgeBaseEntry() {
const queryClient = useQueryClient();

View File

@ -24,7 +24,7 @@ export const useStartAgentMutation = () =>
enable_thinking?: boolean;
reasoning_effort?: string;
stream?: boolean;
agent_id?: string; // Optional again
agent_id?: string;
};
}) => startAgent(threadId, options),
{

View File

@ -14,6 +14,7 @@ export type Thread = {
workflow_name?: string;
workflow_run_name?: string;
is_workflow_execution?: boolean;
agent_id?: string;
is_agent_builder?: boolean;
[key: string]: any;
};

View File

@ -321,7 +321,6 @@ export const agentApi = {
enable_thinking?: boolean;
reasoning_effort?: string;
stream?: boolean;
agent_id?: string; // Optional again
}
): Promise<{ agent_run_id: string } | null> {
const result = await backendApi.post(