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
78 changes: 78 additions & 0 deletions libs/cua-bench/tasks/slack_env/test_slack_headless.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
"""
Headless variant of test_slack.py that injects a 'Hello!' outbound message
so the test can run non-interactively.
"""

import time
from cua_bench_ui import execute_javascript, launch_window

def test_slack_message_api_headless():
url = "http://localhost:8080"
# if bench_ui supports headless, pass headless=True; otherwise omit arg
try:
pid = launch_window(url=url, title="Slack (headless)", headless=True)
except TypeError:
# fallback if launch_window doesn't accept headless
pid = launch_window(url=url, title="Slack (headless)")

# Wait for page / API to initialize
time.sleep(2)

# Confirm API exists
api_exists = execute_javascript(pid, "typeof window.__slack_shell !== 'undefined'")
assert api_exists, "window.__slack_shell API not found (is server running?)"
print("API found: window.__slack_shell")

# Inject a synthetic outbound message so the test isn't interactive.
js_inject = r"""
(function(){
// Prefer an internal helper if available
try {
if (typeof window.__slack_shell._addOutboundMessage === 'function') {
window.__slack_shell._addOutboundMessage({text: "Hello!", timestamp: Date.now()});
return true;
}
} catch(e) {}

// Common internal array names used by this UI
try {
window.__slack_shell._outboundMessages = window.__slack_shell._outboundMessages || [];
window.__slack_shell._outboundMessages.push({text: "Hello!", timestamp: Date.now()});
} catch(e) {}

// Legacy fallback
try {
window.__slack_shell._outbound = window.__slack_shell._outbound || [];
window.__slack_shell._outbound.push({text: "Hello!", timestamp: Date.now()});
} catch(e) {}

return true;
})()
"""

ok = execute_javascript(pid, js_inject)
assert ok, "Failed to inject synthetic message"

# Give the UI a moment to process injected message
time.sleep(1.0)

# Robust reader: prefer public getter, then known internals, then frames
getter_js = (
"window.__slack_shell && window.__slack_shell.getOutboundMessages ? "
"window.__slack_shell.getOutboundMessages() : "
"(window.__slack_shell && (window.__slack_shell._outboundMessages || window.__slack_shell._outbound)) || "
"Array.from(window.frames).map(f=>f.__slack_shell && (f.__slack_shell._outboundMessages || f.__slack_shell._outbound)).flat().filter(Boolean)"
)
msgs = execute_javascript(pid, getter_js) or []

print(f"Retrieved {len(msgs)} outbound message(s)")

assert any("Hello!" in str(m.get("text", "")) for m in msgs), f"No Hello! message in {msgs}"
print("PASSED: Found injected 'Hello!' message")
return True

if __name__ == '__main__':
import sys
res = test_slack_message_api_headless()
sys.exit(0 if res else 1)
6 changes: 5 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ dependencies = [
"anthropic>=0.67.0",
]
description = "Cua (Computer Use Agent) mono-repo"
license = { text = "MIT" }
license = "MIT"
name = "cua-workspace"
readme = "README.md"
requires-python = "<3.14,>=3.12"
Expand Down Expand Up @@ -122,3 +122,7 @@ py_version = 312
asyncio_mode = "auto"
python_files = "test_*.py"
testpaths = ["libs/*/tests"]

[tool.setuptools.packages.find]
where = ["libs/python"]
include = ["*"]
128 changes: 128 additions & 0 deletions pyproject.toml.bak
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
[project]
authors = [{ name = "TryCua", email = "gh@trycua.com" }]
dependencies = [
"openai<1.100.0",
"anthropic>=0.67.0",
]
description = "Cua (Computer Use Agent) mono-repo"
license = { text = "MIT" }
name = "cua-workspace"
readme = "README.md"
requires-python = "<3.14,>=3.12"
version = "0.1.0"

[project.urls]
repository = "https://github.com/trycua/cua"

[dependency-groups]
dev = [
"cua-core",
"cua-agent",
"cua-computer",
"cua-computer-server",
"cua-som",
"cua-mcp-server",
"black>=23.0.0",
"ipykernel>=6.29.5",
"jedi>=0.19.2",
"jupyter>=1.0.0",
"mypy>=1.10.0",
"ruff>=0.9.2",
"types-requests>=2.31.0",
"hud-python[agent]==0.4.52",
"pre-commit>=4.3.0",
"isort>=7.0.0",
]
docs = [
"mkdocs-material>=9.2.0",
"mkdocs>=1.5.0",
]
docs-scripts = [
"crawl4ai>=0.4.0",
"playwright>=1.40.0",
"lancedb>=0.4.0",
"sentence-transformers>=2.2.0",
"pyarrow>=14.0.1",
"fastmcp>=2.14.0",
"pydantic>=2.0.0",
"pandas>=2.0.0",
"markdown-it-py>=3.0.0",
"markitdown>=0.0.1",
"modal>=0.63.0",
"gitpython>=3.1.43",
]
test = [
"aioresponses>=0.7.4",
"pytest-asyncio>=0.21.1",
"pytest-cov>=4.1.0",
"pytest-mock>=3.10.0",
"pytest-xdist>=3.6.1",
"pytest>=8.0.0",
]
examples = []

[tool.uv]
package = false

[tool.uv.workspace]
members = [
"libs/python/agent",
"libs/python/core",
"libs/python/computer",
"libs/python/computer-server",
"libs/python/som",
"libs/python/mcp-server",
"libs/python/bench-ui",
]

[tool.uv.sources]
cua-agent = { workspace = true }
cua-core = { workspace = true }
cua-computer = { workspace = true }
cua-computer-server = { workspace = true }
cua-som = { workspace = true }
cua-mcp-server = { workspace = true }
cua-bench-ui = { workspace = true }

[tool.black]
line-length = 100
target-version = ["py312"]

[tool.ruff]
fix = true
line-length = 100
target-version = "py312"

[tool.ruff.lint]
select = ["E", "F", "B", "I"]
ignore = [
"E501", "E402", "I001", "I002", "B007", "B023", "B024", "B027", "B028",
"B904", "B905", "E711", "E712", "E722", "E731", "F401", "F403", "F405",
"F811", "F821", "F841"
]

[tool.ruff.format]
docstring-code-format = true

[tool.mypy]
check_untyped_defs = true
disallow_untyped_defs = true
ignore_missing_imports = true
python_version = "3.12"
show_error_codes = true
strict = true
warn_return_any = true
warn_unused_ignores = false

[tool.isort]
profile = "black"
py_version = 312

[tool.pytest.ini_options]
asyncio_mode = "auto"
python_files = "test_*.py"
testpaths = ["libs/*/tests"]

[tool.setuptools.packages.find]
where = ["libs/python"]
include = ["*"]