rem legacy workflows, db unused schema cleanup wip

This commit is contained in:
marko-kraemer 2025-07-26 22:31:31 +02:00
parent 5157765f52
commit ef087747ab
18 changed files with 120 additions and 379 deletions

View File

@ -291,19 +291,17 @@ async def start_agent(
client = await db.client
await verify_thread_access(client, thread_id, user_id)
thread_result = await client.table('threads').select('project_id', 'account_id', 'agent_id', 'metadata').eq('thread_id', thread_id).execute()
thread_result = await client.table('threads').select('project_id', 'account_id', 'metadata').eq('thread_id', thread_id).execute()
if not thread_result.data:
raise HTTPException(status_code=404, detail="Thread not found")
thread_data = thread_result.data[0]
project_id = thread_data.get('project_id')
account_id = thread_data.get('account_id')
thread_agent_id = thread_data.get('agent_id')
thread_metadata = thread_data.get('metadata', {})
structlog.contextvars.bind_contextvars(
project_id=project_id,
account_id=account_id,
thread_agent_id=thread_agent_id,
thread_metadata=thread_metadata,
)
@ -316,11 +314,10 @@ async def start_agent(
# Load agent configuration with version support
agent_config = None
effective_agent_id = body.agent_id or thread_agent_id # Use provided agent_id or the one stored in thread
effective_agent_id = body.agent_id # Optional agent ID from request
logger.info(f"[AGENT LOAD] Agent loading flow:")
logger.info(f" - body.agent_id: {body.agent_id}")
logger.info(f" - thread_agent_id: {thread_agent_id}")
logger.info(f" - effective_agent_id: {effective_agent_id}")
if effective_agent_id:
@ -359,7 +356,7 @@ async def start_agent(
logger.info(f"Using agent {agent_config['name']} ({effective_agent_id}) version {agent_config.get('version_name', 'v1')}")
else:
logger.info(f"Using agent {agent_config['name']} ({effective_agent_id}) - no version data")
source = "request" if body.agent_id else "thread"
source = "request" if body.agent_id else "fallback"
else:
logger.info(f"[AGENT LOAD] No effective_agent_id, will try default agent")
@ -399,8 +396,6 @@ async def start_agent(
logger.info(f"[AGENT LOAD] Final agent_config: {agent_config is not None}")
if agent_config:
logger.info(f"[AGENT LOAD] Agent config keys: {list(agent_config.keys())}")
if body.agent_id and body.agent_id != thread_agent_id and agent_config:
logger.info(f"Using agent {agent_config['agent_id']} for this agent run (thread remains agent-agnostic)")
can_use, model_message, allowed_models = await can_use_model(client, account_id, model_name)
@ -516,8 +511,8 @@ async def get_agent_run(agent_run_id: str, user_id: str = Depends(get_current_us
@router.get("/thread/{thread_id}/agent", response_model=ThreadAgentResponse)
async def get_thread_agent(thread_id: str, user_id: str = Depends(get_current_user_id_from_jwt)):
"""Get the agent details for a specific thread. Since threads are now agent-agnostic,
this returns the most recently used agent or the default agent."""
"""Get the agent details for a specific thread. Since threads are fully agent-agnostic,
this returns the most recently used agent from agent_runs only."""
structlog.contextvars.bind_contextvars(
thread_id=thread_id,
)
@ -525,21 +520,20 @@ async def get_thread_agent(thread_id: str, user_id: str = Depends(get_current_us
client = await db.client
try:
# Verify thread access and get thread data including agent_id
# Verify thread access and get thread data
await verify_thread_access(client, thread_id, user_id)
thread_result = await client.table('threads').select('agent_id', 'account_id').eq('thread_id', thread_id).execute()
thread_result = await client.table('threads').select('account_id').eq('thread_id', thread_id).execute()
if not thread_result.data:
raise HTTPException(status_code=404, detail="Thread not found")
thread_data = thread_result.data[0]
thread_agent_id = thread_data.get('agent_id')
account_id = thread_data.get('account_id')
effective_agent_id = None
agent_source = "none"
# First, try to get the most recently used agent from agent_runs
# Get the most recently used agent from agent_runs
recent_agent_result = await client.table('agent_runs').select('agent_id', 'agent_version_id').eq('thread_id', thread_id).not_.is_('agent_id', 'null').order('created_at', desc=True).limit(1).execute()
if recent_agent_result.data:
effective_agent_id = recent_agent_result.data[0]['agent_id']
@ -547,26 +541,12 @@ async def get_thread_agent(thread_id: str, user_id: str = Depends(get_current_us
agent_source = "recent"
logger.info(f"Found most recently used agent: {effective_agent_id} (version: {recent_version_id})")
# If no recent agent, fall back to thread default agent
elif thread_agent_id:
effective_agent_id = thread_agent_id
agent_source = "thread"
logger.info(f"Using thread default agent: {effective_agent_id}")
# If no thread agent, try to get the default agent for the account
else:
default_agent_result = await client.table('agents').select('agent_id').eq('account_id', account_id).eq('is_default', True).execute()
if default_agent_result.data:
effective_agent_id = default_agent_result.data[0]['agent_id']
agent_source = "default"
logger.info(f"Using account default agent: {effective_agent_id}")
# If still no agent found
# If no agent found in agent_runs
if not effective_agent_id:
return {
"agent": None,
"source": "none",
"message": "No agent configured for this thread. Threads are agent-agnostic - you can select any agent."
"message": "No agent has been used in this thread yet. Threads are agent-agnostic - use /agent/start to select an agent."
}
# Fetch the agent details

View File

@ -126,60 +126,6 @@ async def get_thread_knowledge_base(
logger.error(f"Error getting knowledge base for thread {thread_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Failed to retrieve knowledge base")
@router.post("/threads/{thread_id}", response_model=KnowledgeBaseEntryResponse)
async def create_knowledge_base_entry(
thread_id: str,
entry_data: CreateKnowledgeBaseEntryRequest,
user_id: str = Depends(get_current_user_id_from_jwt)
):
if not await is_enabled("knowledge_base"):
raise HTTPException(
status_code=403,
detail="This feature is not available at the moment."
)
"""Create a new knowledge base entry for a thread"""
try:
client = await db.client
thread_result = await client.table('threads').select('account_id').eq('thread_id', thread_id).execute()
if not thread_result.data:
raise HTTPException(status_code=404, detail="Thread not found")
account_id = thread_result.data[0]['account_id']
insert_data = {
'thread_id': thread_id,
'account_id': account_id,
'name': entry_data.name,
'description': entry_data.description,
'content': entry_data.content,
'usage_context': entry_data.usage_context
}
result = await client.table('knowledge_base_entries').insert(insert_data).execute()
if not result.data:
raise HTTPException(status_code=500, detail="Failed to create knowledge base entry")
created_entry = result.data[0]
return KnowledgeBaseEntryResponse(
entry_id=created_entry['entry_id'],
name=created_entry['name'],
description=created_entry['description'],
content=created_entry['content'],
usage_context=created_entry['usage_context'],
is_active=created_entry['is_active'],
content_tokens=created_entry.get('content_tokens'),
created_at=created_entry['created_at'],
updated_at=created_entry['updated_at']
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error creating knowledge base entry for thread {thread_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Failed to create knowledge base entry")
@router.get("/agents/{agent_id}", response_model=KnowledgeBaseListResponse)
async def get_agent_knowledge_base(
@ -495,155 +441,6 @@ async def get_agent_knowledge_base_context(
logger.error(f"Error getting knowledge base context for agent {agent_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Failed to retrieve agent knowledge base context")
@router.put("/{entry_id}", response_model=KnowledgeBaseEntryResponse)
async def update_knowledge_base_entry(
entry_id: str,
entry_data: UpdateKnowledgeBaseEntryRequest,
user_id: str = Depends(get_current_user_id_from_jwt)
):
if not await is_enabled("knowledge_base"):
raise HTTPException(
status_code=403,
detail="This feature is not available at the moment."
)
"""Update a knowledge base entry (works for both thread and agent entries)"""
try:
client = await db.client
entry_result = await client.table('knowledge_base_entries').select('*').eq('entry_id', entry_id).execute()
table_name = 'knowledge_base_entries'
if not entry_result.data:
entry_result = await client.table('agent_knowledge_base_entries').select('*').eq('entry_id', entry_id).execute()
table_name = 'agent_knowledge_base_entries'
if not entry_result.data:
raise HTTPException(status_code=404, detail="Knowledge base entry not found")
update_data = {}
if entry_data.name is not None:
update_data['name'] = entry_data.name
if entry_data.description is not None:
update_data['description'] = entry_data.description
if entry_data.content is not None:
update_data['content'] = entry_data.content
if entry_data.usage_context is not None:
update_data['usage_context'] = entry_data.usage_context
if entry_data.is_active is not None:
update_data['is_active'] = entry_data.is_active
if not update_data:
raise HTTPException(status_code=400, detail="No fields to update")
result = await client.table(table_name).update(update_data).eq('entry_id', entry_id).execute()
if not result.data:
raise HTTPException(status_code=500, detail="Failed to update knowledge base entry")
updated_entry = result.data[0]
return KnowledgeBaseEntryResponse(
entry_id=updated_entry['entry_id'],
name=updated_entry['name'],
description=updated_entry['description'],
content=updated_entry['content'],
usage_context=updated_entry['usage_context'],
is_active=updated_entry['is_active'],
content_tokens=updated_entry.get('content_tokens'),
created_at=updated_entry['created_at'],
updated_at=updated_entry['updated_at'],
source_type=updated_entry.get('source_type'),
source_metadata=updated_entry.get('source_metadata'),
file_size=updated_entry.get('file_size'),
file_mime_type=updated_entry.get('file_mime_type')
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error updating knowledge base entry {entry_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Failed to update knowledge base entry")
@router.delete("/{entry_id}")
async def delete_knowledge_base_entry(
entry_id: str,
user_id: str = Depends(get_current_user_id_from_jwt)
):
if not await is_enabled("knowledge_base"):
raise HTTPException(
status_code=403,
detail="This feature is not available at the moment."
)
"""Delete a knowledge base entry (works for both thread and agent entries)"""
try:
client = await db.client
entry_result = await client.table('knowledge_base_entries').select('entry_id').eq('entry_id', entry_id).execute()
table_name = 'knowledge_base_entries'
if not entry_result.data:
entry_result = await client.table('agent_knowledge_base_entries').select('entry_id').eq('entry_id', entry_id).execute()
table_name = 'agent_knowledge_base_entries'
if not entry_result.data:
raise HTTPException(status_code=404, detail="Knowledge base entry not found")
result = await client.table(table_name).delete().eq('entry_id', entry_id).execute()
return {"message": "Knowledge base entry deleted successfully"}
except HTTPException:
raise
except Exception as e:
logger.error(f"Error deleting knowledge base entry {entry_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Failed to delete knowledge base entry")
@router.get("/{entry_id}", response_model=KnowledgeBaseEntryResponse)
async def get_knowledge_base_entry(
entry_id: str,
user_id: str = Depends(get_current_user_id_from_jwt)
):
if not await is_enabled("knowledge_base"):
raise HTTPException(
status_code=403,
detail="This feature is not available at the moment."
)
"""Get a specific knowledge base entry (works for both thread and agent entries)"""
try:
client = await db.client
result = await client.table('knowledge_base_entries').select('*').eq('entry_id', entry_id).execute()
if not result.data:
result = await client.table('agent_knowledge_base_entries').select('*').eq('entry_id', entry_id).execute()
if not result.data:
raise HTTPException(status_code=404, detail="Knowledge base entry not found")
entry = result.data[0]
return KnowledgeBaseEntryResponse(
entry_id=entry['entry_id'],
name=entry['name'],
description=entry['description'],
content=entry['content'],
usage_context=entry['usage_context'],
is_active=entry['is_active'],
content_tokens=entry.get('content_tokens'),
created_at=entry['created_at'],
updated_at=entry['updated_at'],
source_type=entry.get('source_type'),
source_metadata=entry.get('source_metadata'),
file_size=entry.get('file_size'),
file_mime_type=entry.get('file_mime_type')
)
except HTTPException:
raise
except Exception as e:
logger.error(f"Error getting knowledge base entry {entry_id}: {str(e)}")
raise HTTPException(status_code=500, detail="Failed to retrieve knowledge base entry")
@router.get("/threads/{thread_id}/context")
async def get_knowledge_base_context(

View File

@ -0,0 +1,15 @@
-- Migration: Remove recordings, devices tables and responses field from agent_runs
-- This migration cleans up unused tables and fields
BEGIN;
-- Drop recordings table first (has foreign key to devices)
DROP TABLE IF EXISTS public.recordings CASCADE;
-- Drop devices table
DROP TABLE IF EXISTS public.devices CASCADE;
-- Remove responses column from agent_runs table
ALTER TABLE agent_runs DROP COLUMN IF EXISTS responses;
COMMIT;

View File

@ -0,0 +1,30 @@
BEGIN;
-- Remove old workflow execution and step tables
-- These are no longer needed since steps are now stored as JSON in agent_workflows.steps
-- and executions can be tracked differently if needed
-- Drop workflow step executions first (has foreign keys to other tables)
DROP TABLE IF EXISTS workflow_step_executions CASCADE;
-- Drop workflow executions
DROP TABLE IF EXISTS workflow_executions CASCADE;
-- Drop workflow steps
DROP TABLE IF EXISTS workflow_steps CASCADE;
-- Drop the related enum types that are no longer needed
DROP TYPE IF EXISTS workflow_step_type CASCADE;
DROP TYPE IF EXISTS workflow_execution_status CASCADE;
-- Clean up any related indexes that might still exist
DROP INDEX IF EXISTS idx_workflow_steps_workflow_id CASCADE;
DROP INDEX IF EXISTS idx_workflow_steps_order CASCADE;
DROP INDEX IF EXISTS idx_workflow_executions_workflow_id CASCADE;
DROP INDEX IF EXISTS idx_workflow_executions_agent_id CASCADE;
DROP INDEX IF EXISTS idx_workflow_executions_status CASCADE;
DROP INDEX IF EXISTS idx_workflow_executions_started_at CASCADE;
DROP INDEX IF EXISTS idx_workflow_step_executions_execution_id CASCADE;
DROP INDEX IF EXISTS idx_workflow_step_executions_step_id CASCADE;
COMMIT;

View File

@ -0,0 +1,6 @@
-- Remove unused tables from schema cleanup
-- Drop dependent tables first, then main tables with CASCADE to handle any remaining dependencies
DROP TABLE IF EXISTS knowledge_base_usage_log CASCADE;
DROP TABLE IF EXISTS knowledge_base_entries CASCADE;
DROP TABLE IF EXISTS trigger_events CASCADE;
DROP TABLE IF EXISTS custom_trigger_providers CASCADE;

View File

@ -0,0 +1,19 @@
-- Migration: Remove agent_id and agent_version_id from threads table
-- This makes threads truly agent-agnostic - agent selection is handled only through agent/initiate and agent/start endpoints
BEGIN;
-- Drop indexes first
DROP INDEX IF EXISTS idx_threads_agent_id;
DROP INDEX IF EXISTS idx_threads_agent_version;
-- Remove agent_id column from threads table
ALTER TABLE threads DROP COLUMN IF EXISTS agent_id;
-- Remove agent_version_id column from threads table
ALTER TABLE threads DROP COLUMN IF EXISTS agent_version_id;
-- Update comment to reflect that threads are now completely agent-agnostic
COMMENT ON TABLE threads IS 'Conversation threads - completely agent-agnostic. Agent selection handled via /agent/initiate and /agent/start endpoints.';
COMMIT;

View File

@ -68,20 +68,7 @@ class WorkflowResponse(BaseModel):
created_at: str
updated_at: str
class WorkflowExecutionResponse(BaseModel):
id: str
workflow_id: str
agent_id: str
thread_id: Optional[str]
status: str
started_at: str
completed_at: Optional[str]
duration_seconds: Optional[float]
triggered_by: str
input_data: Optional[Dict[str, Any]]
output_data: Optional[Dict[str, Any]]
error_message: Optional[str]
created_at: str
class WorkflowExecuteRequest(BaseModel):
input_data: Optional[Dict[str, Any]] = None
@ -159,20 +146,6 @@ async def get_agent_workflows(
steps = []
if workflow_data.get('steps'):
steps = convert_json_to_steps(workflow_data['steps'])
else:
workflow_steps_result = await client.table('workflow_steps').select('*').eq('workflow_id', workflow_data['id']).order('step_order').execute()
for step_data in workflow_steps_result.data:
steps.append(WorkflowStepResponse(
id=step_data['id'],
name=step_data['name'],
description=step_data.get('description'),
type=step_data['type'],
config=step_data.get('config', {}),
conditions=step_data.get('conditions'),
order=step_data['step_order'],
created_at=step_data['created_at'],
updated_at=step_data['updated_at']
))
workflows.append(WorkflowResponse(
id=workflow_data['id'],
@ -264,8 +237,6 @@ async def update_agent_workflow(
if workflow_data.steps is not None:
steps_json = convert_steps_to_json(workflow_data.steps)
update_data['steps'] = steps_json
await client.table('workflow_steps').delete().eq('workflow_id', workflow_id).execute()
if update_data:
await client.table('agent_workflows').update(update_data).eq('id', workflow_id).execute()
@ -276,20 +247,6 @@ async def update_agent_workflow(
steps = []
if workflow_data.get('steps'):
steps = convert_json_to_steps(workflow_data['steps'])
else:
workflow_steps_result = await client.table('workflow_steps').select('*').eq('workflow_id', workflow_id).order('step_order').execute()
for step_data in workflow_steps_result.data:
steps.append(WorkflowStepResponse(
id=step_data['id'],
name=step_data['name'],
description=step_data.get('description'),
type=step_data['type'],
config=step_data.get('config', {}),
conditions=step_data.get('conditions'),
order=step_data['step_order'],
created_at=step_data['created_at'],
updated_at=step_data['updated_at']
))
return WorkflowResponse(
id=workflow_data['id'],
@ -409,37 +366,7 @@ async def execute_agent_workflow(
}
)
@router.get("/agents/{agent_id}/workflows/{workflow_id}/executions")
async def get_workflow_executions(
agent_id: str,
workflow_id: str,
user_id: str = Depends(get_current_user_id_from_jwt),
limit: int = Query(20, ge=1, le=100)
):
db = await get_db_connection()
client = await db.client
executions_result = await client.table('workflow_executions').select('*').eq('workflow_id', workflow_id).order('created_at', desc=True).limit(limit).execute()
executions = []
for execution_data in executions_result.data:
executions.append(WorkflowExecutionResponse(
id=execution_data['id'],
workflow_id=execution_data['workflow_id'],
agent_id=execution_data['agent_id'],
thread_id=execution_data.get('thread_id'),
status=execution_data['status'],
started_at=execution_data['started_at'],
completed_at=execution_data.get('completed_at'),
duration_seconds=execution_data.get('duration_seconds'),
triggered_by=execution_data['triggered_by'],
input_data=execution_data.get('input_data'),
output_data=execution_data.get('output_data'),
error_message=execution_data.get('error_message'),
created_at=execution_data['created_at']
))
return executions
@router.post("/agents/{agent_id}/workflows/{workflow_id}/webhook")
async def trigger_workflow_webhook(

View File

@ -400,9 +400,6 @@ class WorkflowExecutor:
await self._validate_workflow_execution(account_id)
await self._session_manager.start_sandbox(project_id)
execution_id = await self._create_workflow_execution_record(
workflow_id, agent_id, thread_id, workflow_input, trigger_result
)
await self._create_workflow_message(thread_id, workflow_config, workflow_input)
agent_run_id = await self._start_workflow_agent_execution(
@ -411,7 +408,6 @@ class WorkflowExecutor:
return {
"success": True,
"execution_id": execution_id,
"thread_id": thread_id,
"agent_run_id": agent_run_id,
"message": "Workflow execution started successfully"
@ -439,22 +435,11 @@ class WorkflowExecutor:
if workflow_config.get('steps'):
steps_json = workflow_config['steps']
else:
steps_json = await self._get_legacy_workflow_steps(workflow_id)
steps_json = []
return workflow_config, steps_json
async def _get_legacy_workflow_steps(self, workflow_id: str) -> list:
client = await self._db.client
workflow_steps_result = await client.table('workflow_steps').select('*').eq('workflow_id', workflow_id).order('step_order').execute()
return [{
'name': step_data['name'],
'description': step_data.get('description'),
'type': step_data['type'],
'config': step_data.get('config', {}),
'conditions': step_data.get('conditions'),
'order': step_data['step_order']
} for step_data in workflow_steps_result.data]
async def _get_agent_data(self, agent_id: str) -> Tuple[Dict[str, Any], str]:
from agent.versioning.domain.entities import AgentId
@ -547,26 +532,7 @@ class WorkflowExecutor:
if not can_run:
raise Exception(f"Billing check failed: {billing_message}")
async def _create_workflow_execution_record(
self,
workflow_id: str,
agent_id: str,
thread_id: str,
workflow_input: Dict[str, Any],
trigger_result: TriggerResult
) -> str:
client = await self._db.client
execution_result = await client.table('workflow_executions').insert({
'workflow_id': workflow_id,
'agent_id': agent_id,
'thread_id': thread_id,
'triggered_by': trigger_result.execution_variables.variables.get('triggered_by', 'trigger'),
'status': 'running',
'input_data': workflow_input
}).execute()
return execution_result.data[0]['id']
async def _create_workflow_message(
self,

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

View File

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

View File

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

View File

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

View File

@ -77,28 +77,6 @@ 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;
agent_id?: string; // Optional again
};
}) => startAgent(threadId, options),
{

View File

@ -14,7 +14,6 @@ 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,6 +321,7 @@ 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(

View File

@ -627,7 +627,7 @@ export const startAgent = async (
enable_thinking?: boolean;
reasoning_effort?: string;
stream?: boolean;
agent_id?: string;
agent_id?: string; // Optional again
},
): Promise<{ agent_run_id: string }> => {
try {
@ -656,7 +656,6 @@ export const startAgent = async (
enable_thinking: false,
reasoning_effort: 'low',
stream: true,
agent_id: undefined,
};
const finalOptions = { ...defaultOptions, ...options };

15
sdk_example.py Normal file
View File

@ -0,0 +1,15 @@
from kortix import Agent, ModelSettings, function_tool
agent = Agent(
name="Haiku agent",
instructions="Always respond in haiku form",
model="o3-mini",
tools=[get_weather],
)
assistant = client.beta.assistants.create(
name="Math Tutor",
instructions="You are a personal math tutor. Answer questions briefly, in a sentence or less.",
model="gpt-4o",
)