Skip to content

Mc/golden agent tuneagent#309

Open
michael-chou359 wants to merge 7 commits into
mainfrom
mc/golden-agent-tuneagent
Open

Mc/golden agent tuneagent#309
michael-chou359 wants to merge 7 commits into
mainfrom
mc/golden-agent-tuneagent

Conversation

@michael-chou359

@michael-chou359 michael-chou359 commented Jun 15, 2026

Copy link
Copy Markdown
Contributor

Signal Endpoint

  • created a signal endpoint to send task configs to agentex on clicking the "save" button in tune agent which will trigger workflow signal in agent worker. Full E2E flow was tested and proof included in PR but only code changes were the POST request endpoint.

Before state:

image

After triggering post request, params successfully updated:

Screenshot 2026-06-11 at 4 44 43 PM

On agentex side, DB updated:

Screenshot 2026-06-11 at 4 46 11 PM

config updated signal also triggered:

image

worker updated:

image

Greptile Summary

This PR adds a merge_params field to the PATCH /tasks/{id} endpoint so that callers can atomically shallow-merge a config patch into the task's params JSONB column without a read-modify-write race. The repository layer uses a single UPDATE … RETURNING with Postgres' || JSONB operator, which is the correct approach.

  • Schema & OpenAPI (tasks.py, openapi.yaml): merge_params: dict[str, Any] | None added to UpdateTaskRequest with correct nullability and documentation.
  • Repository (task_repository.py): merge_params uses COALESCE(params, '{}'::jsonb) || cast(patch, JSONB) in a single atomic statement — no race with concurrent writers.
  • Route (routes/tasks.py): the by-id handler correctly forwards merge_params, but the by-name handler (update_task_by_name) was not updated and silently drops the field.

Confidence Score: 4/5

The by-id PATCH path works correctly, but the by-name PUT endpoint silently drops merge_params on any request that supplies it.

The by-name handler (update_task_by_name) was not updated to forward merge_params to the use case, so callers using that endpoint will have the field silently ignored. The core repository logic (atomic JSONB merge) is sound, but the routing gap means the feature is incomplete and could cause silent data-loss for any consumer relying on the by-name path.

agentex/src/api/routes/tasks.py — the by-name handler needs merge_params forwarded.

Important Files Changed

Filename Overview
agentex/src/api/routes/tasks.py Wires merge_params into the by-id PATCH handler correctly, but the by-name PUT handler was not updated and silently drops merge_params.
agentex/src/api/schemas/tasks.py Adds merge_params field to UpdateTaskRequest with correct typing and clear docstring.
agentex/src/domain/repositories/task_repository.py Adds merge_params atomic JSONB shallow-merge using a single UPDATE…RETURNING statement with COALESCE guard; clean implementation.
agentex/src/domain/services/task_service.py Adds merge_task_params thin delegation to the repository; does not publish a task_updated stream event (already flagged in a prior review thread).
agentex/src/domain/use_cases/tasks_use_case.py Orchestrates merge_params and task_metadata updates; known issues with field ordering when both are supplied and silent stale-entity return are covered by prior threads.
agentex/openapi.yaml Adds merge_params field to the UpdateTaskRequest schema component; matches the Python schema definition.

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Client
    participant Router as tasks.py router
    participant UseCase as TasksUseCase
    participant Service as AgentTaskService
    participant Repo as TaskRepository
    participant DB as Postgres

    Client->>Router: "PATCH /tasks/{id} {merge_params: {...}}"
    Router->>UseCase: "update_mutable_fields_on_task(id, merge_params=...)"
    UseCase->>Service: get_task(id)
    Service->>Repo: get(id)
    Repo->>DB: SELECT task
    DB-->>Repo: TaskORM
    Repo-->>Service: TaskEntity
    Service-->>UseCase: TaskEntity

    alt merge_params provided
        UseCase->>Service: merge_task_params(task_id, patch)
        Service->>Repo: merge_params(task_id, patch)
        Repo->>DB: "UPDATE tasks SET params = COALESCE(params,'{}')::jsonb || patch::jsonb WHERE id=? RETURNING *"
        DB-->>Repo: updated TaskORM
        Repo-->>Service: TaskEntity (merged)
        Service-->>UseCase: TaskEntity (merged)
        Note over UseCase: No task_updated stream event emitted
    end

    alt task_metadata provided
        UseCase->>Service: update_task(task_entity)
        Service->>Repo: update(task)
        Repo->>DB: "UPDATE tasks SET ... WHERE id=?"
        DB-->>Repo: updated TaskORM
        Repo-->>Service: TaskEntity
        Service->>Service: publish task_updated to stream
        Service-->>UseCase: TaskEntity
    end

    UseCase-->>Router: TaskEntity
    Router-->>Client: Task (200 OK)
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Client
    participant Router as tasks.py router
    participant UseCase as TasksUseCase
    participant Service as AgentTaskService
    participant Repo as TaskRepository
    participant DB as Postgres

    Client->>Router: "PATCH /tasks/{id} {merge_params: {...}}"
    Router->>UseCase: "update_mutable_fields_on_task(id, merge_params=...)"
    UseCase->>Service: get_task(id)
    Service->>Repo: get(id)
    Repo->>DB: SELECT task
    DB-->>Repo: TaskORM
    Repo-->>Service: TaskEntity
    Service-->>UseCase: TaskEntity

    alt merge_params provided
        UseCase->>Service: merge_task_params(task_id, patch)
        Service->>Repo: merge_params(task_id, patch)
        Repo->>DB: "UPDATE tasks SET params = COALESCE(params,'{}')::jsonb || patch::jsonb WHERE id=? RETURNING *"
        DB-->>Repo: updated TaskORM
        Repo-->>Service: TaskEntity (merged)
        Service-->>UseCase: TaskEntity (merged)
        Note over UseCase: No task_updated stream event emitted
    end

    alt task_metadata provided
        UseCase->>Service: update_task(task_entity)
        Service->>Repo: update(task)
        Repo->>DB: "UPDATE tasks SET ... WHERE id=?"
        DB-->>Repo: updated TaskORM
        Repo-->>Service: TaskEntity
        Service->>Service: publish task_updated to stream
        Service-->>UseCase: TaskEntity
    end

    UseCase-->>Router: TaskEntity
    Router-->>Client: Task (200 OK)
Loading

Comments Outside Diff (1)

  1. agentex/src/api/routes/tasks.py, line 216-218 (link)

    P1 The update_task_by_name handler does not forward merge_params to the use case, so any caller that uses the by-name endpoint and supplies merge_params will silently have the field dropped. The by-id handler (a few lines above) correctly passes it, but the by-name handler was not updated in this PR.

    Prompt To Fix With AI
    This is a comment left during a code review.
    Path: agentex/src/api/routes/tasks.py
    Line: 216-218
    
    Comment:
    The `update_task_by_name` handler does not forward `merge_params` to the use case, so any caller that uses the by-name endpoint and supplies `merge_params` will silently have the field dropped. The by-id handler (a few lines above) correctly passes it, but the by-name handler was not updated in this PR.
    
    
    
    How can I resolve this? If you propose a fix, please make it concise.

    Fix in Cursor Fix in Claude Code Fix in Codex

Fix All in Cursor Fix All in Claude Code Fix All in Codex

Prompt To Fix All With AI
Fix the following 1 code review issue. Work through them one at a time, proposing concise fixes.

---

### Issue 1 of 1
agentex/src/api/routes/tasks.py:216-218
The `update_task_by_name` handler does not forward `merge_params` to the use case, so any caller that uses the by-name endpoint and supplies `merge_params` will silently have the field dropped. The by-id handler (a few lines above) correctly passes it, but the by-name handler was not updated in this PR.

```suggestion
    updated_task_entity = await task_use_case.update_mutable_fields_on_task(
        name=task_name, task_metadata=request.task_metadata, merge_params=request.merge_params
    )
```

Reviews (4): Last reviewed commit: "comments" | Re-trigger Greptile

@michael-chou359 michael-chou359 requested a review from a team as a code owner June 15, 2026 21:33
@github-actions

github-actions Bot commented Jun 15, 2026

Copy link
Copy Markdown

✱ Stainless preview builds

This PR will update the agentex-sdk SDKs with the following commit messages.

openapi

feat(api): add signal method to tasks

python

chore(internal): regenerate SDK with no functional changes

typescript

chore(internal): regenerate SDK with no functional changes

Edit this comment to update them. They will appear in their respective SDK's changelogs.

agentex-sdk-openapi studio · code · diff

Your SDK build had at least one "note" diagnostic, but this did not represent a regression.
generate ✅

agentex-sdk-typescript studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ✅ (prev: build ⏭️) → lint ✅ (prev: lint ⏭️) → test ✅

npm install https://pkg.stainless.com/s/agentex-sdk-typescript/460ba704eda949903801790df88c602eeeae1c74/dist.tar.gz
agentex-sdk-python studio · code · diff

Your SDK build had at least one "warning" diagnostic, but this did not represent a regression.
generate ⚠️build ✅ (prev: build ⏭️) → lint ✅ (prev: lint ⏭️) → test ✅

pip install https://pkg.stainless.com/s/agentex-sdk-python/6804c8dcc536e804dfc72e36e3a8d12a4521d70a/agentex_client-0.13.1-py3-none-any.whl

This comment is auto-generated by GitHub Actions and is automatically kept up to date as you push.
If you push custom code to the preview branch, re-run this workflow to update the comment.
Last updated: 2026-06-18 23:26:13 UTC

Comment thread agentex/src/domain/use_cases/tasks_use_case.py Outdated
Comment thread agentex/src/domain/use_cases/tasks_use_case.py
Comment on lines +245 to +253
async def merge_task_params(self, task_id: str, patch: dict) -> TaskEntity | None:
"""Atomically merge ``patch`` into ``tasks.params``. Returns the
updated entity, or ``None`` if no task with ``task_id`` exists.

Used by live-config flows (e.g. ConfigModal Save → signal +
DB persistence) so the persisted task row reflects the new
agent config without waiting for the next task to be created.
"""
return await self.task_repository.merge_params(task_id, patch)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 merge_task_params skips the task_updated stream event

update_task always publishes a task_updated event to the task event stream after writing to the DB. merge_task_params only calls task_repository.merge_params and returns, with no equivalent stream publish. When a caller patches only merge_params (no task_metadata), the if task_metadata is not None branch in the use case is skipped, so update_task is never reached and no event is ever emitted. Any consumer watching the stream — including the Temporal worker the PR description says must receive a signal — will not be notified of the config change.

Prompt To Fix With AI
This is a comment left during a code review.
Path: agentex/src/domain/services/task_service.py
Line: 245-253

Comment:
**`merge_task_params` skips the `task_updated` stream event**

`update_task` always publishes a `task_updated` event to the task event stream after writing to the DB. `merge_task_params` only calls `task_repository.merge_params` and returns, with no equivalent stream publish. When a caller patches only `merge_params` (no `task_metadata`), the `if task_metadata is not None` branch in the use case is skipped, so `update_task` is never reached and no event is ever emitted. Any consumer watching the stream — including the Temporal worker the PR description says must receive a signal — will not be notified of the config change.

How can I resolve this? If you propose a fix, please make it concise.

Fix in Cursor Fix in Claude Code Fix in Codex

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant