├── .agentignore ├── .agentindexignore ├── .codex └── setup.sh ├── .cursorignore ├── .cursorindexignore ├── .cursorrules ├── .env.example ├── .github ├── CODE_OF_CONDUCT.md ├── ISSUE_TEMPLATE │ ├── bug_report.yml │ ├── config.yml │ ├── feature_request.yml │ └── refactor.yml ├── README-CN.md ├── README-FR.md ├── README-JA.md ├── SUPPORT.md ├── dependabot.yml ├── i-have-an-announcement.gif ├── julep-cup.png ├── julep-definition.png ├── julep-logo.svg ├── julep-meaning-banner.png └── workflows │ ├── bake-push-to-hub.yml │ ├── bandit-security-check-python-agents-api.yml │ ├── changelog-ci.yml │ ├── claude.yml │ ├── docker-bake-on-pr.yml │ ├── doctoc-on-push.yml │ ├── generate-changelog.yml │ ├── generate-openapi-code-from-typespec.yml │ ├── latest-push-to-hub.yml │ ├── lint-agents-api-pr.yml │ ├── lint-integrations-service-pr.yml │ ├── test-agents-api-pr.yml │ ├── test-integrations-service-pr.yml │ ├── translate-readme.yml │ └── typecheck-agents-api-pr.yml ├── .gitignore ├── .gitmodules ├── AGENTS.md ├── CHANGELOG.md ├── CLAUDE.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── agents-api ├── .dockerignore ├── .gitignore ├── .python-version ├── .tool-versions ├── AGENTS.md ├── CLAUDE.md ├── Dockerfile ├── Dockerfile.worker ├── README.md ├── agents_api │ ├── __init__.py │ ├── activities │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── demo.py │ │ ├── execute_api_call.py │ │ ├── execute_integration.py │ │ ├── execute_system.py │ │ ├── logger.py │ │ ├── pg_query_step.py │ │ ├── sync_items_remote.py │ │ ├── task_steps │ │ │ ├── __init__.py │ │ │ ├── base_evaluate.py │ │ │ ├── get_value_step.py │ │ │ ├── prompt_step.py │ │ │ ├── raise_complete_async.py │ │ │ ├── tool_call_step.py │ │ │ └── transition_step.py │ │ └── tool_executor.py │ ├── app.py │ ├── autogen │ │ ├── .ignore │ │ ├── AGENTS.md │ │ ├── Agents.py │ │ ├── CLAUDE.md │ │ ├── Chat.py │ │ ├── Common.py │ │ ├── Docs.py │ │ ├── Entries.py │ │ ├── Executions.py │ │ ├── Files.py │ │ ├── Jobs.py │ │ ├── Projects.py │ │ ├── Responses.py │ │ ├── Secrets.py │ │ ├── Sessions.py │ │ ├── Tasks.py │ │ ├── Tools.py │ │ ├── Users.py │ │ ├── __init__.py │ │ └── openapi_model.py │ ├── clients │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── async_s3.py │ │ ├── integrations.py │ │ ├── litellm.py │ │ ├── pg.py │ │ ├── sync_s3.py │ │ └── temporal.py │ ├── common │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── exceptions │ │ │ ├── __init__.py │ │ │ ├── agents.py │ │ │ ├── executions.py │ │ │ ├── secrets.py │ │ │ ├── sessions.py │ │ │ ├── tasks.py │ │ │ ├── tools.py │ │ │ ├── users.py │ │ │ └── validation.py │ │ ├── interceptors.py │ │ ├── nlp.py │ │ ├── protocol │ │ │ ├── __init__.py │ │ │ ├── agents.py │ │ │ ├── developers.py │ │ │ ├── models.py │ │ │ ├── sessions.py │ │ │ ├── state_machine.py │ │ │ └── tasks.py │ │ ├── retry_policies.py │ │ └── utils │ │ │ ├── __init__.py │ │ │ ├── checks.py │ │ │ ├── datetime.py │ │ │ ├── db_exceptions.py │ │ │ ├── evaluator.py │ │ │ ├── expressions.py │ │ │ ├── get_doc_search.py │ │ │ ├── humanization_utils.py │ │ │ ├── json.py │ │ │ ├── llm_providers.py │ │ │ ├── memory.py │ │ │ ├── messages.py │ │ │ ├── mmr.py │ │ │ ├── secrets.py │ │ │ ├── task_validation.py │ │ │ ├── template.py │ │ │ ├── types.py │ │ │ ├── usage.py │ │ │ ├── workflows.py │ │ │ └── yaml.py │ ├── dependencies │ │ ├── __init__.py │ │ ├── auth.py │ │ ├── content_length.py │ │ ├── developer_id.py │ │ ├── exceptions.py │ │ └── query_filter.py │ ├── env.py │ ├── exceptions.py │ ├── metrics │ │ ├── __init__.py │ │ └── counters.py │ ├── model_registry.py │ ├── queries │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── agents │ │ │ ├── __init__.py │ │ │ ├── create_agent.py │ │ │ ├── create_or_update_agent.py │ │ │ ├── delete_agent.py │ │ │ ├── get_agent.py │ │ │ ├── list_agents.py │ │ │ ├── patch_agent.py │ │ │ └── update_agent.py │ │ ├── chat │ │ │ ├── __init__.py │ │ │ ├── gather_messages.py │ │ │ └── prepare_chat_context.py │ │ ├── developers │ │ │ ├── __init__.py │ │ │ ├── create_developer.py │ │ │ ├── get_developer.py │ │ │ ├── patch_developer.py │ │ │ └── update_developer.py │ │ ├── docs │ │ │ ├── __init__.py │ │ │ ├── bulk_delete_docs.py │ │ │ ├── create_doc.py │ │ │ ├── delete_doc.py │ │ │ ├── get_doc.py │ │ │ ├── list_docs.py │ │ │ ├── search_docs_by_embedding.py │ │ │ ├── search_docs_by_text.py │ │ │ ├── search_docs_hybrid.py │ │ │ └── utils.py │ │ ├── entries │ │ │ ├── __init__.py │ │ │ ├── create_entries.py │ │ │ ├── delete_entries.py │ │ │ ├── get_history.py │ │ │ └── list_entries.py │ │ ├── executions │ │ │ ├── __init__.py │ │ │ ├── constants.py │ │ │ ├── count_executions.py │ │ │ ├── create_execution.py │ │ │ ├── create_execution_transition.py │ │ │ ├── create_temporal_lookup.py │ │ │ ├── get_execution.py │ │ │ ├── get_execution_status.py │ │ │ ├── get_execution_transition.py │ │ │ ├── get_paused_execution_token.py │ │ │ ├── get_temporal_workflow_data.py │ │ │ ├── list_execution_inputs_data.py │ │ │ ├── list_execution_state_data.py │ │ │ ├── list_execution_transitions.py │ │ │ ├── list_executions.py │ │ │ ├── lookup_temporal_data.py │ │ │ └── prepare_execution_input.py │ │ ├── files │ │ │ ├── __init__.py │ │ │ ├── create_file.py │ │ │ ├── delete_file.py │ │ │ ├── get_file.py │ │ │ └── list_files.py │ │ ├── projects │ │ │ ├── __init__.py │ │ │ ├── create_project.py │ │ │ ├── list_projects.py │ │ │ └── project_exists.py │ │ ├── secrets │ │ │ ├── __init__.py │ │ │ ├── create.py │ │ │ ├── delete.py │ │ │ ├── get_by_name.py │ │ │ ├── list.py │ │ │ └── update.py │ │ ├── sessions │ │ │ ├── __init__.py │ │ │ ├── count_sessions.py │ │ │ ├── create_or_update_session.py │ │ │ ├── create_session.py │ │ │ ├── delete_session.py │ │ │ ├── get_session.py │ │ │ ├── list_sessions.py │ │ │ ├── patch_session.py │ │ │ └── update_session.py │ │ ├── tasks │ │ │ ├── __init__.py │ │ │ ├── create_or_update_task.py │ │ │ ├── create_task.py │ │ │ ├── delete_task.py │ │ │ ├── get_task.py │ │ │ ├── list_tasks.py │ │ │ ├── patch_task.py │ │ │ └── update_task.py │ │ ├── tools │ │ │ ├── __init__.py │ │ │ ├── create_tools.py │ │ │ ├── delete_tool.py │ │ │ ├── get_tool.py │ │ │ ├── get_tool_args_from_metadata.py │ │ │ ├── list_tools.py │ │ │ ├── patch_tool.py │ │ │ └── update_tool.py │ │ ├── usage │ │ │ ├── __init__.py │ │ │ ├── create_usage_record.py │ │ │ └── get_user_cost.py │ │ ├── users │ │ │ ├── __init__.py │ │ │ ├── create_or_update_user.py │ │ │ ├── create_user.py │ │ │ ├── delete_user.py │ │ │ ├── get_user.py │ │ │ ├── list_users.py │ │ │ ├── patch_user.py │ │ │ └── update_user.py │ │ └── utils.py │ ├── rec_sum │ │ ├── __init__.py │ │ ├── data.py │ │ ├── entities.py │ │ ├── entities_example_chat.json │ │ ├── generate.py │ │ ├── summarize.py │ │ ├── summarize_example_chat.json │ │ ├── summarize_example_result.json │ │ ├── trim.py │ │ ├── trim_example_chat.json │ │ ├── trim_example_result.json │ │ └── utils.py │ ├── routers │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── agents │ │ │ ├── __init__.py │ │ │ ├── create_agent.py │ │ │ ├── create_agent_tool.py │ │ │ ├── create_or_update_agent.py │ │ │ ├── delete_agent.py │ │ │ ├── delete_agent_tool.py │ │ │ ├── get_agent_details.py │ │ │ ├── list_agent_tools.py │ │ │ ├── list_agents.py │ │ │ ├── list_models.py │ │ │ ├── patch_agent.py │ │ │ ├── patch_agent_tool.py │ │ │ ├── router.py │ │ │ ├── update_agent.py │ │ │ └── update_agent_tool.py │ │ ├── docs │ │ │ ├── __init__.py │ │ │ ├── bulk_delete_docs.py │ │ │ ├── create_doc.py │ │ │ ├── delete_doc.py │ │ │ ├── embed.py │ │ │ ├── get_doc.py │ │ │ ├── list_docs.py │ │ │ ├── router.py │ │ │ └── search_docs.py │ │ ├── files │ │ │ ├── __init__.py │ │ │ ├── create_file.py │ │ │ ├── delete_file.py │ │ │ ├── get_file.py │ │ │ ├── list_files.py │ │ │ └── router.py │ │ ├── healthz │ │ │ ├── __init__.py │ │ │ ├── check_health.py │ │ │ └── router.py │ │ ├── internal │ │ │ ├── __init__.py │ │ │ └── router.py │ │ ├── jobs │ │ │ ├── __init__.py │ │ │ └── routers.py │ │ ├── projects │ │ │ ├── __init__.py │ │ │ ├── create_project.py │ │ │ ├── list_projects.py │ │ │ └── router.py │ │ ├── responses │ │ │ ├── __init__.py │ │ │ ├── create_response.py │ │ │ ├── get_response.py │ │ │ └── router.py │ │ ├── secrets │ │ │ ├── __init__.py │ │ │ ├── create_secret.py │ │ │ ├── delete_secret.py │ │ │ ├── list_secrets.py │ │ │ ├── router.py │ │ │ └── update_secret.py │ │ ├── sessions │ │ │ ├── __init__.py │ │ │ ├── chat.py │ │ │ ├── create_or_update_session.py │ │ │ ├── create_session.py │ │ │ ├── delete_session.py │ │ │ ├── exceptions.py │ │ │ ├── get_session.py │ │ │ ├── get_session_history.py │ │ │ ├── list_sessions.py │ │ │ ├── metrics.py │ │ │ ├── patch_session.py │ │ │ ├── render.py │ │ │ ├── router.py │ │ │ └── update_session.py │ │ ├── tasks │ │ │ ├── __init__.py │ │ │ ├── create_or_update_task.py │ │ │ ├── create_task.py │ │ │ ├── create_task_execution.py │ │ │ ├── get_execution_details.py │ │ │ ├── get_task_details.py │ │ │ ├── list_execution_transitions.py │ │ │ ├── list_task_executions.py │ │ │ ├── list_tasks.py │ │ │ ├── router.py │ │ │ ├── stream_execution_status.py │ │ │ ├── stream_transitions_events.py │ │ │ └── update_execution.py │ │ ├── users │ │ │ ├── __init__.py │ │ │ ├── create_or_update_user.py │ │ │ ├── create_user.py │ │ │ ├── delete_user.py │ │ │ ├── get_user_details.py │ │ │ ├── list_users.py │ │ │ ├── patch_user.py │ │ │ ├── router.py │ │ │ └── update_user.py │ │ └── utils │ │ │ ├── __init__.py │ │ │ ├── model_converters.py │ │ │ └── model_validation.py │ ├── web.py │ ├── worker │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── codec.py │ │ └── worker.py │ └── workflows │ │ ├── AGENTS.md │ │ ├── CLAUDE.md │ │ ├── __init__.py │ │ ├── demo.py │ │ └── task_execution │ │ ├── __init__.py │ │ ├── helpers.py │ │ └── transition.py ├── docker-compose-api.yml ├── docker-compose.yml ├── gunicorn_conf.py ├── poe_tasks.toml ├── pyproject.toml ├── pytype.toml ├── tests │ ├── __init__.py │ ├── fixtures.py │ ├── sample_tasks │ │ ├── __init__.py │ │ ├── find_selector.yaml │ │ ├── integration_example.yaml │ │ ├── reclaim-example.yaml │ │ ├── screenshot.base64 │ │ ├── screenshot.png │ │ ├── simple_multi_step.yaml │ │ ├── simple_parameter_extractor.yaml │ │ ├── simple_prompt.yaml │ │ └── test_find_selector.py │ ├── test_activities.py │ ├── test_activities_utils.py │ ├── test_agent_metadata_filtering.py │ ├── test_agent_queries.py │ ├── test_agent_routes.py │ ├── test_base_evaluate.py │ ├── test_chat_routes.py │ ├── test_chat_streaming.py │ ├── test_developer_queries.py │ ├── test_docs_metadata_filtering.py │ ├── test_docs_queries.py │ ├── test_docs_routes.py │ ├── test_entry_queries.py │ ├── test_execution_queries.py │ ├── test_execution_workflow.py │ ├── test_expression_validation.py │ ├── test_file_routes.py │ ├── test_files_queries.py │ ├── test_get_doc_search.py │ ├── test_litellm_utils.py │ ├── test_memory_utils.py │ ├── test_messages_truncation.py │ ├── test_metadata_filter_utils.py │ ├── test_middleware.py │ ├── test_mmr.py │ ├── test_model_validation.py │ ├── test_nlp_utilities.py │ ├── test_pg_query_step.py │ ├── test_prepare_for_step.py │ ├── test_query_utils.py │ ├── test_secrets_queries.py │ ├── test_secrets_routes.py │ ├── test_secrets_usage.py │ ├── test_session_queries.py │ ├── test_session_routes.py │ ├── test_task_execution_workflow.py │ ├── test_task_queries.py │ ├── test_task_routes.py │ ├── test_task_validation.py │ ├── test_tool_call_step.py │ ├── test_tool_queries.py │ ├── test_transitions_queries.py │ ├── test_usage_cost.py │ ├── test_usage_tracking.py │ ├── test_user_queries.py │ ├── test_user_routes.py │ ├── test_validation_errors.py │ ├── test_workflow_helpers.py │ ├── test_workflow_routes.py │ └── utils.py ├── uuid_extensions.pyi └── uv.lock ├── blob-store ├── .gitignore ├── AGENTS.md ├── CLAUDE.md ├── Dockerfile ├── docker-compose-ha.yml ├── docker-compose.yml ├── entrypoint.sh └── s3.json.template ├── cli ├── .gitignore ├── AGENTS.md ├── CLAUDE.md ├── README.md ├── cli-reference.md ├── poe_tasks.toml ├── pyproject.toml ├── spec.md ├── src │ └── julep_cli │ │ ├── __init__.py │ │ ├── __main__.py │ │ ├── agents.py │ │ ├── app.py │ │ ├── auth.py │ │ ├── chat.py │ │ ├── executions.py │ │ ├── importt.py │ │ ├── init.py │ │ ├── logs.py │ │ ├── ls.py │ │ ├── models.py │ │ ├── run.py │ │ ├── sync.py │ │ ├── tasks.py │ │ ├── tools.py │ │ ├── utils.py │ │ └── wrapper.py ├── tests │ ├── __init__.py │ └── test_auth.py └── uv.lock ├── cookbooks ├── IDEAS.md ├── README.md ├── __init__.py ├── advanced │ ├── 00-Devfest-Email-Assistant.ipynb │ ├── 01-website-crawler.ipynb │ ├── 02-sarcastic-news-headline-generator.ipynb │ ├── 03-trip-planning-assistant.ipynb │ ├── 04-hook-generator-trending-reels.ipynb │ ├── 05-video-processing-with-natural-language.ipynb │ ├── 06-browser-use.ipynb │ ├── 07-personalized-research-assistant.ipynb │ ├── 08-rag-chatbot.ipynb │ ├── 09-companion-agent.ipynb │ └── 10-reel-generator.ipynb └── basics │ ├── 01-Hello-Agent.ipynb │ ├── 02-Simple-Task.ipynb │ ├── 03-Adding-Tools.ipynb │ ├── 04-Parallel-Steps.ipynb │ └── 05-RAG-and-Docs.ipynb ├── deploy ├── .env.example ├── responses-build-docker-compose.yaml ├── simple-docker-compose.yaml └── standalone-docker-compose.yaml ├── docker-bake.hcl ├── docker-compose.yml ├── documentation ├── AGENTS.md ├── CLAUDE.md ├── README.md ├── advanced │ ├── agentic-patterns.mdx │ ├── architecture-deep-dive.mdx │ ├── chat.mdx │ ├── files.mdx │ ├── lifecycle.mdx │ ├── localsetup.mdx │ ├── multi-agent-multi-user-sessions.mdx │ ├── new-syntax.mdx │ ├── python-expression.mdx │ ├── render.mdx │ ├── secrets-management.mdx │ └── types-of-task-steps.mdx ├── assets │ └── agentic-patterns │ │ ├── evaluator-optimizer-workflow.png │ │ ├── orchestrator-workers-workflow.png │ │ ├── parallelization-workflow.png │ │ ├── prompt-chaining-workflow.png │ │ └── routing-workflow.png ├── concepts │ ├── agents.mdx │ ├── docs.mdx │ ├── execution.mdx │ ├── files.mdx │ ├── projects.mdx │ ├── secrets.mdx │ ├── sessions.mdx │ ├── tasks.mdx │ ├── tools.mdx │ └── users.mdx ├── docs.json ├── favicon.svg ├── guides │ ├── adding-tool-integration.mdx │ ├── advanced │ │ ├── complex-workflows.mdx │ │ ├── integration-patterns.mdx │ │ └── multi-agent-systems.mdx │ ├── cookbooks │ │ ├── community-examples.mdx │ │ ├── industry-solutions.mdx │ │ └── quick-solutions.mdx │ ├── getting-started │ │ ├── chat-with-an-agent.mdx │ │ ├── create-and-execute-julep-task.mdx │ │ └── tool-integration-demo.mdx │ ├── modifying-agent-workflow.mdx │ ├── use-cases │ │ ├── customer-service.mdx │ │ ├── data-analysis.mdx │ │ ├── document-processing.mdx │ │ └── research-assistant.mdx │ └── using-secrets.mdx ├── images │ ├── architecture-diagram.svg │ ├── architecture.svg │ ├── flow.svg │ ├── lifecycle.svg │ ├── open-responses.jpg │ ├── overview-dark.svg │ ├── overview.svg │ └── relationship.svg ├── integrations │ ├── communicationdata │ │ ├── email.mdx │ │ └── weather.mdx │ ├── contributing-integrations.mdx │ ├── mediafile │ │ ├── cloudinary.mdx │ │ ├── ffmpeg.mdx │ │ ├── llamaparse.mdx │ │ └── unstructured.mdx │ ├── search │ │ ├── algolia.mdx │ │ ├── arxiv.mdx │ │ ├── brave.mdx │ │ └── wikipedia.mdx │ ├── supported-integrations.mdx │ ├── supported-models.mdx │ └── webbrowser │ │ ├── browserbase.mdx │ │ ├── remote-browser.mdx │ │ └── spider.mdx ├── introduction │ ├── developer-orientation.mdx │ ├── install.mdx │ ├── julep.mdx │ └── quickstart.mdx ├── julepcli │ ├── commands.mdx │ └── introduction.mdx ├── logo │ ├── dark.svg │ └── light.svg ├── responses │ ├── cli.mdx │ ├── concepts.mdx │ ├── examples.mdx │ ├── quickstart.mdx │ └── roadmap.mdx ├── scripts │ └── entelligence-chat.js ├── sdks │ ├── common │ │ ├── authentication.mdx │ │ ├── error-handling.mdx │ │ ├── secrets.mdx │ │ └── testing.mdx │ ├── index.mdx │ ├── nodejs │ │ ├── advanced-usage.mdx │ │ ├── agents.mdx │ │ ├── installation.mdx │ │ ├── reference.mdx │ │ ├── secrets.mdx │ │ ├── sessions.mdx │ │ ├── tasks.mdx │ │ └── tools-integration.mdx │ └── python │ │ ├── advanced-usage.mdx │ │ ├── agents.mdx │ │ ├── installation.mdx │ │ ├── reference.mdx │ │ ├── secrets.mdx │ │ ├── sessions.mdx │ │ ├── tasks.mdx │ │ └── tools-integration.mdx └── tutorials │ ├── browser-use.mdx │ ├── rag-chatbot.mdx │ ├── trip-planning-input.mdx │ ├── trip-planning-running.mdx │ ├── trip-planning-tools.mdx │ ├── trip-planning-workflow.mdx │ ├── trip-planning.mdx │ └── video-processing.mdx ├── gateway ├── AGENTS.md ├── CLAUDE.md ├── Dockerfile ├── docker-compose.yml ├── entrypoint.sh ├── letsencrypt │ ├── .gitignore │ └── .gitkeep └── traefik.yml.template ├── hasura ├── docker-compose.yml └── metadata │ ├── hasura_metadata_2025_04_07_16_21_57_118.json │ └── hasura_metadata_2025_04_24_14_57_23_154.json ├── integrations-service ├── .dockerignore ├── .python-version ├── AGENTS.md ├── CLAUDE.md ├── Dockerfile ├── README.md ├── docker-compose.yml ├── gunicorn_conf.py ├── integrations │ ├── __init__.py │ ├── __main__.py │ ├── autogen │ │ ├── Agents.py │ │ ├── Chat.py │ │ ├── Common.py │ │ ├── Docs.py │ │ ├── Entries.py │ │ ├── Executions.py │ │ ├── Files.py │ │ ├── Jobs.py │ │ ├── Projects.py │ │ ├── Responses.py │ │ ├── Secrets.py │ │ ├── Sessions.py │ │ ├── Tasks.py │ │ ├── Tools.py │ │ ├── Users.py │ │ └── __init__.py │ ├── env.py │ ├── models │ │ ├── __init__.py │ │ ├── algolia.py │ │ ├── arxiv.py │ │ ├── base_models.py │ │ ├── brave.py │ │ ├── browserbase.py │ │ ├── cloudinary.py │ │ ├── email.py │ │ ├── execution.py │ │ ├── ffmpeg.py │ │ ├── llama_parse.py │ │ ├── mailgun.py │ │ ├── remote_browser.py │ │ ├── spider.py │ │ ├── unstructured.py │ │ ├── weather.py │ │ └── wikipedia.py │ ├── providers.py │ ├── routers │ │ ├── __init__.py │ │ ├── execution │ │ │ ├── __init__.py │ │ │ ├── execute.py │ │ │ └── router.py │ │ └── integrations │ │ │ ├── __init__.py │ │ │ ├── get_integration.py │ │ │ ├── get_integration_tool.py │ │ │ ├── get_integrations.py │ │ │ └── router.py │ ├── utils │ │ ├── __init__.py │ │ ├── execute_integration.py │ │ └── integrations │ │ │ ├── __init__.py │ │ │ ├── algolia.py │ │ │ ├── arxiv.py │ │ │ ├── assets │ │ │ ├── cursor-small.png │ │ │ └── cursor.png │ │ │ ├── brave.py │ │ │ ├── browserbase.py │ │ │ ├── cloudinary.py │ │ │ ├── email.py │ │ │ ├── ffmpeg.py │ │ │ ├── llama_parse.py │ │ │ ├── mailgun.py │ │ │ ├── remote_browser.py │ │ │ ├── spider.py │ │ │ ├── unstructured.py │ │ │ ├── weather.py │ │ │ └── wikipedia.py │ └── web.py ├── poe_tasks.toml ├── pyproject.toml ├── pytest.ini ├── pytype.toml ├── tests │ ├── __init__.py │ ├── conftest.py │ ├── mocks │ │ ├── __init__.py │ │ ├── brave.py │ │ ├── email.py │ │ ├── llama_parse.py │ │ ├── spider.py │ │ ├── weather.py │ │ └── wikipedia.py │ ├── test_provider_execution.py │ └── test_providers.py └── uv.lock ├── llm-proxy ├── .dockerignore ├── .gitignore ├── AGENTS.md ├── CLAUDE.md ├── docker-compose.yml └── litellm-config.yaml ├── memory-store ├── .gitignore ├── AGENTS.md ├── CLAUDE.md ├── Dockerfile.migrations ├── README.md ├── docker-compose.yml └── migrations │ ├── 000001_initial.down.sql │ ├── 000001_initial.up.sql │ ├── 000002_developers.down.sql │ ├── 000002_developers.up.sql │ ├── 000003_users.down.sql │ ├── 000003_users.up.sql │ ├── 000004_agents.down.sql │ ├── 000004_agents.up.sql │ ├── 000005_files.down.sql │ ├── 000005_files.up.sql │ ├── 000006_docs.down.sql │ ├── 000006_docs.up.sql │ ├── 000007_ann.down.sql │ ├── 000007_ann.up.sql │ ├── 000008_tools.down.sql │ ├── 000008_tools.up.sql │ ├── 000009_sessions.down.sql │ ├── 000009_sessions.up.sql │ ├── 000010_tasks.down.sql │ ├── 000010_tasks.up.sql │ ├── 000011_executions.down.sql │ ├── 000011_executions.up.sql │ ├── 000012_transitions.down.sql │ ├── 000012_transitions.up.sql │ ├── 000013_executions_continuous_view.down.sql │ ├── 000013_executions_continuous_view.up.sql │ ├── 000014_temporal_lookup.down.sql │ ├── 000014_temporal_lookup.up.sql │ ├── 000015_entries.down.sql │ ├── 000015_entries.up.sql │ ├── 000016_entry_relations.down.sql │ ├── 000016_entry_relations.up.sql │ ├── 000017_compression.down.sql │ ├── 000017_compression.up.sql │ ├── 000018_doc_search.down.sql │ ├── 000018_doc_search.up.sql │ ├── 000019_system_developer.down.sql │ ├── 000019_system_developer.up.sql │ ├── 000020_executions_task_cascade.down.sql │ ├── 000020_executions_task_cascade.up.sql │ ├── 000021_fix_toolname_contraint.down.sql │ ├── 000021_fix_toolname_contraint.up.sql │ ├── 000022_vector_search.down.sql │ ├── 000022_vector_search.up.sql │ ├── 000023_update_strings_length_constraints.down.sql │ ├── 000023_update_strings_length_constraints.up.sql │ ├── 000024_hybrid_search.down.sql │ ├── 000024_hybrid_search.up.sql │ ├── 000025_default_system_template.down.sql │ ├── 000025_default_system_template.up.sql │ ├── 000026_transition_cursor.down.sql │ ├── 000026_transition_cursor.up.sql │ ├── 000027_add_postgraphile.down.sql │ ├── 000027_add_postgraphile.up.sql │ ├── 000028_new_hybrid_search_implementation.down.sql │ ├── 000028_new_hybrid_search_implementation.up.sql │ ├── 000029_duplicate_doc_prevention.down.sql │ ├── 000029_duplicate_doc_prevention.up.sql │ ├── 000030_add_unaccent_search_config.down.sql │ ├── 000030_add_unaccent_search_config.up.sql │ ├── 000031_add_trigram_search.down.sql │ ├── 000031_add_trigram_search.up.sql │ ├── 000032_enhance_trigram_search.down.sql │ ├── 000032_enhance_trigram_search.up.sql │ ├── 000033_fix_latest_transitions.down.sql │ ├── 000033_fix_latest_transitions.up.sql │ ├── 000034_switch_to_hypercore.down.sql │ ├── 000034_switch_to_hypercore.up.sql │ ├── 000035_enhanced_indices.down.sql │ ├── 000035_enhanced_indices.up.sql │ ├── 000036_usage.down.sql │ ├── 000036_usage.up.sql │ ├── 000037_speed_up_search.down.sql │ ├── 000037_speed_up_search.up.sql │ ├── 000038_usage_cost_monthly.down.sql │ ├── 000038_usage_cost_monthly.up.sql │ ├── 000039_projects.down.sql │ ├── 000039_projects.up.sql │ ├── 000040_add_secrets.down.sql │ ├── 000040_add_secrets.up.sql │ ├── 000041_non_null_forward_tool_calls.down.sql │ └── 000041_non_null_forward_tool_calls.up.sql ├── monitoring ├── AGENTS.md ├── CLAUDE.md ├── README.md ├── docker-compose.yml ├── grafana │ ├── dashboard.yaml │ └── provisioning │ │ ├── dashboards │ │ ├── advanced-visibility-specific.json │ │ ├── clustermonitoring-kubernetes.json │ │ ├── frontend-service-specific.json │ │ ├── history-service-specific.json │ │ ├── main.yaml │ │ ├── matching-service-specific.json │ │ ├── queries-metrics.json │ │ ├── requests-metrics.json │ │ ├── sdk-general.json │ │ ├── sdk-java.json │ │ ├── server-general.json │ │ ├── temporal_cloud.json │ │ └── worker-service-specific.json │ │ └── datasources │ │ └── datasource.yml └── prometheus │ └── config │ └── prometheus.yml ├── openapi.yaml ├── ruff.toml ├── scheduler ├── AGENTS.md ├── CLAUDE.md ├── cert │ └── .gitignore ├── docker-compose.yml └── dynamicconfig │ └── temporal-postgres.yaml ├── schemas ├── create_agent_request.json ├── create_task_request.json └── walk.jq ├── scripts ├── __init__.py ├── generate_changelog.py ├── generate_jwt.py ├── generate_openapi_code.sh ├── readme_translator.py └── templates │ ├── changelog.yaml │ └── header.html └── typespec ├── .gitignore ├── AGENTS.md ├── CLAUDE.md ├── agents ├── endpoints.tsp ├── main.tsp └── models.tsp ├── chat ├── endpoints.tsp ├── main.tsp └── models.tsp ├── common ├── constants.tsp ├── interfaces.tsp ├── main.tsp ├── mixins.tsp ├── scalars.tsp └── types.tsp ├── docs ├── endpoints.tsp ├── main.tsp └── models.tsp ├── entries ├── endpoints.tsp ├── main.tsp └── models.tsp ├── executions ├── endpoints.tsp ├── main.tsp └── models.tsp ├── files ├── endpoints.tsp ├── main.tsp └── models.tsp ├── jobs ├── endpoints.tsp ├── main.tsp └── models.tsp ├── main.tsp ├── package-lock.json ├── package.json ├── projects ├── endpoints.tsp ├── main.tsp └── models.tsp ├── responses ├── endpoints.tsp ├── main.tsp └── models.tsp ├── secrets ├── endpoints.tsp ├── main.tsp └── models.tsp ├── sessions ├── endpoints.tsp ├── main.tsp └── models.tsp ├── tasks ├── endpoints.tsp ├── main.tsp ├── models.tsp ├── step_kind.tsp └── steps.tsp ├── tools ├── algolia.tsp ├── anthropic.tsp ├── arxiv.tsp ├── brave.tsp ├── browserbase │ ├── contexts.tsp │ ├── extensions.tsp │ ├── main.tsp │ └── sessions.tsp ├── cloudinary.tsp ├── email.tsp ├── endpoints.tsp ├── ffmpeg.tsp ├── llama_parse.tsp ├── mailgun.tsp ├── main.tsp ├── models.tsp ├── remote_browser.tsp ├── spider.tsp ├── unstructured.tsp ├── weather.tsp └── wikipedia.tsp ├── tsp-output └── @typespec │ └── openapi3 │ └── openapi-1.0.0.yaml ├── tspconfig.yaml ├── users ├── endpoints.tsp ├── main.tsp └── models.tsp └── versions.tsp /.cursorignore: -------------------------------------------------------------------------------- 1 | .agentignore 2 | -------------------------------------------------------------------------------- /.cursorindexignore: -------------------------------------------------------------------------------- 1 | .agentindexignore 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.yml: -------------------------------------------------------------------------------- 1 | name: "🐛 Bug Report" 2 | description: "Submit a bug report to help us improve" 3 | title: "[Bug]: " 4 | labels: ["bug"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: "📜 Description" 10 | placeholder: "A clear and concise description of what the bug is." 11 | 12 | - type: textarea 13 | id: steps-to-reproduce 14 | attributes: 15 | label: "👟 Reproduction steps" 16 | placeholder: "1. Go to '...' 17 | 2. Click on '....' 18 | 3. Scroll down to '....' 19 | 4. See error" 20 | 21 | - type: checkboxes 22 | id: no-duplicate-issues 23 | attributes: 24 | label: "👀 Have you searched previous issues to see if this has been raised before?" 25 | options: 26 | - label: "I checked and didn't find similar issue" 27 | required: true 28 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Have Question? 4 | url: https://discord.com/invite/JTSBGRZrzj 5 | about: Join Official Discord server -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.yml: -------------------------------------------------------------------------------- 1 | name: 🚀 Feature 2 | description: "Submit a proposal for a new feature" 3 | title: "[Feature]: " 4 | labels: ["enhancement"] 5 | body: 6 | - type: textarea 7 | id: feature-description 8 | validations: 9 | required: true 10 | attributes: 11 | label: "🔖 Feature description" 12 | placeholder: "A clear and concise description of what the feature is." 13 | - type: textarea 14 | id: pitch 15 | attributes: 16 | label: "🎤 Why is this feature needed ?" 17 | placeholder: "Please explain why this feature should be implemented and how it would be used. Add examples, if applicable." 18 | - type: textarea 19 | id: solution 20 | attributes: 21 | label: "✌️ How do you aim to achieve this?" 22 | placeholder: "A clear and concise description of what you want to happen." 23 | - type: checkboxes 24 | id: no-duplicate-issues 25 | attributes: 26 | label: "👀 Have you searched issues and PRs to see if this feature request has been raised before?" 27 | options: 28 | - label: "I checked and didn't find similar issue" 29 | required: true 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/refactor.yml: -------------------------------------------------------------------------------- 1 | name: "🛠️ Refactor" 2 | description: "Submit a bug report to help us improve" 3 | title: "[Refactor]: " 4 | labels: ["refactor"] 5 | body: 6 | - type: textarea 7 | id: description 8 | attributes: 9 | label: "📜 Description" 10 | placeholder: "A clear and concise description of what should be refactored." 11 | 12 | - type: textarea 13 | id: relevant-files 14 | attributes: 15 | label: "👟 Relevant files" 16 | placeholder: "1. `agents-api/Dockerfile` needs to change 17 | 2. `integrations/**/*.py` files need to be reformatted" 18 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: "" # See documentation for possible values 9 | directory: "/" # Location of package manifests 10 | schedule: 11 | interval: "weekly" 12 | -------------------------------------------------------------------------------- /.github/i-have-an-announcement.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/.github/i-have-an-announcement.gif -------------------------------------------------------------------------------- /.github/julep-cup.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/.github/julep-cup.png -------------------------------------------------------------------------------- /.github/julep-definition.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/.github/julep-definition.png -------------------------------------------------------------------------------- /.github/julep-meaning-banner.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/.github/julep-meaning-banner.png -------------------------------------------------------------------------------- /.github/workflows/bandit-security-check-python-agents-api.yml: -------------------------------------------------------------------------------- 1 | name: Bandit security check python agents-api 2 | run-name: ${{ github.actor }} is checking the security of the code 3 | 4 | on: 5 | pull_request: 6 | paths: 7 | - 'agents-api/**' 8 | push: 9 | paths: 10 | - 'agents-api/**' 11 | 12 | jobs: 13 | bandit_check: 14 | name: bandit check security of python code in agents-api 15 | runs-on: ubuntu-latest 16 | 17 | steps: 18 | - uses: mdegis/bandit-action@v1.0.1 19 | with: 20 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 21 | path: "./agents-api/agents_api" 22 | level: high 23 | confidence: high 24 | # exit_zero: true 25 | -------------------------------------------------------------------------------- /.github/workflows/changelog-ci.yml: -------------------------------------------------------------------------------- 1 | name: Changelog on release 2 | 3 | on: 4 | release: 5 | types: [published] 6 | 7 | jobs: 8 | changelog: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | # Checks-out your repository 13 | - uses: actions/checkout@v4 14 | with: 15 | fetch-depth: 0 16 | ref: dev 17 | 18 | # Generate changelog from release notes 19 | - uses: rhysd/changelog-from-release/action@v3 20 | with: 21 | file: CHANGELOG.md 22 | github_token: ${{ secrets.GITHUB_TOKEN }} 23 | pull_request: true 24 | -------------------------------------------------------------------------------- /.github/workflows/docker-bake-on-pr.yml: -------------------------------------------------------------------------------- 1 | name: Bake images on PR 2 | run-name: ${{ github.actor }} is baking images 3 | 4 | on: 5 | pull_request: 6 | 7 | jobs: 8 | Bake-Images: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - uses: actions/checkout@v4 13 | 14 | - name: Set up Docker Buildx 15 | uses: docker/setup-buildx-action@v3 16 | 17 | - name: Login to Docker Hub 18 | uses: docker/login-action@v3 19 | with: 20 | username: julepai 21 | password: "${{ secrets.DOCKER_HUB_PASSWORD }}" 22 | 23 | - name: Bake images 24 | uses: docker/bake-action@v5 25 | with: 26 | files: | 27 | ./docker-bake.hcl 28 | targets: agents-api 29 | push: false 30 | set: | 31 | *.cache-from=type=gha 32 | *.cache-to=type=gha,mode=max 33 | env: 34 | TAG: pr-run-${{ github.run_number }}-${{ github.run_attempt }} 35 | GIT_SHA: ${{ github.sha }} 36 | 37 | concurrency: 38 | group: ${{ github.workflow }}-${{ github.ref }} 39 | cancel-in-progress: ${{ github.event_name == 'pull_request' }} 40 | -------------------------------------------------------------------------------- /.github/workflows/doctoc-on-push.yml: -------------------------------------------------------------------------------- 1 | on: push 2 | 3 | name: TOC Generator 4 | jobs: 5 | generateTOC: 6 | name: TOC Generator 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: technote-space/toc-generator@v4 10 | with: 11 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 12 | MAX_HEADER_LEVEL: 3 13 | TOC_TITLE: '

📖 Table of Contents

' 14 | FOLDING: false 15 | CREATE_PR: true 16 | CHECK_ONLY_DEFAULT_BRANCH: true 17 | -------------------------------------------------------------------------------- /.github/workflows/generate-openapi-code-from-typespec.yml: -------------------------------------------------------------------------------- 1 | name: Generate OpenAPI code 2 | run-name: ${{ github.actor }} is generating openapi code 3 | 4 | on: 5 | pull_request: 6 | paths: 7 | - 'typespec/**' 8 | push: 9 | paths: 10 | - 'typespec/**' 11 | 12 | jobs: 13 | Typecheck: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - uses: actions/setup-node@v4 20 | with: 21 | node-version: 'latest' 22 | cache: npm 23 | cache-dependency-path: 'typespec/package-lock.json' 24 | 25 | - name: Install uv 26 | uses: astral-sh/setup-uv@v4 27 | with: 28 | enable-cache: true 29 | 30 | - uses: actions/setup-python@v5 31 | with: 32 | python-version: "3.12" 33 | 34 | - name: Generate openapi code 35 | run: | 36 | cd typespec; npm ci; cd - 37 | export PATH=$PATH:$PWD/typespec/node_modules/.bin 38 | bash scripts/generate_openapi_code.sh 39 | 40 | concurrency: 41 | group: ${{ github.workflow }}-${{ github.ref }} 42 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 43 | -------------------------------------------------------------------------------- /.github/workflows/latest-push-to-hub.yml: -------------------------------------------------------------------------------- 1 | name: Build and push images to docker hub on merge to main 2 | run-name: ${{ github.actor }} is building and pushing images to docker hub 3 | 4 | on: 5 | push: 6 | branches: 7 | - "main" 8 | 9 | jobs: 10 | Bake-Push-Images: 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v4 15 | 16 | - name: Set up Docker Buildx 17 | uses: docker/setup-buildx-action@v3 18 | 19 | - name: Login to Docker Hub 20 | uses: docker/login-action@v3 21 | with: 22 | username: julepai 23 | password: "${{ secrets.DOCKER_HUB_PASSWORD }}" 24 | 25 | - name: Build and push agent images 26 | uses: docker/bake-action@v5 27 | with: 28 | files: | 29 | ./docker-bake.hcl 30 | targets: agents-api 31 | push: true 32 | set: | 33 | *.cache-from=type=gha 34 | *.cache-to=type=gha,mode=max 35 | env: 36 | TAG: latest 37 | GIT_SHA: ${{ github.sha }} 38 | 39 | concurrency: 40 | group: ${{ github.workflow }}-${{ github.ref }} 41 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} -------------------------------------------------------------------------------- /.github/workflows/lint-integrations-service-pr.yml: -------------------------------------------------------------------------------- 1 | name: Lint integrations-service 2 | run-name: ${{ github.actor }} is linting the code 3 | 4 | on: 5 | pull_request: 6 | paths: 7 | - 'integrations-service/**' 8 | push: 9 | paths: 10 | - 'integrations-service/**' 11 | 12 | jobs: 13 | Lint-And-Format: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Install uv 20 | uses: astral-sh/setup-uv@v4 21 | with: 22 | enable-cache: true 23 | 24 | - name: Set up python and install dependencies 25 | run: | 26 | cd integrations-service 27 | uv python install 28 | uv sync --all-extras --dev 29 | 30 | - name: Lint and format 31 | run: | 32 | cd integrations-service 33 | uv run poe format 34 | uv run poe lint 35 | 36 | - uses: stefanzweifel/git-auto-commit-action@v4 37 | with: 38 | commit_message: "refactor: Lint integrations-service (CI)" 39 | branch: ${{ github.head_ref }} 40 | 41 | concurrency: 42 | group: ${{ github.workflow }}-${{ github.ref }} 43 | cancel-in-progress: ${{ github.ref != 'refs/heads/main' }} 44 | -------------------------------------------------------------------------------- /.github/workflows/test-integrations-service-pr.yml: -------------------------------------------------------------------------------- 1 | name: Test integrations-service 2 | run-name: ${{ github.actor }} is testing the code 3 | 4 | on: 5 | pull_request: 6 | paths: 7 | - 'integrations-service/**' 8 | push: 9 | paths: 10 | - 'integrations-service/**' 11 | 12 | jobs: 13 | Test: 14 | runs-on: ubuntu-latest 15 | 16 | steps: 17 | - uses: actions/checkout@v4 18 | 19 | - name: Install uv 20 | uses: astral-sh/setup-uv@v4 21 | with: 22 | enable-cache: true 23 | 24 | - name: Set up python and install dependencies 25 | run: | 26 | cd integrations-service 27 | uv python install 28 | uv sync --all-extras --dev 29 | 30 | - name: Run tests 31 | run: | 32 | cd integrations-service 33 | uv run poe test 34 | 35 | concurrency: 36 | group: ${{ github.workflow }}-${{ github.ref }} 37 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # BECAUSE DIWANK IS OBSESSED 2 | *gaga* 3 | .DS_Store 4 | *.swp 5 | ngrok* 6 | .env* 7 | .env 8 | *.env 9 | *.pyc 10 | */node_modules/ 11 | .aider* 12 | .vscode/ 13 | schema.sql 14 | 15 | **/.claude/settings.local.json 16 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | # [submodule "code-interpreter/vendor/cohere-ai/cohere-terrarium"] 2 | # path = code-interpreter/vendor/cohere-ai/cohere-terrarium 3 | # url = https://github.com/cohere-ai/cohere-terrarium.git 4 | [submodule "sdks/python-sdk"] 5 | path = sdks/python-sdk 6 | url = https://github.com/julep-ai/python-sdk.git 7 | [submodule "sdks/node-sdk"] 8 | path = sdks/node-sdk 9 | url = https://github.com/julep-ai/node-sdk.git 10 | -------------------------------------------------------------------------------- /CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | *.pyc 3 | *.pyo 4 | *.pyd 5 | __pycache__ 6 | .pytest_cache 7 | .venv 8 | -------------------------------------------------------------------------------- /agents-api/.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /agents-api/.tool-versions: -------------------------------------------------------------------------------- 1 | python 3.12.5 2 | -------------------------------------------------------------------------------- /agents-api/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # check=error=true 3 | 4 | FROM python:3.12-slim 5 | COPY --from=ghcr.io/astral-sh/uv:0.5.5 /uv /uvx /bin/ 6 | 7 | RUN apt-get update && apt-get install -y --no-install-recommends \ 8 | gcc \ 9 | g++ \ 10 | libboost-all-dev \ 11 | libc6-dev \ 12 | libexpat1-dev \ 13 | libffi-dev \ 14 | liblzma-dev \ 15 | libssl-dev \ 16 | make \ 17 | wget \ 18 | && apt-get clean \ 19 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 20 | 21 | WORKDIR /app 22 | 23 | COPY .python-version pyproject.toml uv.lock ./ 24 | 25 | RUN \ 26 | uv sync --frozen --all-extras --no-group dev --color never --python-preference system 27 | 28 | COPY . ./ 29 | 30 | ENV PYTHONUNBUFFERED=1 31 | ENV GUNICORN_CMD_ARGS="--capture-output --enable-stdio-inheritance" 32 | 33 | ENTRYPOINT ["uv", "run", "--offline", "--no-sync", "gunicorn", "agents_api.web:app", "-c", "gunicorn_conf.py"] 34 | -------------------------------------------------------------------------------- /agents-api/Dockerfile.worker: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # check=error=true 3 | 4 | FROM python:3.12-slim 5 | COPY --from=ghcr.io/astral-sh/uv:0.5.5 /uv /uvx /bin/ 6 | 7 | RUN apt-get update && apt-get install -y --no-install-recommends \ 8 | gcc \ 9 | g++ \ 10 | libboost-all-dev \ 11 | libc6-dev \ 12 | libexpat1-dev \ 13 | libffi-dev \ 14 | liblzma-dev \ 15 | libssl-dev \ 16 | make \ 17 | wget \ 18 | && apt-get clean \ 19 | && rm -rf /var/lib/apt/lists/* /tmp/* /var/tmp/* 20 | 21 | WORKDIR /app 22 | 23 | COPY .python-version pyproject.toml uv.lock ./ 24 | 25 | RUN \ 26 | uv sync --frozen --all-extras --no-group dev --color never --python-preference system 27 | 28 | COPY . ./ 29 | 30 | ENV PYTHONUNBUFFERED=1 31 | ENV GUNICORN_CMD_ARGS="--capture-output --enable-stdio-inheritance" 32 | 33 | ENTRYPOINT ["uv", "run", "--offline", "--no-sync", "python", "-m", "agents_api.worker"] 34 | -------------------------------------------------------------------------------- /agents-api/agents_api/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `agents_api` module serves as the foundation of the agent management system within the `agents-api` project. 3 | This module is responsible for defining the structure and capabilities of the API that manages agents. 4 | It includes operations such as creating, updating, listing, and deleting agents, as well as managing documents and tools associated with these agents. 5 | """ 6 | 7 | # Failed decoding arguments fix 8 | from temporalio import workflow 9 | 10 | with workflow.unsafe.imports_passed_through(): 11 | import msgpack as msgpack 12 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/activities/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `activities` module within the agents-api package is designed to facilitate various activities related to agent interactions. This includes handling memory management, generating insights from dialogues, summarizing relationships, and more. 3 | 4 | This module plays a crucial role in enhancing the capabilities of agents by providing them with the tools to understand and process information more effectively. 5 | """ 6 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/demo.py: -------------------------------------------------------------------------------- 1 | from temporalio import activity 2 | 3 | from ..env import testing 4 | 5 | 6 | async def demo_activity(a: int, b: int) -> int: 7 | # Should throw an error if testing is not enabled 8 | msg = "This should not be called in production" 9 | raise Exception(msg) 10 | 11 | 12 | async def mock_demo_activity(a: int, b: int) -> int: 13 | return a + b 14 | 15 | 16 | demo_activity = activity.defn(name="demo_activity")( 17 | demo_activity if not testing else mock_demo_activity, 18 | ) 19 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/logger.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from typing import TextIO 3 | 4 | logger: logging.Logger = logging.getLogger(__name__) 5 | h: logging.StreamHandler[TextIO] = logging.StreamHandler() 6 | fmt: logging.Formatter = logging.Formatter("[%(asctime)s/%(levelname)s] - %(message)s") 7 | h.setFormatter(fmt) 8 | logger.addHandler(h) 9 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/pg_query_step.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from beartype import beartype 4 | from temporalio import activity 5 | 6 | from .. import queries 7 | from ..env import testing 8 | 9 | 10 | @beartype 11 | async def pg_query_step( 12 | query_name: str, 13 | file_name: str, 14 | values: dict[str, Any], 15 | ) -> Any: 16 | (module_name, name) = file_name.split(".") 17 | 18 | module = getattr(queries, module_name) 19 | query_module = getattr(module, name) 20 | query = getattr(query_module, query_name) 21 | 22 | return await query(**values) 23 | 24 | 25 | mock_pg_query_step = pg_query_step 26 | 27 | pg_query_step = activity.defn(name="pg_query_step")( 28 | pg_query_step if not testing else mock_pg_query_step, 29 | ) 30 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/sync_items_remote.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from beartype import beartype 4 | from temporalio import activity 5 | 6 | from ..worker.codec import RemoteObject 7 | 8 | 9 | @beartype 10 | async def save_inputs_remote_fn(inputs: list[Any]) -> list[Any | RemoteObject]: 11 | from ..common.interceptors import offload_if_large 12 | 13 | return [offload_if_large(input) for input in inputs] 14 | 15 | 16 | @beartype 17 | async def load_inputs_remote_fn(inputs: list[Any | RemoteObject]) -> list[Any]: 18 | from ..common.interceptors import load_if_remote 19 | 20 | return [load_if_remote(input) for input in inputs] 21 | 22 | 23 | save_inputs_remote = activity.defn(name="save_inputs_remote")(save_inputs_remote_fn) 24 | load_inputs_remote = activity.defn(name="load_inputs_remote")(load_inputs_remote_fn) 25 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/task_steps/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | 3 | from .base_evaluate import base_evaluate 4 | from .get_value_step import get_value_step 5 | from .prompt_step import prompt_step 6 | from .raise_complete_async import raise_complete_async 7 | from .transition_step import transition_step 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/activities/task_steps/get_value_step.py: -------------------------------------------------------------------------------- 1 | from beartype import beartype 2 | from temporalio import activity 3 | 4 | from ...common.protocol.tasks import StepContext, StepOutcome 5 | 6 | # TODO: We should use this step to query the parent workflow and get the value from the workflow context 7 | # SCRUM-1 8 | 9 | 10 | @activity.defn 11 | @beartype 12 | async def get_value_step( 13 | context: StepContext, 14 | ) -> StepOutcome: 15 | key: str = context.current_step.get # noqa: F841 16 | msg = "Not implemented yet" 17 | raise NotImplementedError(msg) 18 | -------------------------------------------------------------------------------- /agents-api/agents_api/autogen/.ignore: -------------------------------------------------------------------------------- 1 | *.py 2 | !openapi_model.py 3 | -------------------------------------------------------------------------------- /agents-api/agents_api/autogen/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/autogen/__init__.py: -------------------------------------------------------------------------------- 1 | # generated by datamodel-codegen: 2 | # filename: openapi-1.0.0.yaml 3 | -------------------------------------------------------------------------------- /agents-api/agents_api/clients/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/clients/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `clients` module contains client classes and functions for interacting with various external services and APIs, abstracting the complexity of HTTP requests and API interactions to provide a simplified interface for the rest of the application. 3 | 4 | - `pg.py`: Handles communication with the PostgreSQL service, facilitating operations such as retrieving product information. 5 | - `temporal.py`: Provides functionality for connecting to Temporal workflows, enabling asynchronous task execution and management. 6 | """ 7 | -------------------------------------------------------------------------------- /agents-api/agents_api/clients/integrations.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from beartype import beartype 4 | from httpx import AsyncClient 5 | 6 | from ..env import integration_service_url 7 | 8 | __all__: list[str] = ["run_integration_service"] 9 | 10 | 11 | @beartype 12 | async def run_integration_service( 13 | *, 14 | provider: str, 15 | arguments: dict, 16 | setup: dict | None = None, 17 | method: str | None = None, 18 | ) -> Any: 19 | slug = f"{provider}/{method}" if method else provider 20 | url = f"{integration_service_url}/execute/{slug}" 21 | 22 | setup = setup or None 23 | 24 | async with AsyncClient(timeout=600) as client: 25 | response = await client.post( 26 | url, 27 | json={"arguments": arguments, "setup": setup}, 28 | ) 29 | response.raise_for_status() 30 | 31 | return response.json() 32 | -------------------------------------------------------------------------------- /agents-api/agents_api/clients/pg.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | import asyncpg 4 | 5 | from ..env import pg_dsn 6 | 7 | 8 | async def _init_conn(conn) -> None: 9 | for datatype in ["json", "jsonb"]: 10 | await conn.set_type_codec( 11 | datatype, 12 | encoder=json.dumps, 13 | decoder=json.loads, 14 | schema="pg_catalog", 15 | ) 16 | 17 | 18 | async def create_db_pool(dsn: str | None = None, **kwargs): 19 | return await asyncpg.create_pool( 20 | dsn if dsn is not None else pg_dsn, 21 | init=_init_conn, 22 | **kwargs, 23 | ) 24 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/common/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/agents_api/common/__init__.py -------------------------------------------------------------------------------- /agents-api/agents_api/common/exceptions/secrets.py: -------------------------------------------------------------------------------- 1 | """Custom exceptions for secrets management.""" 2 | 3 | from uuid import UUID 4 | 5 | from . import BaseCommonException 6 | 7 | 8 | class SecretNotFoundError(BaseCommonException): 9 | """Exception raised when a requested secret cannot be found.""" 10 | 11 | def __init__(self, developer_id: UUID | str, name: str) -> None: 12 | super().__init__( 13 | f"Secret {name!s} not found for developer {developer_id!s}", http_code=404 14 | ) 15 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/exceptions/tools.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: This module defines custom exceptions specifically for tool-related operations. 2 | """ 3 | Defines tools-related exceptions for the agents API. 4 | """ 5 | 6 | from ...autogen.openapi_model import BaseIntegrationDef 7 | from . import BaseCommonException 8 | 9 | 10 | # AIDEV-NOTE: Base exception class for all tool-related errors, inheriting from BaseCommonException. 11 | class BaseToolsException(BaseCommonException): 12 | """Base exception for tools-related errors.""" 13 | 14 | 15 | # AIDEV-NOTE: Exception raised when an error occurs during the execution of an integration tool. 16 | class IntegrationExecutionException(BaseToolsException): 17 | """Exception raised when an error occurs during an integration execution.""" 18 | 19 | def __init__(self, integration: BaseIntegrationDef, error: str) -> None: 20 | integration_str = integration.provider + ( 21 | "." + integration.method if integration.method else "" 22 | ) 23 | super().__init__( 24 | f"Error in executing {integration_str}: {error}", 25 | http_code=500, 26 | ) 27 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/exceptions/validation.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: This module defines custom exceptions specifically for validation errors. 2 | from . import BaseCommonException 3 | 4 | 5 | # AIDEV-NOTE: Exception raised for validation errors in query parameters. 6 | class QueryParamsValidationError(BaseCommonException): 7 | """Exception raised for validation errors in query parameters.""" 8 | 9 | def __init__(self, message: str) -> None: 10 | super().__init__(message, http_code=400) 11 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/protocol/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `protocol` module defines the core data structures and settings used across the agents API for managing agents, entries, and sessions. It serves as the foundation for the operation and interaction of different parts of the agents API, facilitating the management of agents, their settings, and session data. 3 | 4 | - `AgentDefaultSettings`: Defines default settings for an agent, controlling various aspects of the agent's behavior during operation. 5 | - `Entry`: Represents an entry in the system, encapsulating details such as ID, session ID, source, role, and content. 6 | - `SessionData`: Represents the data associated with a session, including identifiers and session-specific information such as situation, summary, and timestamps. 7 | 8 | These components are crucial for the effective operation and interaction within the agents API. 9 | """ 10 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/protocol/agents.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel 2 | 3 | 4 | class AgentDefaultSettings(BaseModel): 5 | """Defines default settings for an agent. These settings control various aspects of the agent's behavior during operation.""" 6 | 7 | temperature: float = 0.0 8 | """Temperature setting influencing the randomness of the agent's responses. Higher values lead to more random responses.""" 9 | 10 | top_p: float = 1.0 11 | """Top-p sampling setting controlling the nucleus of the probability distribution to sample from.""" 12 | 13 | repetition_penalty: float = 1.0 14 | """Penalty applied to discourage repetition in the agent's responses.""" 15 | 16 | length_penalty: float = 1.0 17 | """Penalty for longer responses, encouraging more concise outputs.""" 18 | 19 | presence_penalty: float = 0.0 20 | """Penalty applied based on the presence of certain words, influencing content generation.""" 21 | 22 | frequency_penalty: float = 0.0 23 | """Penalty that decreases the likelihood of frequently used words in the agent's responses.""" 24 | 25 | min_p: float = 0.01 26 | """Minimum probability threshold for including a word in the agent's response.""" 27 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/protocol/developers.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module defines session-related data structures and settings used across the agents API. 3 | It includes definitions for session settings and session data models. 4 | """ 5 | 6 | from uuid import UUID 7 | 8 | from pydantic import AwareDatetime, BaseModel, EmailStr 9 | 10 | 11 | class Developer(BaseModel): 12 | """ 13 | Represents the data associated with a developer 14 | """ 15 | 16 | id: UUID 17 | email: EmailStr 18 | active: bool 19 | tags: list[str] 20 | settings: dict 21 | created_at: AwareDatetime 22 | created_at: AwareDatetime 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/retry_policies.py: -------------------------------------------------------------------------------- 1 | # from datetime import timedelta 2 | 3 | # from temporalio.common import RetryPolicy 4 | 5 | # DEFAULT_RETRY_POLICY = RetryPolicy( 6 | # initial_interval=timedelta(seconds=1), 7 | # backoff_coefficient=2, 8 | # maximum_attempts=25, 9 | # maximum_interval=timedelta(seconds=300), 10 | # ) 11 | 12 | # FIXME: Adding both interceptors and retry policy (even with `non_retryable_errors` not set) 13 | # is causing the errors to be retried. We need to find a workaround for this. 14 | DEFAULT_RETRY_POLICY = None 15 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `utils` module within the `agents-api` project offers a collection of utility functions designed to support various aspects of the application. This includes: 3 | 4 | - `pg.py`: Utilities for interacting with the PostgreSQL API client, including data mutation processes. 5 | - `datetime.py`: Functions for handling date and time operations, ensuring consistent use of time zones and formats across the application. 6 | - `json.py`: Custom JSON utilities, including a custom JSON encoder for handling specific object types like UUIDs, and a utility function for JSON serialization with support for default values for None objects. 7 | - `memory.py`: Functions for memory management, including utilities to accurately calculate the size of complex nested objects. 8 | 9 | These utilities are essential for the internal operations of the `agents-api`, providing common functionalities that are reused across different parts of the application. 10 | """ 11 | 12 | from .memory import total_size as total_size 13 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/datetime.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | from datetime import UTC, datetime 4 | 5 | 6 | def utcnow(): 7 | return datetime.now(UTC) 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/llm_providers.py: -------------------------------------------------------------------------------- 1 | from pathlib import Path 2 | 3 | import yaml 4 | 5 | config_path = Path("/app/litellm-config.yaml") 6 | 7 | _config = None 8 | 9 | 10 | def get_config(): 11 | global _config 12 | if _config is None: 13 | if not config_path.exists(): 14 | print(f"Warning: LiteLLM config file not found at {config_path}") 15 | return {} 16 | 17 | try: 18 | with open(config_path) as f: 19 | _config = yaml.safe_load(f) 20 | except Exception as e: 21 | print(f"Error loading LiteLLM config: {e}") 22 | return {} 23 | 24 | return _config 25 | 26 | 27 | def get_api_key_env_var_name(model: str) -> str | None: 28 | config = get_config() 29 | 30 | for model_config in config.get("model_list", []): 31 | if model_config.get("model_name") == model: 32 | api_key = model_config.get("litellm_params", {}).get("api_key") 33 | if api_key: 34 | return api_key.split("/", 1)[1] 35 | 36 | return None 37 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/messages.py: -------------------------------------------------------------------------------- 1 | import json 2 | from typing import cast 3 | 4 | from beartype import beartype 5 | 6 | from ...autogen.openapi_model import ( 7 | ChatMLImageContentPart, 8 | ChatMLTextContentPart, 9 | ) 10 | 11 | 12 | @beartype 13 | def content_to_json( 14 | content: str | list[dict] | dict, 15 | ) -> list[dict]: 16 | if isinstance(content, str): 17 | result = [{"type": "text", "text": content}] 18 | elif isinstance(content, list): 19 | result = content 20 | elif isinstance(content, dict): 21 | result = [{"type": "text", "text": json.dumps(content, indent=4)}] 22 | 23 | return result 24 | 25 | 26 | def stringify_content( 27 | msg: str | list[ChatMLTextContentPart] | list[ChatMLImageContentPart] | dict, 28 | ) -> str: 29 | content = "" 30 | if isinstance(msg, list): 31 | content = " ".join([part.text for part in msg if part.type == "text"]) 32 | elif isinstance(msg, str): 33 | content = msg 34 | elif isinstance(msg, dict) and msg["type"] == "text": 35 | content = cast(str, msg["text"]) 36 | 37 | return content 38 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/types.py: -------------------------------------------------------------------------------- 1 | from beartype.vale import Is 2 | from beartype.vale._core._valecore import BeartypeValidator 3 | from pydantic import BaseModel 4 | 5 | 6 | def dict_like(pydantic_model_class: type[BaseModel]) -> BeartypeValidator: 7 | required_fields_set: set[str] = { 8 | field for field, info in pydantic_model_class.model_fields.items() if info.is_required() 9 | } 10 | 11 | return Is[ 12 | lambda x: isinstance(x, pydantic_model_class) 13 | or required_fields_set.issubset(set(x.keys())) 14 | ] 15 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/workflows.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: Workflow name parsing utility for extracting base workflow from transition strings. 2 | from ...autogen.openapi_model import Transition 3 | 4 | PAR_PREFIX = "PAR:" 5 | SEPARATOR = "`" 6 | 7 | 8 | def get_workflow_name(transition: Transition) -> str: 9 | workflow_str = transition.current.workflow 10 | if workflow_str.startswith(PAR_PREFIX): 11 | # Extract between PAR:` and first ` after "workflow" 12 | start_index = len(PAR_PREFIX) + len(SEPARATOR) 13 | assert len(workflow_str) > start_index and SEPARATOR in workflow_str[start_index:], ( 14 | "Workflow string is too short or missing backtick" 15 | ) 16 | workflow_str = workflow_str[start_index:].split(SEPARATOR)[0] 17 | elif workflow_str.startswith(SEPARATOR): 18 | # Extract between backticks 19 | start_index = len(SEPARATOR) 20 | assert len(workflow_str) > start_index and SEPARATOR in workflow_str[start_index:], ( 21 | "Workflow string is too short or missing backtick" 22 | ) 23 | workflow_str = workflow_str[start_index:].split(SEPARATOR)[0] 24 | 25 | return workflow_str 26 | -------------------------------------------------------------------------------- /agents-api/agents_api/common/utils/yaml.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | import yaml 4 | 5 | 6 | def load(string: str) -> Any: 7 | return yaml.load(string, Loader=yaml.CSafeLoader) 8 | 9 | 10 | def dump(value: Any) -> str: 11 | return yaml.dump(value, Dumper=yaml.CSafeDumper) 12 | -------------------------------------------------------------------------------- /agents-api/agents_api/dependencies/__init__.py: -------------------------------------------------------------------------------- 1 | """This module contains dependencies that are crucial for the operation of the agents-api. It includes components for: 2 | 3 | - `auth.py` for API key authentication: This component is responsible for validating the API key provided in the request headers, ensuring that only authorized requests are processed. 4 | - `developer_id.py` for developer identification: Handles developer-specific headers like `X-Developer-Id` and `X-Developer-Email`, facilitating the identification of the developer making the request. 5 | - `exceptions.py` for custom exception handling: Defines custom exceptions that are used throughout the dependencies module to handle errors related to API security and developer identification. 6 | 7 | These components collectively ensure the security and proper operation of the agents-api by authenticating requests, identifying developers, and handling errors in a standardized manner.""" 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/dependencies/auth.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from fastapi import HTTPException, Security 4 | from fastapi.security.api_key import APIKeyHeader 5 | from starlette.status import HTTP_403_FORBIDDEN 6 | 7 | from ..env import api_key, api_key_header_name 8 | 9 | api_key_header: Any = APIKeyHeader(name=api_key_header_name, auto_error=False) 10 | 11 | 12 | async def get_api_key( 13 | user_api_key: str = Security(api_key_header), 14 | ) -> str: 15 | user_api_key = str(user_api_key) 16 | user_api_key = (user_api_key or "").replace("Bearer ", "").strip() 17 | 18 | if user_api_key != api_key: 19 | raise HTTPException(status_code=HTTP_403_FORBIDDEN, detail="Could not validate API KEY") 20 | return user_api_key 21 | -------------------------------------------------------------------------------- /agents-api/agents_api/dependencies/content_length.py: -------------------------------------------------------------------------------- 1 | from fastapi import Header 2 | 3 | from ..env import max_payload_size 4 | 5 | 6 | async def valid_content_length(content_length: int = Header(..., lt=max_payload_size)): 7 | return content_length 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/dependencies/exceptions.py: -------------------------------------------------------------------------------- 1 | class InvalidHeaderFormat(Exception): 2 | pass 3 | -------------------------------------------------------------------------------- /agents-api/agents_api/metrics/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/agents_api/metrics/__init__.py -------------------------------------------------------------------------------- /agents-api/agents_api/queries/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/queries/agents/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `agent` module within the `queries` package provides a comprehensive suite of SQL query functions for managing agents in the PostgreSQL database. This includes: 3 | 4 | - Creating new agents 5 | - Updating existing agents 6 | - Retrieving details about specific agents 7 | - Listing agents with filtering and pagination 8 | - Deleting agents from the database 9 | 10 | Each function in this module constructs and returns SQL queries along with their parameters for database operations. 11 | """ 12 | 13 | from .create_agent import create_agent 14 | from .create_or_update_agent import create_or_update_agent 15 | from .delete_agent import delete_agent 16 | from .get_agent import get_agent 17 | from .list_agents import list_agents 18 | from .patch_agent import patch_agent 19 | from .update_agent import update_agent 20 | 21 | __all__ = [ 22 | "create_agent", 23 | "create_or_update_agent", 24 | "delete_agent", 25 | "get_agent", 26 | "list_agents", 27 | "patch_agent", 28 | "update_agent", 29 | ] 30 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/developers/get_developer.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module for retrieving developer information from the PostgreSQL database. 3 | """ 4 | 5 | from uuid import UUID 6 | 7 | from beartype import beartype 8 | 9 | from ...common.protocol.developers import Developer 10 | from ...common.utils.db_exceptions import common_db_exceptions 11 | from ..utils import pg_query, rewrap_exceptions, wrap_in_class 12 | 13 | developer_query = """ 14 | SELECT * FROM developers WHERE developer_id = $1 AND active = true 15 | """ 16 | 17 | 18 | @rewrap_exceptions(common_db_exceptions("developer", ["get"])) 19 | @wrap_in_class( 20 | Developer, 21 | one=True, 22 | transform=lambda d: {**d, "id": d["developer_id"]}, 23 | ) 24 | @pg_query 25 | @beartype 26 | async def get_developer( 27 | *, 28 | developer_id: UUID, 29 | ) -> tuple[str, list]: 30 | developer_id = str(developer_id) 31 | 32 | return ( 33 | developer_query, 34 | [developer_id], 35 | ) 36 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/developers/patch_developer.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | 3 | from beartype import beartype 4 | 5 | from ...common.protocol.developers import Developer 6 | from ...common.utils.db_exceptions import common_db_exceptions 7 | from ..utils import pg_query, rewrap_exceptions, wrap_in_class 8 | 9 | # Define the raw SQL query 10 | developer_query = """ 11 | UPDATE developers 12 | SET email = $1, active = $2, tags = tags || $3, settings = settings || $4 -- settings 13 | WHERE developer_id = $5 -- developer_id 14 | RETURNING *; 15 | """ 16 | 17 | 18 | @rewrap_exceptions(common_db_exceptions("developer", ["patch"])) 19 | @wrap_in_class(Developer, one=True, transform=lambda d: {**d, "id": d["developer_id"]}) 20 | @pg_query 21 | @beartype 22 | async def patch_developer( 23 | *, 24 | developer_id: UUID, 25 | email: str, 26 | active: bool = True, 27 | tags: list[str] | None = None, 28 | settings: dict | None = None, 29 | ) -> tuple[str, list]: 30 | developer_id = str(developer_id) 31 | 32 | return ( 33 | developer_query, 34 | [email, active, tags or [], settings or {}, developer_id], 35 | ) 36 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/developers/update_developer.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | 3 | from beartype import beartype 4 | 5 | from ...common.protocol.developers import Developer 6 | from ...common.utils.db_exceptions import common_db_exceptions 7 | from ..utils import pg_query, rewrap_exceptions, wrap_in_class 8 | 9 | # Define the raw SQL query 10 | developer_query = """ 11 | UPDATE developers 12 | SET email = $1, active = $2, tags = $3, settings = $4 13 | WHERE developer_id = $5 14 | RETURNING *; 15 | """ 16 | 17 | 18 | @rewrap_exceptions(common_db_exceptions("developer", ["update"])) 19 | @wrap_in_class(Developer, one=True, transform=lambda d: {**d, "id": d["developer_id"]}) 20 | @pg_query 21 | @beartype 22 | async def update_developer( 23 | *, 24 | developer_id: UUID, 25 | email: str, 26 | active: bool = True, 27 | tags: list[str] | None = None, 28 | settings: dict | None = None, 29 | ) -> tuple[str, list]: 30 | developer_id = str(developer_id) 31 | 32 | return ( 33 | developer_query, 34 | [email, active, tags or [], settings or {}, developer_id], 35 | ) 36 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/entries/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `entry` module provides SQL query functions for managing entries 3 | in the TimescaleDB database. This includes operations for: 4 | 5 | - Creating new entries 6 | - Deleting entries 7 | - Retrieving entry history 8 | - Listing entries with filtering and pagination 9 | """ 10 | 11 | from .create_entries import add_entry_relations, create_entries 12 | from .delete_entries import delete_entries 13 | from .get_history import get_history 14 | from .list_entries import list_entries 15 | 16 | __all__ = [ 17 | "add_entry_relations", 18 | "create_entries", 19 | "delete_entries", 20 | "get_history", 21 | "list_entries", 22 | ] 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/executions/constants.py: -------------------------------------------------------------------------------- 1 | ########## 2 | # Consts # 3 | ########## 4 | 5 | OUTPUT_UNNEST_KEY = "$$e7w_unnest$$" 6 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/files/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `files` module within the `queries` package provides SQL query functions for managing files 3 | in the PostgreSQL database. This includes operations for: 4 | 5 | - Creating new files 6 | - Retrieving file details 7 | - Listing files with filtering and pagination 8 | - Deleting files and their associations 9 | """ 10 | 11 | from .create_file import create_file 12 | from .delete_file import delete_file 13 | from .get_file import get_file 14 | from .list_files import list_files 15 | 16 | __all__ = ["create_file", "delete_file", "get_file", "list_files"] 17 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/projects/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `project` module within the `queries` package provides a comprehensive suite of SQL query functions for managing projects in the PostgreSQL database. This includes: 3 | 4 | - Creating new projects 5 | - Updating existing projects 6 | - Retrieving details about specific projects 7 | - Listing projects with filtering and pagination 8 | - Deleting projects from the database 9 | 10 | Each function in this module constructs and returns SQL queries along with their parameters for database operations. 11 | """ 12 | 13 | from .create_project import create_project 14 | from .list_projects import list_projects 15 | 16 | __all__ = [ 17 | "create_project", 18 | "list_projects", 19 | ] 20 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/projects/project_exists.py: -------------------------------------------------------------------------------- 1 | """ 2 | This module contains the functionality for creating agents in the PostgreSQL database. 3 | It includes functions to construct and execute SQL queries for inserting new agent records. 4 | """ 5 | 6 | from uuid import UUID 7 | 8 | from beartype import beartype 9 | 10 | from ...common.utils.db_exceptions import common_db_exceptions 11 | from ..utils import pg_query, rewrap_exceptions 12 | 13 | # Define the raw SQL query for checking project existence 14 | check_project_query = """ 15 | SELECT 16 | CASE 17 | WHEN EXISTS ( 18 | SELECT 1 FROM projects 19 | WHERE developer_id = $1 AND canonical_name = $2 20 | ) THEN 21 | TRUE 22 | ELSE 23 | FALSE 24 | END as project_exists; 25 | """ 26 | 27 | 28 | @rewrap_exceptions(common_db_exceptions("project", ["exists"])) 29 | @pg_query 30 | @beartype 31 | async def project_exists(developer_id: UUID, canonical_name: str) -> tuple[str, list]: 32 | return (check_project_query, [developer_id, canonical_name]) 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/secrets/__init__.py: -------------------------------------------------------------------------------- 1 | """Query functions for secrets.""" 2 | 3 | from .create import create_secret 4 | from .delete import delete_secret 5 | from .get_by_name import get_secret_by_name 6 | from .list import list_secrets 7 | from .update import update_secret 8 | 9 | __all__ = [ 10 | "create_secret", 11 | "delete_secret", 12 | "get_secret_by_name", 13 | "list_secrets", 14 | "update_secret", 15 | ] 16 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/sessions/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `sessions` module within the `queries` package provides SQL query functions for managing sessions 3 | in the PostgreSQL database. This includes operations for: 4 | 5 | - Creating new sessions 6 | - Updating existing sessions 7 | - Retrieving session details 8 | - Listing sessions with filtering and pagination 9 | - Deleting sessions 10 | """ 11 | 12 | from .count_sessions import count_sessions 13 | from .create_or_update_session import create_or_update_session 14 | from .create_session import create_session 15 | from .delete_session import delete_session 16 | from .get_session import get_session 17 | from .list_sessions import list_sessions 18 | from .patch_session import patch_session 19 | from .update_session import update_session 20 | 21 | __all__ = [ 22 | "count_sessions", 23 | "create_or_update_session", 24 | "create_session", 25 | "delete_session", 26 | "get_session", 27 | "list_sessions", 28 | "patch_session", 29 | "update_session", 30 | ] 31 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/tasks/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `task` module within the `queries` package provides SQL query functions for managing tasks 3 | in the TimescaleDB database. This includes operations for: 4 | 5 | - Creating new tasks 6 | - Updating existing tasks 7 | - Retrieving task details 8 | - Listing tasks with filtering and pagination 9 | - Deleting tasks 10 | """ 11 | 12 | from .create_or_update_task import create_or_update_task 13 | from .create_task import create_task 14 | from .delete_task import delete_task 15 | from .get_task import get_task 16 | from .list_tasks import list_tasks 17 | from .patch_task import patch_task 18 | from .update_task import update_task 19 | 20 | __all__ = [ 21 | "create_or_update_task", 22 | "create_task", 23 | "delete_task", 24 | "get_task", 25 | "list_tasks", 26 | "patch_task", 27 | "update_task", 28 | ] 29 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/tools/get_tool.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | 3 | from beartype import beartype 4 | 5 | from ...autogen.openapi_model import Tool 6 | from ...common.utils.db_exceptions import common_db_exceptions 7 | from ..utils import pg_query, rewrap_exceptions, wrap_in_class 8 | 9 | # Define the raw SQL query for getting a tool 10 | tools_query = """ 11 | SELECT * FROM tools 12 | WHERE 13 | developer_id = $1 AND 14 | agent_id = $2 AND 15 | tool_id = $3 16 | LIMIT 1 17 | """ 18 | 19 | 20 | @rewrap_exceptions(common_db_exceptions("tool", ["get"])) 21 | @wrap_in_class( 22 | Tool, 23 | transform=lambda d: { 24 | "id": d.pop("tool_id"), 25 | d["type"]: d.pop("spec"), 26 | **d, 27 | }, 28 | one=True, 29 | ) 30 | @pg_query 31 | @beartype 32 | async def get_tool( 33 | *, 34 | developer_id: UUID, 35 | agent_id: UUID, 36 | tool_id: UUID, 37 | ) -> tuple[str, list]: 38 | developer_id = str(developer_id) 39 | agent_id = str(agent_id) 40 | tool_id = str(tool_id) 41 | 42 | return ( 43 | tools_query, 44 | [ 45 | developer_id, 46 | agent_id, 47 | tool_id, 48 | ], 49 | ) 50 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/usage/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `usage` module within the `queries` package provides functionality for tracking token usage 3 | and costs associated with LLM API calls. This includes: 4 | 5 | - Recording prompt and completion tokens 6 | - Calculating costs based on model pricing 7 | - Storing usage data with developer attribution 8 | - Supporting both standard and custom API usage 9 | 10 | Each function in this module constructs and executes SQL queries for database operations 11 | related to usage tracking and reporting. 12 | """ 13 | 14 | from .create_usage_record import create_usage_record 15 | from .get_user_cost import get_usage_cost 16 | 17 | __all__ = [ 18 | "create_usage_record", 19 | "get_usage_cost", 20 | ] 21 | -------------------------------------------------------------------------------- /agents-api/agents_api/queries/users/__init__.py: -------------------------------------------------------------------------------- 1 | """ 2 | The `user` module within the `queries` package provides SQL query functions for managing users 3 | in the TimescaleDB database. This includes operations for: 4 | 5 | - Creating new users 6 | - Updating existing users 7 | - Retrieving user details 8 | - Listing users with filtering and pagination 9 | - Deleting users 10 | """ 11 | 12 | from .create_or_update_user import create_or_update_user 13 | from .create_user import create_user 14 | from .delete_user import delete_user 15 | from .get_user import get_user 16 | from .list_users import list_users 17 | from .patch_user import patch_user 18 | from .update_user import update_user 19 | 20 | __all__ = [ 21 | "create_or_update_user", 22 | "create_user", 23 | "delete_user", 24 | "get_user", 25 | "list_users", 26 | "patch_user", 27 | "update_user", 28 | ] 29 | -------------------------------------------------------------------------------- /agents-api/agents_api/rec_sum/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/agents_api/rec_sum/__init__.py -------------------------------------------------------------------------------- /agents-api/agents_api/rec_sum/data.py: -------------------------------------------------------------------------------- 1 | import json 2 | from pathlib import Path 3 | from typing import Any 4 | 5 | module_directory: Path = Path(__file__).parent 6 | 7 | 8 | with open(f"{module_directory}/entities_example_chat.json") as _f: 9 | entities_example_chat: Any = json.load(_f) 10 | 11 | 12 | with open(f"{module_directory}/trim_example_chat.json") as _f: 13 | trim_example_chat: Any = json.load(_f) 14 | 15 | 16 | with open(f"{module_directory}/trim_example_result.json") as _f: 17 | trim_example_result: Any = json.load(_f) 18 | 19 | 20 | with open(f"{module_directory}/summarize_example_chat.json") as _f: 21 | summarize_example_chat: Any = json.load(_f) 22 | 23 | 24 | with open(f"{module_directory}/summarize_example_result.json") as _f: 25 | summarize_example_result: Any = json.load(_f) 26 | -------------------------------------------------------------------------------- /agents-api/agents_api/rec_sum/generate.py: -------------------------------------------------------------------------------- 1 | from tenacity import retry, stop_after_attempt, wait_fixed 2 | 3 | from agents_api.clients import litellm 4 | 5 | 6 | @retry(wait=wait_fixed(2), stop=stop_after_attempt(5)) 7 | async def generate( 8 | messages: list[dict], 9 | model: str = "gpt-4o", 10 | **kwargs, 11 | ) -> dict: 12 | result = await litellm.acompletion( 13 | model=model, 14 | messages=messages, 15 | **kwargs, 16 | ) 17 | 18 | return result.choices[0].message.json() 19 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | 3 | from .list_models import list_models # noqa: I001 4 | from .create_agent import create_agent 5 | from .create_agent_tool import create_agent_tool 6 | from .create_or_update_agent import create_or_update_agent 7 | from .delete_agent import delete_agent 8 | from .delete_agent_tool import delete_agent_tool 9 | from .get_agent_details import get_agent_details 10 | from .list_agent_tools import list_agent_tools 11 | from .list_agents import list_agents 12 | from .patch_agent import patch_agent 13 | from .patch_agent_tool import patch_agent_tool 14 | from .router import router 15 | from .update_agent import update_agent 16 | from .update_agent_tool import update_agent_tool 17 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/create_agent.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: This module defines the API endpoint for creating new agents. 2 | from typing import Annotated 3 | from uuid import UUID 4 | 5 | from fastapi import Depends 6 | from starlette.status import HTTP_201_CREATED 7 | 8 | from ...autogen.openapi_model import ( 9 | Agent, 10 | CreateAgentRequest, 11 | ) 12 | from ...dependencies.developer_id import get_developer_id 13 | from ...queries.agents.create_agent import create_agent as create_agent_query 14 | from ..utils.model_validation import validate_model 15 | from .router import router 16 | 17 | 18 | # AIDEV-NOTE: API endpoint to create a new agent. 19 | # It depends on the developer ID and the agent data from the request body. 20 | # Validates the agent model if specified and calls the create_agent_query function. 21 | @router.post("/agents", status_code=HTTP_201_CREATED, tags=["agents"]) 22 | async def create_agent( 23 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 24 | data: CreateAgentRequest, 25 | ) -> Agent: 26 | if data.model: 27 | await validate_model(data.model) 28 | 29 | return await create_agent_query( 30 | developer_id=x_developer_id, 31 | data=data, 32 | ) 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/create_agent_tool.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_201_CREATED 6 | 7 | from ...autogen.openapi_model import CreateToolRequest, Tool 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.tools.create_tools import create_tools as create_tools_query 10 | from .router import router 11 | 12 | 13 | @router.post("/agents/{agent_id}/tools", status_code=HTTP_201_CREATED, tags=["agents"]) 14 | async def create_agent_tool( 15 | agent_id: UUID, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | data: CreateToolRequest, 18 | ) -> Tool: 19 | tools = await create_tools_query( 20 | developer_id=x_developer_id, 21 | agent_id=agent_id, 22 | data=[data], 23 | ) 24 | 25 | return tools[0] 26 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/create_or_update_agent.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_201_CREATED 6 | 7 | from ...autogen.openapi_model import ( 8 | Agent, 9 | CreateOrUpdateAgentRequest, 10 | ) 11 | from ...dependencies.developer_id import get_developer_id 12 | from ...queries.agents.create_or_update_agent import ( 13 | create_or_update_agent as create_or_update_agent_query, 14 | ) 15 | from ..utils.model_validation import validate_model 16 | from .router import router 17 | 18 | 19 | @router.post("/agents/{agent_id}", status_code=HTTP_201_CREATED, tags=["agents"]) 20 | async def create_or_update_agent( 21 | agent_id: UUID, 22 | data: CreateOrUpdateAgentRequest, 23 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 24 | ) -> Agent: 25 | if data.model: 26 | await validate_model(data.model) 27 | 28 | return await create_or_update_agent_query( 29 | developer_id=x_developer_id, 30 | agent_id=agent_id, 31 | data=data, 32 | ) 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/delete_agent.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_202_ACCEPTED 6 | 7 | from ...autogen.openapi_model import ResourceDeletedResponse 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.agents.delete_agent import delete_agent as delete_agent_query 10 | from .router import router 11 | 12 | 13 | @router.delete("/agents/{agent_id}", status_code=HTTP_202_ACCEPTED, tags=["agents"]) 14 | async def delete_agent( 15 | agent_id: UUID, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> ResourceDeletedResponse: 18 | return await delete_agent_query(developer_id=x_developer_id, agent_id=agent_id) 19 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/delete_agent_tool.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import ResourceDeletedResponse 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.tools.delete_tool import delete_tool as delete_tool_query 9 | from .router import router 10 | 11 | 12 | @router.delete("/agents/{agent_id}/tools/{tool_id}", tags=["agents"]) 13 | async def delete_agent_tool( 14 | agent_id: UUID, 15 | tool_id: UUID, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> ResourceDeletedResponse: 18 | return await delete_tool_query( 19 | developer_id=x_developer_id, 20 | agent_id=agent_id, 21 | tool_id=tool_id, 22 | ) 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/get_agent_details.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: This module defines the API endpoint for retrieving a specific agent. 2 | from typing import Annotated 3 | from uuid import UUID 4 | 5 | from fastapi import Depends 6 | 7 | from ...autogen.openapi_model import Agent 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.agents.get_agent import get_agent as get_agent_query 10 | from .router import router 11 | 12 | 13 | # AIDEV-NOTE: API endpoint to get an agent by its ID. 14 | # It depends on the developer ID and the agent ID from the path parameter, and calls the get_agent_query function. 15 | @router.get("/agents/{agent_id}", tags=["agents"]) 16 | async def get_agent_details( 17 | agent_id: UUID, 18 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 19 | ) -> Agent: 20 | return await get_agent_query(developer_id=x_developer_id, agent_id=agent_id) 21 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/list_agent_tools.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated, Literal 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import ListResponse, Tool 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.tools.list_tools import list_tools as list_tools_query 9 | from .router import router 10 | 11 | 12 | @router.get("/agents/{agent_id}/tools", tags=["agents"]) 13 | async def list_agent_tools( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | agent_id: UUID, 16 | limit: int = 100, 17 | offset: int = 0, 18 | sort_by: Literal["created_at", "updated_at"] = "created_at", 19 | direction: Literal["asc", "desc"] = "desc", 20 | ) -> ListResponse[Tool]: 21 | # FIXME: list agent tools is returning an empty list 22 | # SCRUM-22 23 | tools = await list_tools_query( 24 | agent_id=agent_id, 25 | developer_id=x_developer_id, 26 | limit=limit, 27 | offset=offset, 28 | sort_by=sort_by, 29 | direction=direction, 30 | ) 31 | 32 | return ListResponse[Tool](items=tools) 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/list_models.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends, Header 5 | 6 | from ...autogen.openapi_model import ListModelsResponse, ModelInfo 7 | from ...clients.litellm import get_model_list 8 | from ...dependencies.developer_id import get_developer_id 9 | from .router import router 10 | 11 | 12 | @router.get("/agents/models", tags=["agents"]) 13 | async def list_models( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | x_custom_api_key: str | None = Header(None), 16 | ) -> ListModelsResponse: 17 | """ 18 | List all available models that can be used with agents. 19 | 20 | Returns: 21 | ListModelsResponse: A list of available models 22 | """ 23 | models_data = await get_model_list(custom_api_key=x_custom_api_key) 24 | model_infos = [ModelInfo(id=model["id"]) for model in models_data] 25 | 26 | return ListModelsResponse(models=model_infos) 27 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/patch_agent.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_200_OK 6 | 7 | from ...autogen.openapi_model import Agent, PatchAgentRequest 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.agents.patch_agent import patch_agent as patch_agent_query 10 | from ..utils.model_validation import validate_model 11 | from .router import router 12 | 13 | 14 | @router.patch( 15 | "/agents/{agent_id}", 16 | response_model=Agent, 17 | status_code=HTTP_200_OK, 18 | tags=["agents"], 19 | ) 20 | async def patch_agent( 21 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 22 | agent_id: UUID, 23 | data: PatchAgentRequest, 24 | ) -> Agent: 25 | if data.model: 26 | await validate_model(data.model) 27 | 28 | return await patch_agent_query( 29 | agent_id=agent_id, 30 | developer_id=x_developer_id, 31 | data=data, 32 | ) 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/patch_agent_tool.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import PatchToolRequest, Tool 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.tools.patch_tool import patch_tool as patch_tool_query 9 | from .router import router 10 | 11 | 12 | @router.patch("/agents/{agent_id}/tools/{tool_id}", tags=["agents"]) 13 | async def patch_agent_tool( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | agent_id: UUID, 16 | tool_id: UUID, 17 | data: PatchToolRequest, 18 | ) -> Tool: 19 | return await patch_tool_query( 20 | developer_id=x_developer_id, 21 | agent_id=agent_id, 22 | tool_id=tool_id, 23 | data=data, 24 | ) 25 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/update_agent.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_200_OK 6 | 7 | from ...autogen.openapi_model import Agent, UpdateAgentRequest 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.agents.update_agent import update_agent as update_agent_query 10 | from ..utils.model_validation import validate_model 11 | from .router import router 12 | 13 | 14 | @router.put( 15 | "/agents/{agent_id}", 16 | response_model=Agent, 17 | status_code=HTTP_200_OK, 18 | tags=["agents"], 19 | ) 20 | async def update_agent( 21 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 22 | agent_id: UUID, 23 | data: UpdateAgentRequest, 24 | ) -> Agent: 25 | if data.model: 26 | await validate_model(data.model) 27 | 28 | return await update_agent_query( 29 | developer_id=x_developer_id, 30 | agent_id=agent_id, 31 | data=data, 32 | ) 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/agents/update_agent_tool.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import Tool, UpdateToolRequest 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.tools.update_tool import update_tool as update_tool_query 9 | from .router import router 10 | 11 | 12 | @router.put("/agents/{agent_id}/tools/{tool_id}", tags=["agents"]) 13 | async def update_agent_tool( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | agent_id: UUID, 16 | tool_id: UUID, 17 | data: UpdateToolRequest, 18 | ) -> Tool: 19 | return await update_tool_query( 20 | developer_id=x_developer_id, 21 | agent_id=agent_id, 22 | tool_id=tool_id, 23 | data=data, 24 | ) 25 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/docs/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | from .bulk_delete_docs import bulk_delete_agent_docs, bulk_delete_user_docs 3 | from .create_doc import create_agent_doc, create_user_doc 4 | from .delete_doc import delete_agent_doc, delete_user_doc 5 | from .embed import embed 6 | from .get_doc import get_doc 7 | from .list_docs import list_agent_docs, list_user_docs 8 | from .router import router 9 | from .search_docs import search_agent_docs, search_user_docs 10 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/docs/embed.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import ( 7 | EmbedQueryResponse, 8 | MultipleEmbedQueryRequest, 9 | SingleEmbedQueryRequest, 10 | ) 11 | from ...clients import litellm 12 | from ...dependencies.developer_id import get_developer_id 13 | from .router import router 14 | 15 | 16 | @router.post("/embed", tags=["docs"]) 17 | async def embed( 18 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 19 | data: SingleEmbedQueryRequest | MultipleEmbedQueryRequest, 20 | ) -> EmbedQueryResponse: 21 | text_to_embed: str | list[str] = data.text 22 | vectors = await litellm.aembedding( 23 | inputs=text_to_embed, 24 | embed_instruction=data.embed_instruction, 25 | user=str(x_developer_id), 26 | ) 27 | 28 | return EmbedQueryResponse(vectors=vectors) 29 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/docs/get_doc.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import Doc 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.docs.get_doc import get_doc as get_doc_query 9 | from .router import router 10 | 11 | 12 | @router.get("/docs/{doc_id}", tags=["docs"]) 13 | async def get_doc( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | doc_id: UUID, 16 | ) -> Doc: 17 | return await get_doc_query(developer_id=x_developer_id, doc_id=doc_id) 18 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/docs/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/files/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | 3 | from .create_file import create_file 4 | from .delete_file import delete_file 5 | from .get_file import get_file 6 | from .list_files import list_files 7 | from .router import router 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/files/delete_file.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_202_ACCEPTED 6 | 7 | from ...autogen.openapi_model import ResourceDeletedResponse 8 | from ...clients import async_s3 9 | from ...dependencies.developer_id import get_developer_id 10 | from ...queries.files.delete_file import delete_file as delete_file_query 11 | from .router import router 12 | 13 | 14 | async def delete_file_content(file_id: UUID) -> None: 15 | """Delete file content from blob storage using the file ID as the key""" 16 | client = await async_s3.setup() 17 | key = str(file_id) 18 | 19 | await client.delete_object(Bucket=async_s3.blob_store_bucket, Key=key) 20 | 21 | 22 | @router.delete("/files/{file_id}", status_code=HTTP_202_ACCEPTED, tags=["files"]) 23 | async def delete_file( 24 | file_id: UUID, 25 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 26 | ) -> ResourceDeletedResponse: 27 | resource_deleted = await delete_file_query(developer_id=x_developer_id, file_id=file_id) 28 | 29 | # Delete the file content from blob storage 30 | await delete_file_content(file_id) 31 | 32 | return resource_deleted 33 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/files/list_files.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import File 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.files.list_files import list_files as list_files_query 9 | from .get_file import fetch_file_content 10 | from .router import router 11 | 12 | 13 | # TODO: Use streaming for large payloads 14 | @router.get("/files", tags=["files"]) 15 | async def list_files( 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> list[File]: 18 | files = await list_files_query(developer_id=x_developer_id) 19 | 20 | # Fetch the file content from blob storage 21 | for file in files: 22 | file.content = await fetch_file_content(file.id) 23 | 24 | return files 25 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/files/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/healthz/__init__.py: -------------------------------------------------------------------------------- 1 | from .check_health import check_health as check_health 2 | from .router import router as router 3 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/healthz/check_health.py: -------------------------------------------------------------------------------- 1 | import asyncio 2 | 3 | from fastapi import HTTPException 4 | 5 | from ...common.utils.checks import ( 6 | check_integration_service, 7 | check_litellm, 8 | check_postgres, 9 | check_temporal, 10 | ) 11 | from .router import router 12 | 13 | 14 | @router.get("/healthz", tags=["healthz"]) 15 | async def check_health() -> dict: 16 | # Run all health checks concurrently 17 | postgres_status, temporal_status, litellm_status, integration_status = await asyncio.gather( 18 | check_postgres(), 19 | check_temporal(), 20 | check_litellm(), 21 | check_integration_service(), 22 | ) 23 | 24 | # Create health status with results 25 | services = { 26 | "postgres": postgres_status, 27 | "temporal": temporal_status, 28 | "litellm": litellm_status, 29 | "integration_service": integration_status, 30 | } 31 | 32 | # If any service is down, mark overall status as degraded 33 | if any(status == "error" for status in services.values()): 34 | raise HTTPException(status_code=500, detail=services) 35 | 36 | return services 37 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/healthz/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/internal/__init__.py: -------------------------------------------------------------------------------- 1 | from .router import router as router 2 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/jobs/__init__.py: -------------------------------------------------------------------------------- 1 | from .routers import router as router 2 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/projects/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | 3 | from .create_project import create_project 4 | from .list_projects import list_projects 5 | from .router import router 6 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/projects/create_project.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_201_CREATED 6 | 7 | from ...autogen.openapi_model import ( 8 | CreateProjectRequest, 9 | Project, 10 | ) 11 | from ...dependencies.developer_id import get_developer_id 12 | from ...queries.projects.create_project import create_project as create_project_query 13 | from .router import router 14 | 15 | 16 | @router.post("/projects", status_code=HTTP_201_CREATED, tags=["projects"]) 17 | async def create_project( 18 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 19 | data: CreateProjectRequest, 20 | ) -> Project: 21 | return await create_project_query( 22 | developer_id=x_developer_id, 23 | data=data, 24 | ) 25 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/projects/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/responses/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | 3 | from .create_response import create_response 4 | from .get_response import get_response 5 | from .router import router 6 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/responses/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/secrets/__init__.py: -------------------------------------------------------------------------------- 1 | # from .create_secret import create_agent_secret as create_agent_secret 2 | from .create_secret import create_developer_secret as create_developer_secret 3 | 4 | # from .delete_secret import delete_agent_secret as delete_agent_secret 5 | from .delete_secret import delete_developer_secret as delete_developer_secret 6 | 7 | # from .list_secrets import list_agent_secrets as list_agent_secrets 8 | from .list_secrets import list_developer_secrets as list_developer_secrets 9 | from .router import router as router 10 | 11 | # from .update_secret import update_agent_secret as update_agent_secret 12 | from .update_secret import update_developer_secret as update_developer_secret 13 | 14 | # TODO: Add get_secret_by_name endpoint 15 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/secrets/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | 3 | from .chat import chat 4 | from .create_or_update_session import create_or_update_session 5 | from .create_session import create_session 6 | from .delete_session import delete_session 7 | from .get_session import get_session 8 | from .get_session_history import get_session_history 9 | from .list_sessions import list_sessions 10 | from .patch_session import patch_session 11 | from .render import render 12 | from .router import router 13 | from .update_session import update_session 14 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/create_or_update_session.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_201_CREATED 6 | 7 | from ...autogen.openapi_model import CreateOrUpdateSessionRequest, Session 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.sessions.create_or_update_session import ( 10 | create_or_update_session as create_or_update_session_query, 11 | ) 12 | from .router import router 13 | 14 | 15 | @router.post("/sessions/{session_id}", status_code=HTTP_201_CREATED, tags=["sessions"]) 16 | async def create_or_update_session( 17 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 18 | session_id: UUID, 19 | data: CreateOrUpdateSessionRequest, 20 | ) -> Session: 21 | return await create_or_update_session_query( 22 | developer_id=x_developer_id, 23 | session_id=session_id, 24 | data=data, 25 | ) 26 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/create_session.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: This module defines the API endpoint for creating new sessions. 2 | from typing import Annotated 3 | from uuid import UUID 4 | 5 | from fastapi import Depends 6 | from starlette.status import HTTP_201_CREATED 7 | 8 | from ...autogen.openapi_model import CreateSessionRequest, Session 9 | from ...dependencies.developer_id import get_developer_id 10 | from ...queries.sessions.create_session import create_session as create_session_query 11 | from .router import router 12 | 13 | 14 | # AIDEV-NOTE: API endpoint to create a new session. 15 | # It depends on the developer ID and the session data from the request body, and calls the create_session_query function. 16 | @router.post("/sessions", status_code=HTTP_201_CREATED, tags=["sessions"]) 17 | async def create_session( 18 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 19 | data: CreateSessionRequest, 20 | ) -> Session: 21 | return await create_session_query( 22 | developer_id=x_developer_id, 23 | data=data, 24 | ) 25 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/delete_session.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_202_ACCEPTED 6 | 7 | from ...autogen.openapi_model import ResourceDeletedResponse 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.sessions.delete_session import delete_session as delete_session_query 10 | from .router import router 11 | 12 | 13 | @router.delete("/sessions/{session_id}", status_code=HTTP_202_ACCEPTED, tags=["sessions"]) 14 | async def delete_session( 15 | session_id: UUID, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> ResourceDeletedResponse: 18 | return await delete_session_query(developer_id=x_developer_id, session_id=session_id) 19 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/exceptions.py: -------------------------------------------------------------------------------- 1 | class BaseSessionException(Exception): 2 | pass 3 | 4 | 5 | class InputTooBigError(BaseSessionException): 6 | def __init__(self, actual_tokens, required_tokens) -> None: 7 | super().__init__( 8 | f"Input is too big, {actual_tokens} tokens provided, but only {required_tokens} tokens are allowed.", 9 | ) 10 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/get_session.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: This module defines the API endpoint for retrieving a specific session. 2 | from typing import Annotated 3 | from uuid import UUID 4 | 5 | from fastapi import Depends 6 | 7 | from ...autogen.openapi_model import Session 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.sessions.get_session import get_session as get_session_query 10 | from .router import router 11 | 12 | 13 | # AIDEV-NOTE: API endpoint to get a session by its ID. 14 | # It depends on the developer ID and the session ID from the path parameter, and calls the get_session_query function. 15 | @router.get("/sessions/{session_id}", tags=["sessions"]) 16 | async def get_session( 17 | session_id: UUID, 18 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 19 | ) -> Session: 20 | return await get_session_query(developer_id=x_developer_id, session_id=session_id) 21 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/get_session_history.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import History 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.entries.get_history import get_history as get_history_query 9 | from .router import router 10 | 11 | 12 | @router.get("/sessions/{session_id}/history", tags=["sessions"]) 13 | async def get_session_history( 14 | session_id: UUID, 15 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 16 | ) -> History: 17 | return await get_history_query(developer_id=x_developer_id, session_id=session_id) 18 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/metrics.py: -------------------------------------------------------------------------------- 1 | from prometheus_client import Counter 2 | 3 | total_tokens_per_user = Counter( 4 | "total_tokens_per_user", 5 | "Total token count per user", 6 | labelnames=("developer_id",), 7 | ) 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/patch_session.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import PatchSessionRequest, Session 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.sessions.patch_session import patch_session as patch_session_query 9 | from .router import router 10 | 11 | 12 | @router.patch("/sessions/{session_id}", tags=["sessions"]) 13 | async def patch_session( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | session_id: UUID, 16 | data: PatchSessionRequest, 17 | ) -> Session: 18 | return await patch_session_query( 19 | developer_id=x_developer_id, 20 | session_id=session_id, 21 | data=data, 22 | ) 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/sessions/update_session.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import Session, UpdateSessionRequest 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.sessions.update_session import update_session as update_session_query 9 | from .router import router 10 | 11 | 12 | @router.put("/sessions/{session_id}", tags=["sessions"]) 13 | async def update_session( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | session_id: UUID, 16 | data: UpdateSessionRequest, 17 | ) -> Session: 18 | return await update_session_query( 19 | developer_id=x_developer_id, 20 | session_id=session_id, 21 | data=data, 22 | ) 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/tasks/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | from .create_or_update_task import create_or_update_task 3 | from .create_task import create_task 4 | from .create_task_execution import create_task_execution 5 | from .get_execution_details import get_execution_details 6 | from .get_task_details import get_task_details 7 | from .list_execution_transitions import list_execution_transitions 8 | from .list_task_executions import list_task_executions 9 | from .list_tasks import list_tasks 10 | from .router import router 11 | from .stream_execution_status import stream_execution_status 12 | from .stream_transitions_events import stream_transitions_events 13 | from .update_execution import update_execution 14 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/tasks/get_execution_details.py: -------------------------------------------------------------------------------- 1 | from uuid import UUID 2 | 3 | from ...autogen.openapi_model import ( 4 | Execution, 5 | ) 6 | from ...queries.executions.get_execution import ( 7 | get_execution as get_execution_query, 8 | ) 9 | from .router import router 10 | 11 | 12 | @router.get("/executions/{execution_id}", tags=["executions"]) 13 | async def get_execution_details(execution_id: UUID) -> Execution: 14 | return await get_execution_query(execution_id=execution_id) 15 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/tasks/get_task_details.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import ( 7 | Task, 8 | ) 9 | from ...dependencies.developer_id import get_developer_id 10 | from ...queries.tasks.get_task import get_task as get_task_query 11 | from .router import router 12 | 13 | 14 | @router.get("/tasks/{task_id}", tags=["tasks"]) 15 | async def get_task_details( 16 | task_id: UUID, 17 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 18 | ) -> Task: 19 | task = await get_task_query(developer_id=x_developer_id, task_id=task_id) 20 | task_data = task.model_dump() 21 | 22 | for workflow in task_data.get("workflows", []): 23 | if workflow["name"] == "main": 24 | task_data["main"] = workflow.get("steps", []) 25 | break 26 | 27 | return Task(**task_data) 28 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/tasks/list_task_executions.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated, Literal 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import ( 7 | Execution, 8 | ListResponse, 9 | ) 10 | from ...dependencies.developer_id import get_developer_id 11 | from ...queries.executions.list_executions import ( 12 | list_executions as list_task_executions_query, 13 | ) 14 | from .router import router 15 | 16 | 17 | @router.get("/tasks/{task_id}/executions", tags=["tasks"]) 18 | async def list_task_executions( 19 | task_id: UUID, 20 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 21 | limit: int = 100, 22 | offset: int = 0, 23 | sort_by: Literal["created_at", "updated_at"] = "created_at", 24 | direction: Literal["asc", "desc"] = "desc", 25 | ) -> ListResponse[Execution]: 26 | executions = await list_task_executions_query( 27 | task_id=task_id, 28 | developer_id=x_developer_id, 29 | limit=limit, 30 | offset=offset, 31 | sort_by=sort_by, 32 | direction=direction, 33 | ) 34 | return ListResponse[Execution](items=executions) 35 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/tasks/router.py: -------------------------------------------------------------------------------- 1 | from collections.abc import Callable 2 | 3 | from fastapi import APIRouter, Request, Response 4 | from fastapi.routing import APIRoute 5 | 6 | from ...common.utils import yaml 7 | 8 | 9 | class YamlRequest(Request): 10 | async def body(self) -> bytes: 11 | if not hasattr(self, "_body"): 12 | body = await super().body() 13 | 14 | if self.headers.get("content-type") in [ 15 | "application/x-yaml", 16 | "application/yaml", 17 | "text/yaml", 18 | ]: 19 | body = yaml.load(body) 20 | 21 | self._body = body 22 | 23 | return self._body 24 | 25 | 26 | class YamlRoute(APIRoute): 27 | def get_route_handler(self) -> Callable: 28 | original_route_handler = super().get_route_handler() 29 | 30 | async def custom_route_handler(request: Request) -> Response: 31 | request = YamlRequest(request.scope, request.receive) 32 | 33 | return await original_route_handler(request) 34 | 35 | return custom_route_handler 36 | 37 | 38 | router: APIRouter = APIRouter( 39 | route_class=YamlRoute, 40 | ) 41 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/__init__.py: -------------------------------------------------------------------------------- 1 | # ruff: noqa: F401 2 | from .create_or_update_user import create_or_update_user 3 | from .create_user import create_user 4 | from .delete_user import delete_user 5 | from .get_user_details import get_user_details 6 | from .list_users import list_users 7 | from .patch_user import patch_user 8 | from .router import router 9 | from .update_user import update_user 10 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/create_or_update_user.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_201_CREATED 6 | 7 | from ...autogen.openapi_model import CreateOrUpdateUserRequest, User 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.users.create_or_update_user import ( 10 | create_or_update_user as create_or_update_user_query, 11 | ) 12 | from .router import router 13 | 14 | 15 | @router.post("/users/{user_id}", status_code=HTTP_201_CREATED, tags=["users"]) 16 | async def create_or_update_user( 17 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 18 | user_id: UUID, 19 | data: CreateOrUpdateUserRequest, 20 | ) -> User: 21 | return await create_or_update_user_query( 22 | developer_id=x_developer_id, 23 | user_id=user_id, 24 | data=data, 25 | ) 26 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/create_user.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_201_CREATED 6 | 7 | from ...autogen.openapi_model import CreateUserRequest, User 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.users.create_user import create_user as create_user_query 10 | from .router import router 11 | 12 | 13 | @router.post("/users", status_code=HTTP_201_CREATED, tags=["users"]) 14 | async def create_user( 15 | data: CreateUserRequest, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> User: 18 | return await create_user_query( 19 | developer_id=x_developer_id, 20 | data=data, 21 | ) 22 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/delete_user.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | from starlette.status import HTTP_202_ACCEPTED 6 | 7 | from ...autogen.openapi_model import ResourceDeletedResponse 8 | from ...dependencies.developer_id import get_developer_id 9 | from ...queries.users.delete_user import delete_user as delete_user_query 10 | from .router import router 11 | 12 | 13 | @router.delete("/users/{user_id}", status_code=HTTP_202_ACCEPTED, tags=["users"]) 14 | async def delete_user( 15 | user_id: UUID, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> ResourceDeletedResponse: 18 | return await delete_user_query(developer_id=x_developer_id, user_id=user_id) 19 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/get_user_details.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import User 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.users.get_user import get_user as get_user_query 9 | from .router import router 10 | 11 | 12 | @router.get("/users/{user_id}", tags=["users"]) 13 | async def get_user_details( 14 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 15 | user_id: UUID, 16 | ) -> User: 17 | return await get_user_query(developer_id=x_developer_id, user_id=user_id) 18 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/patch_user.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import PatchUserRequest, User 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.users.patch_user import patch_user as patch_user_query 9 | from .router import router 10 | 11 | 12 | @router.patch("/users/{user_id}", tags=["users"]) 13 | async def patch_user( 14 | user_id: UUID, 15 | data: PatchUserRequest, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> User: 18 | return await patch_user_query( 19 | developer_id=x_developer_id, 20 | user_id=user_id, 21 | data=data, 22 | ) 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/users/update_user.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | from uuid import UUID 3 | 4 | from fastapi import Depends 5 | 6 | from ...autogen.openapi_model import UpdateUserRequest, User 7 | from ...dependencies.developer_id import get_developer_id 8 | from ...queries.users.update_user import update_user as update_user_query 9 | from .router import router 10 | 11 | 12 | @router.put("/users/{user_id}", tags=["users"]) 13 | async def update_user( 14 | user_id: UUID, 15 | data: UpdateUserRequest, 16 | x_developer_id: Annotated[UUID, Depends(get_developer_id)], 17 | ) -> User: 18 | return await update_user_query( 19 | developer_id=x_developer_id, 20 | user_id=user_id, 21 | data=data, 22 | ) 23 | -------------------------------------------------------------------------------- /agents-api/agents_api/routers/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/agents_api/routers/utils/__init__.py -------------------------------------------------------------------------------- /agents-api/agents_api/routers/utils/model_validation.py: -------------------------------------------------------------------------------- 1 | # AIDEV-NOTE: Validates model names against LiteLLM and raises HTTPException for invalid names. 2 | from fastapi import HTTPException 3 | from starlette.status import HTTP_400_BAD_REQUEST 4 | 5 | from ...clients.litellm import get_model_list 6 | 7 | 8 | async def validate_model(model_name: str | None) -> None: 9 | """ 10 | Validates if a given model name is available in LiteLLM. 11 | Raises HTTPException if model is not available. 12 | """ 13 | models = await get_model_list() 14 | available_models = [model["id"] for model in models] 15 | 16 | if model_name not in available_models: 17 | raise HTTPException( 18 | status_code=HTTP_400_BAD_REQUEST, 19 | detail=f"Model {model_name} not available. Available models: {available_models}", 20 | ) 21 | -------------------------------------------------------------------------------- /agents-api/agents_api/worker/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/worker/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | 3 | """ 4 | The Worker Module for the Agents API 5 | 6 | This module is responsible for handling background tasks and jobs for the Agents API application. It provides functionalities for managing memory management tasks, among other background operations, to enhance the application's performance and scalability. The worker module interacts with other components of the application by receiving tasks, processing them asynchronously, and reporting on task completion or errors. This module plays a crucial role in ensuring the application can handle complex operations efficiently without blocking the main execution flow. 7 | """ 8 | -------------------------------------------------------------------------------- /agents-api/agents_api/workflows/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /agents-api/agents_api/workflows/__init__.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | # AIDEV-NOTE: Configure Temporal workflow unsafe imports and logging setup for agents-api workflows. 3 | from temporalio import workflow 4 | 5 | with workflow.unsafe.imports_passed_through(): 6 | import logging 7 | 8 | logging.basicConfig(level=logging.INFO) 9 | -------------------------------------------------------------------------------- /agents-api/agents_api/workflows/demo.py: -------------------------------------------------------------------------------- 1 | from datetime import timedelta 2 | 3 | from temporalio import workflow 4 | 5 | from ..common.retry_policies import DEFAULT_RETRY_POLICY 6 | 7 | # AIDEV-NOTE: Sample workflow demonstrating Temporal integration with a simple demo activity. 8 | with workflow.unsafe.imports_passed_through(): 9 | from ..activities.demo import demo_activity 10 | 11 | 12 | @workflow.defn 13 | class DemoWorkflow: 14 | @workflow.run 15 | async def run(self, a: int, b: int) -> int: 16 | return await workflow.execute_activity( 17 | demo_activity, 18 | args=[a, b], 19 | start_to_close_timeout=timedelta(seconds=30), 20 | retry_policy=DEFAULT_RETRY_POLICY, 21 | ) 22 | -------------------------------------------------------------------------------- /agents-api/gunicorn_conf.py: -------------------------------------------------------------------------------- 1 | import os 2 | from agents_api.env import gunicorn_workers 3 | 4 | debug = os.getenv("DEBUG", "false").lower() == "true" 5 | 6 | # Gunicorn config variables 7 | workers = gunicorn_workers if not debug else 1 8 | worker_class = "uvicorn.workers.UvicornWorker" 9 | bind = "0.0.0.0:8080" 10 | keepalive = 120 11 | timeout = 120 12 | errorlog = "-" 13 | accesslog = "-" 14 | -------------------------------------------------------------------------------- /agents-api/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/tests/__init__.py -------------------------------------------------------------------------------- /agents-api/tests/sample_tasks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/tests/sample_tasks/__init__.py -------------------------------------------------------------------------------- /agents-api/tests/sample_tasks/integration_example.yaml: -------------------------------------------------------------------------------- 1 | name: Simple multi step task 2 | 3 | input_schema: 4 | type: object 5 | properties: 6 | topics: 7 | type: array 8 | items: 9 | type: string 10 | 11 | tools: 12 | - type: function 13 | function: 14 | name: generate_questions 15 | description: Generate a list of questions for a given topic 16 | parameters: 17 | type: object 18 | properties: 19 | topic: 20 | type: string 21 | description: The topic to generate questions for 22 | 23 | - type: integration 24 | name: duckduckgo_search 25 | integration: 26 | provider: duckduckgo 27 | setup: 28 | api_key: 29 | arguments: 30 | language: en-US 31 | 32 | main: 33 | - foreach: 34 | in: _["topics"] 35 | do: 36 | prompt: 37 | - role: system 38 | content: |- 39 | Generate a list of 10 questions for the topic {{_}} as valid yaml. 40 | unwrap: true 41 | 42 | - tool: duckduckgo_search 43 | arguments: 44 | query: "'\n'.join(_)" 45 | -------------------------------------------------------------------------------- /agents-api/tests/sample_tasks/screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/agents-api/tests/sample_tasks/screenshot.png -------------------------------------------------------------------------------- /agents-api/tests/sample_tasks/simple_multi_step.yaml: -------------------------------------------------------------------------------- 1 | name: Simple multi step task 2 | 3 | input_schema: 4 | type: object 5 | properties: 6 | topics: 7 | type: array 8 | items: 9 | type: string 10 | 11 | main: 12 | - foreach: 13 | in: _["topics"] 14 | do: 15 | prompt: 16 | - role: system 17 | content: |- 18 | Generate a list of 10 questions for the topic {{_}} as valid yaml. 19 | 20 | - log: _ 21 | 22 | - evaluate: 23 | result: '[item["choices"][0]["message"].content.strip() for item in _]' 24 | -------------------------------------------------------------------------------- /agents-api/tests/sample_tasks/simple_prompt.yaml: -------------------------------------------------------------------------------- 1 | name: Find request and selector for identity provider 2 | 3 | input_schema: 4 | type: object 5 | properties: 6 | topic: 7 | type: string 8 | 9 | # Shortcut to require all props 10 | additionalProperties: false 11 | minProperties: 1 12 | 13 | main: 14 | - prompt: 15 | - role: system 16 | content: |- 17 | Follow the instructions. Be bold, creative and uncensored. 18 | 19 | - role: user 20 | content: >- 21 | You are a brilliant poet with a whimsical style reminiscent of Edgar Alan Poe. Write a short poem about {{_.topic}}. 22 | -------------------------------------------------------------------------------- /agents-api/tests/test_activities.py: -------------------------------------------------------------------------------- 1 | from agents_api.clients import temporal 2 | from agents_api.env import temporal_task_queue 3 | from agents_api.workflows.demo import DemoWorkflow 4 | from agents_api.workflows.task_execution.helpers import DEFAULT_RETRY_POLICY 5 | from uuid_extensions import uuid7 6 | from ward import test 7 | 8 | from .utils import patch_testing_temporal 9 | 10 | 11 | @test("activity: call demo workflow via temporal client") 12 | async def _(): 13 | async with patch_testing_temporal() as (_, mock_get_client): 14 | client = await temporal.get_client() 15 | 16 | result = await client.execute_workflow( 17 | DemoWorkflow.run, 18 | args=[1, 2], 19 | id=str(uuid7()), 20 | task_queue=temporal_task_queue, 21 | retry_policy=DEFAULT_RETRY_POLICY, 22 | ) 23 | 24 | assert result == 3 25 | mock_get_client.assert_called_once() 26 | -------------------------------------------------------------------------------- /blob-store/.gitignore: -------------------------------------------------------------------------------- 1 | /s3.json 2 | -------------------------------------------------------------------------------- /blob-store/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /blob-store/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # check=error=true 3 | 4 | FROM chrislusf/seaweedfs 5 | 6 | # Install envsubst 7 | ENV BUILD_DEPS="gettext" \ 8 | RUNTIME_DEPS="libintl" 9 | 10 | RUN set -x && \ 11 | apk add --update $RUNTIME_DEPS && \ 12 | apk add --virtual build_deps $BUILD_DEPS && \ 13 | cp /usr/bin/envsubst /usr/local/bin/envsubst && \ 14 | apk del build_deps 15 | 16 | # Expected environment variables: 17 | # - S3_ACCESS_KEY 18 | # - S3_SECRET_KEY 19 | 20 | COPY s3.json.template /s3.json.template 21 | COPY entrypoint.sh /entrypoint.sh 22 | 23 | ENTRYPOINT ["/entrypoint.sh"] 24 | -------------------------------------------------------------------------------- /blob-store/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -e 4 | 5 | # Check the environment variables 6 | for var_name in S3_ACCESS_KEY S3_SECRET_KEY 7 | do 8 | if [ -z "`eval echo \\\$$var_name`" ]; then 9 | echo "Error: Environment variable '$var_name' is not set." 10 | exit 1 11 | fi 12 | done 13 | 14 | # Generate the s3.json configuration file 15 | envsubst < /s3.json.template > /s3.json 16 | 17 | if [ "$DEBUG" = "true" ]; then 18 | echo '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@' 19 | echo '@@@ Careful: Debug mode is enabled. @@@' 20 | echo '@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@' 21 | 22 | echo 'Printing s3.json:' 23 | cat /s3.json 24 | fi 25 | 26 | # Forward all arguments to the seaweedfs binary 27 | exec weed server -s3.config=/s3.json "$@" 28 | -------------------------------------------------------------------------------- /blob-store/s3.json.template: -------------------------------------------------------------------------------- 1 | { 2 | "identities": [ 3 | { 4 | "name": "anonymous", 5 | "actions": [ 6 | "Read" 7 | ] 8 | }, 9 | { 10 | "name": "julep", 11 | "credentials": [ 12 | { 13 | "accessKey": "${S3_ACCESS_KEY}", 14 | "secretKey": "${S3_SECRET_KEY}" 15 | } 16 | ], 17 | "actions": [ 18 | "Admin", 19 | "Read", 20 | "List", 21 | "Tagging", 22 | "Write" 23 | ] 24 | } 25 | ], 26 | "accounts": [ 27 | { 28 | "id" : "julep", 29 | "displayName": "Julep", 30 | "emailAddress": "developers@julep.ai" 31 | } 32 | ] 33 | } -------------------------------------------------------------------------------- /cli/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /cli/poe_tasks.toml: -------------------------------------------------------------------------------- 1 | [tasks] 2 | format = "ruff format" 3 | lint = "ruff check" 4 | typecheck = "pyright --threads 8 --skipunannotated julep_cli" 5 | check = [ 6 | "lint", 7 | "format", 8 | "typecheck", 9 | ] 10 | 11 | [tasks.test] 12 | env = { JULEP_CLI_TESTING = "true", PYTHONPATH = "{PYTHONPATH}:." } 13 | cmd = "ward test --exclude .venv" 14 | -------------------------------------------------------------------------------- /cli/src/julep_cli/__init__.py: -------------------------------------------------------------------------------- 1 | from .agents import agents_app as agents_app 2 | from .app import app 3 | from .auth import auth 4 | from .chat import chat 5 | from .executions import executions_app as executions_app 6 | from .importt import importt 7 | from .init import init 8 | from .logs import logs 9 | from .ls import ls 10 | from .run import run 11 | from .sync import sync 12 | from .tasks import tasks_app as tasks_app 13 | from .tools import tools_app as tools_app 14 | from .utils import get_config, save_config 15 | 16 | __all__ = [ 17 | "app", 18 | "auth", 19 | "chat", 20 | "executions_app", 21 | "get_config", 22 | "importt", 23 | "init", 24 | "logs", 25 | "ls", 26 | "run", 27 | "save_config", 28 | "sync", 29 | ] 30 | -------------------------------------------------------------------------------- /cli/src/julep_cli/__main__.py: -------------------------------------------------------------------------------- 1 | try: 2 | from julep_cli.app import app 3 | except ImportError: 4 | from .app import app 5 | 6 | if __name__ == "__main__": 7 | app() 8 | -------------------------------------------------------------------------------- /cli/tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/cli/tests/__init__.py -------------------------------------------------------------------------------- /cookbooks/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/cookbooks/__init__.py -------------------------------------------------------------------------------- /cookbooks/advanced/04-hook-generator-trending-reels.ipynb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/cookbooks/advanced/04-hook-generator-trending-reels.ipynb -------------------------------------------------------------------------------- /cookbooks/advanced/08-rag-chatbot.ipynb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/cookbooks/advanced/08-rag-chatbot.ipynb -------------------------------------------------------------------------------- /cookbooks/advanced/10-reel-generator.ipynb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/cookbooks/advanced/10-reel-generator.ipynb -------------------------------------------------------------------------------- /deploy/.env.example: -------------------------------------------------------------------------------- 1 | # Tag for docker images 2 | TAG=responses-latest 3 | 4 | # Responses API Key 5 | RESPONSES_API_KEY="<:a long api key>" 6 | RESPONSES_API_KEY_HEADER_NAME=Authorization 7 | MEMORY_STORE_PASSWORD="" 8 | 9 | # OpenAI & Unstructured API key (needed for embeddings and file parsing) 10 | OPENAI_API_KEY="<:OPENAI_API_KEY>" 11 | UNSTRUCTURED_API_KEY="" 12 | 13 | # Brave Search API Key (For web search tool) 14 | BRAVE_API_KEY="" 15 | 16 | ### OPTIONAL ### 17 | # Service settings 18 | RESPONSES_API_PORT="<8080>" 19 | 20 | # Provider API Keys (Enable one or more as needed) 21 | 22 | #- ANTHROPIC_API_KEY="" 23 | #- GEMINI_API_KEY="" 24 | #- OPENROUTER_API_KEY="" 25 | #- VOYAGE_API_KEY="" 26 | #- GROQ_API_KEY="" 27 | #- CEREBRAS_API_KEY="" 28 | #- CLOUDFLARE_API_KEY="" 29 | #- CLOUDFLARE_ACCOUNT_ID="" 30 | #- GITHUB_API_KEY="" 31 | #- NVIDIA_NIM_API_KEY="" 32 | #- LLAMA_API_KEY="" 33 | #- GOOGLE_APPLICATION_CREDENTIALS="" 34 | -------------------------------------------------------------------------------- /deploy/responses-build-docker-compose.yaml: -------------------------------------------------------------------------------- 1 | name: open-responses 2 | 3 | include: 4 | - ../agents-api/docker-compose-api.yml 5 | - ../memory-store/docker-compose.yml 6 | - ../integrations-service/docker-compose.yml 7 | # - ../llm-proxy/docker-compose.yml 8 | -------------------------------------------------------------------------------- /documentation/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /documentation/README.md: -------------------------------------------------------------------------------- 1 | # Julep Mintlify Documentation 2 | 3 | ## Development 4 | 5 | Install the [Mintlify CLI](https://www.npmjs.com/package/mintlify) to preview the documentation changes locally. To install, use the following command 6 | 7 | ``` 8 | npm i -g mintlify 9 | ``` 10 | 11 | Run the following command at the root of your documentation (where mint.json is) 12 | 13 | ``` 14 | mintlify dev 15 | ``` 16 | 17 | ### Troubleshooting 18 | 19 | - Mintlify dev isn't running - Run `mintlify install` it'll re-install dependencies. 20 | - Page loads as a 404 - Make sure you are running in a folder with `mint.json` 21 | -------------------------------------------------------------------------------- /documentation/assets/agentic-patterns/evaluator-optimizer-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/documentation/assets/agentic-patterns/evaluator-optimizer-workflow.png -------------------------------------------------------------------------------- /documentation/assets/agentic-patterns/orchestrator-workers-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/documentation/assets/agentic-patterns/orchestrator-workers-workflow.png -------------------------------------------------------------------------------- /documentation/assets/agentic-patterns/parallelization-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/documentation/assets/agentic-patterns/parallelization-workflow.png -------------------------------------------------------------------------------- /documentation/assets/agentic-patterns/prompt-chaining-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/documentation/assets/agentic-patterns/prompt-chaining-workflow.png -------------------------------------------------------------------------------- /documentation/assets/agentic-patterns/routing-workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/documentation/assets/agentic-patterns/routing-workflow.png -------------------------------------------------------------------------------- /documentation/guides/adding-tool-integration.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Adding a Tool Integration' 3 | description: 'Extend Julep with your own tool or API' 4 | --- 5 | 6 | # Adding a Tool Integration 7 | 8 | This guide explains how to connect a new external tool or API to Julep. You will create a small service that wraps the tool and exposes actions that agents can call. 9 | 10 | ## 1. Create an Integration Service 11 | 12 | Use the Julep SDK to define your integration service. Each action should accept structured inputs and return structured outputs. 13 | 14 | ## 2. Register the Service 15 | 16 | Deploy the service and register its OpenAPI specification with your Julep project. The new actions become available to your agents. 17 | 18 | ## 3. Invoke From a Task 19 | 20 | Call the actions from your task steps. The agent can now leverage your custom tool as part of its workflow. 21 | -------------------------------------------------------------------------------- /documentation/guides/advanced/complex-workflows.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Complex Workflows' 3 | description: 'Creating advanced task workflows' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Complex Workflows 8 | 9 | Learn how to build and manage complex task workflows. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/guides/advanced/multi-agent-systems.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Multi-Agent Systems' 3 | description: 'Building complex multi-agent systems' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Multi-Agent Systems 8 | 9 | Learn how to create and manage systems with multiple agents. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/guides/cookbooks/community-examples.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Community Examples' 3 | description: 'Examples from the Julep community' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Community Examples 8 | 9 | Showcase of examples from the Julep community. 10 | 11 | - [Hook Generator](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/04-hook-generator-trending-reels.ipynb) 12 | Generate hook lines for trending reels. 13 | - [Reel Generator](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/10-reel-generator.ipynb) 14 | Create short-form video scripts. 15 | - [Companion Agent](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/09-companion-agent.ipynb) 16 | Story-driven companion agent. 17 | - [Video Processing](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/05-video-processing-with-natural-language.ipynb) 18 | Process videos with natural language. 19 | -------------------------------------------------------------------------------- /documentation/guides/cookbooks/industry-solutions.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Industry Solutions' 3 | description: 'Industry-specific solutions using Julep' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Industry Solutions 8 | 9 | Examples of Julep implementations across different industries. 10 | 11 | - [Website Crawler](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/01-website-crawler.ipynb) 12 | Spider-based website crawler. 13 | - [Trip Planning Assistant](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/03-trip-planning-assistant.ipynb) 14 | Trip planning with weather data. 15 | - [Research Assistant](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/07-personalized-research-assistant.ipynb) 16 | Tailored research assistant. 17 | - [Video Processing](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/05-video-processing-with-natural-language.ipynb) 18 | Process videos with natural language. 19 | -------------------------------------------------------------------------------- /documentation/guides/cookbooks/quick-solutions.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Quick Solutions' 3 | description: 'Ready-to-use solutions for common use cases' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Quick Solutions 8 | 9 | Collection of ready-to-use solutions for common scenarios. 10 | 11 | - [Devfest Email Assistant](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/00-Devfest-Email-Assistant.ipynb) 12 | Event email management. 13 | - [Sarcastic Headlines](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/02-sarcastic-news-headline-generator.ipynb) 14 | Generate witty news headlines. 15 | - [Browser Use](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/06-browser-use.ipynb) 16 | Automate web browsing tasks. 17 | - [RAG Chatbot](https://github.com/julep-ai/julep/blob/dev/cookbooks/advanced/08-rag-chatbot.ipynb) 18 | RAG chatbot demonstration. 19 | -------------------------------------------------------------------------------- /documentation/guides/getting-started/tool-integration-demo.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Tool Integration Demo' 3 | description: 'Learn how to integrate tools with your Julep agent' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Tool Integration Demo 8 | 9 | Step-by-step demonstration of tool integration. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/guides/modifying-agent-workflow.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Modifying Agent Workflow' 3 | description: 'Customize how your agents process tasks' 4 | --- 5 | 6 | # Modifying Agent Workflow 7 | 8 | Julep tasks are flexible workflows that control how an agent operates. This guide shows how to adjust the default behavior. 9 | 10 | ## 1. Edit the Task YAML 11 | 12 | Add, remove, or reorder steps in your task definition. You can insert tool calls, conditional logic, or loops to suit your needs. 13 | 14 | ## 2. Update Agent Configuration 15 | 16 | Point your agent to the new task file or update its task list via the SDK. Your changes apply immediately to new sessions. 17 | 18 | ## 3. Test Iteratively 19 | 20 | Run the task locally or through the API to verify each modification. Adjust prompts and steps until the workflow produces the desired output. 21 | -------------------------------------------------------------------------------- /documentation/guides/use-cases/customer-service.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Customer Service' 3 | description: 'Building a customer service agent with Julep' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Customer Service Example 8 | 9 | Learn how to build an effective customer service agent. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/guides/use-cases/data-analysis.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Data Analysis' 3 | description: 'Performing data analysis with Julep' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Data Analysis Example 8 | 9 | Learn how to analyze data using Julep agents. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/guides/use-cases/document-processing.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Document Processing' 3 | description: 'Document processing with Julep' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Document Processing Example 8 | 9 | Learn how to process and analyze documents with Julep. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/guides/use-cases/research-assistant.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Research Assistant' 3 | description: 'Creating a research assistant with Julep' 4 | groups: ['admin'] 5 | --- 6 | 7 | # Research Assistant Example 8 | 9 | Build an AI-powered research assistant. 10 | 11 | [Placeholder content] -------------------------------------------------------------------------------- /documentation/images/open-responses.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/documentation/images/open-responses.jpg -------------------------------------------------------------------------------- /documentation/tutorials/trip-planning-input.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Trip Planning - Input' 3 | description: 'Define the input schema for the trip planning task' 4 | icon: 'display' 5 | --- 6 | 7 | ### 1. Input Schema 8 | 9 | First, we define what inputs our task expects: 10 | 11 | ```yaml 12 | input_schema: 13 | type: object 14 | properties: 15 | locations: 16 | type: array 17 | items: 18 | type: string 19 | ``` 20 | 21 | This schema specifies that our task expects an array of location strings (e.g., `["New York", "London", "Paris"]`). 22 | 23 | ## Next Step 24 | 25 | - [Tools Configuration](./trip-planning-tools) 26 | 27 | ## Related Concepts 28 | 29 | - [Agents](/concepts/agents) 30 | - [Tasks](/concepts/tasks) 31 | - [Tools](/concepts/tools) 32 | 33 | -------------------------------------------------------------------------------- /documentation/tutorials/trip-planning-tools.mdx: -------------------------------------------------------------------------------- 1 | --- 2 | title: 'Trip Planning - Tools' 3 | description: 'Configure tools for fetching weather and attraction data' 4 | icon: 'display' 5 | --- 6 | 7 | ### 2. Tools Configuration 8 | 9 | Next, we define the external tools our task will use: 10 | 11 | ```yaml 12 | - name: weather 13 | type: integration 14 | integration: 15 | provider: weather 16 | setup: 17 | openweathermap_api_key: YOUR_OPENWEATHERMAP_API_KEY 18 | 19 | - name: internet_search 20 | type: integration 21 | integration: 22 | provider: brave 23 | setup: 24 | api_key: YOUR_BRAVE_API_KEY 25 | ``` 26 | 27 | We're using two integrations: 28 | - The `weather` integration to fetch current weather conditions 29 | - The `brave` search integration to find tourist attractions 30 | 31 | ## Next Step 32 | 33 | - [Workflow Steps](./trip-planning-workflow) 34 | 35 | ## Related Concepts 36 | 37 | - [Agents](/concepts/agents) 38 | - [Tasks](/concepts/tasks) 39 | - [Tools](/concepts/tools) 40 | 41 | -------------------------------------------------------------------------------- /gateway/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /gateway/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # check=error=true 3 | 4 | FROM alpine/git 5 | ARG PLUGIN_MODULE=github.com/julep-ai/traefik-jwt-plugin 6 | ARG PLUGIN_GIT_REPO=https://github.com/julep-ai/traefik-jwt-plugin.git 7 | ARG PLUGIN_GIT_BRANCH=main 8 | RUN git clone ${PLUGIN_GIT_REPO} /plugins-local/src/${PLUGIN_MODULE} \ 9 | --depth 1 --single-branch --branch ${PLUGIN_GIT_BRANCH} 10 | 11 | ################# 12 | 13 | # TODO: Upgrade to Traefik v3 14 | FROM traefik:v2.11 15 | 16 | ENV GATEWAY_PORT=80 17 | ENV AGENTS_API_URL="" 18 | 19 | # Expected environment variables: 20 | # JWT_SHARED_KEY="" 21 | # AGENTS_API_KEY="" 22 | # AGENTS_API_KEY_HEADER_NAME="Authorization" 23 | 24 | COPY --from=0 /plugins-local /plugins-local 25 | 26 | RUN apk add gettext 27 | RUN mkdir -p /etc/traefik 28 | COPY traefik.yml.template /etc/traefik/ 29 | COPY entrypoint.sh /entrypoint.sh 30 | 31 | ENTRYPOINT ["/entrypoint.sh"] 32 | -------------------------------------------------------------------------------- /gateway/entrypoint.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Check the environment variables 4 | AGENTS_API_URL=${AGENTS_API_URL:-http://agents-api:8080} 5 | AGENTS_API_KEY_HEADER_NAME=${AGENTS_API_KEY_HEADER_NAME:-Authorization} 6 | GATEWAY_PORT=${GATEWAY_PORT:-80} 7 | TEMPORAL_UI_PUBLIC_URL=${TEMPORAL_UI_PUBLIC_URL:-http://temporal-ui-public:8080} 8 | HASURA_URL=${HASURA_URL:-http://hasura:8080} 9 | 10 | for var_name in JWT_SHARED_KEY AGENTS_API_KEY 11 | do 12 | if [ -z "`eval echo \\\$$var_name`" ]; then 13 | echo "Error: Environment variable '$var_name' is not set." 14 | exit 1 15 | fi 16 | done 17 | 18 | # Generate the Traefik configuration file 19 | envsubst < /etc/traefik/traefik.yml.template > /etc/traefik/traefik.yml 20 | 21 | # Forward all arguments to the traefik binary 22 | exec traefik "$@" 23 | -------------------------------------------------------------------------------- /gateway/letsencrypt/.gitignore: -------------------------------------------------------------------------------- 1 | *.json 2 | -------------------------------------------------------------------------------- /gateway/letsencrypt/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/gateway/letsencrypt/.gitkeep -------------------------------------------------------------------------------- /hasura/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3.8' 2 | 3 | services: 4 | hasura: 5 | image: hasura/graphql-engine:v2.33.0 6 | profiles: 7 | - multi-tenant 8 | ports: 9 | - "8086:8080" 10 | environment: 11 | HASURA_GRAPHQL_DATABASE_URL: ${PG_DSN:-postgres://postgres:postgres@memory-store:5432/postgres?sslmode=disable} 12 | HASURA_GRAPHQL_SERVER_PORT: 8080 13 | HASURA_GRAPHQL_ENABLE_CONSOLE: "true" 14 | HASURA_GRAPHQL_DEV_MODE: "true" 15 | HASURA_GRAPHQL_ENABLED_LOG_TYPES: startup, http-log, webhook-log, websocket-log, query-log 16 | HASURA_GRAPHQL_ADMIN_SECRET: ${HASURA_ADMIN_SECRET:-hasura} 17 | HASURA_GRAPHQL_UNAUTHORIZED_ROLE: "anonymous" 18 | HASURA_GRAPHQL_JWT_SECRET: ${HASURA_JWT_SECRET:-{"type":"HS512", "key":"${JWT_SHARED_KEY:-secret}", "claims_map":${HASURA_CLAIMS_MAP}}} 19 | HASURA_GRAPHQL_CORS_DOMAIN: "*" 20 | restart: unless-stopped 21 | depends_on: 22 | - memory-store 23 | healthcheck: 24 | test: ["CMD", "wget", "-qO-", "http://localhost:8080/healthz"] 25 | interval: 30s 26 | timeout: 5s 27 | retries: 3 28 | start_period: 10s -------------------------------------------------------------------------------- /integrations-service/.dockerignore: -------------------------------------------------------------------------------- 1 | Dockerfile 2 | *.pyc 3 | *.pyo 4 | *.pyd 5 | __pycache__ 6 | .pytest_cache 7 | .venv 8 | -------------------------------------------------------------------------------- /integrations-service/.python-version: -------------------------------------------------------------------------------- 1 | 3.12 2 | -------------------------------------------------------------------------------- /integrations-service/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /integrations-service/Dockerfile: -------------------------------------------------------------------------------- 1 | # syntax=docker/dockerfile:1 2 | # check=error=true 3 | 4 | FROM python:3.12-slim 5 | 6 | WORKDIR /app 7 | 8 | # Install system dependencies and FFmpeg with all required libraries 9 | RUN apt-get update && apt-get install -y \ 10 | ffmpeg \ 11 | libavcodec-extra \ 12 | libavformat-dev \ 13 | libavutil-dev \ 14 | libswscale-dev \ 15 | && apt-get clean \ 16 | && rm -rf /var/lib/apt/lists/* 17 | 18 | COPY --from=ghcr.io/astral-sh/uv:0.5.5 /uv /uvx /bin/ 19 | 20 | COPY .python-version pyproject.toml uv.lock ./ 21 | 22 | RUN \ 23 | uv sync --frozen --all-extras --no-group dev --color never --python-preference system 24 | 25 | COPY . ./ 26 | 27 | # Set proper signal handling 28 | ENV PYTHONUNBUFFERED=1 29 | ENV GUNICORN_CMD_ARGS="--capture-output --enable-stdio-inheritance" 30 | 31 | # Run the application with proper signal handling 32 | ENTRYPOINT ["uv", "run", "gunicorn", "integrations.web:app", "-c", "gunicorn_conf.py"] 33 | -------------------------------------------------------------------------------- /integrations-service/README.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/README.md -------------------------------------------------------------------------------- /integrations-service/integrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/integrations/__init__.py -------------------------------------------------------------------------------- /integrations-service/integrations/__main__.py: -------------------------------------------------------------------------------- 1 | from .web import main 2 | 3 | if __name__ == "__main__": 4 | main() 5 | -------------------------------------------------------------------------------- /integrations-service/integrations/autogen/__init__.py: -------------------------------------------------------------------------------- 1 | # generated by datamodel-codegen: 2 | # filename: openapi-1.0.0.yaml 3 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/algolia.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from pydantic import ConfigDict, Field 4 | 5 | from .base_models import BaseOutput 6 | 7 | 8 | class AlgoliaSearchOutput(BaseOutput): 9 | """Output model for Algolia search""" 10 | 11 | model_config = ConfigDict(extra="allow") 12 | 13 | hits: list[Any] | None = Field(description="The search results") 14 | metadata: dict[str, Any] | None = Field(description="Additional metadata from the search") 15 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/arxiv.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class ArxivSearchResult(BaseModel): 7 | entry_id: str | None = None 8 | title: str | None = None 9 | updated: str | None = None 10 | published: str | None = None 11 | authors: list[str] | None = None 12 | summary: str | None = None 13 | comment: str | None = None 14 | journal_ref: str | None = None 15 | doi: str | None = None 16 | primary_category: str | None = None 17 | categories: list[str] | None = None 18 | links: list[str] | None = None 19 | pdf_url: str | None = None 20 | pdf_downloaded: dict | None = None 21 | 22 | 23 | class ArxivSearchOutput(BaseOutput): 24 | result: list[ArxivSearchResult] = Field(..., description="A list of search results") 25 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/base_models.py: -------------------------------------------------------------------------------- 1 | from typing import Annotated 2 | 3 | from pydantic import BaseModel, Field 4 | from pydantic_core import Url 5 | 6 | IdentifierName = Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")] 7 | 8 | 9 | class BaseOutput(BaseModel): ... 10 | 11 | 12 | class ProviderInfo(BaseModel): 13 | url: Url | None = None 14 | docs: Url | None = None 15 | icon: Url | None = None 16 | friendly_name: str 17 | 18 | 19 | class BaseProviderMethod(BaseModel): 20 | method: IdentifierName 21 | description: str 22 | arguments: type[BaseModel] 23 | output: type[BaseOutput] 24 | 25 | 26 | class BaseProvider(BaseModel): 27 | provider: IdentifierName 28 | setup: type[BaseModel] | None 29 | methods: list[BaseProviderMethod] 30 | info: ProviderInfo 31 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/brave.py: -------------------------------------------------------------------------------- 1 | from pydantic import BaseModel, Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class SearchResult(BaseModel): 7 | title: str 8 | link: str 9 | snippet: str 10 | 11 | 12 | class BraveSearchOutput(BaseOutput): 13 | result: list[SearchResult] = Field(..., description="A list of search results") 14 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/cloudinary.py: -------------------------------------------------------------------------------- 1 | from pydantic import Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class CloudinaryUploadOutput(BaseOutput): 7 | url: str = Field(..., description="The URL of the uploaded file") 8 | public_id: str = Field(..., description="The public ID of the uploaded file") 9 | base64: str | None = Field( 10 | None, 11 | description="The base64 encoded file if return_base64 is true", 12 | ) 13 | meta_data: dict | None = Field( 14 | None, 15 | description="Additional metadata from the upload response", 16 | ) 17 | 18 | 19 | class CloudinaryEditOutput(BaseOutput): 20 | transformed_url: str = Field(..., description="The transformed URL") 21 | base64: str | None = Field( 22 | None, 23 | description="The base64 encoded file if return_base64 is true", 24 | ) 25 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/email.py: -------------------------------------------------------------------------------- 1 | from pydantic import Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class EmailOutput(BaseOutput): 7 | success: bool = Field(..., description="Whether the email was sent successfully") 8 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/ffmpeg.py: -------------------------------------------------------------------------------- 1 | from pydantic import Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class FfmpegSearchOutput(BaseOutput): 7 | fileoutput: str | None = Field(None, description="The output file from the Ffmpeg command") 8 | result: bool = Field(..., description="Whether the Ffmpeg command was successful") 9 | mime_type: str | None = Field(None, description="The MIME type of the output file") 10 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/llama_parse.py: -------------------------------------------------------------------------------- 1 | from llama_index.core.schema import Document 2 | from pydantic import Field 3 | 4 | from .base_models import BaseOutput 5 | 6 | 7 | class LlamaParseFetchOutput(BaseOutput): 8 | documents: list[Document] = Field(..., description="The documents returned from the spider") 9 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/mailgun.py: -------------------------------------------------------------------------------- 1 | from pydantic import Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class MailgunSendEmailOutput(BaseOutput): 7 | success: bool = Field(..., description="Whether the email was sent successfully") 8 | error: str | None = Field( 9 | None, description="The error message if the email was not sent successfully" 10 | ) 11 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/remote_browser.py: -------------------------------------------------------------------------------- 1 | from pydantic import Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class RemoteBrowserOutput(BaseOutput): 7 | output: str | None = Field(None, description="The output of the action") 8 | error: str | None = Field(None, description="The error of the action") 9 | base64_image: str | None = Field(None, description="The base64 encoded image of the action") 10 | system: str | None = Field(None, description="The system output of the action") 11 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/spider.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from pydantic import BaseModel, Field 4 | 5 | from .base_models import BaseOutput 6 | 7 | 8 | class SpiderResponse(BaseModel): 9 | content: str | list[str] | None = None 10 | error: str | None = None 11 | status: int | None = None 12 | costs: dict[Any, Any] | None = None 13 | url: str | None = None 14 | 15 | 16 | class SpiderOutput(BaseOutput): 17 | result: list[SpiderResponse] = Field(..., description="The responses from the spider") 18 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/unstructured.py: -------------------------------------------------------------------------------- 1 | from typing import Any 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class UnstructuredParseOutput(BaseOutput): 7 | content_type: str 8 | status_code: int 9 | csv_elements: str | None = None 10 | content: list[dict[str, Any]] | None = None 11 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/weather.py: -------------------------------------------------------------------------------- 1 | from pydantic import Field 2 | 3 | from .base_models import BaseOutput 4 | 5 | 6 | class WeatherGetOutput(BaseOutput): 7 | result: str = Field(..., description="The weather data for the specified location") 8 | -------------------------------------------------------------------------------- /integrations-service/integrations/models/wikipedia.py: -------------------------------------------------------------------------------- 1 | from langchain_core.documents import Document 2 | from pydantic import Field 3 | 4 | from .base_models import BaseOutput 5 | 6 | 7 | class WikipediaSearchOutput(BaseOutput): 8 | documents: list[Document] = Field( 9 | ..., 10 | description="The documents returned from the Wikipedia search", 11 | ) 12 | -------------------------------------------------------------------------------- /integrations-service/integrations/routers/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/integrations/routers/__init__.py -------------------------------------------------------------------------------- /integrations-service/integrations/routers/execution/__init__.py: -------------------------------------------------------------------------------- 1 | from .execute import execute as execute 2 | -------------------------------------------------------------------------------- /integrations-service/integrations/routers/execution/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /integrations-service/integrations/routers/integrations/__init__.py: -------------------------------------------------------------------------------- 1 | from .get_integration import get_integration as get_integration 2 | from .get_integration_tool import get_integration_tool as get_integration_tool 3 | from .get_integrations import get_integrations as get_integrations 4 | -------------------------------------------------------------------------------- /integrations-service/integrations/routers/integrations/get_integration.py: -------------------------------------------------------------------------------- 1 | from fastapi import HTTPException 2 | 3 | from ... import providers as available_providers 4 | from ...models.base_models import BaseProvider 5 | from .router import router 6 | 7 | 8 | @router.get("/integrations/{provider}", tags=["integration"]) 9 | async def get_integration(provider: str) -> dict: 10 | integration: BaseProvider | None = getattr(available_providers, provider, None) 11 | 12 | if integration is None: 13 | raise HTTPException(status_code=404, detail="Integration not found") 14 | 15 | return { 16 | "provider": integration.provider, 17 | "setup": integration.setup.model_json_schema() if integration.setup else None, 18 | "methods": [ 19 | { 20 | "method": m.method, 21 | "description": m.description, 22 | "arguments": m.arguments.model_json_schema(), 23 | "output": m.output.model_json_schema(), 24 | } 25 | for m in integration.methods 26 | ], 27 | "info": integration.info.model_dump_json(), 28 | } 29 | -------------------------------------------------------------------------------- /integrations-service/integrations/routers/integrations/get_integrations.py: -------------------------------------------------------------------------------- 1 | from ...providers import available_providers 2 | from .router import router 3 | 4 | 5 | @router.get("/integrations", tags=["integrations"]) 6 | async def get_integrations() -> list[dict]: 7 | return [ 8 | { 9 | "provider": p.provider, 10 | "setup": p.setup.model_json_schema() if p.setup else None, 11 | "methods": [ 12 | { 13 | "method": m.method, 14 | "description": m.description, 15 | "arguments": m.arguments.model_json_schema(), 16 | "output": m.output.model_json_schema(), 17 | } 18 | for m in p.methods 19 | ], 20 | "info": { 21 | "url": p.info.url, 22 | "docs": p.info.docs, 23 | "icon": p.info.icon, 24 | "friendly_name": p.info.friendly_name, 25 | }, 26 | } 27 | for p in available_providers.values() 28 | ] 29 | -------------------------------------------------------------------------------- /integrations-service/integrations/routers/integrations/router.py: -------------------------------------------------------------------------------- 1 | from fastapi import APIRouter 2 | 3 | router: APIRouter = APIRouter() 4 | -------------------------------------------------------------------------------- /integrations-service/integrations/utils/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/integrations/utils/__init__.py -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/integrations/utils/integrations/__init__.py -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/assets/cursor-small.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/integrations/utils/integrations/assets/cursor-small.png -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/assets/cursor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/integrations-service/integrations/utils/integrations/assets/cursor.png -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/brave.py: -------------------------------------------------------------------------------- 1 | import json 2 | 3 | from beartype import beartype 4 | from langchain_community.tools import BraveSearch 5 | from tenacity import retry, stop_after_attempt, wait_exponential 6 | 7 | from ...autogen.Tools import BraveSearchArguments, BraveSearchSetup 8 | from ...models import BraveSearchOutput, SearchResult 9 | 10 | 11 | @beartype 12 | @retry( 13 | wait=wait_exponential(multiplier=1, min=4, max=10), 14 | reraise=True, 15 | stop=stop_after_attempt(4), 16 | ) 17 | async def search(setup: BraveSearchSetup, arguments: BraveSearchArguments) -> BraveSearchOutput: 18 | """ 19 | Searches Brave Search with the provided query. 20 | """ 21 | 22 | tool = BraveSearch.from_api_key(api_key=setup.brave_api_key, search_kwargs={"count": 3}) 23 | 24 | result = tool.run(arguments.query) 25 | 26 | try: 27 | parsed_result = [SearchResult(**item) for item in json.loads(result)] 28 | except json.JSONDecodeError as e: 29 | msg = "Malformed JSON response from Brave Search" 30 | raise ValueError(msg) from e 31 | 32 | return BraveSearchOutput(result=parsed_result) 33 | -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/email.py: -------------------------------------------------------------------------------- 1 | from email.message import EmailMessage 2 | from smtplib import SMTP 3 | 4 | from beartype import beartype 5 | from tenacity import retry, stop_after_attempt, wait_exponential 6 | 7 | from ...autogen.Tools import EmailArguments, EmailSetup 8 | from ...models import EmailOutput 9 | 10 | 11 | @beartype 12 | @retry( 13 | wait=wait_exponential(multiplier=1, min=4, max=10), 14 | reraise=True, 15 | stop=stop_after_attempt(4), 16 | ) 17 | async def send(setup: EmailSetup, arguments: EmailArguments) -> EmailOutput: 18 | """ 19 | Sends an email with the provided details. 20 | """ 21 | 22 | message = EmailMessage() 23 | message.set_content(arguments.body) 24 | message["Subject"] = arguments.subject 25 | message["From"] = arguments.from_ 26 | message["To"] = arguments.to 27 | 28 | with SMTP(setup.host, setup.port) as server: 29 | server.login(setup.user, setup.password) 30 | server.send_message(message) 31 | 32 | return EmailOutput(success=True) 33 | -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/weather.py: -------------------------------------------------------------------------------- 1 | from beartype import beartype 2 | from langchain_community.utilities import OpenWeatherMapAPIWrapper 3 | from tenacity import retry, stop_after_attempt, wait_exponential 4 | 5 | from ...autogen.Tools import WeatherGetArguments, WeatherSetup 6 | from ...models import WeatherGetOutput 7 | 8 | 9 | @beartype 10 | @retry( 11 | wait=wait_exponential(multiplier=1, min=4, max=10), 12 | reraise=True, 13 | stop=stop_after_attempt(4), 14 | ) 15 | async def get(setup: WeatherSetup, arguments: WeatherGetArguments) -> WeatherGetOutput: 16 | """ 17 | Fetches weather data for a specified location using OpenWeatherMap API. 18 | """ 19 | 20 | location = arguments.location 21 | 22 | weather = OpenWeatherMapAPIWrapper(openweathermap_api_key=setup.openweathermap_api_key) 23 | result = weather.run(location) 24 | return WeatherGetOutput(result=result) 25 | -------------------------------------------------------------------------------- /integrations-service/integrations/utils/integrations/wikipedia.py: -------------------------------------------------------------------------------- 1 | from beartype import beartype 2 | from langchain_community.document_loaders import WikipediaLoader 3 | from tenacity import retry, stop_after_attempt, wait_exponential 4 | 5 | from ...autogen.Tools import WikipediaSearchArguments 6 | from ...models import WikipediaSearchOutput 7 | 8 | 9 | @beartype 10 | @retry( 11 | wait=wait_exponential(multiplier=1, min=4, max=10), 12 | reraise=True, 13 | stop=stop_after_attempt(4), 14 | ) 15 | async def search( 16 | arguments: WikipediaSearchArguments, 17 | ) -> WikipediaSearchOutput: 18 | """ 19 | Searches Wikipedia for a given query and returns formatted results. 20 | """ 21 | 22 | query = arguments.query 23 | load_max_docs = arguments.load_max_docs 24 | 25 | loader = WikipediaLoader(query=query, load_max_docs=load_max_docs) 26 | documents = loader.load() 27 | 28 | return WikipediaSearchOutput(documents=documents) 29 | -------------------------------------------------------------------------------- /integrations-service/pytest.ini: -------------------------------------------------------------------------------- 1 | [pytest] 2 | pythonpath = . 3 | testpaths = tests 4 | python_files = test_*.py 5 | python_classes = Test* 6 | python_functions = test_* -------------------------------------------------------------------------------- /integrations-service/tests/__init__.py: -------------------------------------------------------------------------------- 1 | # Empty file to make the tests directory a Python package 2 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/__init__.py: -------------------------------------------------------------------------------- 1 | """Mock implementations of external integration libraries""" 2 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/brave.py: -------------------------------------------------------------------------------- 1 | """Mock implementation of Brave Search API client""" 2 | 3 | 4 | class MockBraveSearchClient: 5 | def __init__(self, api_key: str): 6 | self.api_key = api_key 7 | 8 | def search(self, query: str) -> str: 9 | """Mock search that returns a fixed response""" 10 | return f"Mock Brave search results for: {query}" 11 | 12 | 13 | class MockBraveSearchException(Exception): 14 | """Mock exception for Brave Search errors""" 15 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/email.py: -------------------------------------------------------------------------------- 1 | """Mock implementation of email client""" 2 | 3 | 4 | class MockEmailClient: 5 | def __init__(self, host: str, port: int, user: str, password: str): 6 | self.host = host 7 | self.port = port 8 | self.user = user 9 | self.password = password 10 | 11 | def send(self, to: str, from_: str, subject: str, body: str) -> bool: 12 | """Mock email sending that always succeeds""" 13 | return True 14 | 15 | 16 | class MockEmailException(Exception): 17 | """Mock exception for email errors""" 18 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/llama_parse.py: -------------------------------------------------------------------------------- 1 | """Mock implementation of llama parse client""" 2 | 3 | from llama_index.core.schema import Document 4 | 5 | 6 | class MockLlamaParseClient: 7 | def __init__(self, api_key: str, result_type: str, num_workers: int, language: str): 8 | self.api_key = api_key 9 | self.result_type = result_type 10 | self.num_workers = num_workers 11 | self.language = language 12 | 13 | async def aload_data(self, file_content: bytes, extra_info: dict) -> list[dict]: 14 | """Mock loading data that returns fixed documents""" 15 | return [ 16 | Document(page_content="Mock document content 1", metadata=extra_info), 17 | Document(page_content="Mock document content 2", metadata=extra_info), 18 | ] 19 | 20 | 21 | class MockLlamaParseException(Exception): 22 | """Mock exception for llama parse errors""" 23 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/spider.py: -------------------------------------------------------------------------------- 1 | """Mock implementation of web spider client""" 2 | 3 | from langchain_core.documents import Document 4 | from pydantic import AnyUrl 5 | 6 | 7 | class MockSpiderClient: 8 | def __init__(self, api_key: str): 9 | self.api_key = api_key 10 | 11 | def crawl(self, url: AnyUrl, mode: str = "scrape") -> list[Document]: 12 | """Mock crawl that returns fixed documents""" 13 | return [ 14 | Document(page_content="Mock crawled content 1", metadata={"source": str(url)}), 15 | Document(page_content="Mock crawled content 2", metadata={"source": str(url)}), 16 | ] 17 | 18 | 19 | class MockSpiderException(Exception): 20 | """Mock exception for spider errors""" 21 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/weather.py: -------------------------------------------------------------------------------- 1 | """Mock implementation of weather API client""" 2 | 3 | 4 | class MockWeatherClient: 5 | def __init__(self, api_key: str): 6 | self.api_key = api_key 7 | 8 | def get_weather(self, location: str) -> str: 9 | """Mock weather lookup that returns fixed data""" 10 | return f"Mock weather data for {location}: Sunny, 72°F" 11 | 12 | 13 | class MockWeatherException(Exception): 14 | """Mock exception for weather API errors""" 15 | -------------------------------------------------------------------------------- /integrations-service/tests/mocks/wikipedia.py: -------------------------------------------------------------------------------- 1 | """Mock implementation of Wikipedia API client""" 2 | 3 | from langchain_core.documents import Document 4 | 5 | 6 | class MockWikipediaClient: 7 | def __init__(self, query: str, load_max_docs: int = 2): 8 | """Mock Wikipedia search that returns fixed documents""" 9 | self.result = [ 10 | Document( 11 | page_content=f"Mock Wikipedia content about {query}", 12 | metadata={"source": f"wikipedia/{query}"}, 13 | ) 14 | for _ in range(load_max_docs) 15 | ] 16 | 17 | def load(self, *args, **kwargs) -> list[Document]: 18 | return self.result 19 | 20 | 21 | class MockWikipediaException(Exception): 22 | """Mock exception for Wikipedia API errors""" 23 | -------------------------------------------------------------------------------- /llm-proxy/.dockerignore: -------------------------------------------------------------------------------- 1 | !.keys 2 | -------------------------------------------------------------------------------- /llm-proxy/.gitignore: -------------------------------------------------------------------------------- 1 | .keys 2 | -------------------------------------------------------------------------------- /llm-proxy/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /memory-store/.gitignore: -------------------------------------------------------------------------------- 1 | tmp/ 2 | 3 | *.pyc -------------------------------------------------------------------------------- /memory-store/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /memory-store/Dockerfile.migrations: -------------------------------------------------------------------------------- 1 | FROM migrate/migrate:latest 2 | 3 | # Copy migrations from local directory 4 | COPY migrations/ /migrations/ 5 | 6 | # Set the working directory 7 | WORKDIR / 8 | 9 | # Default command (can be overridden) 10 | ENTRYPOINT ["migrate"] 11 | CMD ["-path", "/migrations", "-database", "postgres://postgres:obviously_not_a_safe_password@memory-store:5432/postgres?sslmode=disable", "up"] 12 | -------------------------------------------------------------------------------- /memory-store/README.md: -------------------------------------------------------------------------------- 1 | ### prototyping flow: 2 | 3 | 1. Install `migrate` (golang-migrate) 4 | 2. In a separate window, `docker compose up db vectorizer-worker` to start db instances 5 | 3. `cd memory-store` and `migrate -database "postgres://postgres:postgres@0.0.0.0:5432/postgres?sslmode=disable" -path ./migrations up` to apply the migrations 6 | 4. `pip install --user -U pgcli` 7 | 5. `pgcli "postgres://postgres:postgres@localhost:5432/postgres"` 8 | 9 | For creating a migration: 10 | `migrate -database "postgres://postgres:postgres@0.0.0.0:5432/postgres?sslmode=disable" -path migrations create -ext sql -seq -dir migrations switch_to_hypercore` 11 | -------------------------------------------------------------------------------- /memory-store/migrations/000001_initial.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the update_updated_at_column function 4 | DROP FUNCTION IF EXISTS update_updated_at_column (); 5 | 6 | -- Drop misc extensions 7 | DROP EXTENSION IF EXISTS "uuid-ossp" CASCADE; 8 | 9 | DROP EXTENSION IF EXISTS citext CASCADE; 10 | 11 | DROP EXTENSION IF EXISTS btree_gist CASCADE; 12 | 13 | DROP EXTENSION IF EXISTS btree_gin CASCADE; 14 | 15 | -- Drop timescale's pgai extensions 16 | DROP EXTENSION IF EXISTS ai CASCADE; 17 | 18 | DROP EXTENSION IF EXISTS vectorscale CASCADE; 19 | 20 | DROP EXTENSION IF EXISTS vector CASCADE; 21 | 22 | -- Drop timescaledb extensions 23 | DROP EXTENSION IF EXISTS timescaledb_toolkit CASCADE; 24 | 25 | DROP EXTENSION IF EXISTS timescaledb CASCADE; 26 | 27 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000001_initial.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- init timescaledb 4 | CREATE EXTENSION IF NOT EXISTS timescaledb CASCADE; 5 | 6 | CREATE EXTENSION IF NOT EXISTS timescaledb_toolkit CASCADE; 7 | 8 | -- add timescale's pgai extension 9 | CREATE EXTENSION IF NOT EXISTS vector CASCADE; 10 | 11 | CREATE EXTENSION IF NOT EXISTS vectorscale CASCADE; 12 | 13 | CREATE EXTENSION IF NOT EXISTS ai CASCADE; 14 | 15 | -- add misc extensions (for indexing etc) 16 | CREATE EXTENSION IF NOT EXISTS btree_gin CASCADE; 17 | 18 | CREATE EXTENSION IF NOT EXISTS btree_gist CASCADE; 19 | 20 | CREATE EXTENSION IF NOT EXISTS citext CASCADE; 21 | 22 | CREATE EXTENSION IF NOT EXISTS "uuid-ossp" CASCADE; 23 | 24 | -- Create function to update the updated_at timestamp 25 | CREATE 26 | OR REPLACE FUNCTION update_updated_at_column () RETURNS TRIGGER AS $$ 27 | BEGIN 28 | NEW.updated_at = CURRENT_TIMESTAMP; 29 | RETURN NEW; 30 | END; 31 | $$ language 'plpgsql'; 32 | 33 | COMMENT ON FUNCTION update_updated_at_column () IS 'Trigger function to automatically update updated_at timestamp'; 34 | 35 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000002_developers.down.sql: -------------------------------------------------------------------------------- 1 | -- Drop the table (this will automatically drop associated indexes and triggers) 2 | DROP TABLE IF EXISTS developers CASCADE; 3 | 4 | -- Note: The update_updated_at_column() function is not dropped as it might be used by other tables 5 | -------------------------------------------------------------------------------- /memory-store/migrations/000003_users.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop trigger first 4 | DROP TRIGGER IF EXISTS update_users_updated_at ON users; 5 | 6 | -- Drop indexes 7 | DROP INDEX IF EXISTS users_metadata_gin_idx; 8 | 9 | -- Drop foreign key constraint 10 | ALTER TABLE IF EXISTS users 11 | DROP CONSTRAINT IF EXISTS users_developer_id_fkey; 12 | 13 | -- Finally drop the table 14 | DROP TABLE IF EXISTS users; 15 | 16 | COMMIT; 17 | -------------------------------------------------------------------------------- /memory-store/migrations/000004_agents.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop trigger first 4 | DROP TRIGGER IF EXISTS trg_agents_updated_at ON agents; 5 | 6 | -- Drop indexes 7 | DROP INDEX IF EXISTS idx_agents_metadata; 8 | 9 | -- Drop table (this will automatically drop associated constraints) 10 | DROP TABLE IF EXISTS agents CASCADE; 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /memory-store/migrations/000005_files.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop file_owners table and its dependencies 4 | DROP TRIGGER IF EXISTS trg_validate_file_owner ON file_owners; 5 | DROP FUNCTION IF EXISTS validate_file_owner(); 6 | DROP TABLE IF EXISTS file_owners; 7 | 8 | -- Drop files table and its dependencies 9 | DROP TRIGGER IF EXISTS trg_files_updated_at ON files; 10 | DROP TABLE IF EXISTS files; 11 | 12 | COMMIT; 13 | -------------------------------------------------------------------------------- /memory-store/migrations/000006_docs.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop doc_owners table and its dependencies 4 | DROP TRIGGER IF EXISTS trg_validate_doc_owner ON doc_owners; 5 | DROP FUNCTION IF EXISTS validate_doc_owner(); 6 | DROP INDEX IF EXISTS idx_doc_owners_owner; 7 | DROP TABLE IF EXISTS doc_owners CASCADE; 8 | 9 | -- Drop docs table and its dependencies 10 | DROP TRIGGER IF EXISTS trg_docs_search_tsv ON docs; 11 | DROP TRIGGER IF EXISTS trg_docs_updated_at ON docs; 12 | DROP FUNCTION IF EXISTS docs_update_search_tsv(); 13 | 14 | -- Drop indexes 15 | DROP INDEX IF EXISTS idx_docs_content_trgm; 16 | DROP INDEX IF EXISTS idx_docs_title_trgm; 17 | DROP INDEX IF EXISTS idx_docs_search_tsv; 18 | DROP INDEX IF EXISTS idx_docs_metadata; 19 | 20 | -- Drop docs table 21 | DROP TABLE IF EXISTS docs CASCADE; 22 | 23 | -- Drop language validation function 24 | DROP FUNCTION IF EXISTS is_valid_language(text); 25 | 26 | COMMIT; 27 | -------------------------------------------------------------------------------- /memory-store/migrations/000007_ann.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DO $$ 4 | DECLARE 5 | vectorizer_id INTEGER; 6 | BEGIN 7 | SELECT id INTO vectorizer_id 8 | FROM ai.vectorizer 9 | WHERE source_table = 'docs'; 10 | 11 | -- Drop the vectorizer if it exists 12 | IF vectorizer_id IS NOT NULL THEN 13 | PERFORM ai.drop_vectorizer(vectorizer_id, drop_all => true); 14 | END IF; 15 | END $$; 16 | 17 | COMMIT; 18 | -------------------------------------------------------------------------------- /memory-store/migrations/000008_tools.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop table and all its dependent objects (indexes, constraints, triggers) 4 | DROP TABLE IF EXISTS tools CASCADE; 5 | 6 | COMMIT; 7 | -------------------------------------------------------------------------------- /memory-store/migrations/000009_sessions.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop triggers first 4 | DROP TRIGGER IF EXISTS trg_validate_participant_before_update ON session_lookup; 5 | 6 | DROP TRIGGER IF EXISTS trg_validate_participant_before_insert ON session_lookup; 7 | 8 | -- Drop the validation function 9 | DROP FUNCTION IF EXISTS validate_participant (); 10 | 11 | -- Drop session_lookup table and its indexes 12 | DROP TABLE IF EXISTS session_lookup; 13 | 14 | -- Drop sessions table and its indexes 15 | DROP TRIGGER IF EXISTS trg_sessions_updated_at ON sessions; 16 | 17 | DROP INDEX IF EXISTS idx_sessions_metadata; 18 | 19 | DROP TABLE IF EXISTS sessions CASCADE; 20 | 21 | -- Drop the enum type 22 | DROP TYPE IF EXISTS participant_type; 23 | 24 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000010_tasks.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the foreign key constraint from tools table if it exists 4 | DO $$ 5 | BEGIN 6 | IF EXISTS ( 7 | SELECT 8 | 1 9 | FROM 10 | information_schema.table_constraints 11 | WHERE 12 | constraint_name = 'fk_tools_task_id' 13 | ) THEN 14 | ALTER TABLE tools 15 | DROP CONSTRAINT fk_tools_task_id; 16 | 17 | END IF; 18 | END $$; 19 | 20 | -- Drop the workflows table first since it depends on tasks 21 | DROP TABLE IF EXISTS workflows CASCADE; 22 | 23 | -- Drop the tasks table and all its dependent objects (CASCADE will handle indexes, triggers, and constraints) 24 | DROP TABLE IF EXISTS tasks CASCADE; 25 | 26 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000011_executions.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP TABLE IF EXISTS executions CASCADE; 4 | 5 | COMMIT; 6 | -------------------------------------------------------------------------------- /memory-store/migrations/000012_transitions.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop foreign key constraint if exists 4 | ALTER TABLE IF EXISTS transitions 5 | DROP CONSTRAINT IF EXISTS fk_transitions_execution; 6 | 7 | -- Drop indexes if they exist 8 | DROP INDEX IF EXISTS idx_transitions_metadata; 9 | 10 | DROP INDEX IF EXISTS idx_transitions_label; 11 | 12 | DROP INDEX IF EXISTS idx_transitions_next; 13 | 14 | DROP INDEX IF EXISTS idx_transitions_current; 15 | 16 | DROP INDEX IF EXISTS transitions_created_at_idx; 17 | 18 | -- Drop the transitions table (this will also remove it from hypertables) 19 | DO $$ 20 | BEGIN 21 | BEGIN 22 | DELETE FROM transitions; 23 | EXCEPTION 24 | WHEN others THEN 25 | RAISE NOTICE 'An error occurred during deleting all from transitions: %, %', SQLSTATE, SQLERRM; 26 | END; 27 | END $$; 28 | 29 | DROP TABLE IF EXISTS transitions; 30 | 31 | -- Drop custom types if they exist 32 | DROP TYPE IF EXISTS transition_cursor; 33 | 34 | DROP TYPE IF EXISTS transition_type; 35 | 36 | -- Drop the trigger and function for transition validation 37 | DROP TRIGGER IF EXISTS validate_transition ON transitions; 38 | 39 | DROP FUNCTION IF EXISTS check_valid_transition (); 40 | 41 | COMMIT; 42 | -------------------------------------------------------------------------------- /memory-store/migrations/000013_executions_continuous_view.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the continuous aggregate policy 4 | DO $$ 5 | BEGIN 6 | BEGIN 7 | SELECT 8 | remove_continuous_aggregate_policy ('latest_transitions'); 9 | EXCEPTION 10 | WHEN others THEN 11 | RAISE NOTICE 'An error occurred during remove_continuous_aggregate_policy(latest_transitions): %, %', SQLSTATE, SQLERRM; 12 | END; 13 | END $$; 14 | 15 | -- Drop the views 16 | DROP VIEW IF EXISTS latest_executions; 17 | 18 | DROP MATERIALIZED VIEW IF EXISTS latest_transitions; 19 | 20 | -- Drop the helper function 21 | DROP FUNCTION IF EXISTS to_text (transition_type); 22 | 23 | COMMIT; 24 | -------------------------------------------------------------------------------- /memory-store/migrations/000014_temporal_lookup.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP TABLE IF EXISTS temporal_executions_lookup CASCADE; 4 | 5 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000014_temporal_lookup.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Create temporal_executions_lookup table 4 | CREATE TABLE IF NOT EXISTS temporal_executions_lookup ( 5 | execution_id UUID NOT NULL, 6 | id TEXT NOT NULL, 7 | run_id TEXT, 8 | first_execution_run_id TEXT, 9 | result_run_id TEXT, 10 | created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, 11 | CONSTRAINT pk_temporal_executions_lookup PRIMARY KEY (execution_id, id), 12 | CONSTRAINT fk_temporal_executions_lookup_execution FOREIGN KEY (execution_id) REFERENCES executions (execution_id) ON DELETE CASCADE 13 | ); 14 | 15 | -- Add comment to table 16 | COMMENT ON TABLE temporal_executions_lookup IS 'Stores temporal workflow execution lookup data for AI agent executions'; 17 | 18 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000015_entries.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP TRIGGER IF EXISTS trg_optimized_update_token_count_after ON entries; 4 | 5 | DROP FUNCTION IF EXISTS optimized_update_token_count_after; 6 | 7 | -- Drop foreign key constraint if it exists 8 | ALTER TABLE IF EXISTS entries 9 | DROP CONSTRAINT IF EXISTS fk_entries_session; 10 | 11 | -- Drop indexes 12 | DROP INDEX IF EXISTS idx_entries_by_session; 13 | 14 | -- Drop the hypertable (this will also drop the table) 15 | DROP TABLE IF EXISTS entries; 16 | 17 | -- Drop the function 18 | DROP FUNCTION IF EXISTS all_jsonb_elements_are_objects; 19 | 20 | -- Drop the enum type 21 | DROP TYPE IF EXISTS chat_role; 22 | 23 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000016_entry_relations.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop trigger first 4 | DROP TRIGGER IF EXISTS trg_enforce_leaf_nodes ON entry_relations; 5 | 6 | -- Drop function 7 | DROP FUNCTION IF EXISTS enforce_leaf_nodes (); 8 | 9 | -- Drop the table and its constraints 10 | DROP TABLE IF EXISTS entry_relations CASCADE; 11 | 12 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000018_doc_search.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the embed and search hybrid function 4 | DROP FUNCTION IF EXISTS embed_and_search_hybrid; 5 | 6 | -- Drop the hybrid search function 7 | DROP FUNCTION IF EXISTS search_hybrid; 8 | 9 | -- Drop the text search function 10 | DROP FUNCTION IF EXISTS search_by_text; 11 | 12 | -- Drop the combined embed and search function 13 | DROP FUNCTION IF EXISTS embed_and_search_by_vector; 14 | 15 | -- Drop the search function 16 | DROP FUNCTION IF EXISTS search_by_vector; 17 | 18 | -- Drop the doc_search_result type 19 | DROP TYPE IF EXISTS doc_search_result; 20 | 21 | -- Drop the embed_with_cache function 22 | DROP FUNCTION IF EXISTS embed_with_cache; 23 | 24 | -- Drop the embeddings cache table 25 | DROP TABLE IF EXISTS embeddings_cache CASCADE; 26 | 27 | COMMIT; 28 | -------------------------------------------------------------------------------- /memory-store/migrations/000019_system_developer.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Remove the system developer 4 | DELETE FROM docs 5 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 6 | 7 | -- Remove the system developer 8 | DELETE FROM executions 9 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 10 | 11 | -- Remove the system developer 12 | DELETE FROM tasks 13 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 14 | 15 | -- Remove the system developer 16 | DELETE FROM agents 17 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 18 | 19 | -- Remove the system developer 20 | DELETE FROM users 21 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 22 | 23 | -- Remove the system developer 24 | DELETE FROM "sessions" 25 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 26 | 27 | -- Remove the system developer 28 | DELETE FROM developers 29 | WHERE developer_id = '00000000-0000-0000-0000-000000000000'::uuid; 30 | 31 | COMMIT; 32 | -------------------------------------------------------------------------------- /memory-store/migrations/000019_system_developer.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Insert system developer with all zeros UUID 4 | INSERT INTO developers ( 5 | developer_id, 6 | email, 7 | active, 8 | tags, 9 | settings 10 | ) VALUES ( 11 | '00000000-0000-0000-0000-000000000000', 12 | 'system@internal.julep.ai', 13 | true, 14 | ARRAY['system', 'paid'], 15 | '{}'::jsonb 16 | ) ON CONFLICT (developer_id) DO NOTHING; 17 | 18 | COMMIT; 19 | -------------------------------------------------------------------------------- /memory-store/migrations/000020_executions_task_cascade.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Remove cascading foreign key constraint 4 | ALTER TABLE executions 5 | DROP CONSTRAINT IF EXISTS fk_executions_task; 6 | 7 | -- Restore original foreign key without cascading behavior 8 | ALTER TABLE executions 9 | ADD CONSTRAINT fk_executions_task 10 | FOREIGN KEY (developer_id, task_id, task_version) 11 | REFERENCES tasks (developer_id, task_id, "version"); 12 | 13 | COMMIT; 14 | -------------------------------------------------------------------------------- /memory-store/migrations/000020_executions_task_cascade.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Temporarily remove foreign key to modify its behavior 4 | ALTER TABLE executions 5 | DROP CONSTRAINT IF EXISTS fk_executions_task; 6 | 7 | -- Recreate foreign key with cascading deletes 8 | ALTER TABLE executions 9 | ADD CONSTRAINT fk_executions_task 10 | FOREIGN KEY (developer_id, task_id, task_version) 11 | REFERENCES tasks (developer_id, task_id, "version") 12 | ON DELETE CASCADE; 13 | 14 | COMMIT; 15 | -------------------------------------------------------------------------------- /memory-store/migrations/000021_fix_toolname_contraint.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the updated unique constraint 4 | ALTER TABLE tools DROP CONSTRAINT IF EXISTS ct_unique_name_per_agent; 5 | 6 | -- Restore the original unique constraint (without developer_id) 7 | ALTER TABLE tools ADD CONSTRAINT ct_unique_name_per_agent 8 | UNIQUE (agent_id, name, task_id); 9 | 10 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000021_fix_toolname_contraint.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the existing unique constraint 4 | ALTER TABLE tools DROP CONSTRAINT IF EXISTS ct_unique_name_per_agent; 5 | 6 | -- Add the new unique constraint including developer_id 7 | ALTER TABLE tools ADD CONSTRAINT ct_unique_name_per_agent 8 | UNIQUE (developer_id, agent_id, name, task_id); 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /memory-store/migrations/000022_vector_search.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP FUNCTION IF EXISTS search_by_vector; 4 | 5 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000023_update_strings_length_constraints.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the updated constraints 4 | ALTER TABLE agents 5 | DROP CONSTRAINT IF EXISTS ct_agents_about_length; 6 | 7 | ALTER TABLE tools 8 | DROP CONSTRAINT IF EXISTS ct_tools_description_length; 9 | 10 | ALTER TABLE files 11 | DROP CONSTRAINT IF EXISTS ct_files_description_length; 12 | 13 | ALTER TABLE tasks 14 | DROP CONSTRAINT IF EXISTS ct_tasks_description_length; 15 | 16 | -- Restore original constraints 17 | ALTER TABLE tools 18 | ADD CONSTRAINT ct_tools_description_length CHECK ( 19 | description IS NULL 20 | OR length(description) <= 1000 21 | ); 22 | 23 | ALTER TABLE files 24 | ADD CONSTRAINT ct_files_description_length CHECK ( 25 | description IS NULL 26 | OR length(description) <= 1000 27 | ); 28 | 29 | ALTER TABLE tasks 30 | ADD CONSTRAINT ct_tasks_description_length CHECK ( 31 | description IS NULL 32 | OR length(description) <= 1000 33 | ); 34 | 35 | ALTER TABLE agents 36 | ADD CONSTRAINT ct_agents_about_length CHECK ( 37 | about IS NULL 38 | OR length(about) <= 5000 39 | ); 40 | 41 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000023_update_strings_length_constraints.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop existing constraints 4 | ALTER TABLE agents 5 | DROP CONSTRAINT IF EXISTS ct_agents_about_length; 6 | 7 | ALTER TABLE tools 8 | DROP CONSTRAINT IF EXISTS ct_tools_description_length; 9 | 10 | ALTER TABLE files 11 | DROP CONSTRAINT IF EXISTS ct_files_description_length; 12 | 13 | ALTER TABLE tasks 14 | DROP CONSTRAINT IF EXISTS ct_tasks_description_length; 15 | 16 | -- Add new constraints with updated length 17 | ALTER TABLE agents 18 | ADD CONSTRAINT ct_agents_about_length CHECK ( 19 | about IS NULL 20 | OR length(about) <= 16000 21 | ); 22 | 23 | ALTER TABLE tools 24 | ADD CONSTRAINT ct_tools_description_length CHECK ( 25 | description IS NULL 26 | OR length(description) <= 16000 27 | ); 28 | 29 | ALTER TABLE files 30 | ADD CONSTRAINT ct_files_description_length CHECK ( 31 | description IS NULL 32 | OR length(description) <= 16000 33 | ); 34 | 35 | ALTER TABLE tasks 36 | ADD CONSTRAINT ct_tasks_description_length CHECK ( 37 | description IS NULL 38 | OR length(description) <= 16000 39 | ); 40 | 41 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000024_hybrid_search.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | DROP FUNCTION IF EXISTS search_hybrid; 4 | 5 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000025_default_system_template.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- First remove the new column and its constraint from agents table 4 | ALTER TABLE agents 5 | DROP CONSTRAINT ct_agents_default_system_template_not_empty; 6 | 7 | ALTER TABLE agents 8 | DROP COLUMN default_system_template; 9 | 10 | -- Then restore the original constraint on sessions table 11 | ALTER TABLE sessions 12 | DROP CONSTRAINT ct_sessions_system_template_not_empty; 13 | 14 | ALTER TABLE sessions 15 | ADD CONSTRAINT ct_sessions_system_template_not_empty CHECK ( 16 | length(trim(system_template)) > 0 17 | ); 18 | 19 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000026_transition_cursor.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the check constraint first 4 | ALTER TABLE transitions 5 | DROP CONSTRAINT ct_transition_cursor_scope_id_not_null; 6 | 7 | -- Remove the scope field from the transition_cursor type 8 | ALTER TYPE transition_cursor DROP ATTRIBUTE scope_id; 9 | 10 | COMMIT; 11 | -------------------------------------------------------------------------------- /memory-store/migrations/000026_transition_cursor.up.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Decompress any existing compressed chunks 4 | SELECT decompress_chunk(c, true) 5 | FROM show_chunks('transitions') c; 6 | 7 | -- Temporarily disable compression 8 | ALTER TABLE transitions SET (timescaledb.compress = false); 9 | 10 | -- Add the scope field to the transition_cursor type 11 | ALTER TYPE transition_cursor ADD ATTRIBUTE scope_id UUID; 12 | 13 | -- Update all existing rows to set the default scope_id 14 | UPDATE transitions 15 | SET current_step.scope_id = '00000000-0000-0000-0000-000000000000'::UUID 16 | WHERE (current_step).scope_id IS NULL; 17 | 18 | UPDATE transitions 19 | SET next_step.scope_id = '00000000-0000-0000-0000-000000000000'::UUID 20 | WHERE (next_step).workflow_name IS NOT NULL AND (next_step).scope_id IS NULL; 21 | 22 | -- Add a check constraint to ensure scope_id is not null for future inserts/updates 23 | ALTER TABLE transitions 24 | ADD CONSTRAINT ct_transition_cursor_scope_id_not_null 25 | CHECK ((current_step).scope_id IS NOT NULL AND 26 | (next_step IS NULL OR (next_step).scope_id IS NOT NULL)); 27 | 28 | -- Re-enable compression 29 | ALTER TABLE transitions SET (timescaledb.compress = true); 30 | 31 | COMMIT; 32 | -------------------------------------------------------------------------------- /memory-store/migrations/000029_duplicate_doc_prevention.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the duplicate doc owner check trigger 4 | DROP TRIGGER IF EXISTS trg_check_duplicate_doc_owner ON doc_owners; 5 | 6 | -- Drop the trigger function 7 | DROP FUNCTION IF EXISTS check_duplicate_doc_owner(); 8 | 9 | -- Drop the content hash trigger 10 | DROP TRIGGER IF EXISTS trg_docs_content_hash ON docs; 11 | 12 | -- Drop the content hash function 13 | DROP FUNCTION IF EXISTS docs_update_content_hash(); 14 | 15 | -- Drop the hash generation function 16 | DROP FUNCTION IF EXISTS generate_content_hash(TEXT, TEXT); 17 | 18 | -- Drop the index 19 | DROP INDEX IF EXISTS idx_docs_content_hash; 20 | 21 | -- Remove the content_hash column 22 | ALTER TABLE docs DROP COLUMN IF EXISTS content_hash; 23 | 24 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000036_usage.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop the usage table (this will also remove it from hypertables) 4 | DO $$ 5 | BEGIN 6 | BEGIN 7 | DELETE FROM usage; 8 | EXCEPTION 9 | WHEN others THEN 10 | RAISE NOTICE 'An error occurred during deleting all from usage: %, %', SQLSTATE, SQLERRM; 11 | END; 12 | END $$; 13 | 14 | DROP TABLE IF EXISTS usage; 15 | 16 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000037_speed_up_search.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | -- Reset work_mem to default (or a reasonable value) 3 | RESET work_mem; 4 | 5 | -- Drop indexes created in the up migration 6 | DROP INDEX IF EXISTS idx_doc_owners_agent_lookup; 7 | DROP INDEX IF EXISTS idx_doc_owners_lookup; 8 | 9 | -- Reset statistics 10 | ALTER TABLE docs ALTER COLUMN title SET STATISTICS 100; 11 | ALTER TABLE docs ALTER COLUMN content SET STATISTICS 100; 12 | 13 | -- Reset index settings 14 | ALTER INDEX idx_docs_metadata SET (fastupdate=on); 15 | ALTER INDEX idx_docs_search_tsv SET (fastupdate=on); 16 | ALTER INDEX idx_docs_title_trgm SET (fastupdate=on); 17 | ALTER INDEX idx_docs_content_trgm SET (fastupdate=on); 18 | 19 | END; -------------------------------------------------------------------------------- /memory-store/migrations/000038_usage_cost_monthly.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Remove the continuous aggregate policy 4 | SELECT remove_continuous_aggregate_policy('usage_cost_monthly'); 5 | 6 | -- Drop the view 7 | DROP VIEW IF EXISTS developer_cost_monthly; 8 | 9 | -- Drop the continuous aggregate with CASCADE to remove any dependent objects (like the index) 10 | DROP MATERIALIZED VIEW IF EXISTS usage_cost_monthly CASCADE; 11 | 12 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000039_projects.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop triggers 4 | DROP TRIGGER IF EXISTS trg_prevent_default_project_deletion ON projects; 5 | DROP TRIGGER IF EXISTS trg_create_default_project ON developers; 6 | 7 | -- Drop functions 8 | DROP FUNCTION IF EXISTS prevent_default_project_deletion(); 9 | DROP FUNCTION IF EXISTS create_default_project(); 10 | 11 | -- Drop views 12 | DROP VIEW IF EXISTS project_docs; 13 | DROP VIEW IF EXISTS project_executions; 14 | DROP VIEW IF EXISTS project_tasks; 15 | DROP VIEW IF EXISTS project_sessions; 16 | 17 | -- Drop indexes 18 | DROP INDEX IF EXISTS idx_project_files_file; 19 | DROP INDEX IF EXISTS idx_project_users_user; 20 | DROP INDEX IF EXISTS idx_project_agents_agent; 21 | DROP INDEX IF EXISTS idx_projects_metadata; 22 | DROP INDEX IF EXISTS idx_projects_developer_id; 23 | 24 | -- Drop association tables 25 | DROP TABLE IF EXISTS project_files; 26 | DROP TABLE IF EXISTS project_users; 27 | DROP TABLE IF EXISTS project_agents; 28 | 29 | -- Drop main table 30 | DROP TABLE IF EXISTS projects; 31 | 32 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000040_add_secrets.down.sql: -------------------------------------------------------------------------------- 1 | BEGIN; 2 | 3 | -- Drop trigger for automatically updating 'updated_at' 4 | DROP TRIGGER IF EXISTS update_secrets_timestamp_trigger ON secrets; 5 | -- Drop trigger function for automatically updating 'updated_at' 6 | DROP FUNCTION IF EXISTS update_secrets_timestamp(); 7 | -- Drop encryption/decryption functions 8 | DROP FUNCTION IF EXISTS decrypt_secret; 9 | DROP FUNCTION IF EXISTS encrypt_secret; 10 | DROP INDEX IF EXISTS idx_secrets_metadata; 11 | DROP INDEX IF EXISTS idx_secrets_name; 12 | DROP INDEX IF EXISTS idx_secrets_developer_id; 13 | DROP TABLE IF EXISTS secrets; 14 | 15 | COMMIT; -------------------------------------------------------------------------------- /memory-store/migrations/000041_non_null_forward_tool_calls.down.sql: -------------------------------------------------------------------------------- 1 | -- Remove the not null constraint 2 | ALTER TABLE sessions ALTER COLUMN forward_tool_calls DROP NOT NULL; 3 | 4 | -- Remove the comment 5 | COMMENT ON COLUMN sessions.forward_tool_calls IS NULL; -------------------------------------------------------------------------------- /memory-store/migrations/000041_non_null_forward_tool_calls.up.sql: -------------------------------------------------------------------------------- 1 | -- Update existing null values to false 2 | UPDATE sessions SET forward_tool_calls = false WHERE forward_tool_calls IS NULL; 3 | 4 | -- Make the column not null 5 | ALTER TABLE sessions ALTER COLUMN forward_tool_calls SET NOT NULL; 6 | 7 | -- Add comment to explain the change 8 | COMMENT ON COLUMN sessions.forward_tool_calls IS 'Whether to forward tool calls directly to the model. Default is false.'; -------------------------------------------------------------------------------- /monitoring/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /monitoring/grafana/dashboard.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: 1 2 | 3 | providers: 4 | - name: "Dashboard provider" 5 | orgId: 1 6 | type: file 7 | disableDeletion: false 8 | updateIntervalSeconds: 10 9 | allowUiUpdates: false 10 | options: 11 | path: /var/lib/grafana/dashboards 12 | foldersFromFilesStructure: true 13 | -------------------------------------------------------------------------------- /monitoring/grafana/provisioning/dashboards/main.yaml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/monitoring/grafana/provisioning/dashboards/main.yaml -------------------------------------------------------------------------------- /monitoring/grafana/provisioning/datasources/datasource.yml: -------------------------------------------------------------------------------- 1 | datasources: 2 | - access: 'proxy' 3 | editable: true 4 | is_default: true 5 | name: 'agents-api' 6 | org_id: 1 7 | type: 'prometheus' 8 | url: 'http://prometheus:9090' 9 | version: 1 10 | -------------------------------------------------------------------------------- /monitoring/prometheus/config/prometheus.yml: -------------------------------------------------------------------------------- 1 | global: 2 | scrape_interval: 5s 3 | scrape_timeout: 3s 4 | evaluation_interval: 5s 5 | alerting: 6 | alertmanagers: 7 | - follow_redirects: true 8 | enable_http2: true 9 | scheme: http 10 | timeout: 10s 11 | api_version: v2 12 | static_configs: 13 | - targets: [] 14 | scrape_configs: 15 | - job_name: agents-api 16 | honor_timestamps: true 17 | scrape_interval: 5s 18 | scrape_timeout: 3s 19 | metrics_path: /metrics 20 | scheme: http 21 | follow_redirects: true 22 | static_configs: 23 | - targets: ['agents-api-multi-tenant:8080', 'worker:14000', 'temporal:15000'] 24 | -------------------------------------------------------------------------------- /openapi.yaml: -------------------------------------------------------------------------------- 1 | typespec/tsp-output/@typespec/openapi3/openapi-1.0.0.yaml -------------------------------------------------------------------------------- /scheduler/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /scheduler/cert/.gitignore: -------------------------------------------------------------------------------- 1 | *.crt 2 | *.key 3 | *.pem 4 | *.csr 5 | *.pem 6 | *.key 7 | *.crt 8 | *.csr 9 | *.pem 10 | -------------------------------------------------------------------------------- /schemas/walk.jq: -------------------------------------------------------------------------------- 1 | # Define a recursive walk function that applies f to every value. 2 | def walk(f): 3 | . as $in 4 | | if type == "object" then 5 | reduce keys[] as $key ({}; . + { ($key): ($in[$key] | walk(f)) }) 6 | elif type == "array" then 7 | map( walk(f) ) 8 | else 9 | . 10 | end 11 | | f; 12 | 13 | # Save the whole document as $root so we can look up definitions. 14 | . as $root 15 | | .components.schemas[$target] + {"$defs": $root.components.schemas} 16 | | walk( 17 | if type=="string" and startswith("#/components/schema") 18 | then 19 | . | sub("components/schemas"; "$defs") 20 | else 21 | . 22 | end 23 | ) 24 | 25 | -------------------------------------------------------------------------------- /scripts/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/julep-ai/julep/7723b94022aebd60a504b36923a5ca5312183455/scripts/__init__.py -------------------------------------------------------------------------------- /scripts/generate_jwt.py: -------------------------------------------------------------------------------- 1 | from datetime import UTC, datetime, timedelta 2 | 3 | import jwt 4 | 5 | dev_secret = "" 6 | prod_secret = "" 7 | test_secret = "your-supersupersecret-jwt-token-with-at-least-32-characters-long" 8 | encoded_jwt = jwt.encode( 9 | { 10 | "sub": "097720c5-ab84-438c-b8b0-68e0eabd31ff", 11 | "email": "e@mail.com", 12 | "iat": datetime.now(UTC), # Specify timezone 13 | "exp": datetime.now(UTC) + timedelta(days=100), # Specify timezone 14 | }, 15 | test_secret, 16 | algorithm="HS512", 17 | ) 18 | print(encoded_jwt) 19 | -------------------------------------------------------------------------------- /scripts/generate_openapi_code.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # Turn on echo command 4 | set -x 5 | 6 | # Exit on error 7 | set -e 8 | 9 | uv_run () { 10 | uvx \ 11 | --with ruff --with datamodel-code-generator \ 12 | --from ${2:-poethepoet} \ 13 | $1 14 | } 15 | 16 | codegen_then_format () { 17 | uv_run 'poe codegen' && \ 18 | uv_run 'poe format' && \ 19 | uv_run 'poe lint' || exit 0 20 | } 21 | 22 | generate_json_schema_local () { 23 | \cat openapi.yaml | yq -o json | jq -f ./schemas/walk.jq --arg target "${1}" > $2 24 | } 25 | 26 | generate_json_schema () { 27 | curl -sL http://dev.julep.ai/api/openapi.json | jq -f ./schemas/walk.jq --arg target "${1}" > $2 28 | } 29 | 30 | cd typespec/ && \ 31 | tsp compile . 32 | cd - 33 | 34 | generate_json_schema CreateTaskRequest ./schemas/create_task_request.json 35 | generate_json_schema CreateAgentRequest ./schemas/create_agent_request.json 36 | 37 | cd agents-api && \ 38 | codegen_then_format 39 | cd - 40 | 41 | cd integrations-service && \ 42 | codegen_then_format 43 | cd - 44 | -------------------------------------------------------------------------------- /typespec/.gitignore: -------------------------------------------------------------------------------- 1 | # Ignore everything in tsp-output 2 | tsp-output/**/*.* 3 | 4 | # Don't ignore the openapi3 directory 5 | !tsp-output/@typespec/openapi3/ 6 | 7 | # But don't ignore openapi-*.yaml files in tsp-output/@typespec/openapi3/ 8 | !tsp-output/@typespec/openapi3/openapi-*.yaml 9 | -------------------------------------------------------------------------------- /typespec/CLAUDE.md: -------------------------------------------------------------------------------- 1 | AGENTS.md -------------------------------------------------------------------------------- /typespec/agents/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | import "../common"; 3 | import "./models.tsp"; 4 | 5 | using TypeSpec.Http; 6 | using Common; 7 | 8 | namespace Agents; 9 | 10 | // 11 | // AGENT ENDPOINTS 12 | // 13 | 14 | interface Endpoints 15 | extends LimitOffsetPagination, 16 | CreateEndpoint, 17 | CreateOrUpdateEndpoint, 18 | UpdateEndpoint, 19 | PatchEndpoint, 20 | DeleteEndpoint<"Delete Agent by id">, 21 | GetEndpoint { 22 | 23 | @route("models") 24 | @get 25 | @doc("List all available models") 26 | listModels(): ListModelsResponse; 27 | } 28 | -------------------------------------------------------------------------------- /typespec/agents/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Agents; 5 | 6 | // 7 | // AGENTS 8 | // -------------------------------------------------------------------------------- /typespec/chat/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Chat; 5 | 6 | // 7 | // CHAT 8 | // -------------------------------------------------------------------------------- /typespec/common/main.tsp: -------------------------------------------------------------------------------- 1 | import "./constants.tsp"; 2 | import "./interfaces.tsp"; 3 | import "./mixins.tsp"; 4 | import "./scalars.tsp"; 5 | import "./types.tsp"; 6 | 7 | namespace Common; 8 | 9 | // 10 | // COMMON 11 | // 12 | -------------------------------------------------------------------------------- /typespec/common/types.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/events"; 2 | import "@typespec/http"; 3 | import "@typespec/openapi"; 4 | 5 | using TypeSpec.Events; 6 | using TypeSpec.Http; 7 | using TypeSpec.OpenAPI; 8 | 9 | namespace Common; 10 | 11 | // 12 | // COMMON TYPES 13 | // 14 | 15 | alias Metadata = Record; 16 | alias MetadataFilter = Record; 17 | 18 | model ResourceDeletedResponse { 19 | @doc("ID of deleted resource") 20 | id: uuid; 21 | ...HasDeletedAt; 22 | ...HasJobs; 23 | } 24 | 25 | model BulkResourceDeletedResponse { 26 | @doc("IDs of deleted resources") 27 | ids: uuid[]; 28 | ...HasDeletedAt; 29 | ...HasJobs; 30 | } 31 | 32 | model PaginationOptions { 33 | @query 34 | @doc("Limit the number of items returned") 35 | limit: limit = 100, 36 | 37 | @query 38 | @doc("Offset the items returned") 39 | offset: offset = 0, 40 | 41 | /** Sort by a field */ 42 | @query sort_by: sortBy = "created_at", 43 | 44 | /** Sort direction */ 45 | @query direction: sortDirection = "asc", 46 | 47 | /** Object to filter results by metadata */ 48 | @query metadata_filter: Record = #{}, 49 | } 50 | 51 | @events 52 | union StreamEvent { 53 | T; 54 | } 55 | -------------------------------------------------------------------------------- /typespec/docs/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Docs; 5 | 6 | // 7 | // DOCS 8 | // -------------------------------------------------------------------------------- /typespec/entries/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | 3 | import "../common"; 4 | import "../sessions"; 5 | import "./models.tsp"; 6 | 7 | using TypeSpec.Http; 8 | 9 | using Common; 10 | using Sessions; 11 | 12 | namespace Entries; 13 | 14 | // 15 | // ENTRY ENDPOINTS 16 | // 17 | 18 | interface Endpoints 19 | extends DeleteEndpoint<"Clear the history of a Session (resets the Session)"> { 20 | @get 21 | @doc("Get history of a Session") 22 | history( 23 | @path 24 | @doc("ID of parent") 25 | id: uuid, 26 | ): History; 27 | } 28 | -------------------------------------------------------------------------------- /typespec/entries/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Entries; 5 | 6 | // 7 | // ENTRIES 8 | // -------------------------------------------------------------------------------- /typespec/executions/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Executions; 5 | 6 | // 7 | // EXECUTIONS 8 | // -------------------------------------------------------------------------------- /typespec/files/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | import "./models.tsp"; 3 | 4 | using Common; 5 | 6 | namespace Files; 7 | 8 | // 9 | // FILE ENDPOINTS 10 | // 11 | 12 | interface Endpoints 13 | extends GetEndpoint, 14 | CreateEndpoint {} 15 | -------------------------------------------------------------------------------- /typespec/files/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Files; 5 | 6 | // 7 | // FILES 8 | // 9 | -------------------------------------------------------------------------------- /typespec/files/models.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | 3 | using Common; 4 | 5 | namespace Files; 6 | 7 | // 8 | // FILE MODELS 9 | // 10 | 11 | model File { 12 | ...HasId; 13 | ...HasCreatedAt; 14 | 15 | /** Name of the file */ 16 | name: identifierSafeUnicode; 17 | 18 | /** Description of the file */ 19 | description: string = ""; 20 | 21 | /** MIME type of the file */ 22 | mime_type: mimeType | null = null; 23 | 24 | /** Base64 encoded content of the file */ 25 | content: string; 26 | 27 | /** Project canonical name of the file */ 28 | project?: canonicalName; 29 | 30 | /** Size of the file in bytes */ 31 | @visibility("read") 32 | @minValue(1) 33 | size: uint64; 34 | 35 | /** Hash of the file */ 36 | @visibility("read") 37 | hash: string; 38 | } 39 | 40 | /** Payload for creating a file */ 41 | @withVisibility("create") 42 | model CreateFileRequest { 43 | ...File; 44 | } 45 | -------------------------------------------------------------------------------- /typespec/jobs/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | import "./models.tsp"; 3 | 4 | using Common; 5 | 6 | namespace Jobs; 7 | 8 | // 9 | // JOB ENDPOINTS 10 | // 11 | 12 | interface Endpoints 13 | extends GetEndpoint< 14 | JobStatus, 15 | "Get the status of an existing Job by its id" 16 | > {} 17 | -------------------------------------------------------------------------------- /typespec/jobs/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Jobs; 5 | 6 | // 7 | // JOBS 8 | // -------------------------------------------------------------------------------- /typespec/jobs/models.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | 3 | using Common; 4 | 5 | namespace Jobs; 6 | 7 | // 8 | // JOB MODELS 9 | // 10 | 11 | /** Current state (one of: pending, in_progress, retrying, succeeded, aborted, failed) */ 12 | enum JobState { 13 | pending, 14 | in_progress, 15 | retrying, 16 | succeeded, 17 | aborted, 18 | failed, 19 | "unknown", 20 | } 21 | 22 | model JobStatus { 23 | ...HasId; 24 | ...HasTimestamps; 25 | 26 | /** Name of the job */ 27 | name: identifierSafeUnicode = identifierSafeUnicode(""); 28 | 29 | /** Reason for the current state of the job */ 30 | reason: string = ""; 31 | 32 | /** Whether this Job supports progress updates */ 33 | has_progress: boolean = false; 34 | 35 | /** Progress percentage */ 36 | @minValue(0) 37 | @maxValue(100) 38 | progress: float32 = 0.0; 39 | 40 | /** Current state of the job */ 41 | state: JobState = JobState.pending; 42 | } -------------------------------------------------------------------------------- /typespec/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "julep-typespec", 3 | "version": "0.4.0", 4 | "type": "module", 5 | "dependencies": { 6 | "@typespec/compiler": "0.61.x", 7 | "@typespec/events": "0.61.x", 8 | "@typespec/http": "0.61.x", 9 | "@typespec/openapi": "0.61.x", 10 | "@typespec/openapi3": "0.61.x", 11 | "@typespec/rest": "0.61.x", 12 | "@typespec/sse": "0.61.x", 13 | "@typespec/versioning": "0.61.x" 14 | }, 15 | "private": true 16 | } 17 | -------------------------------------------------------------------------------- /typespec/projects/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | import "../common"; 3 | import "./models.tsp"; 4 | 5 | using TypeSpec.Http; 6 | using Common; 7 | 8 | namespace Projects; 9 | 10 | // 11 | // PROJECT ENDPOINTS 12 | // 13 | 14 | interface Endpoints 15 | extends LimitOffsetPagination, 16 | CreateEndpoint, 17 | CreateOrUpdateEndpoint, 18 | UpdateEndpoint, 19 | PatchEndpoint, 20 | DeleteEndpoint<"Delete Project by id">, 21 | GetEndpoint { 22 | } 23 | -------------------------------------------------------------------------------- /typespec/projects/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Projects; 5 | 6 | // 7 | // PROJECTS 8 | // 9 | -------------------------------------------------------------------------------- /typespec/projects/models.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | 3 | import "../common"; 4 | 5 | using TypeSpec.Http; 6 | 7 | using Common; 8 | 9 | namespace Projects; 10 | 11 | // 12 | // PROJECT MODELS 13 | // 14 | 15 | @doc("Project model") 16 | model Project { 17 | ...HasId; 18 | ...HasMetadata; 19 | ...HasTimestamps; 20 | 21 | @doc("Canonical name of the project (unique per developer)") 22 | canonical_name?: canonicalName; 23 | 24 | @doc("Display name of the project") 25 | name: displayName; 26 | 27 | } 28 | 29 | /** Payload for updating a project */ 30 | @withVisibility("create", "update") 31 | model UpdateProjectRequest { 32 | ...Project; 33 | } 34 | 35 | /** Payload for patching a project */ 36 | model PatchProjectRequest is UpdateProjectRequest {} 37 | 38 | /** Payload for creating a project */ 39 | @withVisibility("create") 40 | model CreateProjectRequest { 41 | ...UpdateProjectRequest; 42 | } 43 | 44 | model CreateOrUpdateProjectRequest extends CreateProjectRequest { 45 | @path 46 | id: uuid; 47 | ...UpdateProjectRequest; 48 | } 49 | -------------------------------------------------------------------------------- /typespec/responses/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | import "./models.tsp"; 3 | import "../common"; 4 | 5 | using TypeSpec.Http; 6 | using Common; 7 | 8 | namespace Responses; 9 | 10 | interface ResponsesEndpoints extends GetResponsesEndpoints, CreateResponsesEndpoints {} 11 | 12 | interface CreateResponsesEndpoints { 13 | @doc("Creates a model response. Provide text or image inputs to generate text or JSON outputs.") 14 | @post 15 | createResponse( 16 | @body 17 | body: CreateResponse 18 | ): Response; 19 | } 20 | 21 | interface GetResponsesEndpoints { 22 | @get 23 | @doc("Get a response by id") 24 | getResponse( 25 | @path 26 | @doc("ID of the response") 27 | id: string, 28 | 29 | @query 30 | @doc("Specify additional output data to include in the model response") 31 | include?: Includable[]; 32 | ): Response; 33 | } -------------------------------------------------------------------------------- /typespec/responses/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Responses; 5 | 6 | // 7 | // RESPONSES 8 | // -------------------------------------------------------------------------------- /typespec/secrets/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | 3 | import "./models.tsp"; 4 | import "../common"; 5 | 6 | using TypeSpec.Http; 7 | 8 | using Common; 9 | 10 | namespace Secrets; 11 | 12 | // 13 | // SECRET ENDPOINTS 14 | // 15 | 16 | interface DeveloperSecretsEndpoints 17 | extends ChildLimitOffsetPagination, 18 | ChildCreateEndpoint, 19 | ChildUpdateEndpoint, 20 | ChildDeleteEndpoint<"Delete a secret by id"> {} 21 | 22 | interface AgentSecretsEndpoints 23 | extends ChildLimitOffsetPagination, 24 | ChildCreateEndpoint, 25 | ChildUpdateEndpoint, 26 | ChildDeleteEndpoint<"Delete a secret by id"> {} 27 | -------------------------------------------------------------------------------- /typespec/secrets/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Secrets; 5 | 6 | // 7 | // SECRETS 8 | // -------------------------------------------------------------------------------- /typespec/secrets/models.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | 3 | using Common; 4 | 5 | namespace Secrets; 6 | 7 | // 8 | // SECRET MODELS 9 | // 10 | 11 | /** A secret that can be used in tasks and sessions */ 12 | model Secret { 13 | ...HasId; 14 | ...HasTimestamps; 15 | ...HasMetadata; 16 | 17 | /** Name of the secret */ 18 | name: string; 19 | 20 | /** Description of what the secret is used for */ 21 | description?: string; 22 | 23 | /** The decrypted secret value */ 24 | value: string; 25 | } 26 | 27 | @withVisibility("create", "update") 28 | model UpdateSecretRequest { 29 | ...Secret; 30 | } 31 | 32 | @withVisibility("create") 33 | model CreateSecretRequest { 34 | ...UpdateSecretRequest; 35 | } 36 | 37 | 38 | model PatchSecretRequest is UpdateSecretRequest {} 39 | -------------------------------------------------------------------------------- /typespec/sessions/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | import "./models.tsp"; 3 | 4 | using Common; 5 | 6 | namespace Sessions; 7 | 8 | // 9 | // SESSION ENDPOINTS 10 | // 11 | 12 | interface Endpoints 13 | extends LimitOffsetPagination, 14 | CreateEndpoint, 15 | CreateOrUpdateEndpoint, 16 | UpdateEndpoint, 17 | PatchEndpoint, 18 | DeleteEndpoint<"Delete a session by its id">, 19 | GetEndpoint {} -------------------------------------------------------------------------------- /typespec/sessions/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Sessions; 5 | 6 | // 7 | // SESSIONS 8 | // -------------------------------------------------------------------------------- /typespec/tasks/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Tasks; 5 | 6 | // 7 | // TASKS 8 | // -------------------------------------------------------------------------------- /typespec/tools/browserbase/contexts.tsp: -------------------------------------------------------------------------------- 1 | import "../../common"; 2 | 3 | using Common; 4 | 5 | namespace Tools; 6 | 7 | // TODO: Implement these 8 | /** browserbase context provider */ 9 | model BrowserbaseContextIntegrationDef extends BaseBrowserbaseIntegrationDef { 10 | /** The specific method of the integration to call */ 11 | method?: "create_context" = "create_context"; 12 | 13 | /** The arguments for the method */ 14 | arguments?: BrowserbaseContextArguments; 15 | } 16 | 17 | model BrowserbaseContextArguments { 18 | /** The Project ID. Can be found in Settings. */ 19 | projectId: string; 20 | } 21 | 22 | model BrowserbaseContextOutput { 23 | id: string; 24 | uploadUrl?: url; 25 | publicKey?: string; 26 | cipherAlgorithm?: string; 27 | initializationVectorSize?: uint16; 28 | } 29 | 30 | -------------------------------------------------------------------------------- /typespec/tools/browserbase/extensions.tsp: -------------------------------------------------------------------------------- 1 | import "../../common"; 2 | 3 | using Common; 4 | 5 | namespace Tools; 6 | 7 | 8 | /** browserbase extension provider */ 9 | model BrowserbaseExtensionIntegrationDef extends BaseBrowserbaseIntegrationDef { 10 | /** The specific method of the integration to call */ 11 | method?: "install_extension_from_github"; 12 | 13 | /** The arguments for the method */ 14 | arguments?: BrowserbaseExtensionArguments; 15 | } 16 | 17 | model BrowserbaseExtensionArguments { 18 | /** The GitHub repository name. */ 19 | repositoryName: string; 20 | 21 | /** Ref to install from a branch or tag. */ 22 | ref?: string; 23 | } 24 | 25 | model BrowserbaseExtensionOutput { 26 | /** The installed Extension ID. */ 27 | id: string; 28 | } 29 | -------------------------------------------------------------------------------- /typespec/tools/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | import "../agents"; 3 | import "./models.tsp"; 4 | 5 | using Common; 6 | using Agents; 7 | 8 | namespace Tools; 9 | 10 | // 11 | // TOOL ENDPOINTS 12 | // 13 | 14 | interface AgentEndpoints 15 | extends ChildLimitOffsetPagination, 16 | ChildCreateEndpoint, 17 | ChildUpdateEndpoint, 18 | ChildPatchEndpoint, 19 | ChildDeleteEndpoint<"Delete an existing tool by id"> {} 20 | -------------------------------------------------------------------------------- /typespec/tools/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | import "./anthropic.tsp"; 4 | import "./brave.tsp"; 5 | import "./email.tsp"; 6 | import "./spider.tsp"; 7 | import "./weather.tsp"; 8 | import "./wikipedia.tsp"; 9 | import "./browserbase"; 10 | import "./remote_browser.tsp"; 11 | import "./llama_parse.tsp"; 12 | import "./ffmpeg.tsp"; 13 | import "./cloudinary.tsp"; 14 | import "./arxiv.tsp"; 15 | import "./unstructured.tsp"; 16 | import "./algolia.tsp"; 17 | 18 | namespace Tools; 19 | 20 | // 21 | // TOOLS 22 | // -------------------------------------------------------------------------------- /typespec/tspconfig.yaml: -------------------------------------------------------------------------------- 1 | emit: 2 | - "@typespec/openapi3" 3 | 4 | options: 5 | "@typespec/openapi3": 6 | file-type: yaml 7 | output-file: "openapi-{version}.yaml" 8 | new-line: lf 9 | omit-unreachable-types: true 10 | # openapi-versions: ["3.1.0"] 11 | -------------------------------------------------------------------------------- /typespec/users/endpoints.tsp: -------------------------------------------------------------------------------- 1 | import "../common"; 2 | import "./models.tsp"; 3 | 4 | using Common; 5 | 6 | namespace Users; 7 | 8 | // 9 | // USER ENDPOINTS 10 | // 11 | 12 | interface Endpoints 13 | extends LimitOffsetPagination, 14 | CreateEndpoint, 15 | CreateOrUpdateEndpoint, 16 | UpdateEndpoint, 17 | PatchEndpoint, 18 | DeleteEndpoint<"Delete a user by id">, 19 | GetEndpoint {} -------------------------------------------------------------------------------- /typespec/users/main.tsp: -------------------------------------------------------------------------------- 1 | import "./endpoints.tsp"; 2 | import "./models.tsp"; 3 | 4 | namespace Users; 5 | 6 | // 7 | // USERS 8 | // -------------------------------------------------------------------------------- /typespec/users/models.tsp: -------------------------------------------------------------------------------- 1 | import "@typespec/http"; 2 | 3 | import "../common"; 4 | 5 | using TypeSpec.Http; 6 | 7 | using Common; 8 | 9 | namespace Users; 10 | 11 | // 12 | // USER MODELS 13 | // 14 | 15 | model User { 16 | ...HasId; 17 | ...HasMetadata; 18 | ...HasTimestamps; 19 | 20 | /** Name of the user */ 21 | name: identifierSafeUnicode = identifierSafeUnicode(""); 22 | 23 | /** About the user */ 24 | about: string = ""; 25 | 26 | /** Project canonical name of the user */ 27 | project?: canonicalName; 28 | } 29 | 30 | /** Payload for updating a user */ 31 | @withVisibility("create", "update") 32 | model UpdateUserRequest { 33 | ...User; 34 | } 35 | 36 | /** Payload for patching a user */ 37 | model PatchUserRequest is UpdateUserRequest {} 38 | 39 | /** Payload for creating a user (and associated documents) */ 40 | model CreateUserRequest is UpdateUserRequest {} 41 | 42 | model CreateOrUpdateUserRequest extends CreateUserRequest { 43 | @path 44 | id: uuid; 45 | } -------------------------------------------------------------------------------- /typespec/versions.tsp: -------------------------------------------------------------------------------- 1 | namespace Versions; 2 | 3 | enum ApiVersions { 4 | v1_0: "1.0.0", 5 | } 6 | --------------------------------------------------------------------------------