cowork-dash 0.1.5__tar.gz → 0.1.6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (32) hide show
  1. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/CHANGELOG.md +10 -0
  2. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/PKG-INFO +1 -1
  3. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/agent.py +4 -1
  4. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/app.py +61 -15
  5. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/layout.py +2 -0
  6. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/pyproject.toml +1 -1
  7. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/.claude/settings.local.json +0 -0
  8. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/.gitignore +0 -0
  9. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/LICENSE +0 -0
  10. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/MANIFEST.in +0 -0
  11. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/README.md +0 -0
  12. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/__init__.py +0 -0
  13. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/__main__.py +0 -0
  14. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/assets/app.js +0 -0
  15. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/assets/favicon.ico +0 -0
  16. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/assets/favicon.svg +0 -0
  17. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/assets/styles.css +0 -0
  18. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/canvas.py +0 -0
  19. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/cli.py +0 -0
  20. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/components.py +0 -0
  21. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/config.py +0 -0
  22. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/file_utils.py +0 -0
  23. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/cowork_dash/tools.py +0 -0
  24. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/docs/CLI_USAGE.md +0 -0
  25. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/docs/dark.png +0 -0
  26. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/docs/light.png +0 -0
  27. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/examples/example_agent.py +0 -0
  28. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/examples/python_api_example.py +0 -0
  29. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/templates/index.html +0 -0
  30. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/tests/__init__.py +0 -0
  31. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/tests/conftest.py +0 -0
  32. {cowork_dash-0.1.5 → cowork_dash-0.1.6}/tests/test_core.py +0 -0
@@ -5,6 +5,15 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.1.6] - 2026-01-25
9
+
10
+ ### Fixed
11
+ - Duplicate agent response rendering issue
12
+ - Agent state now resets on page refresh for clean sessions
13
+ - Tool calls indicator disappearing during execution (race condition fix)
14
+ - Missing return value in interrupt handling callback
15
+ - Default agent workspace now uses environment variable or current directory
16
+
8
17
  ## [0.1.5] - 2026-01-24
9
18
 
10
19
  ### Added
@@ -109,6 +118,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
109
118
  - Resizable split-pane interface
110
119
  - Upload/download functionality for files
111
120
 
121
+ [0.1.6]: https://github.com/dkedar7/cowork-dash/compare/v0.1.5...v0.1.6
112
122
  [0.1.5]: https://github.com/dkedar7/cowork-dash/compare/v0.1.4...v0.1.5
113
123
  [0.1.4]: https://github.com/dkedar7/cowork-dash/compare/v0.1.3...v0.1.4
114
124
  [0.1.3]: https://github.com/dkedar7/cowork-dash/compare/v0.1.2...v0.1.3
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: cowork-dash
3
- Version: 0.1.5
3
+ Version: 0.1.6
4
4
  Summary: AI Agent Web Interface with Filesystem and Canvas Visualization
5
5
  Project-URL: Homepage, https://github.com/dkedar7/cowork-dash
6
6
  Project-URL: Documentation, https://github.com/dkedar7/cowork-dash/blob/main/README.md
@@ -1,3 +1,4 @@
1
+ import os
1
2
  import uuid
2
3
  from deepagents import create_deep_agent
3
4
  from langgraph.checkpoint.memory import InMemorySaver
@@ -92,7 +93,9 @@ Work iteratively like a human using Jupyter:
92
93
 
93
94
  The workspace is your sandbox - feel free to create files, organize content, and help users manage their projects."""
94
95
 
95
- backend = FilesystemBackend(root_dir=str("/"), virtual_mode=True)
96
+ # Get workspace root from environment variable or default to current directory
97
+ workspace_root = os.getenv("DEEPAGENT_WORKSPACE_ROOT", os.getcwd())
98
+ backend = FilesystemBackend(root_dir=workspace_root, virtual_mode=True)
96
99
 
97
100
  agent = create_deep_agent(
98
101
  system_prompt=SYSTEM_PROMPT,
@@ -4,6 +4,7 @@ import sys
4
4
  import json
5
5
  import base64
6
6
  import re
7
+ import copy
7
8
  import shutil
8
9
  import platform
9
10
  import subprocess
@@ -850,9 +851,36 @@ def resume_agent_from_interrupt(decision: str, action: str = "approve", action_r
850
851
  thread.start()
851
852
 
852
853
  def get_agent_state() -> Dict[str, Any]:
853
- """Get current agent state (thread-safe)."""
854
+ """Get current agent state (thread-safe).
855
+
856
+ Returns a deep copy of mutable collections to prevent race conditions.
857
+ """
858
+ with _agent_state_lock:
859
+ state = _agent_state.copy()
860
+ # Deep copy mutable collections to prevent race conditions during rendering
861
+ state["tool_calls"] = copy.deepcopy(_agent_state["tool_calls"])
862
+ state["todos"] = copy.deepcopy(_agent_state["todos"])
863
+ state["canvas"] = copy.deepcopy(_agent_state["canvas"])
864
+ return state
865
+
866
+ def reset_agent_state():
867
+ """Reset agent state for a fresh session (thread-safe).
868
+
869
+ Called on page load to ensure clean state after browser refresh.
870
+ Preserves canvas items loaded from canvas.md.
871
+ """
854
872
  with _agent_state_lock:
855
- return _agent_state.copy()
873
+ _agent_state["running"] = False
874
+ _agent_state["thinking"] = ""
875
+ _agent_state["todos"] = []
876
+ _agent_state["tool_calls"] = []
877
+ _agent_state["response"] = ""
878
+ _agent_state["error"] = None
879
+ _agent_state["interrupt"] = None
880
+ _agent_state["start_time"] = None
881
+ _agent_state["stop_requested"] = False
882
+ _agent_state["last_update"] = time.time()
883
+ # Note: canvas is preserved - it's loaded from canvas.md on startup
856
884
 
857
885
  # =============================================================================
858
886
  # DASH APP
@@ -921,15 +949,32 @@ app.layout = create_layout
921
949
 
922
950
  # Initial message display
923
951
  @app.callback(
924
- Output("chat-messages", "children"),
952
+ [Output("chat-messages", "children"),
953
+ Output("skip-history-render", "data", allow_duplicate=True),
954
+ Output("session-initialized", "data", allow_duplicate=True)],
925
955
  [Input("chat-history", "data")],
926
- [State("theme-store", "data")],
927
- prevent_initial_call=False
956
+ [State("theme-store", "data"),
957
+ State("skip-history-render", "data"),
958
+ State("session-initialized", "data")],
959
+ prevent_initial_call="initial_duplicate"
928
960
  )
929
- def display_initial_messages(history, theme):
930
- """Display initial welcome message or chat history."""
961
+ def display_initial_messages(history, theme, skip_render, session_initialized):
962
+ """Display initial welcome message or chat history.
963
+
964
+ On first call (page load), resets agent state for a fresh session.
965
+ Skip rendering if skip_render flag is set - this prevents duplicate renders
966
+ when poll_agent_updates already handles the rendering.
967
+ """
968
+ # Reset agent state on page load (first callback trigger)
969
+ if not session_initialized:
970
+ reset_agent_state()
971
+
972
+ # Skip if flag is set (poll_agent_updates already rendered)
973
+ if skip_render:
974
+ return no_update, False, True # Reset skip flag, mark session initialized
975
+
931
976
  if not history:
932
- return []
977
+ return [], False, True
933
978
 
934
979
  colors = get_colors(theme or "light")
935
980
  messages = []
@@ -946,7 +991,7 @@ def display_initial_messages(history, theme):
946
991
  todos_block = format_todos_inline(msg["todos"], colors)
947
992
  if todos_block:
948
993
  messages.append(todos_block)
949
- return messages
994
+ return messages, False, True
950
995
 
951
996
  # Chat callbacks
952
997
  @app.callback(
@@ -1005,7 +1050,8 @@ def handle_send_immediate(n_clicks, n_submit, message, history, theme, current_w
1005
1050
  @app.callback(
1006
1051
  [Output("chat-messages", "children", allow_duplicate=True),
1007
1052
  Output("chat-history", "data", allow_duplicate=True),
1008
- Output("poll-interval", "disabled", allow_duplicate=True)],
1053
+ Output("poll-interval", "disabled", allow_duplicate=True),
1054
+ Output("skip-history-render", "data", allow_duplicate=True)],
1009
1055
  Input("poll-interval", "n_intervals"),
1010
1056
  [State("chat-history", "data"),
1011
1057
  State("pending-message", "data"),
@@ -1069,7 +1115,7 @@ def poll_agent_updates(n_intervals, history, pending_message, theme):
1069
1115
  messages.append(interrupt_block)
1070
1116
 
1071
1117
  # Disable polling - wait for user to respond to interrupt
1072
- return messages, no_update, True
1118
+ return messages, no_update, True, no_update
1073
1119
 
1074
1120
  # Check if agent is done
1075
1121
  if not state["running"]:
@@ -1115,8 +1161,8 @@ def poll_agent_updates(n_intervals, history, pending_message, theme):
1115
1161
  if todos_block:
1116
1162
  final_messages.append(todos_block)
1117
1163
 
1118
- # Disable polling
1119
- return final_messages, history, True
1164
+ # Disable polling, set skip flag to prevent display_initial_messages from re-rendering
1165
+ return final_messages, history, True, True
1120
1166
  else:
1121
1167
  # Agent still running - show loading with current thinking/tool_calls/todos
1122
1168
  messages = render_history_messages(history)
@@ -1142,8 +1188,8 @@ def poll_agent_updates(n_intervals, history, pending_message, theme):
1142
1188
  # Add loading indicator
1143
1189
  messages.append(format_loading(colors))
1144
1190
 
1145
- # Continue polling
1146
- return messages, no_update, False
1191
+ # Continue polling, no skip flag needed
1192
+ return messages, no_update, False, no_update
1147
1193
 
1148
1194
 
1149
1195
  # Stop button visibility - show when agent is running
@@ -37,6 +37,8 @@ def create_layout(workspace_root, app_title, app_subtitle, colors, styles, agent
37
37
  "content": message
38
38
  }]),
39
39
  dcc.Store(id="pending-message", data=None),
40
+ dcc.Store(id="skip-history-render", data=False), # Flag to skip display_initial_messages render
41
+ dcc.Store(id="session-initialized", data=False), # Flag to track if session has been initialized
40
42
  dcc.Store(id="expanded-folders", data=[]),
41
43
  dcc.Store(id="file-to-view", data=None),
42
44
  dcc.Store(id="file-click-tracker", data={}),
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "cowork-dash"
7
- version = "0.1.5"
7
+ version = "0.1.6"
8
8
  description = "AI Agent Web Interface with Filesystem and Canvas Visualization"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes