Skip to content
Merged
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
60 changes: 10 additions & 50 deletions coding-agent/src/coding_agent/ui/http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@

from agentkit.config.loader import load_config as load_agent_toml
from agentkit.errors import ConfigError
from agentkit.tape.extract import ToolCallRecord, TurnTrace, extract_turns
from agentkit.result.reducers import result_from_turn_trace
from agentkit.tape.extract import TurnTrace, extract_turns
from agentkit.tape.tape import Tape
from coding_agent.approval import ApprovalPolicy
from coding_agent.environment import (
Expand Down Expand Up @@ -116,15 +117,6 @@

# Constants
APPROVAL_TIMEOUT_SECONDS = 120

_SESSION_RESULT_TOOL_DETAIL_KEYS = (
"command",
"path",
"file_path",
"pattern",
)
_SESSION_RESULT_MAX_TOOL_ITEMS = 5
_SESSION_RESULT_MAX_TOOL_DETAIL_CHARS = 160
SESSION_IDLE_TIMEOUT_MINUTES = 30
_SERVER_CONFIG_ENV = "CODING_AGENT_SERVER_CONFIG"
_GITHUB_API_BASE_URL = "https://api.github.com"
Expand Down Expand Up @@ -2153,44 +2145,6 @@ async def _get_visible_session(
return session


def _compact_session_result_text(text: str, *, max_chars: int) -> str:
compact = " ".join(text.split())
if len(compact) <= max_chars:
return compact
return compact[: max_chars - 3].rstrip() + "..."


def _session_result_tool_detail(call: ToolCallRecord) -> str | None:
for key in _SESSION_RESULT_TOOL_DETAIL_KEYS:
value = call.arguments.get(key)
if not isinstance(value, str) or value.strip() == "":
continue
return _compact_session_result_text(
value,
max_chars=_SESSION_RESULT_MAX_TOOL_DETAIL_CHARS,
)
return None


def _session_result_verification_summary(turn: TurnTrace | None) -> str | None:
if turn is None or not turn.tool_calls:
return None

items: list[str] = []
for call in turn.tool_calls[:_SESSION_RESULT_MAX_TOOL_ITEMS]:
name = call.name.strip() or "unnamed_tool"
detail = _session_result_tool_detail(call)
if detail is None:
items.append(name)
else:
items.append(f"{name}: {detail}")

remaining = len(turn.tool_calls) - len(items)
if remaining > 0:
items.append(f"+{remaining} more")
return "Tool activity: " + "; ".join(items)


def _session_runtime_tape(session: Session) -> Tape | None:
runtime_ctx = session.runtime_ctx
if runtime_ctx is None:
Expand Down Expand Up @@ -2240,6 +2194,12 @@ async def get_session_result(
session = await _get_visible_session(session_id, auth_context)
summary = session.as_dict()
latest_turn = await _session_result_latest_turn(session)
turn_result = None if latest_turn is None else result_from_turn_trace(latest_turn)
verification_summary = (
None
if turn_result is None or turn_result.verification_summary is None
else turn_result.verification_summary.summary
)
return SessionResultResponse(
session_id=session.id,
status=summary["status"],
Expand All @@ -2249,8 +2209,8 @@ async def get_session_result(
origin=session.origin,
provider_name=session.provider_name,
model_name=session.model_name,
final_answer=None if latest_turn is None else latest_turn.final_output,
verification_summary=_session_result_verification_summary(latest_turn),
final_answer=None if turn_result is None else turn_result.final_output,
verification_summary=verification_summary,
failure_details=_session_result_failure_details(session),
)

Expand Down
47 changes: 47 additions & 0 deletions coding-agent/tests/ui/test_http_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@
from agentkit.errors import ConfigError
from agentkit.checkpoint.models import CheckpointMeta
from agentkit.providers.models import DoneEvent, TextEvent, ToolCallEvent
from agentkit.result.models import TurnResult, VerificationSummary
from agentkit.tape.extract import TurnTrace
from agentkit.tape.models import Entry
from agentkit.tape.tape import Tape
from agentkit.tools import FatalToolExecutionError
Expand Down Expand Up @@ -3769,6 +3771,51 @@ async def test_get_session_success(self, client):


class TestRemoteResultPublicationContract:
async def test_session_result_endpoint_uses_agentkit_reducer_without_response_change(
self, client: AsyncClient, monkeypatch: pytest.MonkeyPatch
) -> None:
session = register_session(
"result-agentkit-reducer",
execution_binding=CloudWorkspaceBinding(
workspace_url="docker://agent-ws-result/workspace",
workspace_id="ws-agentkit-result",
),
provider_name="openai",
model_name="result-model",
)
tape = Tape(tape_id="runtime-tape")
tape.append(
Entry(kind="message", payload={"role": "user", "content": "fix it"})
)
tape.append(
Entry(kind="message", payload={"role": "assistant", "content": "ignored"})
)
session.runtime_ctx = SimpleNamespace(tape=tape)
session.tape_id = tape.tape_id

def fake_result_from_turn_trace(turn: TurnTrace) -> TurnResult:
assert turn.user_input == "fix it"
return TurnResult(
final_output="Reducer final answer.",
verification_summary=VerificationSummary(
summary="Reducer verification summary."
),
)

monkeypatch.setattr(
http_server,
"result_from_turn_trace",
fake_result_from_turn_trace,
)

response = await client.get(f"/sessions/{session.id}/result")

assert response.status_code == 200
data = response.json()
assert data["final_answer"] == "Reducer final answer."
assert data["verification_summary"] == "Reducer verification summary."
assert data["failure_details"] is None

async def test_session_result_includes_final_answer_and_tool_activity_from_runtime_tape(
self, client: AsyncClient
) -> None:
Expand Down