Skip to content

[Question] Is 'final' property necessary given terminal states? Can TaskArtifactUpdateEvent come after terminal state? #1232

@darrelmiller

Description

@darrelmiller

Question

Is the final property in TaskStatusUpdateEvent necessary considering that tasks now have explicit terminal states?

Current State

TaskStatusUpdateEvent Definition

message TaskStatusUpdateEvent {
  string task_id = 1 [(google.api.field_behavior) = REQUIRED];
  string context_id = 2 [(google.api.field_behavior) = REQUIRED];
  TaskStatus status = 3 [(google.api.field_behavior) = REQUIRED];
  // If true, this is the final event in the stream for this interaction.
  bool final = 4 [(google.api.field_behavior) = REQUIRED];
  google.protobuf.Struct metadata = 5;
}

TaskState Enum with Terminal States

enum TaskState {
  TASK_STATE_COMPLETED = 3;   // Terminal state
  TASK_STATE_FAILED = 4;       // Terminal state
  TASK_STATE_CANCELLED = 5;    // Terminal state
  TASK_STATE_REJECTED = 7;     // Terminal state
  // ... non-terminal states
}

The Question

The final field appears redundant because:

  1. Terminal states are explicit: COMPLETED, FAILED, CANCELLED, and REJECTED are clearly marked as terminal states in the enum
  2. Derivable information: Clients can determine if an event is final by checking if status.state is a terminal state
  3. Specification requirement: The spec states "The stream MUST close when the task reaches a terminal state"

So why have a separate final boolean when this information is already encoded in the TaskState?

Related Question: Can TaskArtifactUpdateEvent Come After Terminal State?

This leads to an important related question: Can a TaskArtifactUpdateEvent be sent after a task reaches a terminal state?

Scenario 1: Strict Interpretation

If final = true means "absolutely no more events", then:

  • Once TaskStatusUpdateEvent with terminal state is sent, no more events (including artifacts) can follow
  • The final flag provides an explicit signal to close the stream

Scenario 2: Flexible Interpretation

If terminal states don't necessarily mean "stream closed", then:

  • Agent could send TaskStatusUpdateEvent with COMPLETED state
  • Then follow with additional TaskArtifactUpdateEvent messages for late-arriving artifacts
  • The final flag would signal when the stream truly ends

Current Specification Ambiguity

The specification states:

"The stream MUST close when the task reaches a terminal state"

But does this mean:

  • Option A: Stream closes immediately upon sending status with terminal state
  • Option B: Stream can remain open for artifact updates even after terminal state
  • Option C: The final flag explicitly controls stream closure independent of task state

Use Cases to Consider

Use Case 1: Slow Artifact Generation

1. Agent sends TaskStatusUpdateEvent: state=WORKING, final=false
2. Agent sends TaskStatusUpdateEvent: state=COMPLETED, final=false (task done but artifacts still uploading)
3. Agent sends TaskArtifactUpdateEvent: artifact_id="report1"
4. Agent sends TaskArtifactUpdateEvent: artifact_id="report2"  
5. Agent sends TaskStatusUpdateEvent: state=COMPLETED, final=true (truly done)

Is this valid? Or should artifacts come before the terminal state?

Use Case 2: Cancellation with Partial Results

1. Agent sends TaskStatusUpdateEvent: state=WORKING
2. Agent sends TaskStatusUpdateEvent: state=CANCELLED, final=false
3. Agent sends TaskArtifactUpdateEvent: artifact_id="partial_results" (what was completed before cancel)
4. Agent sends TaskStatusUpdateEvent: state=CANCELLED, final=true

Should partial results come before or after terminal state?

Questions for Clarification

  1. Is final truly necessary, or can clients simply derive it from terminal states?

  2. Can events be sent after terminal state? Specifically, can TaskArtifactUpdateEvent messages arrive after a TaskStatusUpdateEvent with a terminal state?

  3. What is the intended stream lifecycle?

    • Must all artifacts be sent before terminal state?
    • Can status be updated to terminal, then artifacts added, then "truly final" signal?
    • Is final meant to handle edge cases not covered by terminal states?
  4. Should the specification be more explicit about:

    • The ordering requirements between status updates and artifact updates
    • Whether terminal states implicitly close streams or if final is the definitive signal
    • What clients should do if they receive artifacts after a terminal state

Recommendation

The specification should clarify:

  1. The precise relationship between terminal states and the final flag
  2. Whether final is redundant or serves a specific purpose
  3. The allowed ordering of status updates and artifact updates
  4. Stream closure semantics with concrete examples

This would help implementers understand the event lifecycle and avoid ambiguous edge cases.

Related Issues

Metadata

Metadata

Assignees

Labels

P1Priority for TSC ReviewTSC ReviewTo be reviewed by the Technical Steering Committee

Type

No type

Projects

Status

In progress

Relationships

None yet

Development

No branches or pull requests

Issue actions