Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions schema/schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,20 @@
],
"description": "The input specification for a command."
},
"AgentMessageClear": {
"description": "Clear the accumulated streamed content for the current agent message. Subsequent agent_message_chunk updates start appending from empty.",
"properties": {
"_meta": {
"additionalProperties": true,
"description": "The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)",
"type": [
"object",
"null"
]
}
},
"type": "object"
},
"AvailableCommandsUpdate": {
"description": "Available commands are ready or have changed",
"properties": {
Expand Down Expand Up @@ -3767,6 +3781,24 @@
"sessionUpdate"
],
"type": "object"
},
{
"allOf": [
{
"$ref": "#/$defs/AgentMessageClear"
}
],
"description": "Clear the accumulated streamed content for the current agent message. Subsequent agent_message_chunk updates start appending from empty.",
"properties": {
"sessionUpdate": {
"const": "agent_message_clear",
"type": "string"
}
},
"required": [
"sessionUpdate"
],
"type": "object"
}
]
},
Expand Down
1 change: 1 addition & 0 deletions scripts/gen_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
"SessionUpdate9": "ConfigOptionUpdate",
"SessionUpdate10": "SessionInfoUpdate",
"SessionUpdate11": "UsageUpdate",
"SessionUpdate12": "AgentMessageClear",
"ToolCallContent1": "ContentToolCallContent",
"ToolCallContent2": "FileEditToolCallContent",
"ToolCallContent3": "TerminalToolCallContent",
Expand Down
1 change: 1 addition & 0 deletions src/acp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
)
from .helpers import (
audio_block,
clear_agent_message,
embedded_blob_resource,
embedded_text_resource,
image_block,
Expand Down
5 changes: 5 additions & 0 deletions src/acp/contrib/session_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

from ..schema import (
AgentMessageChunk,
AgentMessageClear,
AgentPlanUpdate,
AgentThoughtChunk,
AvailableCommand,
Expand Down Expand Up @@ -238,6 +239,10 @@ def _apply_update(self, update: Any) -> None:
self._agent_messages.append(update.model_copy(deep=True))
return

if isinstance(update, AgentMessageClear):
self._agent_messages.clear()
return

if isinstance(update, AgentThoughtChunk):
self._agent_thoughts.append(update.model_copy(deep=True))

Expand Down
11 changes: 11 additions & 0 deletions src/acp/helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

from .schema import (
AgentMessageChunk,
AgentMessageClear,
AgentPlanUpdate,
AgentThoughtChunk,
AudioContentBlock,
Expand Down Expand Up @@ -39,6 +40,7 @@

SessionUpdate = (
AgentMessageChunk
| AgentMessageClear
| AgentPlanUpdate
| AgentThoughtChunk
| AvailableCommandsUpdate
Expand All @@ -53,6 +55,7 @@

__all__ = [
"audio_block",
"clear_agent_message",
"embedded_blob_resource",
"embedded_text_resource",
"image_block",
Expand Down Expand Up @@ -167,6 +170,14 @@ def update_agent_message_text(text: str) -> AgentMessageChunk:
return update_agent_message(text_block(text))


def clear_agent_message() -> AgentMessageClear:
"""Clear the accumulated streamed content for the current agent message.

Subsequent agent_message_chunk updates will start appending from empty.
"""
return AgentMessageClear(session_update="agent_message_clear")


def update_agent_thought(content: ContentBlock) -> AgentThoughtChunk:
return AgentThoughtChunk(session_update="agent_thought_chunk", content=content)

Expand Down
14 changes: 14 additions & 0 deletions src/acp/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -2238,6 +2238,19 @@ class AgentThoughtChunk(ContentChunk):
session_update: Annotated[Literal["agent_thought_chunk"], Field(alias="sessionUpdate")]


class AgentMessageClear(BaseModel):
# Clear the accumulated streamed content for the current agent message.
# Subsequent agent_message_chunk updates start appending from empty.
field_meta: Annotated[
Optional[Dict[str, Any]],
Field(
alias="_meta",
description="The _meta property is reserved by ACP to allow clients and agents to attach additional\nmetadata to their interactions. Implementations MUST NOT make assumptions about values at\nthese keys.\n\nSee protocol docs: [Extensibility](https://agentclientprotocol.com/protocol/extensibility)",
),
] = None
session_update: Annotated[Literal["agent_message_clear"], Field(alias="sessionUpdate")]


class ClientRequest(BaseModel):
# JSON RPC Request Id
#
Expand Down Expand Up @@ -2831,6 +2844,7 @@ class SessionNotification(BaseModel):
ConfigOptionUpdate,
SessionInfoUpdate,
UsageUpdate,
AgentMessageClear,
],
Field(description="The actual update content.", discriminator="session_update"),
]
Expand Down
14 changes: 14 additions & 0 deletions tests/contrib/test_contrib_session_state.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import pytest

from acp import clear_agent_message
from acp.contrib.session_state import SessionAccumulator
from acp.schema import (
AgentMessageChunk,
Expand Down Expand Up @@ -107,6 +108,19 @@ def test_session_accumulator_tracks_messages_and_commands():
assert agent_content.text == "Hi!"


def test_session_accumulator_agent_message_clear_clears_accumulated_chunks():
acc = SessionAccumulator()
acc.apply(notification("s", AgentMessageChunk(session_update="agent_message_chunk", content=TextContentBlock(type="text", text="Thinking..."))))
acc.apply(notification("s", AgentMessageChunk(session_update="agent_message_chunk", content=TextContentBlock(type="text", text=" draft"))))
assert len(acc.snapshot().agent_messages) == 2
acc.apply(notification("s", clear_agent_message()))
assert len(acc.snapshot().agent_messages) == 0
acc.apply(notification("s", AgentMessageChunk(session_update="agent_message_chunk", content=TextContentBlock(type="text", text="Final result."))))
snapshot = acc.snapshot()
assert len(snapshot.agent_messages) == 1
assert snapshot.agent_messages[0].content.text == "Final result."


def test_session_accumulator_auto_resets_on_new_session():
acc = SessionAccumulator()
acc.apply(
Expand Down
1 change: 1 addition & 0 deletions tests/golden/session_update_agent_message_clear.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"sessionUpdate":"agent_message_clear"}
4 changes: 4 additions & 0 deletions tests/test_golden.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@

from acp import (
audio_block,
clear_agent_message,
embedded_blob_resource,
embedded_text_resource,
image_block,
Expand All @@ -30,6 +31,7 @@
)
from acp.schema import (
AgentMessageChunk,
AgentMessageClear,
AgentPlanUpdate,
AgentThoughtChunk,
AllowedOutcome,
Expand Down Expand Up @@ -86,6 +88,7 @@
"request_permission_request": RequestPermissionRequest,
"request_permission_response_selected": RequestPermissionResponse,
"session_update_agent_message_chunk": AgentMessageChunk,
"session_update_agent_message_clear": AgentMessageClear,
"session_update_agent_thought_chunk": AgentThoughtChunk,
"session_update_config_option_update": ConfigOptionUpdate,
"session_update_plan": AgentPlanUpdate,
Expand Down Expand Up @@ -144,6 +147,7 @@
"tool_content_terminal": lambda: tool_terminal_ref("term_001"),
"session_update_user_message_chunk": lambda: update_user_message_text("What's the capital of France?"),
"session_update_agent_message_chunk": lambda: update_agent_message_text("The capital of France is Paris."),
"session_update_agent_message_clear": lambda: clear_agent_message(),
"session_update_agent_thought_chunk": lambda: update_agent_thought_text("Thinking about best approach..."),
"session_update_plan": lambda: update_plan([
plan_entry(
Expand Down