Skip to content
Draft
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
16 changes: 11 additions & 5 deletions frontend/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2674,11 +2674,17 @@ class AppController {
this._ceoTerm?.appendMessage({ role: 'system', text: '/clear only works in EA chat.', source: 'system' });
return;
}
// Forget old conversation and create a new one
this._eaChatConvId = null;
localStorage.removeItem('ea-chat-conv-id');
await this._ensureEaChatConversation();
this._ceoTerm?.showChat(this._EA_CHAT, []);
if (!this._eaChatConvId) {
await this._ensureEaChatConversation();
}
if (!this._eaChatConvId) return;
try {
const resp = await fetch(`/api/conversation/${this._eaChatConvId}/clear`, { method: 'POST' });
if (!resp.ok) throw new Error(`Server error (${resp.status})`);
this._ceoTerm?.showChat(this._EA_CHAT, []);
} catch (e) {
this._ceoTerm?.appendMessage({ role: 'system', text: `Failed to clear chat: ${e.message}`, source: 'system' });
}
}},
];
}
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@1mancompany/onemancompany",
"version": "0.7.77",
"version": "0.7.78",
"description": "The AI Operating System for One-Person Companies",
"bin": {
"onemancompany": "bin/cli.js"
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[project]
name = "onemancompany"
version = "0.7.77"
version = "0.7.78"
description = "A one-man company simulation with pixel art visualization and LangChain AI agents"
requires-python = ">=3.12"
dependencies = [
Expand Down
8 changes: 4 additions & 4 deletions src/onemancompany/api/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -6783,14 +6783,14 @@ async def close_conversation(conv_id: str, wait_hooks: bool = False) -> dict:

@router.post("/api/conversation/{conv_id}/clear")
async def clear_conversation_history(conv_id: str) -> dict:
"""Clear all 1-on-1 message history for the current conversation's employee."""
"""Clear message history for all same-type conversations of this employee."""
try:
conv = _get_conv_svc().get(conv_id)
except ValueError:
raise HTTPException(status_code=404, detail="Conversation not found")

if conv.type != "oneonone":
raise HTTPException(status_code=400, detail="Clear history is only supported for oneonone conversations")
if conv.type not in (ConversationType.ONE_ON_ONE.value, ConversationType.EA_CHAT.value):
raise HTTPException(status_code=400, detail="Clear history is only supported for oneonone and ea_chat conversations")
if not conv.employee_id:
raise HTTPException(status_code=400, detail="Conversation has no employee_id")

Expand Down Expand Up @@ -6818,7 +6818,7 @@ async def clear_conversation_history(conv_id: str) -> dict:
except Exception:
logger.warning("[conversation] skip unreadable meta when clearing history: {}", conv_dir)
continue
if c.type != "oneonone" or c.employee_id != conv.employee_id:
if c.type != conv.type or c.employee_id != conv.employee_id:
continue
scanned += 1
msg_path = conv_dir / "messages.yaml"
Expand Down
50 changes: 50 additions & 0 deletions tests/integration/test_conversation_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,56 @@ async def test_clear_current_agent_oneonone_history(client, tmp_path):
assert resp.json()["id"] == conv_id_current


@pytest.mark.asyncio
async def test_clear_ea_chat_history_persists_across_reopen(client, tmp_path):
# Old EA chat with history
resp = await client.post("/api/conversation/create", json={
"type": "ea_chat",
"employee_id": "00004",
"tools_enabled": True,
})
conv_id_old = resp.json()["id"]

msg_path_old = tmp_path / "employees" / "00004" / "conversations" / conv_id_old / "messages.yaml"
msg_path_old.parent.mkdir(parents=True, exist_ok=True)
msg_path_old.write_text(yaml.dump([
{"sender": "ceo", "role": "CEO", "text": "legacy ea", "timestamp": "2026-03-19T00:00:00+00:00", "attachments": []},
], allow_unicode=True), encoding="utf-8")

await client.post(f"/api/conversation/{conv_id_old}/close")

# Start a new current EA chat
resp = await client.post("/api/conversation/create", json={
"type": "ea_chat",
"employee_id": "00004",
"tools_enabled": True,
"reuse_existing": False,
})
conv_id_current = resp.json()["id"]
assert conv_id_current != conv_id_old

# Clear current EA chat history
resp = await client.post(f"/api/conversation/{conv_id_current}/clear")
assert resp.status_code == 200
data = resp.json()
assert data["status"] == "cleared"
assert data["employee_id"] == "00004"

# Old history should be wiped on disk
assert yaml.safe_load(msg_path_old.read_text(encoding="utf-8")) == []

# Reopen EA chat should not bring old history back
resp = await client.post("/api/conversation/create", json={
"type": "ea_chat",
"employee_id": "00004",
"tools_enabled": True,
})
reopened_id = resp.json()["id"]
resp = await client.get(f"/api/conversation/{reopened_id}/messages")
assert resp.status_code == 200
assert resp.json()["messages"] == []


@pytest.mark.asyncio
async def test_create_invalid_type(client):
resp = await client.post("/api/conversation/create", json={
Expand Down