Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
75b621a
initial docs
jp-agenta Feb 11, 2026
0616af1
first throw
jp-agenta Feb 12, 2026
587820d
Merge branch 'main' into feat/add-gateway-tools
jp-agenta Feb 12, 2026
0bec1e2
wip
jp-agenta Feb 16, 2026
71af149
merge main
jp-agenta Feb 16, 2026
a97c3d9
fix migrations
jp-agenta Feb 16, 2026
780baa4
working tools
jp-agenta Feb 17, 2026
8cfc36e
many fixes
jp-agenta Feb 17, 2026
db821f2
minor fix
jp-agenta Feb 17, 2026
97c87ae
Merge branch 'main' into feat/add-gateway-tools
jp-agenta Feb 18, 2026
0cc60f8
cleanup docs
jp-agenta Feb 18, 2026
ff16243
almost there
jp-agenta Feb 18, 2026
2b264e6
fix schemas.inputs
jp-agenta Feb 18, 2026
09387b9
working chat with execution
jp-agenta Feb 19, 2026
f692da3
functional add tool widget
jp-agenta Feb 19, 2026
8e01fb9
sticky search
jp-agenta Feb 19, 2026
dbd811a
speed-run test done
jp-agenta Feb 19, 2026
7e489df
ruff and eslint
jp-agenta Feb 19, 2026
b3cb99a
fix review issues
jp-agenta Feb 19, 2026
229793b
Merge branch 'main' into feat/add-gateway-tools
jp-agenta Feb 19, 2026
4545854
fix migration headers
jp-agenta Feb 19, 2026
a3da4dc
eslint
jp-agenta Feb 19, 2026
e60c117
quick deisng fix in actions list
jp-agenta Feb 19, 2026
3fd49ba
Local CR / PR prep
jp-agenta Feb 19, 2026
7474686
fixing issues from CR
jp-agenta Feb 19, 2026
3655869
fix gateway-tools review issues and polish UX flows
mmabrouk Feb 23, 2026
50af996
fix(frontend): address devin review comments for tools auth and slug UX
mmabrouk Feb 23, 2026
9fc3aed
style(api): format tools router to satisfy ruff check
mmabrouk Feb 23, 2026
96bb20b
More fixes
jp-agenta Feb 25, 2026
daa05ad
Merge pull request #3808 from Agenta-AI/feat/gateway-tools-remediatio…
jp-agenta Feb 25, 2026
f07a973
Merge branch 'main' into feat/add-gateway-tools
jp-agenta Feb 25, 2026
0201d1d
ruff
jp-agenta Feb 25, 2026
1a1b9c5
Merge branch 'release/v0.87.0' into feat/add-gateway-tools
jp-agenta Feb 25, 2026
6920a54
ruff
jp-agenta Feb 25, 2026
b2f7b33
CFR fixes
jp-agenta Feb 25, 2026
807689d
More fixes from CR
jp-agenta Feb 25, 2026
f113254
Merge branch 'release/v0.87.0' into feat/add-gateway-tools
jp-agenta Feb 25, 2026
0ba3003
Merge branch 'release/v0.87.0' into feat/add-gateway-tools
jp-agenta Feb 25, 2026
de2fe3e
Add slug to connections list
jp-agenta Feb 25, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/02-check-python-formatting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ jobs:
run: pip install ruff==0.14.0

- name: Run Ruff formatting check
run: ruff format --check api sdk
run: ruff format --check
2 changes: 1 addition & 1 deletion .github/workflows/03-check-python-linting.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ jobs:
run: pip install ruff==0.14.0

- name: Run Ruff linting check
run: ruff check api sdk
run: ruff check
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
**/*.next
**/*.pnpm-store
**/*.env*
!**/*.env.example*
!**/*env.example*
**/*.DS_Store
**/*.vscode
**/*.pem
Expand Down Expand Up @@ -47,15 +49,23 @@ sdk/agenta/templates/agenta.py
web/ee/public/__env.js
web/oss/public/__env.js

web/oss/tests/datalayer/results
web/tests/results
web/oss/tests/results
web/ee/tests/results
api/tests/results/
api/oss/tests/results/
api/ee/tests/results/
sdk/tests/results/
sdk/oss/tests/results/
sdk/ee/tests/results/
services/tests/results/
services/oss/tests/results/
services/ee/tests/results/
.*
!**/.gitkeep
!api/.dockerignore
!services/.dockerignore
!.env.example

# Temporary SDK symlinks created by run.sh --local
api/sdk
Expand Down
1 change: 1 addition & 0 deletions .gitleaks.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ paths = [
regexes = [
# ------------------------------------------------------------ FALSE POSITIVES
'''is_completion=True''',
'''is_valid=true''',
'''YOUR_API_KEY''',
'''_SECRET_KEY''',
# ------------------------------------------------------------ PUBLIC KEYS
Expand Down
17 changes: 17 additions & 0 deletions .gitleaksignore
Original file line number Diff line number Diff line change
Expand Up @@ -263,3 +263,20 @@ bb4b06cd13e5aca1c75886990f164b643360da2b:sdk/tests/legacy/debugging/simple-app/c
3db7c34a8f206fb4a19e525ac5a964185d502c4a:api/oss/tests/manual/tracing/crud.http:agenta-api-key:3
3db7c34a8f206fb4a19e525ac5a964185d502c4a:api/oss/tests/manual/tracing/windowing.http:agenta-api-key:3
8465021df57fca629f14c269d3f37d18d6fdcd11:services/completion-new-sdk-prompt/docker-compose.yml:openai-api-key-new:10
0f2247579fc6022ccf2834fa5330cb30cd39133b:api/manual_test_embeds.py:generic-api-key:285
06ea99910acc6e5bd5eeb4c3aee263de9e4f4e29:EMBEDS_STATUS.md:generic-api-key:239
06ea99910acc6e5bd5eeb4c3aee263de9e4f4e29:EMBEDS_STATUS.md:generic-api-key:248
06ea99910acc6e5bd5eeb4c3aee263de9e4f4e29:api/manual_test_embeds.py:generic-api-key:302
06ea99910acc6e5bd5eeb4c3aee263de9e4f4e29:api/oss/tests/pytest/e2e/workflows/test_workflow_embeds_cross_entity.py:generic-api-key:64
06ea99910acc6e5bd5eeb4c3aee263de9e4f4e29:api/oss/tests/pytest/e2e/workflows/test_workflow_embeds_cross_entity.py:generic-api-key:197
75b621a2e286568b8c0adc3efefedf6365c43b9e:api/oss/tests/manual/composio/catalog.http:generic-api-key:2
75b621a2e286568b8c0adc3efefedf6365c43b9e:api/oss/tests/manual/composio/auth.http:generic-api-key:2
75b621a2e286568b8c0adc3efefedf6365c43b9e:api/oss/tests/manual/composio/execute.http:generic-api-key:2
75b621a2e286568b8c0adc3efefedf6365c43b9e:api/oss/tests/manual/composio/connections.http:generic-api-key:2
75b621a2e286568b8c0adc3efefedf6365c43b9e:docs/designs/gateway-tools/examples.llm-provider-keys-and-tool-provider-keys.md:generic-api-key:301
75b621a2e286568b8c0adc3efefedf6365c43b9e:docs/designs/gateway-tools/examples.llm-provider-keys-and-tool-provider-keys.md:generic-api-key:313
9b02348e6037157ba341bdcb1b7e11f55689ac13:docs/design/agents-feature/pre-research/research-vellum-composio-api.md:generic-api-key:225
9b02348e6037157ba341bdcb1b7e11f55689ac13:docs/design/agents-feature/pre-research/research-vellum-composio-api.md:generic-api-key:315
9b02348e6037157ba341bdcb1b7e11f55689ac13:docs/design/agents-feature/pre-research/research-vellum-composio-api.md:generic-api-key:366
8bf2b0643b024e17904269830d941cb324a26b0f:docs/design/agents-feature/research-composio-oauth.md:curl-auth-header:150
ce2aa0c2d9990d25d5771b65e0fad6db01518e14:sdk/tests/integration/conftest.py:agenta-api-key:23
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""add tool_connections table

Revision ID: e5f6a1b2c3d4
Revises: c2d3e4f5a6b7
Create Date: 2026-02-09 12:00:00.000000

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql


# revision identifiers, used by Alembic.
revision: str = "e5f6a1b2c3d4"
down_revision: Union[str, None] = "c2d3e4f5a6b7"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# -- TOOL CONNECTIONS -------------------------------------------------------
op.create_table(
"tool_connections",
sa.Column("project_id", sa.UUID(), nullable=False),
sa.Column("id", sa.UUID(), nullable=False),
sa.Column("slug", sa.String(), nullable=False),
sa.Column("name", sa.String(), nullable=True),
sa.Column("description", sa.String(), nullable=True),
#
sa.Column("provider_key", sa.String(), nullable=False),
sa.Column("integration_key", sa.String(), nullable=False),
#
sa.Column("tags", postgresql.JSONB(none_as_null=True), nullable=True),
sa.Column("flags", postgresql.JSONB(none_as_null=True), nullable=True),
sa.Column("data", postgresql.JSON(none_as_null=True), nullable=True),
sa.Column("status", postgresql.JSONB(none_as_null=True), nullable=True),
sa.Column("meta", postgresql.JSON(none_as_null=True), nullable=True),
#
sa.Column(
"created_at",
sa.TIMESTAMP(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=False,
),
sa.Column("updated_at", sa.TIMESTAMP(timezone=True), nullable=True),
sa.Column("deleted_at", sa.TIMESTAMP(timezone=True), nullable=True),
sa.Column("created_by_id", sa.UUID(), nullable=False),
sa.Column("updated_by_id", sa.UUID(), nullable=True),
sa.Column("deleted_by_id", sa.UUID(), nullable=True),
#
sa.PrimaryKeyConstraint("project_id", "id"),
sa.UniqueConstraint(
"project_id",
"provider_key",
"integration_key",
"slug",
name="uq_tool_connections_project_provider_integration_slug",
),
sa.ForeignKeyConstraint(
["project_id"],
["projects.id"],
ondelete="CASCADE",
),
sa.Index(
"ix_tool_connections_project_provider_integration",
"project_id",
"provider_key",
"integration_key",
),
)


def downgrade() -> None:
op.drop_table("tool_connections")
7 changes: 7 additions & 0 deletions api/ee/src/models/shared_models.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,11 @@ class Permission(str, Enum):
VIEW_EVALUATION_QUEUES = "view_evaluation_queues"
EDIT_EVALUATION_QUEUES = "edit_evaluation_queues"

# Tools
VIEW_TOOLS = "view_tools"
EDIT_TOOLS = "edit_tools"
RUN_TOOLS = "run_tools"

@classmethod
def default_permissions(cls, role):
VIEWER_PERMISSIONS = [
Expand Down Expand Up @@ -176,6 +181,8 @@ def default_permissions(cls, role):
cls.VIEW_EVALUATION_RESULTS,
cls.VIEW_EVALUATION_METRICS,
cls.VIEW_EVALUATION_QUEUES,
#
cls.VIEW_TOOLS,
]
defaults = {
WorkspaceRole.OWNER: [p for p in cls],
Expand Down
39 changes: 39 additions & 0 deletions api/entrypoints/routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@

from oss.src.core.ai_services.service import AIServicesService
from oss.src.apis.fastapi.ai_services.router import AIServicesRouter
from oss.src.dbs.postgres.tools.dao import ToolsDAO
from oss.src.core.tools.providers.composio import ComposioToolsAdapter
from oss.src.core.tools.registry import ToolsGatewayRegistry
from oss.src.core.tools.service import ToolsService
from oss.src.apis.fastapi.tools.router import ToolsRouter


from oss.src.routers import (
Expand Down Expand Up @@ -165,6 +170,9 @@ async def lifespan(*args, **kwargs):

yield

for adapter in _composio_adapters.values():
await adapter.close()


app = FastAPI(
lifespan=lifespan,
Expand Down Expand Up @@ -242,6 +250,8 @@ async def lifespan(*args, **kwargs):
evaluations_dao = EvaluationsDAO()
folders_dao = FoldersDAO()

tools_dao = ToolsDAO()

# SERVICES ---------------------------------------------------------------------

vault_service = VaultService(
Expand Down Expand Up @@ -335,6 +345,25 @@ async def lifespan(*args, **kwargs):
evaluations_worker=evaluations_worker,
)

# Tools adapter + service
_composio_adapters = {}
if env.composio.enabled:
_composio_adapters["composio"] = ComposioToolsAdapter(
api_key=env.composio.api_key, # type: ignore[arg-type] # guarded by .enabled
api_url=env.composio.api_url,
)
else:
log.warning("Composio not enabled — set COMPOSIO_API_KEY to activate gateway tools")

tools_adapter_registry = ToolsGatewayRegistry(
adapters=_composio_adapters,
)

tools_service = ToolsService(
tools_dao=tools_dao,
adapter_registry=tools_adapter_registry,
)

# ROUTERS ----------------------------------------------------------------------

secrets = VaultRouter(
Expand Down Expand Up @@ -412,6 +441,10 @@ async def lifespan(*args, **kwargs):
simple_evaluations_service=simple_evaluations_service,
)

tools = ToolsRouter(
tools_service=tools_service,
)

invocations_service = InvocationsService(
tracing_router=tracing,
applications_service=applications_service,
Expand Down Expand Up @@ -570,6 +603,12 @@ async def lifespan(*args, **kwargs):
tags=["Environments"],
)

app.include_router(
router=tools.router,
prefix="/preview/tools",
tags=["Tools"],
)

app.include_router(
router=evaluations.admin_router,
prefix="/admin/evaluations",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
"""add tool_connections table

Revision ID: e5f6a1b2c3d4
Revises: c2d3e4f5a6b7
Create Date: 2026-02-09 12:00:00.000000

"""

from typing import Sequence, Union

from alembic import op
import sqlalchemy as sa
from sqlalchemy.dialects import postgresql


# revision identifiers, used by Alembic.
revision: str = "e5f6a1b2c3d4"
down_revision: Union[str, None] = "c2d3e4f5a6b7"
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None


def upgrade() -> None:
# -- TOOL CONNECTIONS -------------------------------------------------------
# Note: SQLAlchemy will automatically create the enum type when creating the table
op.create_table(
"tool_connections",
sa.Column("project_id", sa.UUID(), nullable=False),
sa.Column("id", sa.UUID(), nullable=False),
sa.Column("slug", sa.String(), nullable=False),
sa.Column("name", sa.String(), nullable=True),
sa.Column("description", sa.String(), nullable=True),
#
sa.Column("provider_key", sa.String(), nullable=False),
sa.Column("integration_key", sa.String(), nullable=False),
#
sa.Column("tags", postgresql.JSONB(none_as_null=True), nullable=True),
sa.Column("flags", postgresql.JSONB(none_as_null=True), nullable=True),
sa.Column("data", postgresql.JSON(none_as_null=True), nullable=True),
sa.Column("status", postgresql.JSONB(none_as_null=True), nullable=True),
sa.Column("meta", postgresql.JSON(none_as_null=True), nullable=True),
#
sa.Column(
"created_at",
sa.TIMESTAMP(timezone=True),
server_default=sa.text("CURRENT_TIMESTAMP"),
nullable=False,
),
sa.Column("updated_at", sa.TIMESTAMP(timezone=True), nullable=True),
sa.Column("deleted_at", sa.TIMESTAMP(timezone=True), nullable=True),
sa.Column("created_by_id", sa.UUID(), nullable=False),
sa.Column("updated_by_id", sa.UUID(), nullable=True),
sa.Column("deleted_by_id", sa.UUID(), nullable=True),
#
sa.PrimaryKeyConstraint("project_id", "id"),
sa.UniqueConstraint(
"project_id",
"provider_key",
"integration_key",
"slug",
name="uq_tool_connections_project_provider_integration_slug",
),
sa.ForeignKeyConstraint(
["project_id"],
["projects.id"],
ondelete="CASCADE",
),
sa.Index(
"ix_tool_connections_project_provider_integration",
"project_id",
"provider_key",
"integration_key",
),
)


def downgrade() -> None:
op.drop_table("tool_connections")
4 changes: 3 additions & 1 deletion api/oss/docker/Dockerfile.gh
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,9 @@ COPY --from=builder /app/entrypoints /app/entrypoints
COPY --from=builder /app/sdk /app/sdk

RUN set -eux; \
sed -i -e '$a\' /etc/cron.d/queries-cron
for cron_file in /etc/cron.d/queries-cron; do \
sed -i -e '$a\' "${cron_file}"; \
done

LABEL org.opencontainers.image.title="agenta-api" \
org.opencontainers.image.description="Agenta API GH runtime image" \
Expand Down
Empty file.
Loading