-
Notifications
You must be signed in to change notification settings - Fork 43
feat(agentex): add register-build endpoint and BUILD_ONLY agent status #256
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
07afdac
d684b2f
d0077a7
646ad01
ec31b2d
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,33 @@ | ||
| """add build_only agent status | ||
|
|
||
| Revision ID: c7a1b2d3e4f5 | ||
| Revises: 6c942325c828 | ||
| Create Date: 2026-05-29 12:00:00.000000 | ||
|
|
||
| """ | ||
| from typing import Sequence, Union | ||
|
|
||
| from alembic import op | ||
| import sqlalchemy as sa | ||
|
|
||
|
|
||
| # revision identifiers, used by Alembic. | ||
| revision: str = 'c7a1b2d3e4f5' | ||
| down_revision: Union[str, None] = '6c942325c828' | ||
| branch_labels: Union[str, Sequence[str], None] = None | ||
| depends_on: Union[str, Sequence[str], None] = None | ||
|
|
||
|
|
||
| def upgrade() -> None: | ||
| # ### commands auto generated by Alembic - please adjust! ### | ||
| op.execute(""" | ||
| ALTER TYPE agentstatus ADD VALUE IF NOT EXISTS 'BUILD_ONLY'; | ||
| """) | ||
| # ### end Alembic commands ### | ||
|
|
||
|
|
||
| def downgrade() -> None: | ||
| # Postgres does not support removing a value from an enum type, so there is | ||
| # nothing to do on downgrade (mirrors the add_unhealthy_status migration). | ||
| # ### end Alembic commands ### | ||
| pass |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -167,6 +167,55 @@ async def register_agent( | |
| await self.ensure_healthcheck_workflow(agent) | ||
| return agent | ||
|
|
||
| async def register_build( | ||
| self, | ||
| name: str, | ||
| description: str, | ||
| registration_metadata: dict[str, Any] | None = None, | ||
| agent_input_type: AgentInputType | None = None, | ||
| ) -> AgentEntity: | ||
| """ | ||
| Create an agent row for a build, before any deployment exists. | ||
|
|
||
| Unlike register_agent, this does NOT populate acp_url (there is no | ||
| running pod yet) and leaves the agent in BUILD_ONLY status so it can be | ||
| permissioned/shared prior to deploy. Deploy-time registration later | ||
| flips the agent to READY and sets the acp_url. | ||
|
|
||
| Idempotent: if an agent with the same name already exists, it is | ||
| returned unchanged so that re-building an existing agent never clobbers | ||
| a live deployment's status or acp_url. | ||
| """ | ||
| try: | ||
| existing = await self.agent_repo.get(name=name) | ||
|
Collaborator
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. only nit is what happens here for soft-deleted agents, should they stay deleted or do we fall through to the code below that 'resurrects' them as build-only?
Contributor
Author
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. I think it makes sense to ressurect |
||
| logger.info( | ||
| f"Agent {name} already exists, returning existing agent for build" | ||
| ) | ||
| return existing | ||
|
smoreinis marked this conversation as resolved.
|
||
| except ItemDoesNotExist: | ||
| logger.info(f"Agent {name} not found, creating build-only agent") | ||
|
|
||
| agent = AgentEntity( | ||
| id=orm_id(), | ||
| name=name, | ||
| description=description, | ||
| status=AgentStatus.BUILD_ONLY, | ||
| status_reason="Agent build registered; not yet deployed.", | ||
| acp_url=None, | ||
| registration_metadata=registration_metadata, | ||
| agent_input_type=agent_input_type, | ||
| ) | ||
| # If multiple builds for the same new agent race, the first wins and the | ||
| # rest re-fetch the persisted row instead of erroring. | ||
| try: | ||
| agent = await self.agent_repo.create(item=agent) | ||
| except DuplicateItemError: | ||
| logger.info( | ||
| f"Agent {name} was likely created in parallel, returning existing" | ||
| ) | ||
| agent = await self.agent_repo.get(name=name) | ||
| return agent | ||
|
|
||
| async def complete_deployment_registration( | ||
| self, | ||
| agent: AgentEntity, | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.