-
Notifications
You must be signed in to change notification settings - Fork 558
feat(agent): playground build kit (default agent config) #4926
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,47 @@ | ||||||||||||||||||
| """Read-only overlays attached to application inspect/fetch responses.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| from typing import Any, Dict, List | ||||||||||||||||||
|
|
||||||||||||||||||
| from agenta.sdk.agents.adapters.agenta_builtins import GETTING_STARTED_WITH_AGENTA_SLUG | ||||||||||||||||||
| from agenta.sdk.agents.platform.op_catalog import PLATFORM_OPS | ||||||||||||||||||
|
|
||||||||||||||||||
| from oss.src.core.workflows.static_catalog import ( | ||||||||||||||||||
| STATIC_SLUG_PREFIX, | ||||||||||||||||||
| StaticWorkflowCatalog, | ||||||||||||||||||
| _STATIC_WORKFLOWS, | ||||||||||||||||||
| ) | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def _workflow_embed(slug: str) -> Dict[str, Any]: | ||||||||||||||||||
| return {"@ag.embed": {"@ag.references": {"workflow": {"slug": slug}}}} | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def _reserved_static_tool_slugs() -> List[str]: | ||||||||||||||||||
| catalog = StaticWorkflowCatalog() | ||||||||||||||||||
| slugs: List[str] = [] | ||||||||||||||||||
| for slug in _STATIC_WORKFLOWS: | ||||||||||||||||||
| if not slug.startswith(STATIC_SLUG_PREFIX): | ||||||||||||||||||
| continue | ||||||||||||||||||
| revision = catalog.retrieve_revision(slug=slug) | ||||||||||||||||||
| if revision and revision.flags and revision.flags.is_skill: | ||||||||||||||||||
| continue | ||||||||||||||||||
| slugs.append(slug) | ||||||||||||||||||
|
Comment on lines
+25
to
+28
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win Tighten the reserved-workflow filter. This currently appends reserved slugs even when Suggested fix revision = catalog.retrieve_revision(slug=slug)
- if revision and revision.flags and revision.flags.is_skill:
+ if not revision or not revision.flags or revision.flags.is_skill:
continue
slugs.append(slug)📝 Committable suggestion
Suggested change
|
||||||||||||||||||
| return slugs | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def build_agent_template_overlay() -> Dict[str, Any]: | ||||||||||||||||||
| """Build the playground-only agent-template overlay from platform-owned sources.""" | ||||||||||||||||||
|
|
||||||||||||||||||
| return { | ||||||||||||||||||
| "tools": [ | ||||||||||||||||||
| *[{"type": "platform", "op": op_name} for op_name in PLATFORM_OPS], | ||||||||||||||||||
| *[_workflow_embed(slug) for slug in _reserved_static_tool_slugs()], | ||||||||||||||||||
| ], | ||||||||||||||||||
| "skills": [_workflow_embed(GETTING_STARTED_WITH_AGENTA_SLUG)], | ||||||||||||||||||
| "sandbox": { | ||||||||||||||||||
| "permissions": { | ||||||||||||||||||
| "write_files": "allow", | ||||||||||||||||||
| "execute_code": "allow", | ||||||||||||||||||
| } | ||||||||||||||||||
| }, | ||||||||||||||||||
| } | ||||||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -66,9 +66,12 @@ | |
| SimpleApplicationCreateRequest, | ||
| SimpleApplicationEditRequest, | ||
| SimpleApplicationQueryRequest, | ||
| SimpleApplicationAdditionalContext, | ||
| SimpleApplicationResponse, | ||
| SimpleApplicationsResponse, | ||
| PlaygroundBuildKitContext, | ||
| ) | ||
| from oss.src.apis.fastapi.applications.overlay import build_agent_template_overlay | ||
| from oss.src.apis.fastapi.applications.utils import ( | ||
| parse_application_variant_query_request_from_params, | ||
| parse_application_variant_query_request_from_body, | ||
|
|
@@ -1905,6 +1908,13 @@ async def fetch_simple_application( | |
| simple_application_response = SimpleApplicationResponse( | ||
| count=1 if simple_application else 0, | ||
| application=simple_application, | ||
| additional_context=SimpleApplicationAdditionalContext( | ||
| playground_build_kit=PlaygroundBuildKitContext( | ||
| agent_template_overlay=build_agent_template_overlay(), | ||
| ), | ||
| ) | ||
| if simple_application | ||
| else None, | ||
|
Comment on lines
+1911
to
+1917
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🩺 Stability & Availability | 🟠 Major | ⚡ Quick win Don’t let build-kit synthesis blank the whole fetch response.
Source: Path instructions |
||
| ) | ||
|
|
||
| return simple_application_response | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,116 @@ | ||
| from types import SimpleNamespace | ||
| from unittest.mock import AsyncMock | ||
| from uuid import uuid4 | ||
|
|
||
| import pytest | ||
|
|
||
| from agenta.sdk.agents.adapters.agenta_builtins import GETTING_STARTED_WITH_AGENTA_SLUG | ||
| from agenta.sdk.agents.platform.op_catalog import PLATFORM_OPS | ||
|
|
||
| from oss.src.apis.fastapi.applications import router as applications_router_module | ||
| from oss.src.apis.fastapi.applications.overlay import build_agent_template_overlay | ||
| from oss.src.apis.fastapi.applications.router import SimpleApplicationsRouter | ||
| from oss.src.core.applications.dtos import SimpleApplication | ||
| from oss.src.core.workflows.static_catalog import ( | ||
| STATIC_SLUG_PREFIX, | ||
| StaticWorkflowCatalog, | ||
| _STATIC_WORKFLOWS, | ||
| ) | ||
|
|
||
|
|
||
| def _embed_slug(entry: dict) -> str | None: | ||
| refs = entry.get("@ag.embed", {}).get("@ag.references", {}) | ||
| workflow = refs.get("workflow") or refs.get("workflow_revision") or {} | ||
| return workflow.get("slug") | ||
|
|
||
|
|
||
| def test_agent_template_overlay_contains_platform_ops_authoring_skill_and_permissions(): | ||
| overlay = build_agent_template_overlay() | ||
|
|
||
| platform_tools = [ | ||
| tool | ||
| for tool in overlay["tools"] | ||
| if isinstance(tool, dict) and tool.get("type") == "platform" | ||
| ] | ||
| assert platform_tools == [ | ||
| {"type": "platform", "op": op_name} for op_name in PLATFORM_OPS | ||
| ] | ||
|
|
||
| assert overlay["skills"] == [ | ||
| { | ||
| "@ag.embed": { | ||
| "@ag.references": { | ||
| "workflow": {"slug": GETTING_STARTED_WITH_AGENTA_SLUG} | ||
| } | ||
| } | ||
| } | ||
| ] | ||
| assert overlay["sandbox"] == { | ||
| "permissions": {"write_files": "allow", "execute_code": "allow"} | ||
| } | ||
|
|
||
|
|
||
| def test_agent_template_overlay_includes_reserved_static_workflow_tool_embeds(): | ||
| overlay = build_agent_template_overlay() | ||
| tool_embed_slugs = { | ||
| _embed_slug(tool) | ||
| for tool in overlay["tools"] | ||
| if isinstance(tool, dict) and "@ag.embed" in tool | ||
| } | ||
| catalog = StaticWorkflowCatalog() | ||
|
|
||
| expected_slugs = set() | ||
| for slug in _STATIC_WORKFLOWS: | ||
| revision = catalog.retrieve_revision(slug=slug) | ||
| if ( | ||
| slug.startswith(STATIC_SLUG_PREFIX) | ||
| and revision | ||
| and revision.flags | ||
| and not revision.flags.is_skill | ||
| ): | ||
| expected_slugs.add(slug) | ||
|
|
||
| assert tool_embed_slugs == expected_slugs | ||
|
|
||
|
|
||
| @pytest.mark.asyncio | ||
| async def test_fetch_simple_application_includes_build_kit_context(monkeypatch): | ||
| project_id = uuid4() | ||
| user_id = uuid4() | ||
| application_id = uuid4() | ||
|
|
||
| class DummySimpleApplicationsService: | ||
| applications_service = object() | ||
|
|
||
| async def fetch(self, **kwargs): | ||
| assert kwargs["project_id"] == project_id | ||
| assert kwargs["application_id"] == application_id | ||
| return SimpleApplication(id=application_id, slug="agent") | ||
|
|
||
| monkeypatch.setattr( | ||
| applications_router_module, | ||
| "check_action_access", | ||
| AsyncMock(return_value=True), | ||
| raising=False, | ||
| ) | ||
|
|
||
| router = SimpleApplicationsRouter( | ||
| simple_applications_service=DummySimpleApplicationsService() | ||
| ) | ||
| request = SimpleNamespace( | ||
| state=SimpleNamespace(project_id=str(project_id), user_id=str(user_id)) | ||
| ) | ||
|
|
||
| response = await router.fetch_simple_application( | ||
| request, | ||
| application_id=application_id, | ||
| ) | ||
|
|
||
| overlay = ( | ||
| response.additional_context.playground_build_kit.agent_template_overlay | ||
| if response.additional_context | ||
| and response.additional_context.playground_build_kit | ||
| else None | ||
| ) | ||
| assert response.application is not None | ||
| assert overlay == build_agent_template_overlay() |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| # Default agent config (playground build kit) | ||
|
|
||
| The platform tools, the Agenta authoring skill, and the build permissions are a playground build | ||
| kit, modeled as an **agent-template overlay**: a partial agent template the platform serves | ||
| read-only on the inspect response. The frontend merges the overlay onto `parameters.agent` on a | ||
| playground run so the assistant can build and improve the agent, and leaves it out on commit. The | ||
| agent service stays dumb: it runs the template it receives. The published agent ships with only | ||
| the user's own config. | ||
|
|
||
| ## Files | ||
|
|
||
| - `design.md`: the design. The overlay model (the frontend merges, the backend serves, the | ||
| service runs as-is), the overlay shape (a partial `parameters.agent`, skills as `@ag.embed`), | ||
| where it lives on the inspect response (`additional_context.playground_build_kit.agent_template_overlay`), the | ||
| merge semantics, the frontend run-and-commit behavior, the advanced-drawer UI, what the backend | ||
| does not do, the interface notes, and the change set. | ||
| - `research.md`: the code trace behind the design. Where the default comes from, how platform | ||
| tools and skills are shaped, the run path, and the commit path. | ||
| - `status.md`: where the design stands, the contract for the frontend, open questions, and | ||
| coordination. | ||
|
|
||
| ## In one line | ||
|
|
||
| The frontend reads a read-only `agent_template_overlay` from the inspect response, merges its | ||
| tools, skill, and sandbox permissions onto `parameters.agent` on a kit-on run, and leaves them out | ||
| on commit. The backend only serves the overlay. The service never knows it exists. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift
Model
agent_template_overlayexplicitly instead of usingdict.This is now a backend/frontend contract, but
Optional[dict]leaves the OpenAPI schema and runtime validation opaque. Please promote the overlay shape into concrete Pydantic models (or typed submodels for tools, skills, and sandbox) so downstream clients get a stable contract. As per coding guidelines, "Define explicit request and response models inmodels.py."Source: Coding guidelines