Skip to content

Commit 1d53e80

Browse files
docs: clarify that task name is optional and get-or-create by name (#269)
Documents the task identity contract in the places assistants and clients already read: a task is identified by a UUID id, while name is optional (nullable) and globally unique when set. Because task/create is get-or-create keyed on name, reusing a name returns the existing task (with its history) rather than creating a new one — so omit name, or make it unique, when each call should produce a fresh task. Updates CLAUDE.md, the Task concepts doc, the CreateTaskRequest.name field description (surfaced via OpenAPI/SDK), and the _get_or_create_task docstring. <!-- greptile_comment --> <h3>Greptile Summary</h3> This is a documentation-only PR that clarifies the task identity contract across all the places where developers and assistants discover it. The core behavior — that `task/create` is a get-or-create keyed on `name`, that passing `params` on a name-matched task overwrites them, and that `task_metadata` is creation-only — is accurately reflected in all updated files. - **CLAUDE.md** receives a concise one-sentence expansion of the Tasks bullet point, capturing the UUID/name distinction and get-or-create semantics. - **`agentex/docs/docs/concepts/task.md`** gains a new \"Task Identity\" section with a callout warning that matches the actual behavior verified in `_get_or_create_task`. - **`CreateTaskRequest` schema** (`agents_rpc.py` + `openapi.yaml`) and the `_get_or_create_task` docstring are updated with matching, accurate descriptions of the mutation side-effect when `params` is provided on an existing task. <details><summary><h3>Confidence Score: 5/5</h3></summary> Documentation-only change with no logic modifications; all descriptions were verified against the implementation. Every claim in the updated docs — get-or-create keyed on name, params overwrite on name-match, task_metadata creation-only — was confirmed against the actual _get_or_create_task implementation. The descriptions in CLAUDE.md, task.md, openapi.yaml, agents_rpc.py, and the docstring are mutually consistent. No code paths were altered. No files require special attention. </details> <h3>Important Files Changed</h3> | Filename | Overview | |----------|----------| | CLAUDE.md | One-line Tasks bullet expanded with accurate id/name/get-or-create description; no logic changes. | | agentex/docs/docs/concepts/task.md | New 'Task Identity' section added with accurate descriptions of id, name uniqueness, get-or-create behavior, params overwrite, and task_metadata creation-only semantics — all verified against the implementation. | | agentex/openapi.yaml | name and params field descriptions updated to reflect get-or-create semantics; matches agents_rpc.py descriptions exactly. | | agentex/src/api/schemas/agents_rpc.py | CreateTaskRequest.name and .params Field descriptions expanded; consistent with openapi.yaml and the docstring. | | agentex/src/domain/use_cases/agents_acp_use_case.py | _get_or_create_task docstring updated to accurately describe the params-overwrite mutation path and task_metadata creation-only behavior; verified to match the code exactly. | </details> <details><summary><h3>Flowchart</h3></summary> ```mermaid %%{init: {'theme': 'neutral'}}%% flowchart TD A[task/create called] --> B{task_id provided?} B -- Yes --> C[Fetch task by ID] B -- No --> D{task_name provided?} D -- Yes --> E{Name exists?} D -- No --> F[Create new task\nname=None] E -- No --> G[Create new task\nwith name] E -- Yes --> H{task_params provided?} H -- No --> I[Return existing task\nas-is] H -- Yes --> J{params differ?} J -- No --> I J -- Yes --> K[Overwrite task.params\nthen return task] C --> H F --> L[task_metadata applied] G --> L L --> M[Return new task] ``` </details> <sub>Reviews (3): Last reviewed commit: ["docs: plainer wording for get-or-create ..."](0943b4c) | [Re-trigger Greptile](https://app.greptile.com/api/retrigger?id=35384849)</sub> <!-- /greptile_comment --> --------- Co-authored-by: Cursor <cursoragent@cursor.com>
1 parent 8b6d69d commit 1d53e80

5 files changed

Lines changed: 46 additions & 5 deletions

File tree

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -261,7 +261,7 @@ Tests are organized by type and use different strategies:
261261
### Key Domain Concepts
262262

263263
- **Agents**: Autonomous entities that execute tasks, managed via ACP protocol
264-
- **Tasks**: Work units with lifecycle states (pending → running → completed/failed)
264+
- **Tasks**: Work units with lifecycle states (pending → running → completed/failed). Identified by a UUID `id`; the human-readable `name` is **optional** (nullable) and, when set, globally unique. `task/create` is get-or-create keyed on `name`, so reusing an existing name returns that task with its prior history instead of creating a new one — omit `name` (or make it unique) whenever each call should produce a fresh task.
265265
- **Messages**: Communication between system and agents (stored in MongoDB)
266266
- **Spans**: Execution traces for observability (OpenTelemetry-style)
267267
- **Events**: Domain events for async communication

agentex/docs/docs/concepts/task.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,21 @@ A **Task** represents a stateful conversation or workflow session. It's the top-
1313

1414
Think of a task like a chat session, customer support ticket, or workflow execution that can span multiple interactions over time.
1515

16+
## Task Identity: `id` and `name`
17+
18+
Every task has two identifiers:
19+
20+
- **`id`** — a UUID assigned by Agentex. Always present and always unique.
21+
- **`name`** — an **optional**, human-readable label. It is nullable, but when you do set it, it must be **globally unique** (the uniqueness is platform-wide, not per-agent).
22+
23+
`task/create` is **get-or-create keyed on `name`**:
24+
25+
- If you **omit `name`** (or pass `null`), Agentex always creates a brand-new task. This is the right default when each call should be independent — for example, an orchestrator delegating a fresh sub-task on every invocation.
26+
- If you **provide a `name` that already exists**, Agentex returns the **existing** task — including its prior message history — rather than creating a new one. The incoming `params` overwrite the existing row, while `task_metadata` is only applied at creation time.
27+
28+
!!! warning "Reusing a name returns the old task"
29+
Because `task/create` reuses a task by name, sending the same `name` twice does **not** give you two tasks — the second call resolves to the first task with its existing conversation. If you want a new task every time, leave `name` unset or append a unique suffix (e.g. a UUID). Use `task_metadata.display_name` or `params` for a human-facing label rather than relying on `name`.
30+
1631
## Task Relationships
1732

1833
!!! info "For Detailed Implementation"

agentex/openapi.yaml

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4503,14 +4503,19 @@ components:
45034503
- type: string
45044504
- type: 'null'
45054505
title: Name
4506-
description: The name of the task to create
4506+
description: 'Optional human-readable name for the task. When set it must
4507+
be globally unique. task/create is get-or-create by name: reusing an existing
4508+
name returns the existing task (with its prior history) instead of creating
4509+
a new one, so omit name (or make it unique, e.g. by appending a UUID)
4510+
whenever each call should produce a fresh task.'
45074511
params:
45084512
anyOf:
45094513
- additionalProperties: true
45104514
type: object
45114515
- type: 'null'
45124516
title: Params
4513-
description: The parameters for the task
4517+
description: The parameters for the task. On a get-or-create by name, providing
4518+
params overwrites the existing task's params (it is not a pure read).
45144519
task_metadata:
45154520
anyOf:
45164521
- additionalProperties: true

agentex/src/api/schemas/agents_rpc.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,22 @@ class AgentRPCMethod(str, Enum):
2222

2323

2424
class CreateTaskRequest(BaseModel):
25-
name: str | None = Field(None, description="The name of the task to create")
25+
name: str | None = Field(
26+
None,
27+
description=(
28+
"Optional human-readable name for the task. When set it must be globally "
29+
"unique. task/create is get-or-create by name: reusing an existing name "
30+
"returns the existing task (with its prior history) instead of creating a "
31+
"new one, so omit name (or make it unique, e.g. by appending a UUID) "
32+
"whenever each call should produce a fresh task."
33+
),
34+
)
2635
params: dict[str, Any] | None = Field(
27-
None, description="The parameters for the task"
36+
None,
37+
description=(
38+
"The parameters for the task. On a get-or-create by name, providing params "
39+
"overwrites the existing task's params (it is not a pure read)."
40+
),
2841
)
2942
task_metadata: dict[str, Any] | None = Field(
3043
None,

agentex/src/domain/use_cases/agents_acp_use_case.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,14 @@ async def _get_or_create_task(
271271
) -> TaskEntity:
272272
"""Return the existing task if *task_id* is provided, otherwise create a new one.
273273
274+
Lookup is by id or name. A non-null *task_name* must be globally unique: if it
275+
matches an existing task, that task is returned (get-or-create) with its prior
276+
history rather than a fresh one. This branch can also mutate the existing task:
277+
when *task_params* is provided and differs from the stored value, it overwrites
278+
the existing task's params before the task is returned (*task_metadata* is only
279+
applied at creation time). When neither an id nor a matching name is given, a
280+
brand-new task is created (name may be None).
281+
274282
Note: Only one of task_id or task_name should be provided (enforced by validators).
275283
"""
276284

0 commit comments

Comments
 (0)