talon-agent 5.14.0 → 5.18.2
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.
- package/LICENSE +202 -21
- package/LICENSE-MIT +21 -0
- package/NOTICE +16 -0
- package/README.md +14 -7
- package/package.json +6 -4
- package/prompts/system/heartbeat-agent.md +1 -1
- package/src/backend/agy/factory.ts +3 -0
- package/src/backend/agy/mcp/config.ts +14 -2
- package/src/backend/claude-sdk/factory.ts +3 -0
- package/src/backend/claude-sdk/options.ts +24 -3
- package/src/backend/codex/factory.ts +3 -0
- package/src/backend/codex/init.ts +4 -0
- package/src/backend/codex/mcp-config.ts +10 -0
- package/src/backend/codex/oauth-incompat.ts +1 -1
- package/src/backend/codex/token-usage.ts +2 -2
- package/src/backend/openai-agents/factory.ts +3 -0
- package/src/backend/openai-agents/mcp-pool.ts +4 -0
- package/src/backend/remote-server/factory.ts +3 -0
- package/src/backend/remote-server/mcp.ts +3 -0
- package/src/backend/runtime/prompt/prompt-format.ts +3 -3
- package/src/bootstrap.ts +8 -0
- package/src/cli/commands/backup.ts +61 -5
- package/src/cli/commands/mesh.ts +133 -0
- package/src/cli/config.ts +3 -1
- package/src/cli/daemon-api.ts +22 -0
- package/src/cli/index.ts +6 -0
- package/src/cli/install-sources.ts +40 -5
- package/src/cli/plugin.ts +10 -0
- package/src/cli/setup.ts +45 -4
- package/src/cli/skill.ts +3 -0
- package/src/core/agent-runtime/backend-registry.ts +16 -0
- package/src/core/backup/archive/crypt.ts +429 -0
- package/src/core/backup/archive/manifest-auth.ts +98 -0
- package/src/core/backup/passphrase.ts +130 -0
- package/src/core/backup/plan.ts +66 -13
- package/src/core/backup/restore-guard.ts +101 -0
- package/src/core/backup/restore.ts +249 -32
- package/src/core/backup/snapshot.ts +418 -60
- package/src/core/backup/sources/plugins.ts +223 -0
- package/src/core/backup/sources/relocate.ts +136 -0
- package/src/core/backup/sources/sessions.ts +198 -0
- package/src/core/backup/store.ts +3 -1
- package/src/core/backup/types.ts +66 -0
- package/src/core/backup/upload.ts +66 -6
- package/src/core/config/index.ts +140 -8
- package/src/core/daemon/control.ts +9 -0
- package/src/core/daemon/discovery.ts +7 -0
- package/src/core/engine/backend-router/headroom.ts +29 -5
- package/src/core/engine/backend-router/usage.ts +6 -2
- package/src/core/engine/gateway-actions/fetch-url/guard.ts +201 -0
- package/src/core/engine/gateway-actions/{fetch-url.ts → fetch-url/index.ts} +60 -32
- package/src/core/engine/gateway-actions/index.ts +4 -2
- package/src/core/engine/gateway-actions/native/index.ts +24 -0
- package/src/core/engine/gateway-actions/whatsapp-account.ts +1 -1
- package/src/core/engine/gateway-auth.ts +164 -0
- package/src/core/engine/gateway-routes.ts +100 -5
- package/src/core/engine/gateway.ts +12 -4
- package/src/core/mcp-hub/guest-scope.ts +170 -29
- package/src/core/mcp-hub/index.ts +33 -16
- package/src/core/mcp-hub/talon-server.ts +71 -14
- package/src/core/mesh/credentials/admin.ts +146 -0
- package/src/core/mesh/credentials/index.ts +19 -0
- package/src/core/mesh/credentials/store.ts +443 -0
- package/src/core/mesh/credentials/token.ts +45 -0
- package/src/core/mesh/credentials/types.ts +83 -0
- package/src/core/mesh/devices/service.ts +58 -6
- package/src/core/mesh/links/bridge-links.ts +46 -4
- package/src/core/mesh/links/node-binaries.ts +1 -1
- package/src/core/mesh/links/node-provision.ts +8 -1
- package/src/core/models/active-model.ts +1 -1
- package/src/core/plugin/loader.ts +4 -0
- package/src/core/plugin/mcp.ts +4 -0
- package/src/core/tools/bridge.ts +2 -1
- package/src/core/types.ts +13 -0
- package/src/core/weaver/weaver.ts +47 -15
- package/src/frontend/discord/callbacks/components/agent-buttons.ts +1 -0
- package/src/frontend/discord/handlers/delivery.ts +3 -0
- package/src/frontend/discord/handlers/queue.ts +1 -0
- package/src/frontend/native/bridge/auth-guard.ts +277 -0
- package/src/frontend/native/bridge/auth.ts +84 -1
- package/src/frontend/native/bridge/credentials/claims.ts +51 -0
- package/src/frontend/native/bridge/credentials/principal.ts +200 -0
- package/src/frontend/native/bridge/credentials/upgrade.ts +129 -0
- package/src/frontend/native/bridge/routes/auth.ts +37 -0
- package/src/frontend/native/bridge/routes/chats.ts +20 -2
- package/src/frontend/native/bridge/routes/host.ts +11 -1
- package/src/frontend/native/bridge/routes/index.ts +2 -0
- package/src/frontend/native/bridge/routes/mesh.ts +72 -15
- package/src/frontend/native/bridge/routes/table.ts +73 -51
- package/src/frontend/native/bridge/server.ts +266 -83
- package/src/frontend/native/index.ts +54 -3
- package/src/frontend/native/turn/turn.ts +2 -0
- package/src/frontend/teams/turn.ts +1 -0
- package/src/frontend/telegram/actions/outgoing-log.ts +70 -0
- package/src/frontend/telegram/actions/send.ts +4 -0
- package/src/frontend/telegram/admin.ts +20 -0
- package/src/frontend/telegram/commands/admin.ts +1 -1
- package/src/frontend/telegram/commands/state.ts +7 -9
- package/src/frontend/telegram/handlers/access.ts +31 -10
- package/src/frontend/telegram/handlers/delivery.ts +14 -1
- package/src/frontend/telegram/handlers/group-access.ts +50 -0
- package/src/frontend/telegram/handlers/messages.ts +1 -0
- package/src/frontend/telegram/handlers/queue.ts +14 -0
- package/src/frontend/telegram/handlers/state.ts +2 -2
- package/src/frontend/telegram/index.ts +32 -9
- package/src/frontend/telegram/middleware.ts +2 -2
- package/src/frontend/telegram/polling/poll-deadline.ts +52 -0
- package/src/frontend/telegram/{stale-command.ts → polling/stale-command.ts} +1 -1
- package/src/frontend/telegram/{update-offset.ts → polling/update-offset.ts} +1 -1
- package/src/frontend/telegram/userbot.ts +103 -10
- package/src/frontend/terminal/index.ts +8 -1
- package/src/frontend/whatsapp/commands.ts +3 -3
- package/src/frontend/whatsapp/messages/inbound.ts +1 -0
- package/src/plugins/playwright/index.ts +1 -1
- package/src/storage/backup/index.ts +1 -1
- package/src/storage/db.ts +23 -0
package/LICENSE
CHANGED
|
@@ -1,21 +1,202 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
1
|
+
|
|
2
|
+
Apache License
|
|
3
|
+
Version 2.0, January 2004
|
|
4
|
+
http://www.apache.org/licenses/
|
|
5
|
+
|
|
6
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
7
|
+
|
|
8
|
+
1. Definitions.
|
|
9
|
+
|
|
10
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
11
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
12
|
+
|
|
13
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
14
|
+
the copyright owner that is granting the License.
|
|
15
|
+
|
|
16
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
17
|
+
other entities that control, are controlled by, or are under common
|
|
18
|
+
control with that entity. For the purposes of this definition,
|
|
19
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
20
|
+
direction or management of such entity, whether by contract or
|
|
21
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
22
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
23
|
+
|
|
24
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
25
|
+
exercising permissions granted by this License.
|
|
26
|
+
|
|
27
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
28
|
+
including but not limited to software source code, documentation
|
|
29
|
+
source, and configuration files.
|
|
30
|
+
|
|
31
|
+
"Object" form shall mean any form resulting from mechanical
|
|
32
|
+
transformation or translation of a Source form, including but
|
|
33
|
+
not limited to compiled object code, generated documentation,
|
|
34
|
+
and conversions to other media types.
|
|
35
|
+
|
|
36
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
37
|
+
Object form, made available under the License, as indicated by a
|
|
38
|
+
copyright notice that is included in or attached to the work
|
|
39
|
+
(an example is provided in the Appendix below).
|
|
40
|
+
|
|
41
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
42
|
+
form, that is based on (or derived from) the Work and for which the
|
|
43
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
44
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
45
|
+
of this License, Derivative Works shall not include works that remain
|
|
46
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
47
|
+
the Work and Derivative Works thereof.
|
|
48
|
+
|
|
49
|
+
"Contribution" shall mean any work of authorship, including
|
|
50
|
+
the original version of the Work and any modifications or additions
|
|
51
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
52
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
53
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
54
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
55
|
+
means any form of electronic, verbal, or written communication sent
|
|
56
|
+
to the Licensor or its representatives, including but not limited to
|
|
57
|
+
communication on electronic mailing lists, source code control systems,
|
|
58
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
59
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
60
|
+
excluding communication that is conspicuously marked or otherwise
|
|
61
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
62
|
+
|
|
63
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
64
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
65
|
+
subsequently incorporated within the Work.
|
|
66
|
+
|
|
67
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
68
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
69
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
70
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
71
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
72
|
+
Work and such Derivative Works in Source or Object form.
|
|
73
|
+
|
|
74
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
75
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
76
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
77
|
+
(except as stated in this section) patent license to make, have made,
|
|
78
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
79
|
+
where such license applies only to those patent claims licensable
|
|
80
|
+
by such Contributor that are necessarily infringed by their
|
|
81
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
82
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
83
|
+
institute patent litigation against any entity (including a
|
|
84
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
85
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
86
|
+
or contributory patent infringement, then any patent licenses
|
|
87
|
+
granted to You under this License for that Work shall terminate
|
|
88
|
+
as of the date such litigation is filed.
|
|
89
|
+
|
|
90
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
91
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
92
|
+
modifications, and in Source or Object form, provided that You
|
|
93
|
+
meet the following conditions:
|
|
94
|
+
|
|
95
|
+
(a) You must give any other recipients of the Work or
|
|
96
|
+
Derivative Works a copy of this License; and
|
|
97
|
+
|
|
98
|
+
(b) You must cause any modified files to carry prominent notices
|
|
99
|
+
stating that You changed the files; and
|
|
100
|
+
|
|
101
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
102
|
+
that You distribute, all copyright, patent, trademark, and
|
|
103
|
+
attribution notices from the Source form of the Work,
|
|
104
|
+
excluding those notices that do not pertain to any part of
|
|
105
|
+
the Derivative Works; and
|
|
106
|
+
|
|
107
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
108
|
+
distribution, then any Derivative Works that You distribute must
|
|
109
|
+
include a readable copy of the attribution notices contained
|
|
110
|
+
within such NOTICE file, excluding those notices that do not
|
|
111
|
+
pertain to any part of the Derivative Works, in at least one
|
|
112
|
+
of the following places: within a NOTICE text file distributed
|
|
113
|
+
as part of the Derivative Works; within the Source form or
|
|
114
|
+
documentation, if provided along with the Derivative Works; or,
|
|
115
|
+
within a display generated by the Derivative Works, if and
|
|
116
|
+
wherever such third-party notices normally appear. The contents
|
|
117
|
+
of the NOTICE file are for informational purposes only and
|
|
118
|
+
do not modify the License. You may add Your own attribution
|
|
119
|
+
notices within Derivative Works that You distribute, alongside
|
|
120
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
121
|
+
that such additional attribution notices cannot be construed
|
|
122
|
+
as modifying the License.
|
|
123
|
+
|
|
124
|
+
You may add Your own copyright statement to Your modifications and
|
|
125
|
+
may provide additional or different license terms and conditions
|
|
126
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
127
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
128
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
129
|
+
the conditions stated in this License.
|
|
130
|
+
|
|
131
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
132
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
133
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
134
|
+
this License, without any additional terms or conditions.
|
|
135
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
136
|
+
the terms of any separate license agreement you may have executed
|
|
137
|
+
with Licensor regarding such Contributions.
|
|
138
|
+
|
|
139
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
140
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
141
|
+
except as required for reasonable and customary use in describing the
|
|
142
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
143
|
+
|
|
144
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
145
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
146
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
147
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
148
|
+
implied, including, without limitation, any warranties or conditions
|
|
149
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
150
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
151
|
+
appropriateness of using or redistributing the Work and assume any
|
|
152
|
+
risks associated with Your exercise of permissions under this License.
|
|
153
|
+
|
|
154
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
155
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
156
|
+
unless required by applicable law (such as deliberate and grossly
|
|
157
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
158
|
+
liable to You for damages, including any direct, indirect, special,
|
|
159
|
+
incidental, or consequential damages of any character arising as a
|
|
160
|
+
result of this License or out of the use or inability to use the
|
|
161
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
162
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
163
|
+
other commercial damages or losses), even if such Contributor
|
|
164
|
+
has been advised of the possibility of such damages.
|
|
165
|
+
|
|
166
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
167
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
168
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
169
|
+
or other liability obligations and/or rights consistent with this
|
|
170
|
+
License. However, in accepting such obligations, You may act only
|
|
171
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
172
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
173
|
+
defend, and hold each Contributor harmless for any liability
|
|
174
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
175
|
+
of your accepting any such warranty or additional liability.
|
|
176
|
+
|
|
177
|
+
END OF TERMS AND CONDITIONS
|
|
178
|
+
|
|
179
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
180
|
+
|
|
181
|
+
To apply the Apache License to your work, attach the following
|
|
182
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
183
|
+
replaced with your own identifying information. (Don't include
|
|
184
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
185
|
+
comment syntax for the file format. We also recommend that a
|
|
186
|
+
file or class name and description of purpose be included on the
|
|
187
|
+
same "printed page" as the copyright notice for easier
|
|
188
|
+
identification within third-party archives.
|
|
189
|
+
|
|
190
|
+
Copyright [yyyy] [name of copyright owner]
|
|
191
|
+
|
|
192
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
193
|
+
you may not use this file except in compliance with the License.
|
|
194
|
+
You may obtain a copy of the License at
|
|
195
|
+
|
|
196
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
197
|
+
|
|
198
|
+
Unless required by applicable law or agreed to in writing, software
|
|
199
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
200
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
201
|
+
See the License for the specific language governing permissions and
|
|
202
|
+
limitations under the License.
|
package/LICENSE-MIT
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 The Falconry
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
Talon
|
|
2
|
+
Copyright 2026 The Falconry
|
|
3
|
+
|
|
4
|
+
This product is licensed under the Apache License, Version 2.0 (see LICENSE).
|
|
5
|
+
|
|
6
|
+
Prior licensing
|
|
7
|
+
---------------
|
|
8
|
+
Every release up to and including v5.18.1 was published under the MIT
|
|
9
|
+
License, preserved verbatim in LICENSE-MIT. That grant is irrevocable: anyone
|
|
10
|
+
who received those versions keeps their MIT rights to them, and the
|
|
11
|
+
contributions made under it remain available on those terms.
|
|
12
|
+
|
|
13
|
+
The relicensing relies on the MIT License's own permission to sublicense, so
|
|
14
|
+
the earlier contributions are redistributed here under Apache-2.0 with the
|
|
15
|
+
original MIT notice retained. Contributions made from this release onward are
|
|
16
|
+
licensed under Apache-2.0 per section 5 of that licence.
|
package/README.md
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
[](https://www.typescriptlang.org/)
|
|
10
10
|
[](#frontends)
|
|
11
11
|
[](#backends)
|
|
12
|
-
[](LICENSE)
|
|
13
|
+
[](https://github.com/thefalconry/talon/actions/workflows/ci.yml)
|
|
14
14
|
|
|
15
15
|
Multi-platform agentic AI harness. Runs on **Telegram**, **WhatsApp**, **Discord**, **Microsoft Teams**, the **Terminal**, and a **cross-platform Desktop/Mobile companion app** (Flutter), with a pluggable backend (**Claude Agent SDK**, **Kilo**, **OpenCode**, **Codex**, **Antigravity**, or **OpenAI Agents**) and full tool access through MCP.
|
|
16
16
|
|
|
@@ -39,7 +39,7 @@ Multi-platform agentic AI harness. Runs on **Telegram**, **WhatsApp**, **Discord
|
|
|
39
39
|
## Quick Start
|
|
40
40
|
|
|
41
41
|
```bash
|
|
42
|
-
git clone https://github.com/
|
|
42
|
+
git clone https://github.com/thefalconry/talon.git && cd talon
|
|
43
43
|
npm install
|
|
44
44
|
|
|
45
45
|
# Interactive setup (select frontend, configure tokens, pick model)
|
|
@@ -73,7 +73,7 @@ modules are embedded in the binary.
|
|
|
73
73
|
|
|
74
74
|
```bash
|
|
75
75
|
# Homebrew (macOS / Linux)
|
|
76
|
-
brew install
|
|
76
|
+
brew install thefalconry/talon/talon
|
|
77
77
|
|
|
78
78
|
# Debian / Ubuntu — download the .deb for your arch from the release, then:
|
|
79
79
|
sudo apt install ./talon_<version>_amd64.deb # or _arm64.deb
|
|
@@ -498,6 +498,9 @@ Config file: `~/.talon/config.json`
|
|
|
498
498
|
| `disabledTools` | --- | Hide individual tools by name (`end_turn` cannot be disabled) |
|
|
499
499
|
| `adminUserId` | --- | Telegram user ID for `/admin` commands |
|
|
500
500
|
| `allowedUsers` | --- | Whitelist of Telegram user IDs |
|
|
501
|
+
| `allowedGroups` | --- | Telegram group IDs the bot serves. Unset: groups the admin is in are still admitted (legacy, warned at startup) |
|
|
502
|
+
| `operatorIds` | --- | Extra operator identities (`"123"`, `"wa_dm_<number>"`, `"discord:<id>"`, `"teams:<id>"`) — only operators get the full tool set |
|
|
503
|
+
| `guestDmScope` | on | Conversation-only tools for non-operator senders. Always applied in groups; `enabled: false` exempts DMs (legacy) |
|
|
501
504
|
| `apiId` / `apiHash` | --- | Telegram API credentials for full message history |
|
|
502
505
|
| `whatsapp` | --- | WhatsApp frontend: pairing, allowlists, group policy ([above](#whatsapp)) |
|
|
503
506
|
| `discord` | --- | Discord frontend: bot token, application ID, guild / channel allowlists |
|
|
@@ -564,7 +567,7 @@ Commands: `/model`, `/effort`, `/context`, `/status`, `/reset`, `/rename`, `/res
|
|
|
564
567
|
|
|
565
568
|
## Production
|
|
566
569
|
|
|
567
|
-
**Docker:** the image runs the daemon on Bun (`bun src/index.ts`); `~/.talon` and `~/.claude` are bind-mounted from the host into the container's `HOME=/home/bun`. Prebuilt images are on GHCR (`ghcr.io/
|
|
570
|
+
**Docker:** the image runs the daemon on Bun (`bun src/index.ts`); `~/.talon` and `~/.claude` are bind-mounted from the host into the container's `HOME=/home/bun`. Prebuilt images are on GHCR (`ghcr.io/thefalconry/talon:latest`), and a first boot can be configured entirely from `TALON_*` environment variables — see **[docs/docker.md](docs/docker.md)** for the quick install, and **[docs/truenas.md](docs/truenas.md)** for a step-by-step TrueNAS SCALE install.
|
|
568
571
|
|
|
569
572
|
```bash
|
|
570
573
|
docker compose up -d
|
|
@@ -576,7 +579,7 @@ The image is also ready for the **Antigravity (`agy`) backend**: add `-f docker-
|
|
|
576
579
|
|
|
577
580
|
**Systemd:** unit file at `packaging/systemd/talon.service` — copy to `/etc/systemd/system/`, set `User=` and `WorkingDirectory=`, then `systemctl enable --now talon`.
|
|
578
581
|
|
|
579
|
-
**Health endpoint:** `GET http://localhost:19876/health` returns
|
|
582
|
+
**Health endpoint:** `GET http://localhost:19876/health` returns the daemon's identity (`app`, `mode`, `pid`, `port`, `startedAt`, `ok`). With the gateway token (`Authorization: Bearer $(cat ~/.talon/keys/gateway-token)`) it also returns uptime, memory, queue depth, active sessions, and last activity timestamp. Every other gateway route requires that token.
|
|
580
583
|
|
|
581
584
|
**Logging:** Structured JSON via pino to `~/.talon/talon.log`. Rotated on startup when the file exceeds 10MB.
|
|
582
585
|
|
|
@@ -607,4 +610,8 @@ smoke-tests the CLI and the MCP supervisor from it.
|
|
|
607
610
|
|
|
608
611
|
## License
|
|
609
612
|
|
|
610
|
-
|
|
613
|
+
Apache License 2.0 — see [LICENSE](LICENSE).
|
|
614
|
+
|
|
615
|
+
Releases up to and including v5.18.1 were published under the MIT License,
|
|
616
|
+
kept at [LICENSE-MIT](LICENSE-MIT). That grant is irrevocable for those
|
|
617
|
+
versions and still covers the contributions made under it — see [NOTICE](NOTICE).
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "talon-agent",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.18.2",
|
|
4
4
|
"description": "Multi-frontend AI agent with full tool access, streaming, cron jobs, and plugin system",
|
|
5
|
-
"author": "
|
|
6
|
-
"license": "
|
|
5
|
+
"author": "The Falconry",
|
|
6
|
+
"license": "Apache-2.0",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "https://github.com/
|
|
9
|
+
"url": "https://github.com/thefalconry/talon.git"
|
|
10
10
|
},
|
|
11
11
|
"keywords": [
|
|
12
12
|
"telegram",
|
|
@@ -52,6 +52,8 @@
|
|
|
52
52
|
"src/login.ts",
|
|
53
53
|
"prompts/",
|
|
54
54
|
"README.md",
|
|
55
|
+
"NOTICE",
|
|
56
|
+
"LICENSE-MIT",
|
|
55
57
|
"tsconfig.json"
|
|
56
58
|
],
|
|
57
59
|
"scripts": {
|
|
@@ -40,7 +40,7 @@ is a primary responsibility, not an optional extra. Goal tools
|
|
|
40
40
|
(`update_goal`, `list_goals`, …) require an explicit `chat_id` parameter
|
|
41
41
|
in heartbeat mode — use the chat id shown next to each goal.
|
|
42
42
|
|
|
43
|
-
OUTBOUND MESSAGING: You also have access to the frontend tool servers — {{toolList}} — which expose `send`, `react`, and the rest of the messaging surface. Because there is NO ambient chat in heartbeat mode, every outbound tool call MUST include an explicit `chat_id` parameter. The bridge promotes that chat_id to the routing target, so `send(type="text", text="...", chat_id=N)` from `{{exampleFrontend}}-tools` delivers a message to chat N on that frontend. Known chat IDs live in your memory.md (per-frontend — for Telegram,
|
|
43
|
+
OUTBOUND MESSAGING: You also have access to the frontend tool servers — {{toolList}} — which expose `send`, `react`, and the rest of the messaging surface. Because there is NO ambient chat in heartbeat mode, every outbound tool call MUST include an explicit `chat_id` parameter. The bridge promotes that chat_id to the routing target, so `send(type="text", text="...", chat_id=N)` from `{{exampleFrontend}}-tools` delivers a message to chat N on that frontend. Known chat IDs live in your memory.md (per-frontend — for Telegram, Ada's DM ID and group IDs are recorded; other frontends list their own). Without `chat_id`, the gateway returns 'No active chat context and no explicit numeric chat_id'. Cross-frontend: every tool server also carries `send_via(frontend=..., target=..., text=...)`, which delivers through ANY enabled frontend — target is the numeric chat id as a string, or for WhatsApp a phone number ("+353871234567") or wa_dm_/wa_group_ id.
|
|
44
44
|
|
|
45
45
|
Reaching out is part of the job, not an exception: when a run turns up
|
|
46
46
|
something a user would genuinely want to know — a goal completed or
|
|
@@ -52,6 +52,9 @@ import {
|
|
|
52
52
|
const agyFactory: BackendFactory = {
|
|
53
53
|
id: "agy",
|
|
54
54
|
label: "Antigravity",
|
|
55
|
+
// Its own shell/file tools can't be withheld per turn, so guest-scoped
|
|
56
|
+
// turns (non-operator senders) are refused rather than run with them.
|
|
57
|
+
guestToolScope: "refused",
|
|
55
58
|
doctor: (config, isActive) => agyDoctorChecks(config, isActive),
|
|
56
59
|
|
|
57
60
|
async init(config, ctx) {
|
|
@@ -45,6 +45,7 @@ import {
|
|
|
45
45
|
} from "../../../core/mcp-hub/index.js";
|
|
46
46
|
import { frontendsForChat } from "../../runtime/frontends.js";
|
|
47
47
|
import { logWarn } from "../../../util/log.js";
|
|
48
|
+
import { gatewayAuthHeaders } from "../../../core/engine/gateway-auth.js";
|
|
48
49
|
import { AGY_MCP_PREFIX } from "../constants.js";
|
|
49
50
|
|
|
50
51
|
// ── Paths ───────────────────────────────────────────────────────────────────
|
|
@@ -77,6 +78,8 @@ function agyMcpSnapshotDir(override?: string): string {
|
|
|
77
78
|
*/
|
|
78
79
|
export interface AgyMcpServer {
|
|
79
80
|
disabled: boolean;
|
|
81
|
+
/** Gateway bearer token (`agy mcp add --header` writes this shape). */
|
|
82
|
+
headers: Record<string, string>;
|
|
80
83
|
serverUrl: string;
|
|
81
84
|
}
|
|
82
85
|
|
|
@@ -129,8 +132,13 @@ export function buildAgyMcpServers(args: {
|
|
|
129
132
|
const { chatId, bridgeUrl, frontends, braveApiKey } = args;
|
|
130
133
|
const scope = args.scope ?? agyScopeSlug(chatId);
|
|
131
134
|
const servers: Record<string, AgyMcpServer> = {};
|
|
135
|
+
const headers = gatewayAuthHeaders();
|
|
132
136
|
const add = (name: string, url: string) => {
|
|
133
|
-
servers[agyServerKey(scope, name)] = {
|
|
137
|
+
servers[agyServerKey(scope, name)] = {
|
|
138
|
+
disabled: false,
|
|
139
|
+
headers,
|
|
140
|
+
serverUrl: url,
|
|
141
|
+
};
|
|
134
142
|
};
|
|
135
143
|
|
|
136
144
|
for (const frontend of frontendsForChat(chatId, frontends)) {
|
|
@@ -198,7 +206,11 @@ function writeConfigAtomic(
|
|
|
198
206
|
mkdirSync(dirname(path), { recursive: true });
|
|
199
207
|
const tmp = `${path}.talon-${randomBytes(6).toString("hex")}.tmp`;
|
|
200
208
|
try {
|
|
201
|
-
|
|
209
|
+
// Owner-only: Talon's entries carry the gateway token.
|
|
210
|
+
writeFileSync(tmp, `${JSON.stringify(file, null, 2)}\n`, {
|
|
211
|
+
encoding: "utf-8",
|
|
212
|
+
mode: 0o600,
|
|
213
|
+
});
|
|
202
214
|
renameSync(tmp, path);
|
|
203
215
|
} catch (err) {
|
|
204
216
|
try {
|
|
@@ -41,6 +41,9 @@ const claudeSdkFactory: BackendFactory = {
|
|
|
41
41
|
// no migration is needed.
|
|
42
42
|
id: "claude",
|
|
43
43
|
label: "Anthropic",
|
|
44
|
+
// Guest turns run with no SDK built-ins and only guest-allowed MCP
|
|
45
|
+
// servers (see options.ts), so the hub's guest scope is the whole surface.
|
|
46
|
+
guestToolScope: "enforced",
|
|
44
47
|
doctor: (config, isActive) => claudeDoctorChecks(config, isActive),
|
|
45
48
|
|
|
46
49
|
async init(config, ctx) {
|
|
@@ -32,10 +32,14 @@ import {
|
|
|
32
32
|
import { toolFingerprint } from "../runtime/cache/cache-telemetry.js";
|
|
33
33
|
import { reportToolFingerprint } from "../runtime/cache/cache-metrics.js";
|
|
34
34
|
import { log, logError } from "../../util/log.js";
|
|
35
|
+
import {
|
|
36
|
+
GATEWAY_TOKEN_ENV,
|
|
37
|
+
gatewayToken,
|
|
38
|
+
} from "../../core/engine/gateway-auth.js";
|
|
35
39
|
import { getConfig, getBridgePort } from "./state.js";
|
|
36
40
|
import { ALLOWED_TOOLS_CHAT, EFFORT_MAP } from "./constants.js";
|
|
37
41
|
import {
|
|
38
|
-
|
|
42
|
+
isGuestTurn,
|
|
39
43
|
isGuestPluginAllowed,
|
|
40
44
|
} from "../../core/mcp-hub/guest-scope.js";
|
|
41
45
|
import { VALID_TOOL_FRONTENDS } from "../../core/mcp-hub/talon-server.js";
|
|
@@ -92,6 +96,8 @@ export function getActiveFrontends(): readonly string[] {
|
|
|
92
96
|
export type HubMcpEntry = {
|
|
93
97
|
type: "http";
|
|
94
98
|
url: string;
|
|
99
|
+
/** Gateway bearer token — see `hubAuthHeaders`. */
|
|
100
|
+
headers: Record<string, string>;
|
|
95
101
|
alwaysLoad?: boolean;
|
|
96
102
|
/** Per-server tool-call timeout in ms (overrides MCP_TOOL_TIMEOUT). */
|
|
97
103
|
timeout?: number;
|
|
@@ -106,6 +112,18 @@ export type HubMcpEntry = {
|
|
|
106
112
|
*/
|
|
107
113
|
const FRONTEND_TOOL_CALL_TIMEOUT_MS = 3_900_000; // 65 min
|
|
108
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Hub auth header for the Claude CLI's MCP config. The SDK hands that config
|
|
117
|
+
* to the CLI on its command line, which other local accounts can read — so
|
|
118
|
+
* the header carries a `${TALON_GATEWAY_TOKEN}` reference the CLI expands
|
|
119
|
+
* from its environment (inherited from the daemon), never the value itself.
|
|
120
|
+
* `gatewayToken()` runs first so the variable is guaranteed to be exported.
|
|
121
|
+
*/
|
|
122
|
+
function hubAuthHeaders(): Record<string, string> {
|
|
123
|
+
gatewayToken();
|
|
124
|
+
return { Authorization: `Bearer \${${GATEWAY_TOKEN_ENV}}` };
|
|
125
|
+
}
|
|
126
|
+
|
|
109
127
|
/**
|
|
110
128
|
* Build the MCP servers map for a chat query.
|
|
111
129
|
* Includes frontend-specific tool servers and Brave Search, if configured.
|
|
@@ -130,6 +148,7 @@ export function buildMcpServers(chatId: string): Record<string, HubMcpEntry> {
|
|
|
130
148
|
servers[`${frontend}-tools`] = {
|
|
131
149
|
type: "http",
|
|
132
150
|
url: talonHubUrl(bridgeUrl, frontend, chatId),
|
|
151
|
+
headers: hubAuthHeaders(),
|
|
133
152
|
// Always include the frontend's tools in the turn-1 prompt instead of
|
|
134
153
|
// deferring them behind the SDK's tool search. These are the bot's
|
|
135
154
|
// primary surface — it needs `end_turn`/`send`/`react` on EVERY turn to
|
|
@@ -155,6 +174,7 @@ export function buildMcpServers(chatId: string): Record<string, HubMcpEntry> {
|
|
|
155
174
|
servers["brave-search"] = {
|
|
156
175
|
type: "http",
|
|
157
176
|
url: pluginHubUrl(bridgeUrl, "brave-search", chatId),
|
|
177
|
+
headers: hubAuthHeaders(),
|
|
158
178
|
};
|
|
159
179
|
}
|
|
160
180
|
|
|
@@ -176,6 +196,7 @@ export function buildPluginMcpServers(
|
|
|
176
196
|
servers[name] = {
|
|
177
197
|
type: "http",
|
|
178
198
|
url: pluginHubUrl(bridgeUrl, name, chatId),
|
|
199
|
+
headers: hubAuthHeaders(),
|
|
179
200
|
};
|
|
180
201
|
}
|
|
181
202
|
return servers;
|
|
@@ -393,10 +414,10 @@ export function buildSdkOptions(
|
|
|
393
414
|
const { postToolUseFailureHook, postToolBatchHook } =
|
|
394
415
|
buildTurnTerminatorHooks();
|
|
395
416
|
|
|
396
|
-
// Guest
|
|
417
|
+
// Guest turns (non-operator sender) get no SDK built-ins at all — Bash/Read/
|
|
397
418
|
// Write/Skill live outside the hub, so the hub's guest scope can't hide
|
|
398
419
|
// them — and only the plugin servers the guest scope allows.
|
|
399
|
-
const guest =
|
|
420
|
+
const guest = isGuestTurn(chatId);
|
|
400
421
|
const builtinTools = guest
|
|
401
422
|
? []
|
|
402
423
|
: config.nativeTools
|
|
@@ -42,6 +42,9 @@ import {
|
|
|
42
42
|
const codexFactory: BackendFactory = {
|
|
43
43
|
id: "codex",
|
|
44
44
|
label: "Codex",
|
|
45
|
+
// Its own shell/file tools can't be withheld per turn, so guest-scoped
|
|
46
|
+
// turns (non-operator senders) are refused rather than run with them.
|
|
47
|
+
guestToolScope: "refused",
|
|
45
48
|
doctor: (config) => codexDoctorChecks(config),
|
|
46
49
|
|
|
47
50
|
async init(config, ctx) {
|
|
@@ -30,6 +30,7 @@ import { getState } from "./state.js";
|
|
|
30
30
|
import { asCodexConfig, buildCodexMcpServers } from "./mcp-config.js";
|
|
31
31
|
import { detectCodexAuth, type CodexAuthInfo } from "./auth.js";
|
|
32
32
|
import { startDiscovery } from "./discovery.js";
|
|
33
|
+
import { gatewayToken } from "../../core/engine/gateway-auth.js";
|
|
33
34
|
import {
|
|
34
35
|
computeAuthFingerprint,
|
|
35
36
|
loadOAuthIncompatStore,
|
|
@@ -199,6 +200,9 @@ export function ensureCodex(chatId: string): Codex {
|
|
|
199
200
|
const codexPathOverride =
|
|
200
201
|
process.env.TALON_CODEX_BINARY || state.config.codexBinary || undefined;
|
|
201
202
|
|
|
203
|
+
// Export TALON_GATEWAY_TOKEN before snapshotting the env: the MCP entries
|
|
204
|
+
// name it via `bearer_token_env_var`.
|
|
205
|
+
gatewayToken();
|
|
202
206
|
const codex = new Codex({
|
|
203
207
|
apiKey,
|
|
204
208
|
baseUrl,
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
hubPluginServerNames,
|
|
31
31
|
} from "../../core/mcp-hub/index.js";
|
|
32
32
|
import type { ToolExclusionConfig } from "../../core/tools/mcp-env.js";
|
|
33
|
+
import { GATEWAY_TOKEN_ENV } from "../../core/engine/gateway-auth.js";
|
|
33
34
|
import { frontendsForChat } from "../runtime/frontends.js";
|
|
34
35
|
|
|
35
36
|
/**
|
|
@@ -69,6 +70,12 @@ export interface CodexMcpServer {
|
|
|
69
70
|
* Serialised as `default_tools_approval_mode` in the TOML config.
|
|
70
71
|
*/
|
|
71
72
|
default_tools_approval_mode?: CodexToolApprovalMode;
|
|
73
|
+
/**
|
|
74
|
+
* Env var holding the hub's bearer token. Codex reads the value from its
|
|
75
|
+
* own environment (inherited from the daemon), so the token never lands
|
|
76
|
+
* in the `--config` flags on its command line.
|
|
77
|
+
*/
|
|
78
|
+
bearer_token_env_var: string;
|
|
72
79
|
}
|
|
73
80
|
|
|
74
81
|
/**
|
|
@@ -140,6 +147,7 @@ export function buildCodexMcpServers(args: {
|
|
|
140
147
|
servers[`${frontend}-tools`] = {
|
|
141
148
|
url: talonHubUrl(bridgeUrl, frontend, chatId),
|
|
142
149
|
default_tools_approval_mode: TALON_MCP_DEFAULT_APPROVAL,
|
|
150
|
+
bearer_token_env_var: GATEWAY_TOKEN_ENV,
|
|
143
151
|
};
|
|
144
152
|
}
|
|
145
153
|
|
|
@@ -149,6 +157,7 @@ export function buildCodexMcpServers(args: {
|
|
|
149
157
|
servers["brave-search"] = {
|
|
150
158
|
url: pluginHubUrl(bridgeUrl, "brave-search", chatId),
|
|
151
159
|
default_tools_approval_mode: TALON_MCP_DEFAULT_APPROVAL,
|
|
160
|
+
bearer_token_env_var: GATEWAY_TOKEN_ENV,
|
|
152
161
|
};
|
|
153
162
|
}
|
|
154
163
|
|
|
@@ -157,6 +166,7 @@ export function buildCodexMcpServers(args: {
|
|
|
157
166
|
servers[name] = {
|
|
158
167
|
url: pluginHubUrl(bridgeUrl, name, chatId),
|
|
159
168
|
default_tools_approval_mode: TALON_MCP_DEFAULT_APPROVAL,
|
|
169
|
+
bearer_token_env_var: GATEWAY_TOKEN_ENV,
|
|
160
170
|
};
|
|
161
171
|
}
|
|
162
172
|
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
* Keyed by auth fingerprint
|
|
40
40
|
* ─────────────────────────
|
|
41
41
|
*
|
|
42
|
-
* If
|
|
42
|
+
* If Ada switches OAuth accounts (e.g. work vs personal) the cache
|
|
43
43
|
* file at `~/.codex/auth.json` changes, and what we learned about
|
|
44
44
|
* account A doesn't necessarily apply to account B. To stay correct
|
|
45
45
|
* across credential changes we tag the store with a fingerprint of the
|
|
@@ -71,7 +71,7 @@ interface CodexTokenTotals {
|
|
|
71
71
|
* "rate_limit_reached_type": null
|
|
72
72
|
* }
|
|
73
73
|
*
|
|
74
|
-
* Exhausted (the silent-exit case on
|
|
74
|
+
* Exhausted (the silent-exit case on Ada's free ChatGPT OAuth):
|
|
75
75
|
* {
|
|
76
76
|
* "limit_id": "premium",
|
|
77
77
|
* "primary": null,
|
|
@@ -242,7 +242,7 @@ export async function readLastTokenCount(
|
|
|
242
242
|
* Returns `null` only when the file can't be found or no `token_count`
|
|
243
243
|
* event exists in it. Returns `{ usage: undefined, rateLimits: {...} }`
|
|
244
244
|
* when a usage-exhausted turn writes a `token_count` event with
|
|
245
|
-
* `info: null` but populated rate_limits (the literal shape on
|
|
245
|
+
* `info: null` but populated rate_limits (the literal shape on Ada's
|
|
246
246
|
* exhausted OAuth account, 2026-05-21).
|
|
247
247
|
*/
|
|
248
248
|
export async function readLastRolloutSnapshot(
|
|
@@ -40,6 +40,9 @@ import {
|
|
|
40
40
|
const openAIAgentsFactory: BackendFactory = {
|
|
41
41
|
id: "openai-agents",
|
|
42
42
|
label: "OpenAI Agents",
|
|
43
|
+
// Its own shell/file tools can't be withheld per turn, so guest-scoped
|
|
44
|
+
// turns (non-operator senders) are refused rather than run with them.
|
|
45
|
+
guestToolScope: "refused",
|
|
43
46
|
doctor: (config) => openAIAgentsDoctorChecks(config),
|
|
44
47
|
|
|
45
48
|
async init(config, ctx) {
|