├── .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 |
--------------------------------------------------------------------------------