deepagents-talon 0.0.1__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 (50) hide show
  1. deepagents_talon-0.0.1/.gitignore +252 -0
  2. deepagents_talon-0.0.1/CHANGELOG.md +3 -0
  3. deepagents_talon-0.0.1/Makefile +41 -0
  4. deepagents_talon-0.0.1/PKG-INFO +197 -0
  5. deepagents_talon-0.0.1/README.md +163 -0
  6. deepagents_talon-0.0.1/deepagents_talon/__init__.py +68 -0
  7. deepagents_talon-0.0.1/deepagents_talon/__main__.py +218 -0
  8. deepagents_talon-0.0.1/deepagents_talon/_version.py +3 -0
  9. deepagents_talon-0.0.1/deepagents_talon/channels/__init__.py +22 -0
  10. deepagents_talon-0.0.1/deepagents_talon/channels/base.py +192 -0
  11. deepagents_talon-0.0.1/deepagents_talon/channels/whatsapp.py +745 -0
  12. deepagents_talon-0.0.1/deepagents_talon/channels/whatsapp_bridge/bridge.js +591 -0
  13. deepagents_talon-0.0.1/deepagents_talon/channels/whatsapp_bridge/package-lock.json +2117 -0
  14. deepagents_talon-0.0.1/deepagents_talon/channels/whatsapp_bridge/package.json +9 -0
  15. deepagents_talon-0.0.1/deepagents_talon/config.py +157 -0
  16. deepagents_talon-0.0.1/deepagents_talon/cron/__init__.py +26 -0
  17. deepagents_talon-0.0.1/deepagents_talon/cron/jobs.py +737 -0
  18. deepagents_talon-0.0.1/deepagents_talon/cron/scheduler.py +170 -0
  19. deepagents_talon-0.0.1/deepagents_talon/cron/tools.py +261 -0
  20. deepagents_talon-0.0.1/deepagents_talon/data_lifecycle.py +140 -0
  21. deepagents_talon-0.0.1/deepagents_talon/fleet.py +417 -0
  22. deepagents_talon-0.0.1/deepagents_talon/host.py +584 -0
  23. deepagents_talon-0.0.1/deepagents_talon/interfaces.py +198 -0
  24. deepagents_talon-0.0.1/deepagents_talon/mcp.py +133 -0
  25. deepagents_talon-0.0.1/deepagents_talon/media.py +383 -0
  26. deepagents_talon-0.0.1/deepagents_talon/observability.py +185 -0
  27. deepagents_talon-0.0.1/deepagents_talon/py.typed +1 -0
  28. deepagents_talon-0.0.1/deepagents_talon/runtime.py +1046 -0
  29. deepagents_talon-0.0.1/deepagents_talon/speech.py +305 -0
  30. deepagents_talon-0.0.1/pyproject.toml +128 -0
  31. deepagents_talon-0.0.1/tests/__init__.py +1 -0
  32. deepagents_talon-0.0.1/tests/channels/__init__.py +1 -0
  33. deepagents_talon-0.0.1/tests/channels/test_base.py +100 -0
  34. deepagents_talon-0.0.1/tests/channels/test_whatsapp.py +477 -0
  35. deepagents_talon-0.0.1/tests/cron/__init__.py +1 -0
  36. deepagents_talon-0.0.1/tests/cron/test_jobs.py +117 -0
  37. deepagents_talon-0.0.1/tests/cron/test_scheduler.py +173 -0
  38. deepagents_talon-0.0.1/tests/integration_tests/__init__.py +1 -0
  39. deepagents_talon-0.0.1/tests/integration_tests/test_core_flows.py +161 -0
  40. deepagents_talon-0.0.1/tests/test_config.py +108 -0
  41. deepagents_talon-0.0.1/tests/test_data_lifecycle.py +47 -0
  42. deepagents_talon-0.0.1/tests/test_fleet.py +383 -0
  43. deepagents_talon-0.0.1/tests/test_host.py +391 -0
  44. deepagents_talon-0.0.1/tests/test_import_compat.py +10 -0
  45. deepagents_talon-0.0.1/tests/test_mcp.py +124 -0
  46. deepagents_talon-0.0.1/tests/test_media.py +139 -0
  47. deepagents_talon-0.0.1/tests/test_observability.py +150 -0
  48. deepagents_talon-0.0.1/tests/test_runtime.py +952 -0
  49. deepagents_talon-0.0.1/tests/test_speech.py +65 -0
  50. deepagents_talon-0.0.1/uv.lock +4914 -0
@@ -0,0 +1,252 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[codz]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ develop-eggs/
13
+ dist/
14
+ downloads/
15
+ eggs/
16
+ .eggs/
17
+ lib/
18
+ !libs/cli/frontend/src/lib/
19
+ lib64/
20
+ parts/
21
+ sdist/
22
+ var/
23
+ wheels/
24
+ share/python-wheels/
25
+ *.egg-info/
26
+ .installed.cfg
27
+ *.egg
28
+ MANIFEST
29
+
30
+ # PyInstaller
31
+ # Usually these files are written by a python script from a template
32
+ # before PyInstaller builds the exe, so as to inject date/other infos into it.
33
+ *.manifest
34
+ *.spec
35
+
36
+ # Installer logs
37
+ pip-log.txt
38
+ pip-delete-this-directory.txt
39
+
40
+ # Unit test / coverage reports
41
+ htmlcov/
42
+ .tox/
43
+ .nox/
44
+ .coverage
45
+ .coverage.*
46
+ .cache
47
+ nosetests.xml
48
+ coverage.xml
49
+ *.cover
50
+ *.py.cover
51
+ .hypothesis/
52
+ .pytest_cache/
53
+ cover/
54
+
55
+ # Translations
56
+ *.mo
57
+ *.pot
58
+
59
+ # Django stuff:
60
+ *.log
61
+ local_settings.py
62
+ db.sqlite3
63
+ db.sqlite3-journal
64
+
65
+ # Flask stuff:
66
+ instance/
67
+ .webassets-cache
68
+
69
+ # Scrapy stuff:
70
+ .scrapy
71
+
72
+ # Sphinx documentation
73
+ docs/_build/
74
+
75
+ # PyBuilder
76
+ .pybuilder/
77
+ target/
78
+
79
+ # Jupyter Notebook
80
+ .ipynb_checkpoints
81
+
82
+ # IPython
83
+ profile_default/
84
+ ipython_config.py
85
+
86
+ # pyenv
87
+ # For a library or package, you might want to ignore these files since the code is
88
+ # intended to run in multiple environments; otherwise, check them in:
89
+ # .python-version
90
+
91
+ # pipenv
92
+ # According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
93
+ # However, in case of collaboration, if having platform-specific dependencies or dependencies
94
+ # having no cross-platform support, pipenv may install dependencies that don't work, or not
95
+ # install all needed dependencies.
96
+ #Pipfile.lock
97
+
98
+ # UV
99
+ # Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
100
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
101
+ # commonly ignored for libraries.
102
+ #uv.lock
103
+
104
+ # poetry
105
+ # Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
106
+ # This is especially recommended for binary packages to ensure reproducibility, and is more
107
+ # commonly ignored for libraries.
108
+ # https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
109
+ #poetry.lock
110
+ #poetry.toml
111
+
112
+ # pdm
113
+ # Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
114
+ # pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
115
+ # https://pdm-project.org/en/latest/usage/project/#working-with-version-control
116
+ #pdm.lock
117
+ #pdm.toml
118
+ .pdm-python
119
+ .pdm-build/
120
+
121
+ # pixi
122
+ # Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
123
+ #pixi.lock
124
+ # Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
125
+ # in the .venv directory. It is recommended not to include this directory in version control.
126
+ .pixi
127
+
128
+ # PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
129
+ __pypackages__/
130
+
131
+ # Celery stuff
132
+ celerybeat-schedule
133
+ celerybeat.pid
134
+
135
+ # SageMath parsed files
136
+ *.sage.py
137
+
138
+ # Environments
139
+ .env
140
+ .env.*
141
+ .envrc
142
+ env.local
143
+ *.env.local
144
+ .venv
145
+ env/
146
+ venv/
147
+ ENV/
148
+ env.bak/
149
+ venv.bak/
150
+
151
+ # Local credentials and secrets
152
+ *.pem
153
+ *.key
154
+ *.crt
155
+ *.p12
156
+ *.pfx
157
+ *.jks
158
+ credentials.json
159
+ token.json
160
+ Cookies
161
+ Cookies.db
162
+ cookies.sqlite
163
+ cookies.txt
164
+
165
+ # Spyder project settings
166
+ .spyderproject
167
+ .spyproject
168
+
169
+ # Rope project settings
170
+ .ropeproject
171
+
172
+ # mkdocs documentation
173
+ /site
174
+
175
+ # mypy
176
+ .mypy_cache/
177
+ .dmypy.json
178
+ dmypy.json
179
+
180
+ # Pyre type checker
181
+ .pyre/
182
+
183
+ # pytype static type analyzer
184
+ .pytype/
185
+
186
+ # Cython debug symbols
187
+ cython_debug/
188
+
189
+ # PyCharm
190
+ # JetBrains specific template is maintained in a separate JetBrains.gitignore that can
191
+ # be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
192
+ # and can be added to the global gitignore or merged into this file. For a more nuclear
193
+ # option (not recommended) you can uncomment the following to ignore the entire idea folder.
194
+ #.idea/
195
+
196
+ # Abstra
197
+ # Abstra is an AI-powered process automation framework.
198
+ # Ignore directories containing user credentials, local state, and settings.
199
+ # Learn more at https://abstra.io/docs
200
+ .abstra/
201
+
202
+ # Visual Studio Code
203
+ # Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
204
+ # that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
205
+ # and can be added to the global gitignore or merged into this file. However, if you prefer,
206
+ # you could uncomment the following to ignore the entire vscode folder
207
+ # .vscode/
208
+
209
+ # Ruff stuff:
210
+ .ruff_cache/
211
+
212
+ # PyPI configuration file
213
+ .pypirc
214
+
215
+ # Cursor
216
+ # Cursor is an AI-powered code editor. `.cursorignore` specifies files/directories to
217
+ # exclude from AI features like autocomplete and code analysis. Recommended for sensitive data
218
+ # refer to https://docs.cursor.com/context/ignore-files
219
+ .cursorignore
220
+ .cursorindexingignore
221
+
222
+ # Marimo
223
+ marimo/_static/
224
+ marimo/_lsp/
225
+ __marimo__/
226
+
227
+ # LangGraph
228
+ .langgraph_api
229
+
230
+ #claude
231
+ .claude
232
+
233
+ # Harbor local job output
234
+ jobs/
235
+
236
+ .idea
237
+ TEXTUAL_REFACTOR_PLAN.md
238
+ libs/cli/TEXTUAL_PROGRESS.md
239
+
240
+ /tmp/
241
+
242
+ # macOS
243
+ .DS_Store
244
+ */tmp/.DS_Store
245
+
246
+ CLAUDE.md
247
+ .worktrees/
248
+
249
+ # Frontend build artifacts (source tree; package data under libs/cli/deepagents_cli/deploy/frontend_dist/ is tracked)
250
+ libs/cli/frontend/node_modules/
251
+ libs/cli/frontend/dist/
252
+ node_modules/
@@ -0,0 +1,3 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project will be documented in this file.
@@ -0,0 +1,41 @@
1
+ .PHONY: lint format type typecheck test tests test_watch help
2
+
3
+ .DEFAULT_GOAL := help
4
+
5
+ .EXPORT_ALL_VARIABLES:
6
+ UV_FROZEN = true
7
+
8
+ TEST_FILE ?= tests/
9
+ PYTEST_EXTRA ?=
10
+
11
+ test: ## Run unit tests
12
+ test tests:
13
+ uv run --group test pytest --disable-socket --allow-unix-socket $(PYTEST_EXTRA) $(TEST_FILE) \
14
+ --timeout 10 --cov=deepagents_talon --cov-report=term-missing
15
+
16
+ test_watch: ## Run tests in watch mode
17
+ uv run --group test ptw . -- $(TEST_FILE)
18
+
19
+ lint format: PYTHON_FILES=deepagents_talon/ tests/
20
+ lint_diff format_diff: PYTHON_FILES=$(shell git diff --relative=libs/talon --name-only --diff-filter=d main | grep -E '\.py$$|\.ipynb$$')
21
+
22
+ lint: ## Run linters and type checker
23
+ lint lint_diff:
24
+ [ "$(PYTHON_FILES)" = "" ] || uv run --group test ruff check $(PYTHON_FILES)
25
+ [ "$(PYTHON_FILES)" = "" ] || uv run --group test ruff format $(PYTHON_FILES) --diff
26
+ $(MAKE) type
27
+
28
+ type: ## Run type checker
29
+ type typecheck:
30
+ uv run --group test ty check deepagents_talon
31
+
32
+ format: ## Run code formatters
33
+ format format_diff:
34
+ [ "$(PYTHON_FILES)" = "" ] || uv run --group test ruff format $(PYTHON_FILES)
35
+ [ "$(PYTHON_FILES)" = "" ] || uv run --group test ruff check --fix $(PYTHON_FILES)
36
+
37
+ help: ## Show this help message
38
+ @echo "Usage: make [target] [TEST_FILE=path/to/tests/]"
39
+ @echo ""
40
+ @echo "Targets:"
41
+ @awk 'BEGIN {FS = ":.*##"} /^[a-zA-Z_-]+:.*##/ {printf " %-20s %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@@ -0,0 +1,197 @@
1
+ Metadata-Version: 2.4
2
+ Name: deepagents-talon
3
+ Version: 0.0.1
4
+ Summary: Local runtime host for long-running Deep Agents channels and schedules (experimental)
5
+ Project-URL: Homepage, https://docs.langchain.com/oss/python/deepagents/overview
6
+ Project-URL: Documentation, https://reference.langchain.com/python/deepagents/
7
+ Project-URL: Repository, https://github.com/langchain-ai/deepagents
8
+ Project-URL: Issues, https://github.com/langchain-ai/deepagents/issues
9
+ License: MIT
10
+ Keywords: agents,ai,channels,deepagents,runtime,scheduling
11
+ Classifier: Development Status :: 3 - Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
20
+ Classifier: Topic :: Software Development :: Libraries :: Python Modules
21
+ Requires-Python: >=3.11
22
+ Requires-Dist: deepagents-code<1.0.0,>=0.1.11
23
+ Requires-Dist: deepagents<0.7.0,>=0.6.8
24
+ Requires-Dist: fleet-deepagents-export<1.0.0,>=0.0.1
25
+ Requires-Dist: langchain-mcp-adapters<1.0.0,>=0.2.2
26
+ Provides-Extra: speech
27
+ Requires-Dist: librosa<1.0.0,>=0.11.0; extra == 'speech'
28
+ Requires-Dist: numpy<3.0.0,>=2.4.6; extra == 'speech'
29
+ Requires-Dist: phonemizer<4.0.0,>=3.3.0; extra == 'speech'
30
+ Requires-Dist: torch<2.13.0,>=2.12.0; extra == 'speech'
31
+ Requires-Dist: torchaudio<2.12.0,>=2.11.0; extra == 'speech'
32
+ Requires-Dist: transformers<6.0.0,>=5.10.2; extra == 'speech'
33
+ Description-Content-Type: text/markdown
34
+
35
+ # Deep Agents Talon
36
+
37
+ Deep Agents Talon is the local runtime host for long-running Deep Agents. It owns the process lifecycle for channel adapters, cron schedulers, and the agent runtime in a single event loop.
38
+
39
+ > **Experimental:** Talon is an experimental runtime and is subject to change or removal at any time.
40
+
41
+ Talon currently includes:
42
+
43
+ - A host process with graceful shutdown, per-conversation serialization, and `/stop` cancellation.
44
+ - A generic channel protocol plus a WhatsApp adapter backed by a loopback Node bridge.
45
+ - A persistent cron scheduler with agent-facing cron tool helpers.
46
+ - MCP tool loading from the assistant manifest directory.
47
+ - Optional LangSmith tracing for each channel or cron-triggered run.
48
+
49
+ ## Quickstart
50
+
51
+ ```bash
52
+ uv sync --group test
53
+ AGENT_ASSISTANT_ID=local AGENT_MODEL=openai:gpt-5.2 uv run deepagents-talon --once
54
+ ```
55
+
56
+ If `AGENT_MODEL` is unset, Talon starts with the echo runtime. This is useful for checking host lifecycle and channel wiring without provider credentials.
57
+
58
+ Assistant state lives under `~/.deepagents/<assistant_id>/` by default. The host creates restrictive state directories for the materialized agent manifest, channel sessions, and cron jobs. The default local execution workspace is `/workspace`; set `DEEPAGENTS_TALON_WORKSPACE` to use a different directory.
59
+
60
+ ## Fleet Exports
61
+
62
+ Talon can host an operator-unzipped LangSmith Fleet export through the `fleet-deepagents-export` library:
63
+
64
+ ```bash
65
+ unzip path/to/fleet-export.zip -d ./fleet
66
+
67
+ DEEPAGENTS_TALON_FLEET_DIR=./fleet \
68
+ AGENT_ASSISTANT_ID=fleet-local \
69
+ uv run deepagents-talon --once
70
+ ```
71
+
72
+ In Fleet mode, Talon uses the model from `fleet/config.json` unless `DEEPAGENTS_TALON_MODEL` or `AGENT_MODEL` is set. The Fleet loader resolves MCP registry references through LangSmith, so provide the required `LANGSMITH_API_KEY`, `LANGSMITH_TENANT_ID`, `LANGSMITH_ORGANIZATION_ID`, and when needed `LANGSMITH_USER_ID`, `BUILTIN_MCP_URL`, `LANGSMITH_HOST_URL`, and `HOST_LANGCHAIN_API_URL`. Locally-authored agents without `DEEPAGENTS_TALON_FLEET_DIR` continue to load from the assistant manifest directory and Talon's plain MCP config discovery.
73
+
74
+ OAuth-backed Fleet MCP tools must be authorized once from an interactive shell before starting a headless host. Run the host in `--once` mode with the same Fleet directory and LangSmith environment you will use in production, complete the browser authorization if prompted, then start the long-running host:
75
+
76
+ ```bash
77
+ DEEPAGENTS_TALON_FLEET_DIR=./fleet \
78
+ AGENT_ASSISTANT_ID=fleet-local \
79
+ uv run deepagents-talon --once
80
+ ```
81
+
82
+ During a long-running Fleet session, Talon treats a 401/403 from an MCP tool as an expired OAuth credential signal. It reloads the Fleet components once, which re-mints tokens and rebuilds MCP connections, then retries the failed graph invocation once. If authorization still fails, Talon returns a structured `mcp_auth_failed` error instead of looping.
83
+
84
+ ## WhatsApp
85
+
86
+ The WhatsApp channel uses a local Node bridge packaged with this library. The Python adapter talks to the bridge over loopback only.
87
+
88
+ ```bash
89
+ cd deepagents_talon/channels/whatsapp_bridge
90
+ npm install
91
+ cd ../../..
92
+
93
+ DEEPAGENTS_TALON_WHATSAPP_ENABLED=true \
94
+ DEEPAGENTS_TALON_WHATSAPP_START_BRIDGE=true \
95
+ AGENT_ASSISTANT_ID=whatsapp-local \
96
+ AGENT_MODEL=openai:gpt-5.2 \
97
+ uv run deepagents-talon --whatsapp
98
+ ```
99
+
100
+ The bridge prints a QR code during pairing. By default, inbound exposure is `self`, so only messages from the paired account trigger the agent. Configure `DEEPAGENTS_TALON_WHATSAPP_EXPOSURE=allowlist` with `DEEPAGENTS_TALON_WHATSAPP_ALLOWLIST_CHATS` or `DEEPAGENTS_TALON_WHATSAPP_MENTION_PATTERNS` to allow specific chats. Outbound WhatsApp messages include a `deepagents bot` header by default so self-message conversations clearly distinguish agent replies from operator messages. Set `DEEPAGENTS_TALON_WHATSAPP_BOT_HEADER` to customize that label. Markdown image/video references in assistant replies may attach files only when they are relative paths inside `DEEPAGENTS_TALON_OUTBOUND_MEDIA_DIR`, or inside `DEEPAGENTS_TALON_WORKSPACE` when no outbound media directory is configured.
101
+
102
+ Inbound voice transcription is opt-in:
103
+
104
+ ```bash
105
+ DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_ENABLED=true
106
+ ```
107
+
108
+ When enabled without `DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_MODEL`, Talon uses the same local default as the original WhatsApp example: `nvidia/parakeet-tdt-0.6b-v3` through Transformers, with ffmpeg converting inbound audio to 16 kHz mono WAV first. Set `DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_DEVICE=cuda` to use a GPU. The legacy example variables `SPEECH_ENABLED` and `SPEECH_DEVICE` are also accepted. Setting `DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_MODEL` to a non-Parakeet model keeps the existing OpenAI SDK transcription path.
109
+
110
+ `open` exposure allows arbitrary WhatsApp senders to trigger the agent while it runs with the operator's model credentials, channel credentials, MCP tool access, and local-host access when the local execution backend is active. Enabling it requires explicit acknowledgement:
111
+
112
+ ```bash
113
+ DEEPAGENTS_TALON_WHATSAPP_EXPOSURE=open
114
+ DEEPAGENTS_TALON_WHATSAPP_OPEN_ACK=allow-arbitrary-senders
115
+ ```
116
+
117
+ See `../../examples/talon-whatsapp/` for a runnable Docker Compose topology and `.env` reference.
118
+
119
+ ## Tracing
120
+
121
+ LangSmith tracing is opt-in. Set both values before starting the host:
122
+
123
+ ```bash
124
+ LANGSMITH_TRACING=true
125
+ LANGSMITH_API_KEY=...
126
+ LANGSMITH_PROJECT=deepagents-talon
127
+ ```
128
+
129
+ When enabled, Talon wraps each agent run in a LangSmith tracing context with assistant id, conversation id, trigger metadata, and source message metadata.
130
+
131
+ ## MCP Tools
132
+
133
+ Talon loads MCP servers from one config file. It checks `DEEPAGENTS_TALON_MCP_CONFIG`, then `MCP_CONFIG`, then `~/.deepagents/<assistant_id>/agent/tools.json`, then `~/.deepagents/.mcp.json`. Add Talon-local servers by editing `tools.json` directly:
134
+
135
+ ```json
136
+ {
137
+ "mcpServers": {
138
+ "linear": {
139
+ "type": "http",
140
+ "url": "https://mcp.example/mcp"
141
+ }
142
+ }
143
+ }
144
+ ```
145
+
146
+ Run `deepagents-talon mcp config` to print the resolved config paths, and `deepagents-talon mcp login <server>` for OAuth-backed servers.
147
+
148
+ ## Cron Observability
149
+
150
+ Cron jobs are persisted in `cron/jobs.json` under the assistant state directory. Scheduler lifecycle events are emitted through the standard Python logger as `talon_event` JSON records:
151
+
152
+ - `cron.tick`
153
+ - `cron.dispatch`
154
+ - `cron.success`
155
+ - `cron.failure`
156
+ - `cron.delivery`
157
+ - `cron.delivery_suppressed`
158
+ - `cron.delivery_failure`
159
+
160
+ These logs complement the persisted `last_status` and `last_error` fields.
161
+
162
+ ## Security and Data Lifecycle
163
+
164
+ Talon is single-operator by design. It does not provide multi-tenant isolation, and channel exposure should be treated as direct access to the operator's agent.
165
+
166
+ Attacker-influenceable inputs include channel message text, voice transcripts, channel media metadata, downloaded media files when a channel adapter persists them for processing, web or search result content, MCP tool results, and imported manifest instructions. Treat all of those inputs as untrusted content entering the agent context.
167
+
168
+ Outbound data leaves Talon through these integrations:
169
+
170
+ - Model providers receive conversation text, cron prompts, voice transcripts, selected tool outputs, and system or manifest instructions.
171
+ - LangSmith receives trace metadata and serialized run inputs/outputs when `LANGSMITH_TRACING=true`.
172
+ - MCP servers receive tool arguments chosen by the model and may receive conversation-derived values.
173
+ - Tavily or other search tools receive query strings chosen by the model and may include conversation-derived values.
174
+ - Channel providers receive assistant replies and outbound media paths supplied to the channel adapter.
175
+
176
+ Sensitive local state is stored under `~/.deepagents/<assistant_id>/` by default with `0700` directories and `0600` cron files:
177
+
178
+ - `cron/jobs.json` stores cron prompts, origin conversation ids, message ids, run status, and errors. Active jobs are retained while enabled. Completed jobs are deleted on startup after `DEEPAGENTS_TALON_CRON_RETENTION_DAYS`, default `30`.
179
+ - `channels/whatsapp/` stores WhatsApp `LocalAuth` credentials and Chromium profile state. These credentials are retained until the operator deletes the directory, because automatic deletion would silently unpair the channel.
180
+ - `media/inbound/` is reserved for downloaded inbound media. Files older than `DEEPAGENTS_TALON_INBOUND_MEDIA_RETENTION_HOURS`, default `24`, are deleted on startup. The WhatsApp bridge stores downloaded inbound media under the assistant's inbound media directory and passes local paths plus MIME metadata to the host.
181
+
182
+ Conversation persistence is intentionally not durable yet. Runtime conversation state is in-memory unless a future backend explicitly adds thread persistence.
183
+
184
+ ## Development
185
+
186
+ ```bash
187
+ uv sync --group test
188
+ uv run --group test pytest tests/
189
+ uv run deepagents-talon
190
+ ```
191
+
192
+ Focused verification:
193
+
194
+ ```bash
195
+ make lint
196
+ make test
197
+ ```
@@ -0,0 +1,163 @@
1
+ # Deep Agents Talon
2
+
3
+ Deep Agents Talon is the local runtime host for long-running Deep Agents. It owns the process lifecycle for channel adapters, cron schedulers, and the agent runtime in a single event loop.
4
+
5
+ > **Experimental:** Talon is an experimental runtime and is subject to change or removal at any time.
6
+
7
+ Talon currently includes:
8
+
9
+ - A host process with graceful shutdown, per-conversation serialization, and `/stop` cancellation.
10
+ - A generic channel protocol plus a WhatsApp adapter backed by a loopback Node bridge.
11
+ - A persistent cron scheduler with agent-facing cron tool helpers.
12
+ - MCP tool loading from the assistant manifest directory.
13
+ - Optional LangSmith tracing for each channel or cron-triggered run.
14
+
15
+ ## Quickstart
16
+
17
+ ```bash
18
+ uv sync --group test
19
+ AGENT_ASSISTANT_ID=local AGENT_MODEL=openai:gpt-5.2 uv run deepagents-talon --once
20
+ ```
21
+
22
+ If `AGENT_MODEL` is unset, Talon starts with the echo runtime. This is useful for checking host lifecycle and channel wiring without provider credentials.
23
+
24
+ Assistant state lives under `~/.deepagents/<assistant_id>/` by default. The host creates restrictive state directories for the materialized agent manifest, channel sessions, and cron jobs. The default local execution workspace is `/workspace`; set `DEEPAGENTS_TALON_WORKSPACE` to use a different directory.
25
+
26
+ ## Fleet Exports
27
+
28
+ Talon can host an operator-unzipped LangSmith Fleet export through the `fleet-deepagents-export` library:
29
+
30
+ ```bash
31
+ unzip path/to/fleet-export.zip -d ./fleet
32
+
33
+ DEEPAGENTS_TALON_FLEET_DIR=./fleet \
34
+ AGENT_ASSISTANT_ID=fleet-local \
35
+ uv run deepagents-talon --once
36
+ ```
37
+
38
+ In Fleet mode, Talon uses the model from `fleet/config.json` unless `DEEPAGENTS_TALON_MODEL` or `AGENT_MODEL` is set. The Fleet loader resolves MCP registry references through LangSmith, so provide the required `LANGSMITH_API_KEY`, `LANGSMITH_TENANT_ID`, `LANGSMITH_ORGANIZATION_ID`, and when needed `LANGSMITH_USER_ID`, `BUILTIN_MCP_URL`, `LANGSMITH_HOST_URL`, and `HOST_LANGCHAIN_API_URL`. Locally-authored agents without `DEEPAGENTS_TALON_FLEET_DIR` continue to load from the assistant manifest directory and Talon's plain MCP config discovery.
39
+
40
+ OAuth-backed Fleet MCP tools must be authorized once from an interactive shell before starting a headless host. Run the host in `--once` mode with the same Fleet directory and LangSmith environment you will use in production, complete the browser authorization if prompted, then start the long-running host:
41
+
42
+ ```bash
43
+ DEEPAGENTS_TALON_FLEET_DIR=./fleet \
44
+ AGENT_ASSISTANT_ID=fleet-local \
45
+ uv run deepagents-talon --once
46
+ ```
47
+
48
+ During a long-running Fleet session, Talon treats a 401/403 from an MCP tool as an expired OAuth credential signal. It reloads the Fleet components once, which re-mints tokens and rebuilds MCP connections, then retries the failed graph invocation once. If authorization still fails, Talon returns a structured `mcp_auth_failed` error instead of looping.
49
+
50
+ ## WhatsApp
51
+
52
+ The WhatsApp channel uses a local Node bridge packaged with this library. The Python adapter talks to the bridge over loopback only.
53
+
54
+ ```bash
55
+ cd deepagents_talon/channels/whatsapp_bridge
56
+ npm install
57
+ cd ../../..
58
+
59
+ DEEPAGENTS_TALON_WHATSAPP_ENABLED=true \
60
+ DEEPAGENTS_TALON_WHATSAPP_START_BRIDGE=true \
61
+ AGENT_ASSISTANT_ID=whatsapp-local \
62
+ AGENT_MODEL=openai:gpt-5.2 \
63
+ uv run deepagents-talon --whatsapp
64
+ ```
65
+
66
+ The bridge prints a QR code during pairing. By default, inbound exposure is `self`, so only messages from the paired account trigger the agent. Configure `DEEPAGENTS_TALON_WHATSAPP_EXPOSURE=allowlist` with `DEEPAGENTS_TALON_WHATSAPP_ALLOWLIST_CHATS` or `DEEPAGENTS_TALON_WHATSAPP_MENTION_PATTERNS` to allow specific chats. Outbound WhatsApp messages include a `deepagents bot` header by default so self-message conversations clearly distinguish agent replies from operator messages. Set `DEEPAGENTS_TALON_WHATSAPP_BOT_HEADER` to customize that label. Markdown image/video references in assistant replies may attach files only when they are relative paths inside `DEEPAGENTS_TALON_OUTBOUND_MEDIA_DIR`, or inside `DEEPAGENTS_TALON_WORKSPACE` when no outbound media directory is configured.
67
+
68
+ Inbound voice transcription is opt-in:
69
+
70
+ ```bash
71
+ DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_ENABLED=true
72
+ ```
73
+
74
+ When enabled without `DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_MODEL`, Talon uses the same local default as the original WhatsApp example: `nvidia/parakeet-tdt-0.6b-v3` through Transformers, with ffmpeg converting inbound audio to 16 kHz mono WAV first. Set `DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_DEVICE=cuda` to use a GPU. The legacy example variables `SPEECH_ENABLED` and `SPEECH_DEVICE` are also accepted. Setting `DEEPAGENTS_TALON_VOICE_TRANSCRIPTION_MODEL` to a non-Parakeet model keeps the existing OpenAI SDK transcription path.
75
+
76
+ `open` exposure allows arbitrary WhatsApp senders to trigger the agent while it runs with the operator's model credentials, channel credentials, MCP tool access, and local-host access when the local execution backend is active. Enabling it requires explicit acknowledgement:
77
+
78
+ ```bash
79
+ DEEPAGENTS_TALON_WHATSAPP_EXPOSURE=open
80
+ DEEPAGENTS_TALON_WHATSAPP_OPEN_ACK=allow-arbitrary-senders
81
+ ```
82
+
83
+ See `../../examples/talon-whatsapp/` for a runnable Docker Compose topology and `.env` reference.
84
+
85
+ ## Tracing
86
+
87
+ LangSmith tracing is opt-in. Set both values before starting the host:
88
+
89
+ ```bash
90
+ LANGSMITH_TRACING=true
91
+ LANGSMITH_API_KEY=...
92
+ LANGSMITH_PROJECT=deepagents-talon
93
+ ```
94
+
95
+ When enabled, Talon wraps each agent run in a LangSmith tracing context with assistant id, conversation id, trigger metadata, and source message metadata.
96
+
97
+ ## MCP Tools
98
+
99
+ Talon loads MCP servers from one config file. It checks `DEEPAGENTS_TALON_MCP_CONFIG`, then `MCP_CONFIG`, then `~/.deepagents/<assistant_id>/agent/tools.json`, then `~/.deepagents/.mcp.json`. Add Talon-local servers by editing `tools.json` directly:
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "linear": {
105
+ "type": "http",
106
+ "url": "https://mcp.example/mcp"
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ Run `deepagents-talon mcp config` to print the resolved config paths, and `deepagents-talon mcp login <server>` for OAuth-backed servers.
113
+
114
+ ## Cron Observability
115
+
116
+ Cron jobs are persisted in `cron/jobs.json` under the assistant state directory. Scheduler lifecycle events are emitted through the standard Python logger as `talon_event` JSON records:
117
+
118
+ - `cron.tick`
119
+ - `cron.dispatch`
120
+ - `cron.success`
121
+ - `cron.failure`
122
+ - `cron.delivery`
123
+ - `cron.delivery_suppressed`
124
+ - `cron.delivery_failure`
125
+
126
+ These logs complement the persisted `last_status` and `last_error` fields.
127
+
128
+ ## Security and Data Lifecycle
129
+
130
+ Talon is single-operator by design. It does not provide multi-tenant isolation, and channel exposure should be treated as direct access to the operator's agent.
131
+
132
+ Attacker-influenceable inputs include channel message text, voice transcripts, channel media metadata, downloaded media files when a channel adapter persists them for processing, web or search result content, MCP tool results, and imported manifest instructions. Treat all of those inputs as untrusted content entering the agent context.
133
+
134
+ Outbound data leaves Talon through these integrations:
135
+
136
+ - Model providers receive conversation text, cron prompts, voice transcripts, selected tool outputs, and system or manifest instructions.
137
+ - LangSmith receives trace metadata and serialized run inputs/outputs when `LANGSMITH_TRACING=true`.
138
+ - MCP servers receive tool arguments chosen by the model and may receive conversation-derived values.
139
+ - Tavily or other search tools receive query strings chosen by the model and may include conversation-derived values.
140
+ - Channel providers receive assistant replies and outbound media paths supplied to the channel adapter.
141
+
142
+ Sensitive local state is stored under `~/.deepagents/<assistant_id>/` by default with `0700` directories and `0600` cron files:
143
+
144
+ - `cron/jobs.json` stores cron prompts, origin conversation ids, message ids, run status, and errors. Active jobs are retained while enabled. Completed jobs are deleted on startup after `DEEPAGENTS_TALON_CRON_RETENTION_DAYS`, default `30`.
145
+ - `channels/whatsapp/` stores WhatsApp `LocalAuth` credentials and Chromium profile state. These credentials are retained until the operator deletes the directory, because automatic deletion would silently unpair the channel.
146
+ - `media/inbound/` is reserved for downloaded inbound media. Files older than `DEEPAGENTS_TALON_INBOUND_MEDIA_RETENTION_HOURS`, default `24`, are deleted on startup. The WhatsApp bridge stores downloaded inbound media under the assistant's inbound media directory and passes local paths plus MIME metadata to the host.
147
+
148
+ Conversation persistence is intentionally not durable yet. Runtime conversation state is in-memory unless a future backend explicitly adds thread persistence.
149
+
150
+ ## Development
151
+
152
+ ```bash
153
+ uv sync --group test
154
+ uv run --group test pytest tests/
155
+ uv run deepagents-talon
156
+ ```
157
+
158
+ Focused verification:
159
+
160
+ ```bash
161
+ make lint
162
+ make test
163
+ ```