Repository: WorkflowAI/WorkflowAI
Pull request #55: AI roadmap agent updates
Author: login: yannbu
Created: 2025-04-08T11:07:53Z | Merged: 2025-04-08T14:25:02Z

Related to https://linear.app/workflowai/issue/WOR-3666/suggested-agents-relevancy-based-on-company-url


Diff:
diff --git a/api/api/dependencies/services.py b/api/api/dependencies/services.py
index 2d7959149..01ea80021 100644
--- a/api/api/dependencies/services.py
+++ b/api/api/dependencies/services.py
@@ -22,7 +22,6 @@
 from api.services.api_keys import APIKeyService
 from api.services.feedback_svc import FeedbackTokenGenerator
 from api.services.groups import GroupService
-from api.services.internal_tasks.agent_suggestions_service import TaskSuggestionsService
 from api.services.internal_tasks.internal_tasks_service import InternalTasksService
 from api.services.models import ModelsService
 from api.services.payments_service import PaymentService, PaymentSystemService
@@ -66,13 +65,6 @@ def file_storage_dependency() -> FileStorage:
 FileStorageDep = Annotated[FileStorage, Depends(file_storage_dependency)]
 
 
-def task_suggestions_service() -> TaskSuggestionsService:
-    return TaskSuggestionsService()
-
-
-AgentSuggestionsServiceDep = Annotated[TaskSuggestionsService, Depends(task_suggestions_service)]
-
-
 def group_service(
     storage: StorageDep,
     event_router: EventRouterDep,
diff --git a/api/api/main_router.py b/api/api/main_router.py
index f69e73196..ed5f4bb09 100644
--- a/api/api/main_router.py
+++ b/api/api/main_router.py
@@ -7,7 +7,7 @@
     feedback_v1,
     stripe_webhooks,
 )
-from api.routers.agents import home_agent, meta_agent, new_task_agent, new_tool_agent
+from api.routers.agents import meta_agent, new_tool_agent
 from api.tags import RouteTags
 from core.domain.tenant_data import PublicOrganizationData
 
@@ -57,7 +57,6 @@ def _tenant_router():
     tenant_router.include_router(runs_by_id.router, tags=[RouteTags.RUNS])
     tenant_router.include_router(upload.router, tags=[RouteTags.UPLOAD])
     tenant_router.include_router(reviews.router, tags=[RouteTags.REVIEWS])
-    tenant_router.include_router(new_task_agent.router, tags=[RouteTags.NEW_AGENT])
     # TODO: remove once the client has been updated
     tenant_router.include_router(payments.router, deprecated=True, include_in_schema=False)
     tenant_router.include_router(meta_agent.router, tags=[RouteTags.PROMPT_ENGINEER_AGENT])
@@ -87,7 +86,3 @@ def _authenticated_router():
 
 
 main_router.include_router(_authenticated_router())
-main_router.include_router(  # Routes for the landing page, unauthenticated
-    home_agent.router,
-    tags=[RouteTags.HOME_AGENT],
-)
diff --git a/api/api/routers/agents/home_agent.py b/api/api/routers/agents/home_agent.py
deleted file mode 100644
index 58821c359..000000000
--- a/api/api/routers/agents/home_agent.py
+++ /dev/null
@@ -1,91 +0,0 @@
-from fastapi import APIRouter
-from fastapi.responses import StreamingResponse
-from pydantic import BaseModel, Field
-
-from api.dependencies.services import AgentSuggestionsServiceDep
-from api.services.internal_tasks.agent_suggestions_service import (
-    SuggestedAgentOutputExampleOutputWithSchema,
-    SuggestLlmAgentsForCompanyOutputAndStatus,
-)
-from core.agents.suggest_llm_features_for_company_agent import (
-    AgentSuggestionChatMessage,
-    SuggestedAgent,
-)
-from core.utils.streams import format_model_for_sse
-
-router = APIRouter(prefix="/agents/home", include_in_schema=False)
-
-
-class TaskSuggestionChatRequest(BaseModel):
-    messages: list[AgentSuggestionChatMessage] = Field(
-        description="The list of previous messages in the conversation, the last message is the most recent one",
-    )
-
-
-@router.post(
-    "/messages",
-    description="Allows to chat with an assistant and get agent suggestions",
-    responses={
-        200: {
-            "content": {
-                "application/json": {
-                    "schema": SuggestLlmAgentsForCompanyOutputAndStatus.model_json_schema(),
-                },
-                "text/event-stream": {
-                    "schema": SuggestLlmAgentsForCompanyOutputAndStatus.model_json_schema(),
-                },
-            },
-        },
-    },
-)
-async def get_agent_suggestion_chat(
-    request: TaskSuggestionChatRequest,
-    agent_suggestions_service: AgentSuggestionsServiceDep,
-) -> StreamingResponse:
-    return StreamingResponse(
-        (
-            format_model_for_sse(chunk)
-            async for chunk in agent_suggestions_service.stream_agent_suggestions(
-                request.messages,
-                storage=None,  # No storage available, since user is not authenticated
-            )
-        ),
-        media_type="text/event-stream",
-    )
-
-
-class AgentSuggestionPreviewRequest(BaseModel):
-    suggested_agent: SuggestedAgent = Field(
-        description="The agent suggestion to generate output preview for",
-    )
-
-
-@router.post(
-    "/agents/preview",
-    description="Preview an agent suggestion's output",
-    responses={
-        200: {
-            "content": {
-                "application/json": {
-                    "schema": SuggestedAgentOutputExampleOutputWithSchema.model_json_schema(),
-                },
-                "text/event-stream": {
-                    "schema": SuggestedAgentOutputExampleOutputWithSchema.model_json_schema(),
-                },
-            },
-        },
-    },
-)
-async def get_agent_suggestion_preview(
-    request: AgentSuggestionPreviewRequest,
-    agent_suggestions_service: AgentSuggestionsServiceDep,
-) -> StreamingResponse:
-    return StreamingResponse(
-        (
-            format_model_for_sse(chunk)
-            async for chunk in agent_suggestions_service.stream_agent_output_preview(
-                request.suggested_agent,
-            )
-        ),
-        media_type="text/event-stream",
-    )
diff --git a/api/api/routers/agents/new_task_agent.py b/api/api/routers/agents/new_task_agent.py
deleted file mode 100644
index 12673d698..000000000
--- a/api/api/routers/agents/new_task_agent.py
+++ /dev/null
@@ -1,48 +0,0 @@
-from fastapi import APIRouter, HTTPException
-from fastapi.responses import StreamingResponse
-
-from api.dependencies.analytics import UserPropertiesDep
-from api.dependencies.security import UserOrganizationDep
-from api.dependencies.services import AgentSuggestionsServiceDep
-from api.dependencies.storage import StorageDep
-from api.services.internal_tasks.agent_suggestions_service import SuggestLlmAgentsForCompanyOutputAndStatus
-from core.utils.streams import format_model_for_sse
-
-router = APIRouter(prefix="/agents/new-agent")
-
-
-@router.post(
-    "/messages",
-    description="Allows to chat with an assistant and get agent suggestions",
-    responses={
-        200: {
-            "content": {
-                "application/json": {
-                    "schema": SuggestLlmAgentsForCompanyOutputAndStatus.model_json_schema(),
-                },
-                "text/event-stream": {
-                    "schema": SuggestLlmAgentsForCompanyOutputAndStatus.model_json_schema(),
-                },
-            },
-        },
-    },
-)
-async def get_agent_suggestion_chat(
-    user_org: UserOrganizationDep,
-    agent_suggestions_service: AgentSuggestionsServiceDep,
-    storage: StorageDep,
-    user_properties: UserPropertiesDep,
-) -> StreamingResponse:
-    if not user_org:
-        raise HTTPException(400, "Can not find organization for user")
-    return StreamingResponse(
-        (
-            format_model_for_sse(chunk)
-            async for chunk in agent_suggestions_service.stream_agent_suggestions(
-                [],
-                user_email=user_properties.user_email,
-                storage=storage,
-            )
-        ),
-        media_type="text/event-stream",
-    )
diff --git a/api/api/services/features.py b/api/api/services/features.py
index 212987ef0..33f151d6f 100644
--- a/api/api/services/features.py
+++ b/api/api/services/features.py
@@ -7,13 +7,13 @@
 from pydantic import BaseModel
 
 from api.services.internal_tasks._internal_tasks_utils import OFFICIALLY_SUGGESTED_TOOLS, officially_suggested_tools
-from api.services.internal_tasks.agent_suggestions_service import (
-    get_supported_task_input_types,
-    get_supported_task_output_types,
-)
 from api.services.slack_notifications import SlackNotificationDestination, get_user_and_org_str, send_slack_notification
 from core.agents.agent_output_example import SuggestedAgentOutputExampleInput, stream_suggested_agent_output_example
 from core.agents.agent_suggestion_validator_agent import SuggestedAgentValidationInput, run_suggested_agent_validation
+from core.agents.chat_task_schema_generation.chat_task_schema_generation_task import (
+    InputSchemaFieldType,
+    OutputSchemaFieldType,
+)
 from core.agents.chat_task_schema_generation.chat_task_schema_generation_task_utils import build_json_schema_with_defs
 from core.agents.chat_task_schema_generation.schema_generation_agent import (
     SchemaBuilderInput,
@@ -22,6 +22,9 @@
 from core.agents.company_agent_suggestion_agent import (
     INSTUCTIONS as AGENT_SUGGESTION_INSTRUCTIONS,
 )
+from core.agents.company_agent_suggestion_agent import (
+    CompanyContext as CompanyContextInput,
+)
 from core.agents.company_agent_suggestion_agent import (
     SuggestAgentForCompanyInput,
     SuggestedAgent,
@@ -43,6 +46,15 @@
 from core.utils.iter_utils import safe_map
 from core.utils.schema_utils import json_schema_from_json
 
+
+def get_supported_task_input_types() -> list[str]:
+    return [type.value for type in InputSchemaFieldType] + ["enum", "array", "object"]
+
+
+def get_supported_task_output_types() -> list[str]:
+    return [type.value for type in OutputSchemaFieldType] + ["enum", "array", "object"]
+
+
 _logger = logging.getLogger(__name__)
 
 
@@ -149,7 +161,8 @@ async def get_features_by_tag(
     async def _stream_company_context(self, company_url: str) -> AsyncIterator[CompanyContext]:
         try:
             async for chunk in stream_perplexity_search(
-                f"What does this company do:{company_url} ? Provide a concise description of the company and its products. Do not add any markdown or formatting (ex: bold, italic, underline, etc.) in the response, except line breaks, punctation and eventual bullet points.",
+                f"""What does this company do:{company_url}? Provide a concise description of the company and its products. Do not add any markdown or formatting (ex: bold, italic, underline, etc.) in the response, except line breaks, punctation and eventual bullet points.
+                Always browse the actual company domain ({company_url}) to get the most accurate and up to date description.""",
             ):
                 yield CompanyContext(public=chunk, private=chunk)
         except Exception as e:
@@ -200,7 +213,7 @@ async def _build_agent_suggestion_input(
                 ],
                 SuggestAgentForCompanyInput.ToolDescription.from_internal_tool,
             ),
-            company_context=SuggestAgentForCompanyInput.CompanyContext(
+            company_context=CompanyContextInput(
                 company_url=company_domain,
                 company_url_content=company_context,
                 # Existing agent are deactivate for now as I felt they were perturbating generation pertinence in some cases.
@@ -251,9 +264,10 @@ async def _stream_feature_suggestions(
         input: SuggestAgentForCompanyInput,
     ) -> AsyncIterator[CompanyFeaturePreviewList]:
         validation_decisions: dict[str, bool] = {}
+        features: list[BaseFeature] = []
 
         async for chunk in stream_suggest_agents_for_company(input):
-            features: list[BaseFeature] = []
+            features = []
             for agent in chunk.suggested_agents or []:
                 if isinstance(agent, dict):  # pyright: ignore[reportUnnecessaryIsInstance]
                     # For some reason, a dict is sometimes returned instead of a SuggestedAgent
diff --git a/api/api/services/features_test.py b/api/api/services/features_test.py
index c153ed72d..5d1ffd1f8 100644
--- a/api/api/services/features_test.py
+++ b/api/api/services/features_test.py
@@ -30,6 +30,9 @@
     SchemaBuilderInput,
     SchemaBuilderOutput,
 )
+from core.agents.company_agent_suggestion_agent import (
+    CompanyContext as CompanyContextInput,
+)
 from core.agents.company_agent_suggestion_agent import (
     SuggestAgentForCompanyInput,
     SuggestAgentForCompanyOutput,
@@ -436,7 +439,7 @@ async def mock_build_agent_suggestion_input(*args: Any, **kwargs: Any) -> Sugges
             supported_agent_input_types=[],
             supported_agent_output_types=[],
             available_tools=[],
-            company_context=SuggestAgentForCompanyInput.CompanyContext(
+            company_context=CompanyContextInput(
                 company_url=company_domain,
                 company_url_content=company_context_chunks[0].private,
                 existing_agents=[],
@@ -898,6 +901,8 @@ async def mock_is_validated(agent_name: str, instructions: str, validation_decis
         patch.object(service, "_is_agent_validated", side_effect=mock_is_validated),  # Use side_effect to pass args
     ):
         mock_input = Mock(spec=SuggestAgentForCompanyInput)
+        mock_input.company_context = None
+
         actual_outputs = [
             output
             async for output in service._stream_feature_suggestions(company_context, mock_input)  # pyright: ignore[reportPrivateUsage]
diff --git a/api/api/services/internal_tasks/agent_suggestions_service.py b/api/api/services/internal_tasks/agent_suggestions_service.py
deleted file mode 100644
index 07cf7e7fb..000000000
--- a/api/api/services/internal_tasks/agent_suggestions_service.py
+++ /dev/null
@@ -1,182 +0,0 @@
-import logging
-from typing import Any, AsyncIterator
-
-from pydantic import Field
-from typing_extensions import Literal
-
-from api.services.internal_tasks.internal_tasks_service import InternalTasksService
-from api.services.tasks import list_agent_summaries
-from core.agents.agent_input_output_example import (
-    SuggestedAgentInputOutputExampleInput,
-    SuggestedAgentInputOutputExampleOutput,
-    stream_suggested_agent_input_output_example,
-)
-from core.agents.chat_task_schema_generation.chat_task_schema_generation_task import (
-    AgentBuilderInput,
-    ChatMessageWithExtractedURLContent,
-    InputSchemaFieldType,
-    OutputSchemaFieldType,
-    agent_builder,
-)
-from core.agents.chat_task_schema_generation.chat_task_schema_generation_task_utils import build_json_schema_with_defs
-from core.agents.detect_company_domain_task import (
-    DetectCompanyDomainTaskInput,
-    run_detect_company_domain_task,
-)
-from core.agents.extract_company_info_from_domain_task import (
-    safe_extract_company_domain,
-    safe_generate_company_description_from_domain,
-)
-from core.agents.suggest_llm_features_for_company_agent import (
-    AgentSuggestionChatMessage,
-    SuggestedAgent,
-    SuggestLlmAgentForCompanyInput,
-    SuggestLlmAgentForCompanyOutput,
-    suggest_llm_agents_for_company,
-)
-from core.runners.workflowai.workflowai_runner import WorkflowAIRunner
-from core.storage.backend_storage import BackendStorage
-from core.utils.iter_utils import safe_map
-
-
-def get_supported_task_input_types() -> list[str]:
-    return [type.value for type in InputSchemaFieldType] + ["enum", "array", "object"]
-
-
-def get_supported_task_output_types() -> list[str]:
-    return [type.value for type in OutputSchemaFieldType] + ["enum", "array", "object"]
-
-
-class SuggestLlmAgentsForCompanyOutputAndStatus(SuggestLlmAgentForCompanyOutput):
-    status: Literal["extracting_company_domain", "analyzing_company_context", "generating_agent_suggestions"]
-
-
-class SuggestedAgentOutputExampleOutputWithSchema(SuggestedAgentInputOutputExampleOutput):
-    agent_input_schema: dict[str, Any] | None = Field(
-        default=None,
-        description="The JSON schema of the agent input",
-    )
-    agent_output_schema: dict[str, Any] | None = Field(
-        default=None,
-        description="The JSON schema of the agent output",
-    )
-
-
-class TaskSuggestionsService:
-    def __init__(self):
-        self._logger = logging.getLogger(self.__class__.__name__)
-
-    async def stream_agent_suggestions(
-        self,
-        messages: list[AgentSuggestionChatMessage] | None,
-        storage: BackendStorage | None,
-        user_email: str | None = None,
-    ) -> AsyncIterator[SuggestLlmAgentsForCompanyOutputAndStatus]:
-        if messages is None:
-            messages = []
-
-        if not user_email:
-            # Extract company domain from messages
-            yield SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-            )
-
-            detect_company_domain_output = await run_detect_company_domain_task(
-                DetectCompanyDomainTaskInput(messages=[message.to_chat_message() for message in messages]),
-            )
-
-            if not detect_company_domain_output.company_domain:
-                yield SuggestLlmAgentsForCompanyOutputAndStatus(
-                    status="extracting_company_domain",
-                    assistant_message=AgentSuggestionChatMessage(
-                        role="ASSISTANT",
-                        content_str=detect_company_domain_output.failure_assistant_answer
-                        or "Please provide your company domain",  # fallback message
-                    ),
-                )
-                return
-            company_domain = detect_company_domain_output.company_domain
-        else:
-            # Extract company domain from user email
-            company_domain = await safe_extract_company_domain(user_email)
-
-        yield SuggestLlmAgentsForCompanyOutputAndStatus(
-            status="analyzing_company_context",
-        )
-
-        company_description = await safe_generate_company_description_from_domain(company_domain)
-
-        yield SuggestLlmAgentsForCompanyOutputAndStatus(
-            status="generating_agent_suggestions",
-        )
-
-        agent_suggestion_input = SuggestLlmAgentForCompanyInput(
-            supported_agent_input_types=get_supported_task_input_types(),
-            supported_agent_output_types=get_supported_task_output_types(),
-            available_tools=safe_map(
-                WorkflowAIRunner.internal_tools.values(),
-                SuggestLlmAgentForCompanyInput.ToolDescription.from_internal_tool,
-            ),
-            company_context=SuggestLlmAgentForCompanyInput.CompanyContext(
-                company_name=company_description.company_name if company_description else None,
-                company_description=company_description.model_dump_json() if company_description else None,
-                # We can only feed the existing agents if the user is authenticated
-                existing_agents=[str(a) for a in await list_agent_summaries(storage)] if storage else [],
-            ),
-            messages=messages,
-        )
-
-        async for chunk in suggest_llm_agents_for_company(agent_suggestion_input):
-            yield SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-                assistant_message=chunk.assistant_message,
-            )
-
-    async def stream_agent_output_preview(
-        self,
-        suggested_agent: SuggestedAgent | None,
-    ) -> AsyncIterator[SuggestedAgentInputOutputExampleOutput]:
-        if suggested_agent is None:
-            return
-        agent_schema_gen_message = f"""{suggested_agent.agent_description}
-{suggested_agent.explanation}
-Input: {suggested_agent.input_specifications}
-Output: {suggested_agent.output_specifications}
-"""
-
-        agent_schema_gen_output = await agent_builder(
-            # User content is omitted here for latency reasons, this endpoint needs to be fast
-            AgentBuilderInput(
-                previous_messages=[],
-                new_message=ChatMessageWithExtractedURLContent(role="USER", content=agent_schema_gen_message),
-            ),
-            use_cache="always",
-        )
-
-        input_schema = (
-            build_json_schema_with_defs(agent_schema_gen_output.new_agent_schema.input_schema)
-            if agent_schema_gen_output.new_agent_schema
-            else None
-        )
-        output_schema = (
-            build_json_schema_with_defs(agent_schema_gen_output.new_agent_schema.output_schema)
-            if agent_schema_gen_output.new_agent_schema
-            else None
-        )
-
-        if output_schema:
-            output_schema = InternalTasksService.add_explanation_to_schema_if_needed(output_schema, self._logger)
-
-        agent_output_example_input = SuggestedAgentInputOutputExampleInput(
-            agent_description=suggested_agent.agent_description,
-            explaination=suggested_agent.explanation,
-            destination_department=suggested_agent.department,
-            input_json_schema=input_schema,
-            output_json_schema=output_schema,
-        )
-        async for chunk in stream_suggested_agent_input_output_example(agent_output_example_input):
-            yield SuggestedAgentOutputExampleOutputWithSchema(
-                **chunk.model_dump(),
-                agent_input_schema=input_schema,
-                agent_output_schema=output_schema,
-            )
diff --git a/api/api/services/internal_tasks/agent_suggestions_service_test.py b/api/api/services/internal_tasks/agent_suggestions_service_test.py
deleted file mode 100644
index aa306a16d..000000000
--- a/api/api/services/internal_tasks/agent_suggestions_service_test.py
+++ /dev/null
@@ -1,491 +0,0 @@
-from unittest.mock import AsyncMock, Mock, patch
-
-import pytest
-
-from api.services.internal_tasks.agent_suggestions_service import (
-    SuggestLlmAgentsForCompanyOutputAndStatus,
-    TaskSuggestionsService,
-)
-from core.agents.agent_input_output_example import SuggestedAgentInputOutputExampleOutput
-from core.agents.chat_task_schema_generation.chat_task_schema_generation_task import (
-    AgentBuilderOutput,
-    AgentSchema,
-    InputObjectFieldConfig,
-    OutputObjectFieldConfig,
-)
-from core.agents.detect_company_domain_task import (
-    DetectCompanyDomainTaskInput,
-    DetectCompanyDomainTaskOutput,
-)
-from core.agents.extract_company_info_from_domain_task import (
-    ExtractCompanyInfoFromDomainTaskInput,
-    ExtractCompanyInfoFromDomainTaskOutput,
-    Product,
-)
-from core.agents.suggest_llm_features_for_company_agent import (
-    AgentSuggestionChatMessage,
-    SuggestedAgent,
-    SuggestLlmAgentForCompanyOutput,
-)
-from core.domain.fields.chat_message import ChatMessage
-from core.storage.backend_storage import BackendStorage
-from tests.utils import mock_aiter
-
-
-@pytest.fixture
-def service():
-    return TaskSuggestionsService()
-
-
-class TestTaskSuggestionsService:
-    async def test_stream_task_suggestions_with_successful_domain_detection(self, service: TaskSuggestionsService):
-        # Arrange
-        messages = [AgentSuggestionChatMessage(role="USER", content_str="Hi, I work at test.com")]
-
-        mock_domain_detection = DetectCompanyDomainTaskOutput(
-            company_domain="test.com",
-        )
-
-        mock_company_info = ExtractCompanyInfoFromDomainTaskOutput(
-            company_name="TestCo",
-            description="A test company",
-            locations=["USA"],
-            industries=["Technology"],
-            products=[
-                Product(
-                    name="Test Product",
-                    features=["Feature 1", "Feature 2"],
-                    description="A test product",
-                    target_users=["Developers"],
-                ),
-            ],
-        )
-
-        mock_suggestions = [
-            SuggestLlmAgentForCompanyOutput(
-                assistant_message=AgentSuggestionChatMessage(role="ASSISTANT", content_str="Suggestion 1"),
-            ),
-            SuggestLlmAgentForCompanyOutput(
-                assistant_message=AgentSuggestionChatMessage(role="ASSISTANT", content_str="Suggestion 2"),
-            ),
-        ]
-
-        with (
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.run_detect_company_domain_task",
-                new_callable=AsyncMock,
-                return_value=mock_domain_detection,
-            ) as mock_detect,
-            patch(
-                "core.agents.extract_company_info_from_domain_task._extract_company_info_from_domain",
-                new_callable=AsyncMock,
-                return_value=mock_company_info,
-            ) as mock_extract,
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.suggest_llm_agents_for_company",
-                return_value=mock_aiter(*mock_suggestions),
-            ) as mock_stream,
-        ):
-            mock_storage = Mock(spec=BackendStorage)
-            mock_storage.fetch_tasks = Mock(return_value=mock_aiter())
-            results = [c async for c in service.stream_agent_suggestions(messages, storage=mock_storage)]
-
-            # Assert
-            assert len(results) == 5  # 3 status updates + 2 suggestions
-            assert results[0] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-            )
-            assert results[1] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="analyzing_company_context",
-            )
-            assert results[2] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-            )
-            assert results[3] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-                assistant_message=AgentSuggestionChatMessage(
-                    role="ASSISTANT",
-                    content_str="Suggestion 1",
-                ),
-            )
-
-            mock_detect.assert_awaited_once_with(
-                DetectCompanyDomainTaskInput(
-                    messages=[ChatMessage(role="USER", content="Hi, I work at test.com")],
-                ),
-            )
-            mock_extract.assert_awaited_once_with(
-                ExtractCompanyInfoFromDomainTaskInput(company_domain="test.com"),
-                use_cache="always",
-            )
-            mock_stream.assert_called_once()
-            mock_storage.fetch_tasks.assert_called_once()
-            call_args = mock_stream.call_args[0][0]
-            assert call_args.messages == messages
-            assert call_args.company_context.company_name == "TestCo"
-
-    async def test_stream_task_suggestions_with_failed_domain_detection(self, service: TaskSuggestionsService):
-        # Arrange
-        messages = [AgentSuggestionChatMessage(role="USER", content_str="Hi, can you help me?")]
-
-        mock_domain_detection = DetectCompanyDomainTaskOutput(
-            company_domain=None,
-            failure_assistant_answer="I couldn't detect your company domain. Could you please provide it?",
-        )
-
-        with patch(
-            "api.services.internal_tasks.agent_suggestions_service.run_detect_company_domain_task",
-            new_callable=AsyncMock,
-            return_value=mock_domain_detection,
-        ) as mock_detect:
-            mock_storage = Mock(spec=BackendStorage)
-            mock_storage.fetch_tasks = Mock(return_value=mock_aiter())
-            results = [c async for c in service.stream_agent_suggestions(messages, storage=mock_storage)]
-
-            # Assert
-            assert len(results) == 2  # Initial status + failure message
-            assert results[0] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-            )
-            assert results[1] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-                assistant_message=AgentSuggestionChatMessage(
-                    role="ASSISTANT",
-                    content_str="I couldn't detect your company domain. Could you please provide it?",
-                ),
-            )
-
-            mock_detect.assert_awaited_once_with(
-                DetectCompanyDomainTaskInput(
-                    messages=[ChatMessage(role="USER", content="Hi, can you help me?")],
-                ),
-            )
-            mock_storage.fetch_tasks.assert_not_called()
-
-    async def test_stream_task_suggestions_with_empty_messages(self, service: TaskSuggestionsService):
-        # Test with empty messages list
-        mock_domain_detection = DetectCompanyDomainTaskOutput(
-            company_domain=None,
-            failure_assistant_answer="Please provide your company domain to get started.",
-        )
-
-        with patch(
-            "api.services.internal_tasks.agent_suggestions_service.run_detect_company_domain_task",
-            new_callable=AsyncMock,
-            return_value=mock_domain_detection,
-        ) as mock_detect:
-            mock_storage = Mock(spec=BackendStorage)
-            mock_storage.fetch_tasks = Mock(return_value=mock_aiter())
-            results = [c async for c in service.stream_agent_suggestions([], storage=mock_storage)]
-
-            assert len(results) == 2
-            assert results[0] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-            )
-            assert results[1] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-                assistant_message=AgentSuggestionChatMessage(
-                    role="ASSISTANT",
-                    content_str="Please provide your company domain to get started.",
-                ),
-            )
-
-            mock_detect.assert_awaited_once_with(DetectCompanyDomainTaskInput(messages=[]))
-            mock_storage.fetch_tasks.assert_not_called()
-
-    async def test_stream_task_suggestions_with_none_messages(self, service: TaskSuggestionsService):
-        # Test with None messages
-        mock_domain_detection = DetectCompanyDomainTaskOutput(
-            company_domain=None,
-            failure_assistant_answer="Please provide your company domain to get started.",
-        )
-
-        with patch(
-            "api.services.internal_tasks.agent_suggestions_service.run_detect_company_domain_task",
-            new_callable=AsyncMock,
-            return_value=mock_domain_detection,
-        ) as mock_detect:
-            mock_storage = Mock(spec=BackendStorage)
-            mock_storage.fetch_tasks = Mock(return_value=mock_aiter())
-            results = [c async for c in service.stream_agent_suggestions(None, storage=mock_storage)]
-
-            assert len(results) == 2
-            assert results[0] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-            )
-            assert results[1] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-                assistant_message=AgentSuggestionChatMessage(
-                    role="ASSISTANT",
-                    content_str="Please provide your company domain to get started.",
-                ),
-            )
-
-            mock_detect.assert_awaited_once_with(DetectCompanyDomainTaskInput(messages=[]))
-            mock_storage.fetch_tasks.assert_not_called()
-
-    async def test_stream_task_output_preview_with_valid_task(self, service: TaskSuggestionsService):
-        # Arrange
-        suggested_task = SuggestedAgent(
-            agent_description="Test task",
-            explanation="Test explanation",
-            input_specifications="input specs",
-            output_specifications="output specs",
-            department="Engineering",
-        )
-
-        mock_schema = AgentSchema(
-            agent_name="Test Task",
-            input_schema=InputObjectFieldConfig(),
-            output_schema=OutputObjectFieldConfig(),
-        )
-
-        mock_schema_gen_output = AgentBuilderOutput(
-            answer_to_user="Test answer",
-            new_agent_schema=mock_schema,
-        )
-
-        mock_preview_chunks = [
-            SuggestedAgentInputOutputExampleOutput(agent_output_example={"example": "Example"}),
-            SuggestedAgentInputOutputExampleOutput(agent_output_example={"example": "Example string"}),
-        ]
-
-        with (
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.agent_builder",
-                new_callable=AsyncMock,
-                return_value=mock_schema_gen_output,
-            ) as mock_run_schema,
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.stream_suggested_agent_input_output_example",
-                return_value=mock_aiter(*mock_preview_chunks),
-            ) as mock_stream,
-        ):
-            # Act
-            results = [c async for c in service.stream_agent_output_preview(suggested_task)]
-
-            # Assert
-            assert len(results) == 2
-            assert results[0].agent_output_example == {"example": "Example"}
-            assert results[1].agent_output_example == {"example": "Example string"}
-
-            mock_run_schema.assert_awaited_once()
-            schema_input = mock_run_schema.call_args[0][0]
-            assert schema_input.new_message.content == (
-                "Test task\nTest explanation\nInput: input specs\nOutput: output specs\n"
-            )
-
-            mock_stream.assert_called_once()
-            preview_input = mock_stream.call_args[0][0]
-            assert preview_input.agent_description == "Test task"
-            assert preview_input.explaination == "Test explanation"
-            assert preview_input.destination_department == "Engineering"
-
-    async def test_stream_task_output_preview_with_no_schema(self, service: TaskSuggestionsService):
-        # Test when schema generation returns no schema
-        suggested_task = SuggestedAgent(
-            agent_description="Test task",
-            explanation="Test explanation",
-            input_specifications="input specs",
-            output_specifications="output specs",
-            department="Engineering",
-        )
-
-        mock_schema_gen_output = AgentBuilderOutput(
-            answer_to_user="Test answer",
-            new_agent_schema=None,  # No schema generated
-        )
-
-        with (
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.agent_builder",
-                new_callable=AsyncMock,
-                return_value=mock_schema_gen_output,
-            ),
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.stream_suggested_agent_input_output_example",
-                return_value=mock_aiter(
-                    SuggestedAgentInputOutputExampleOutput(agent_output_example={"example": "Example"}),
-                ),
-            ) as mock_stream,
-        ):
-            results = [c async for c in service.stream_agent_output_preview(suggested_task)]
-
-            assert len(results) == 1
-            preview_input = mock_stream.call_args[0][0]
-            assert preview_input.input_json_schema is None
-            assert preview_input.output_json_schema is None
-
-    async def test_stream_task_suggestions_with_provided_domain(self, service: TaskSuggestionsService):
-        # Arrange
-        messages = [AgentSuggestionChatMessage(role="USER", content_str="Hi, can you help me?")]
-        user_email = "john@example.com"
-
-        mock_company_info = ExtractCompanyInfoFromDomainTaskOutput(
-            company_name="ExampleCo",
-            description="An example company",
-            locations=["USA"],
-            industries=["Technology"],
-            products=[
-                Product(
-                    name="Example Product",
-                    features=["Feature 1"],
-                    description="An example product",
-                    target_users=["Users"],
-                ),
-            ],
-        )
-
-        mock_suggestions = [
-            SuggestLlmAgentForCompanyOutput(
-                assistant_message=AgentSuggestionChatMessage(role="ASSISTANT", content_str="Suggestion 1"),
-            ),
-        ]
-
-        with (
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.run_detect_company_domain_task",
-            ) as mock_detect,
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.safe_extract_company_domain",
-                return_value=ExtractCompanyInfoFromDomainTaskInput(company_domain="example.com"),
-            ),
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.safe_generate_company_description_from_domain",
-                return_value=mock_company_info,
-            ) as mock_extract,
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.suggest_llm_agents_for_company",
-                return_value=mock_aiter(*mock_suggestions),
-            ) as mock_stream,
-        ):
-            # Act
-            mock_storage = Mock(spec=BackendStorage)
-            mock_storage.fetch_tasks = Mock(return_value=mock_aiter())
-            results = [
-                c
-                async for c in service.stream_agent_suggestions(
-                    messages,
-                    user_email=user_email,
-                    storage=mock_storage,
-                )
-            ]
-
-            # Assert
-            assert len(results) == 3  # 2 status updates + 1 suggestion
-            assert results[0] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="analyzing_company_context",
-            )
-            assert results[1] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-            )
-            assert results[2] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-                assistant_message=AgentSuggestionChatMessage(
-                    role="ASSISTANT",
-                    content_str="Suggestion 1",
-                ),
-            )
-
-            # Verify domain detection was not called
-            mock_detect.assert_not_called()
-
-            # Verify company info extraction was called with provided domain
-            mock_extract.assert_awaited_once_with(
-                ExtractCompanyInfoFromDomainTaskInput(company_domain="example.com"),
-            )
-
-            # Verify task suggestions were generated with correct context
-            assert mock_stream.call_count == 1
-            call_args = mock_stream.call_args[0][0]
-            assert call_args.messages == messages
-            assert call_args.company_context.company_name == "ExampleCo"
-            mock_storage.fetch_tasks.assert_called_once()
-
-    async def test_stream_task_suggestions_with_successful_domain_detection_no_storage(
-        self,
-        service: TaskSuggestionsService,
-    ):
-        # Happy path without storage provider
-
-        # Arrange
-        messages = [AgentSuggestionChatMessage(role="USER", content_str="Hi, I work at test.com")]
-
-        mock_domain_detection = DetectCompanyDomainTaskOutput(
-            company_domain="test.com",
-        )
-
-        mock_company_info = ExtractCompanyInfoFromDomainTaskOutput(
-            company_name="TestCo",
-            description="A test company",
-            locations=["USA"],
-            industries=["Technology"],
-            products=[
-                Product(
-                    name="Test Product",
-                    features=["Feature 1", "Feature 2"],
-                    description="A test product",
-                    target_users=["Developers"],
-                ),
-            ],
-        )
-
-        mock_suggestions = [
-            SuggestLlmAgentForCompanyOutput(
-                assistant_message=AgentSuggestionChatMessage(role="ASSISTANT", content_str="Suggestion 1"),
-            ),
-            SuggestLlmAgentForCompanyOutput(
-                assistant_message=AgentSuggestionChatMessage(role="ASSISTANT", content_str="Suggestion 2"),
-            ),
-        ]
-
-        with (
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.run_detect_company_domain_task",
-                new_callable=AsyncMock,
-                return_value=mock_domain_detection,
-            ) as mock_detect,
-            patch(
-                "core.agents.extract_company_info_from_domain_task._extract_company_info_from_domain",
-                new_callable=AsyncMock,
-                return_value=mock_company_info,
-            ) as mock_extract,
-            patch(
-                "api.services.internal_tasks.agent_suggestions_service.suggest_llm_agents_for_company",
-                return_value=mock_aiter(*mock_suggestions),
-            ) as mock_stream,
-        ):
-            results = [c async for c in service.stream_agent_suggestions(messages, storage=None)]
-
-            # Assert
-            assert len(results) == 5  # 3 status updates + 2 suggestions
-            assert results[0] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="extracting_company_domain",
-            )
-            assert results[1] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="analyzing_company_context",
-            )
-            assert results[2] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-            )
-            assert results[3] == SuggestLlmAgentsForCompanyOutputAndStatus(
-                status="generating_agent_suggestions",
-                assistant_message=AgentSuggestionChatMessage(
-                    role="ASSISTANT",
-                    content_str="Suggestion 1",
-                ),
-            )
-
-            mock_detect.assert_awaited_once_with(
-                DetectCompanyDomainTaskInput(
-                    messages=[ChatMessage(role="USER", content="Hi, I work at test.com")],
-                ),
-            )
-            mock_extract.assert_awaited_once_with(
-                ExtractCompanyInfoFromDomainTaskInput(company_domain="test.com"),
-                use_cache="always",
-            )
-            mock_stream.assert_called_once()
-            call_args = mock_stream.call_args[0][0]
-            assert call_args.messages == messages
-            assert call_args.company_context.company_name == "TestCo"
diff --git a/api/api/tags.py b/api/api/tags.py
index 5b77ac0f8..049d1fdce 100644
--- a/api/api/tags.py
+++ b/api/api/tags.py
@@ -16,8 +16,6 @@ class RouteTags(str, Enum):
     API_KEYS = "API Keys"
     REVIEWS = "Reviews"
     UPLOAD = "Upload Files"
-    HOME_AGENT = "Home Agent"
-    NEW_AGENT = "New Agent"
     VERSIONS = "Versions"
     PAYMENTS = "Payments"
     NEW_TOOL_AGENT = "New Tool Agent"
diff --git a/api/core/agents/company_agent_suggestion_agent.py b/api/core/agents/company_agent_suggestion_agent.py
index 12b9710fa..1edcf8ef4 100644
--- a/api/core/agents/company_agent_suggestion_agent.py
+++ b/api/core/agents/company_agent_suggestion_agent.py
@@ -36,6 +36,25 @@ class SuggestedAgent(BaseModel):
     )
 
 
+class CompanyContext(BaseModel):
+    company_url: str | None = Field(
+        default=None,
+        description="An URL provided by the client in order for they to get agent suggestions",
+    )
+    company_url_content: str | None = Field(
+        default=None,
+        description="The content of the 'company_url'",
+    )
+    latest_news: str | None = Field(
+        default=None,
+        description="A description of the latest news for the company (ex: new product launch, new features, acquisitions, new regulations, industry trends, competitors news)",
+    )
+    existing_agents: list[str] | None = Field(
+        default=None,
+        description="The list of existing agents for the company",
+    )
+
+
 class SuggestAgentForCompanyInput(BaseModel):
     supported_agent_input_types: list[str] | None = Field(
         default=None,
@@ -67,24 +86,6 @@ def from_internal_tool(cls, tool: InternalTool):
         description="The list of available tools that can be used by suggested agents",
     )
 
-    class CompanyContext(BaseModel):
-        company_url: str | None = Field(
-            default=None,
-            description="An URL provided by the client in order for they to get agent suggestions",
-        )
-        company_url_content: str | None = Field(
-            default=None,
-            description="The content of the 'company_url'",
-        )
-        latest_news: str | None = Field(
-            default=None,
-            description="A description of the latest news for the company (ex: new product launch, new features, acquisitions, new regulations, industry trends, competitors news)",
-        )
-        existing_agents: list[str] | None = Field(
-            default=None,
-            description="The list of existing agents for the company",
-        )
-
     company_context: CompanyContext | None = Field(
         default=None,
         description="The context of the company",
@@ -231,7 +232,7 @@ class SuggestAgentForCompanyOutput(BaseModel):
     - Use case related to documentation, compatibility, privacy policies, etc.
     - Content Accessibility Enhancer (too vague)
 
-    Think step by step before proposing an agent. Make sure to follow the instructions and the examples and avoid the agents to avoid.
+    Make sure to follow the instructions above, and to avoid the agents mentioned in the 'Agents to AVOID' section.
 
     # Guidelines for writing the name and description of the suggested agents
     - the 'suggested_agents.name' must follow the following convention: [subject that is acted upon] + [the action], in Title Case. Ex: 'Sentiment Analysis', 'Text Summarization', 'Location Detection'. Avoid using "Generation" in the agent name, as all agents perform generation anyway.


Reviews:
user: login: guillaq
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:07:02Z
user: login: guillaq
state: APPROVED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:07:40Z
user: login: yannbu
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-04-08T14:13:09Z

Review comments:
diff_hunk: @@ -43,6 +50,15 @@
 from core.utils.iter_utils import safe_map
 from core.utils.schema_utils import json_schema_from_json
 
+
+def get_supported_task_input_types() -> list[str]:
path: api/api/services/features.py
user: login: guillaq
body: is that used anywhere ? 
created_at: 2025-04-08T14:07:02Z
author_association: CONTRIBUTOR
diff_hunk: @@ -231,7 +232,7 @@ class SuggestAgentForCompanyOutput(BaseModel):
     - Use case related to documentation, compatibility, privacy policies, etc.
     - Content Accessibility Enhancer (too vague)
 
-    Think step by step before proposing an agent. Make sure to follow the instructions and the examples and avoid the agents to avoid.
+    Make sure to follow the instructions above, and to avoid the agents mentionned in the 'Agents to AVOID' section.
path: api/core/agents/company_agent_suggestion_agent.py
user: login: guillaq
body: ```suggestion
    Make sure to follow the instructions above, and to avoid the agents mentioned in the 'Agents to AVOID' section.
```
created_at: 2025-04-08T14:07:36Z
author_association: CONTRIBUTOR
diff_hunk: @@ -43,6 +50,15 @@
 from core.utils.iter_utils import safe_map
 from core.utils.schema_utils import json_schema_from_json
 
+
+def get_supported_task_input_types() -> list[str]:
path: api/api/services/features.py
user: login: yannbu
body: yes, in features.py but you don't see a diff because get_supported_task_input_types was used from another module before (that I've deleted)
created_at: 2025-04-08T14:13:09Z
author_association: CONTRIBUTOR

PR comments:
user: login: vercel[bot]
created_at: 2025-04-08T11:07:58Z
body: [vc]: #upwoUBWpdTepzBovGTWgwskStv3mszh8DqXLJ8ONhkI=:eyJpc01vbm9yZXBvIjp0cnVlLCJ0eXBlIjoiZ2l0aHViIiwicHJvamVjdHMiOlt7Im5hbWUiOiJ3b3JrZmxvd2FpLmNvbSIsImluc3BlY3RvclVybCI6Imh0dHBzOi8vdmVyY2VsLmNvbS93b3JrZmxvd2FpL3dvcmtmbG93YWkuY29tL0R3c0p5YmpEYm9MWG5DV1ZiY2d6enVyd3VDVEYiLCJwcmV2aWV3VXJsIjoid29ya2Zsb3dhaWNvbS1naXQteWFubi13b3ItMzY2Ni1zdWdnZXN0ZWQtYWdlLWI2YzY2ZS13b3JrZmxvd2FpLnZlcmNlbC5hcHAiLCJuZXh0Q29tbWl0U3RhdHVzIjoiREVQTE9ZRUQiLCJsaXZlRmVlZGJhY2siOnsicmVzb2x2ZWQiOjAsInVucmVzb2x2ZWQiOjAsInRvdGFsIjowLCJsaW5rIjoid29ya2Zsb3dhaWNvbS1naXQteWFubi13b3ItMzY2Ni1zdWdnZXN0ZWQtYWdlLWI2YzY2ZS13b3JrZmxvd2FpLnZlcmNlbC5hcHAifSwicm9vdERpcmVjdG9yeSI6ImNsaWVudCJ9XX0=
**The latest updates on your projects**. Learn more about [Vercel for Git ↗︎](https://vercel.link/github-learn-more)

| Name | Status | Preview | Comments | Updated (UTC) |
| :--- | :----- | :------ | :------- | :------ |
| **workflowai.com** | ✅ Ready ([Inspect](https://vercel.com/workflowai/workflowai.com/DwsJybjDboLXnCWVbcgzzurwuCTF)) | [Visit Preview](https://workflowaicom-git-yann-wor-3666-suggested-age-b6c66e-workflowai.vercel.app) | 💬 [**Add feedback**](https://vercel.live/open-feedback/workflowaicom-git-yann-wor-3666-suggested-age-b6c66e-workflowai.vercel.app?via=pr-comment-feedback-link) | Apr 8, 2025 2:22pm |


author_association: NONE
user: login: yannbu
created_at: 2025-04-08T14:05:42Z
body: @guillaq the MR is ready, could you check ? thanks !
author_association: CONTRIBUTOR