@fastagent-sh/fastagent 0.18.0 → 0.20.0

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 (222) hide show
  1. package/README.md +25 -7
  2. package/dist/agent.d.ts +1 -1
  3. package/dist/agent.js +1 -1
  4. package/dist/atomic-write.d.ts +23 -0
  5. package/dist/atomic-write.js +53 -0
  6. package/dist/{host/node.d.ts → channel.d.ts} +24 -28
  7. package/dist/channel.js +1 -0
  8. package/dist/channels/agentcore-limits.d.ts +9 -0
  9. package/dist/channels/agentcore-limits.js +9 -0
  10. package/dist/channels/agentcore-service.d.ts +55 -0
  11. package/dist/channels/agentcore-service.js +107 -0
  12. package/dist/channels/agentcore.d.ts +22 -20
  13. package/dist/channels/agentcore.js +20 -11
  14. package/dist/channels/busy.d.ts +1 -1
  15. package/dist/channels/busy.js +1 -1
  16. package/dist/channels/control.d.ts +55 -7
  17. package/dist/channels/control.js +312 -67
  18. package/dist/channels/discover.d.ts +59 -0
  19. package/dist/{engines/pi/channel.js → channels/discover.js} +19 -34
  20. package/dist/channels/feishu/card.js +1 -1
  21. package/dist/channels/feishu/context-buffer.d.ts +1 -1
  22. package/dist/channels/feishu/context-buffer.js +4 -4
  23. package/dist/channels/feishu/feishu-api.js +6 -9
  24. package/dist/channels/feishu/feishu.d.ts +1 -1
  25. package/dist/channels/feishu/feishu.js +41 -24
  26. package/dist/channels/feishu/invoke-turn.d.ts +1 -1
  27. package/dist/channels/feishu/invoke-turn.js +3 -4
  28. package/dist/channels/feishu/preview.d.ts +1 -1
  29. package/dist/channels/feishu/preview.js +7 -3
  30. package/dist/channels/feishu/ws-ingress.d.ts +1 -1
  31. package/dist/channels/github/github.d.ts +1 -1
  32. package/dist/channels/http.d.ts +11 -7
  33. package/dist/channels/http.js +1 -109
  34. package/dist/channels/kit/attachment-path.d.ts +12 -0
  35. package/dist/channels/kit/attachment-path.js +43 -0
  36. package/dist/channels/{context-buffer.d.ts → kit/context-buffer.d.ts} +9 -0
  37. package/dist/channels/{context-buffer.js → kit/context-buffer.js} +13 -2
  38. package/dist/channels/{invoke-turn-kit.d.ts → kit/invoke-turn-kit.d.ts} +14 -3
  39. package/dist/channels/{invoke-turn-kit.js → kit/invoke-turn-kit.js} +17 -6
  40. package/dist/channels/{preview-kit.d.ts → kit/preview-kit.d.ts} +3 -1
  41. package/dist/channels/{seen.js → kit/seen.js} +1 -1
  42. package/dist/channels/kit/signature.d.ts +12 -0
  43. package/dist/channels/kit/signature.js +17 -0
  44. package/dist/channels/{state.js → kit/state.js} +4 -7
  45. package/dist/channels/{stop-command.d.ts → kit/stop-command.d.ts} +1 -1
  46. package/dist/channels/{stop-command.js → kit/stop-command.js} +5 -5
  47. package/dist/channels/{tasks.d.ts → kit/tasks.d.ts} +1 -1
  48. package/dist/channels/{tasks.js → kit/tasks.js} +11 -5
  49. package/dist/channels/{thread-participants.js → kit/thread-participants.js} +1 -1
  50. package/dist/channels/{turn-queue.js → kit/turn-queue.js} +2 -2
  51. package/dist/channels/{turn-store.d.ts → kit/turn-store.d.ts} +19 -3
  52. package/dist/channels/{turn-store.js → kit/turn-store.js} +30 -3
  53. package/dist/channels/lark/lark.d.ts +1 -1
  54. package/dist/channels/serve.d.ts +73 -0
  55. package/dist/channels/serve.js +243 -0
  56. package/dist/channels/slack/bot-auth.js +3 -14
  57. package/dist/channels/slack/context-buffer.d.ts +2 -2
  58. package/dist/channels/slack/context-buffer.js +2 -2
  59. package/dist/channels/slack/invoke-turn.d.ts +2 -2
  60. package/dist/channels/slack/invoke-turn.js +13 -6
  61. package/dist/channels/slack/onboard.js +5 -5
  62. package/dist/channels/slack/onboarding-state.d.ts +7 -3
  63. package/dist/channels/slack/onboarding-state.js +13 -20
  64. package/dist/channels/slack/parse.js +2 -2
  65. package/dist/channels/slack/preview.d.ts +1 -1
  66. package/dist/channels/slack/preview.js +11 -3
  67. package/dist/channels/slack/register-webhook.js +1 -1
  68. package/dist/channels/slack/scaffold/slack-send.ts +2 -17
  69. package/dist/channels/slack/slack-api.js +23 -55
  70. package/dist/channels/slack/slack.d.ts +1 -1
  71. package/dist/channels/slack/slack.js +20 -20
  72. package/dist/channels/slack/welcomed.js +1 -1
  73. package/dist/channels/telegram/context-buffer.d.ts +2 -2
  74. package/dist/channels/telegram/context-buffer.js +2 -2
  75. package/dist/channels/telegram/invoke-turn.d.ts +1 -1
  76. package/dist/channels/telegram/invoke-turn.js +1 -1
  77. package/dist/channels/telegram/parse.d.ts +21 -1
  78. package/dist/channels/telegram/parse.js +67 -13
  79. package/dist/channels/telegram/preview.d.ts +1 -1
  80. package/dist/channels/telegram/preview.js +6 -2
  81. package/dist/channels/telegram/scaffold/channel.ts +7 -3
  82. package/dist/channels/telegram/telegram-api.js +5 -6
  83. package/dist/channels/telegram/telegram.d.ts +3 -3
  84. package/dist/channels/telegram/telegram.js +60 -72
  85. package/dist/channels/telegram/turn-store.d.ts +2 -2
  86. package/dist/channels/telegram/turn-store.js +2 -2
  87. package/dist/cli/add-slack.js +6 -5
  88. package/dist/cli/commands/add.js +1 -5
  89. package/dist/cli/commands/attach.d.ts +2 -4
  90. package/dist/cli/commands/attach.js +17 -15
  91. package/dist/cli/commands/deploy.d.ts +50 -5
  92. package/dist/cli/commands/deploy.js +183 -134
  93. package/dist/cli/commands/dev.js +25 -40
  94. package/dist/cli/commands/fire.js +1 -1
  95. package/dist/cli/commands/info.js +7 -5
  96. package/dist/cli/commands/init.js +1 -2
  97. package/dist/cli/commands/schedule.js +1 -1
  98. package/dist/cli/commands/start.js +80 -121
  99. package/dist/cli/commands/tool.js +5 -7
  100. package/dist/cli/program.js +1 -1
  101. package/dist/cli/serve.d.ts +22 -70
  102. package/dist/cli/serve.js +66 -257
  103. package/dist/cli/shared.d.ts +40 -10
  104. package/dist/cli/shared.js +53 -6
  105. package/dist/core.d.ts +3 -5
  106. package/dist/core.js +7 -5
  107. package/dist/deploy/agentcore/logs.d.ts +2 -2
  108. package/dist/deploy/agentcore/logs.js +2 -2
  109. package/dist/deploy/agentcore/plan.d.ts +12 -10
  110. package/dist/deploy/agentcore/plan.js +39 -31
  111. package/dist/deploy/agentcore/run.d.ts +5 -4
  112. package/dist/deploy/agentcore/run.js +13 -36
  113. package/dist/deploy/channel-ingress.d.ts +73 -0
  114. package/dist/deploy/channel-ingress.js +101 -0
  115. package/dist/deploy/docker/plan.d.ts +3 -7
  116. package/dist/deploy/docker/plan.js +4 -15
  117. package/dist/deploy/docker/run.d.ts +18 -1
  118. package/dist/deploy/docker/run.js +10 -0
  119. package/dist/deploy/fly/plan.d.ts +4 -5
  120. package/dist/deploy/fly/plan.js +7 -22
  121. package/dist/deploy/fly/run.d.ts +9 -23
  122. package/dist/deploy/fly/run.js +32 -68
  123. package/dist/deploy/preflight.d.ts +6 -7
  124. package/dist/deploy/preflight.js +27 -23
  125. package/dist/deploy/railway/plan.d.ts +4 -5
  126. package/dist/deploy/railway/plan.js +11 -26
  127. package/dist/deploy/railway/run.d.ts +9 -9
  128. package/dist/deploy/railway/run.js +40 -40
  129. package/dist/deploy/runner.js +22 -2
  130. package/dist/deploy/secrets.d.ts +18 -9
  131. package/dist/deploy/secrets.js +64 -12
  132. package/dist/dev-supervisor.js +11 -6
  133. package/dist/engines/pi/agent-session-factory.d.ts +104 -0
  134. package/dist/engines/pi/agent-session-factory.js +295 -0
  135. package/dist/engines/pi/auth.js +43 -43
  136. package/dist/engines/pi/config.d.ts +5 -5
  137. package/dist/engines/pi/config.js +1 -1
  138. package/dist/engines/pi/create.d.ts +67 -42
  139. package/dist/engines/pi/create.js +142 -72
  140. package/dist/engines/pi/definition.d.ts +42 -8
  141. package/dist/engines/pi/definition.js +114 -11
  142. package/dist/engines/pi/invoke-session.d.ts +22 -19
  143. package/dist/engines/pi/invoke-session.js +286 -100
  144. package/dist/engines/pi/login.js +39 -20
  145. package/dist/engines/pi/models.d.ts +14 -0
  146. package/dist/engines/pi/models.js +9 -1
  147. package/dist/engines/pi/open.d.ts +10 -8
  148. package/dist/engines/pi/open.js +21 -11
  149. package/dist/engines/pi/report.d.ts +0 -4
  150. package/dist/engines/pi/report.js +0 -7
  151. package/dist/engines/pi/search-tools.js +1 -1
  152. package/dist/engines/pi/service.d.ts +23 -0
  153. package/dist/engines/pi/service.js +27 -0
  154. package/dist/engines/pi/session-builder.js +87 -118
  155. package/dist/engines/pi/session-control.d.ts +28 -14
  156. package/dist/engines/pi/session-control.js +570 -438
  157. package/dist/engines/pi/session-inheritance.d.ts +30 -0
  158. package/dist/engines/pi/session-inheritance.js +261 -0
  159. package/dist/engines/pi/session-markers.d.ts +48 -0
  160. package/dist/engines/pi/session-markers.js +59 -0
  161. package/dist/engines/pi/session-settings.d.ts +15 -3
  162. package/dist/engines/pi/session-settings.js +22 -1
  163. package/dist/engines/pi/session-store.d.ts +140 -0
  164. package/dist/engines/pi/session-store.js +666 -0
  165. package/dist/engines/pi/tool-context.d.ts +36 -13
  166. package/dist/engines/pi/tool-context.js +51 -4
  167. package/dist/engines/pi/tool.d.ts +5 -5
  168. package/dist/engines/pi/tool.js +3 -3
  169. package/dist/engines/pi/turn-kit.d.ts +32 -6
  170. package/dist/engines/pi/turn-kit.js +28 -1
  171. package/dist/engines/pi/wake-tool.js +1 -1
  172. package/dist/env.js +1 -2
  173. package/dist/index.d.ts +1 -0
  174. package/dist/index.js +1 -0
  175. package/dist/loader.d.ts +49 -7
  176. package/dist/loader.js +79 -18
  177. package/dist/log.d.ts +3 -0
  178. package/dist/log.js +5 -1
  179. package/dist/node.d.ts +16 -0
  180. package/dist/node.js +20 -0
  181. package/dist/paths.d.ts +26 -0
  182. package/dist/paths.js +37 -2
  183. package/dist/pi.d.ts +14 -8
  184. package/dist/pi.js +6 -5
  185. package/dist/scaffold/add-channel.js +2 -2
  186. package/dist/scaffold/init.js +7 -2
  187. package/dist/scaffold/templates/persona.md +2 -2
  188. package/dist/scaffold/templates/tools/fetch-url.ts +0 -2
  189. package/dist/schedule/discover.js +3 -15
  190. package/dist/schedule/state.js +4 -9
  191. package/dist/schedule/wake-alarm.d.ts +13 -7
  192. package/dist/schedule/wake-alarm.js +88 -46
  193. package/dist/schedule/wakeups.d.ts +2 -2
  194. package/dist/schedule/wakeups.js +11 -8
  195. package/dist/service.d.ts +157 -0
  196. package/dist/service.js +376 -0
  197. package/dist/session-remote.d.ts +8 -3
  198. package/dist/session-remote.js +162 -92
  199. package/dist/session.d.ts +229 -93
  200. package/dist/session.js +61 -23
  201. package/dist/telegram.d.ts +1 -1
  202. package/dist/telegram.js +1 -1
  203. package/dist/tunnel.d.ts +18 -3
  204. package/dist/tunnel.js +32 -40
  205. package/package.json +14 -5
  206. package/dist/engines/pi/channel.d.ts +0 -37
  207. package/dist/engines/pi/harness.d.ts +0 -115
  208. package/dist/engines/pi/harness.js +0 -154
  209. package/dist/engines/pi/invoke.d.ts +0 -60
  210. package/dist/engines/pi/invoke.js +0 -459
  211. package/dist/engines/pi/read-image.d.ts +0 -4
  212. package/dist/engines/pi/read-image.js +0 -62
  213. package/dist/engines/pi/sessions.d.ts +0 -60
  214. package/dist/engines/pi/sessions.js +0 -464
  215. package/dist/host/node.js +0 -52
  216. /package/dist/channels/{preview-kit.js → kit/preview-kit.js} +0 -0
  217. /package/dist/channels/{seen.d.ts → kit/seen.d.ts} +0 -0
  218. /package/dist/channels/{state.d.ts → kit/state.d.ts} +0 -0
  219. /package/dist/channels/{text.d.ts → kit/text.d.ts} +0 -0
  220. /package/dist/channels/{text.js → kit/text.js} +0 -0
  221. /package/dist/channels/{thread-participants.d.ts → kit/thread-participants.d.ts} +0 -0
  222. /package/dist/channels/{turn-queue.d.ts → kit/turn-queue.d.ts} +0 -0
package/dist/session.d.ts CHANGED
@@ -1,63 +1,193 @@
1
1
  /**
2
2
  * Session control plane — the engine-neutral serving extension beside Agent Handler
3
- * (docs/design/session-control.md). Pure types, zero dependencies; importing any engine
4
- * implementation here is forbidden, exactly like agent.ts.
3
+ * (docs/design/session-control.md). Zero dependencies, no engine import, exactly like agent.ts.
5
4
  *
6
- * The plane model: `invoke` is the only data plane (no run exists without an invoke); `dispatch`
7
- * modulates the run an invoke drives; `state`/`entries`/`events` observe, strictly read-only.
5
+ * `invoke` remains the only data plane: no run exists without one. Everything here observes a run,
6
+ * modulates it, or manages the records it leaves behind and the shape follows which of those a
7
+ * call is, not the transport that carries it. A session's PROPERTIES (name, model, thinking level,
8
+ * where its leaf points) are updated; things that HAPPEN to a run (steer, abort, compact) are
9
+ * actions; the set of sessions is a collection. One verb over all three would make a client spell
10
+ * the session id on every call and read "delete" as something dispatched INTO a session that is
11
+ * about to stop existing.
8
12
  */
9
13
  import type { Json, Prompt } from "./agent.ts";
10
14
  export interface SessionControl {
11
15
  capabilities(): SessionCapabilities;
12
- /** The names this agent exposes — what a composer's `/` completion LISTS. A listing, not a
13
- * dispatch surface: the data plane takes prompts as text, so what typing one means (expanding it,
14
- * sending "use the X skill", filtering a menu) is the client's business. Sessionless (the
16
+ /** The names this agent exposes — what a composer's `/` completion LISTS. A listing, not an
17
+ * invocation surface: the data plane takes prompts as text, so what typing one means (expanding
18
+ * it, sending "use the X skill", filtering a menu) is the client's business. Sessionless (the
15
19
  * definition is a deployment fact) but ASYNC, because a definition is allowed to be live: an
16
20
  * implementation that re-reads it per turn must answer from that same read, or the list and the
17
21
  * behavior diverge. `[]` is a complete answer, not a missing one; a definition the implementation
18
22
  * cannot read at all is a deployment fault and MAY reject. */
19
23
  commands(): Promise<AgentCommand[]>;
20
- state(session: string): Promise<SessionState>;
24
+ sessions: SessionCollection;
25
+ }
26
+ /** The deployment's sessions, as a collection. */
27
+ export interface SessionCollection {
28
+ /** Every session this DEPLOYMENT holds — what a GUI shows as its conversation list, and the only
29
+ * call that is not about ONE session. Deployment-level on purpose: a multi-tenant facade in front
30
+ * of one deployment MUST NOT expose it, because it answers for every user at once. Such a facade
31
+ * does not need it either — `Scope.session` is the Caller's own string, so it already holds the
32
+ * mapping this would return (design §5).
33
+ *
34
+ * The one read that MAY reject: `[]` is a complete answer for a deployment with no sessions, so
35
+ * it would be a lie for a store that cannot be enumerated. Every other read stays TOTAL — their
36
+ * absent fields are answers a control-less deployment gives too. */
37
+ list(): Promise<SessionSummary[]>;
38
+ /**
39
+ * Copy `from`'s history up to entry `at` into a session called `into` — the growth verb beside
40
+ * {@link SessionUpdate.leafEntryId}'s walk, and the two together are what make a session tree
41
+ * usable. Cloning is this with the source's own `leafEntryId`.
42
+ *
43
+ * IDEMPOTENT: `into` is the CALLER's id (the plane never invents one), so repeating a fork that
44
+ * already landed is `ok: true` and writes nothing — a client that retries a request whose response
45
+ * it never saw does not get a second record. `into` naming a session that exists but came from
46
+ * somewhere else rejects `invalid_command`: same id, different history is what the id would then
47
+ * be lying about.
48
+ *
49
+ * Answers a result, not the new session: the caller minted `into` and can {@link get} it.
50
+ */
51
+ fork(options: {
52
+ from: string;
53
+ at: string;
54
+ into: string;
55
+ }): Promise<SessionResult>;
56
+ /** Bind an id. A PURE BINDING — an id plus the transport it travels on: no state, no lifecycle,
57
+ * nothing to dispose, and it does not check that the session exists (the calls on it answer that,
58
+ * each in its own vocabulary). Two handles for one id are interchangeable. */
59
+ get(session: string): Session;
60
+ }
61
+ /**
62
+ * Can this id be ADDRESSED by a client? A session id is an opaque Caller string, and the data plane
63
+ * takes any of it — but a control plane carries the id as a URL path segment, and three strings are
64
+ * not path segments: the empty one, `.` and `..`. URL normalisation eats them before any router
65
+ * sees them (`encodeURIComponent` does not help; the spec normalises `%2E` too), so a request for
66
+ * `.` arrives as a request for the collection and answers about something else entirely.
67
+ *
68
+ * The rule lives HERE, in the contract, because both sides enforce it and they must not drift: a
69
+ * transport rejects such an id rather than sending a request that will silently address its
70
+ * neighbour, and an implementation refuses to MINT one (a fork target nothing could open) — while a
71
+ * session a channel already created under one keeps running, and keeps appearing in `list()`, since
72
+ * hiding it would be the silent half of the same problem.
73
+ */
74
+ export declare function isAddressableSession(session: string): boolean;
75
+ /**
76
+ * One session, bound. Every call here is about THIS session, so the id is spelled once.
77
+ *
78
+ * The split inside it is the one the contract is built on: {@link update} sets PROPERTIES (durable,
79
+ * last-wins, applied by the next turn), while the action methods do things TO A RUN (admitted or
80
+ * rejected now, outcome later on the event stream). {@link SessionResult} says which of the two a
81
+ * given answer is.
82
+ */
83
+ export interface Session {
84
+ readonly id: string;
85
+ state(): Promise<SessionState>;
21
86
  /** `since` is an APPEND-ORDER position cursor: "every record appended after the one with this
22
87
  * id", regardless of branch structure. Reconstructing the active path in a branched session is
23
88
  * the client's job via `parentId` chains from `leafEntryId`. An unknown cursor falls back to a
24
89
  * full backfill (correct, merely larger). */
25
- entries(session: string, options?: {
90
+ entries(options?: {
26
91
  since?: string;
27
92
  }): Promise<SessionEntries>;
28
- events(session: string): AsyncIterable<SessionEvent>;
29
- dispatch(session: string, command: SessionCommand): Promise<SessionResult>;
93
+ events(): AsyncIterable<SessionEvent>;
94
+ /** Set durable session properties. Last-wins, applied by every later turn; an empty patch is a
95
+ * no-op that still answers `ok: true`. Fields outside {@link SessionCapabilities.updatable}
96
+ * reject `unsupported_capability`; invalid values reject `invalid_command`. Takes the same lease
97
+ * as a run (`session_busy` while one is in flight).
98
+ *
99
+ * VALIDATION is all-or-nothing: a rejected patch leaves nothing behind, which is what makes
100
+ * `ok: false` safe to retry. The WRITES need not be one operation — an engine may record each
101
+ * property separately — so a failure BETWEEN them answers {@link PARTIAL_UPDATE_CODE}, naming
102
+ * what landed, after an event reporting the record as it now is. */
103
+ update(patch: SessionUpdate): Promise<SessionResult>;
104
+ /** Join the active run: delivered after the current turn's tool calls, before the next model
105
+ * call. Not polyfillable — its delivery point is an engine primitive. */
106
+ steer(prompt: Prompt): Promise<SessionResult>;
107
+ /** Queue for the active run, FIFO, delivered when it is otherwise idle. */
108
+ followUp(prompt: Prompt): Promise<SessionResult>;
109
+ /** Stop the active run — its queues, its retry delay, its cancellable tool work — or an in-flight
110
+ * {@link compact}, which is the same kind of thing: a model call a client must be able to stop. */
111
+ abort(): Promise<SessionResult>;
112
+ /** Summarize the history at a session boundary. ACCEPT-FAST: a full model call, so `ok: true`
113
+ * means admitted and the outcome travels as `compaction_finished{summary|error|aborted}`. */
114
+ compact(options?: {
115
+ instructions?: string;
116
+ }): Promise<SessionResult>;
117
+ /** Destroy the record. The plane's only IRREVERSIBLE call, guarded by the same bearer token as
118
+ * everything else — the only key the framework owns (design §14). Live {@link events} streams for
119
+ * this session END; a later {@link state} answers for a session that no longer exists. */
120
+ delete(): Promise<SessionResult>;
30
121
  }
122
+ /** The durable properties {@link Session.update} sets. Every field is optional and last-wins; which
123
+ * ones a deployment accepts is {@link SessionCapabilities.updatable}. */
124
+ export interface SessionUpdate {
125
+ /** The display name `list()` reports — a label, not an identity: the id stays the Caller's. */
126
+ name?: string;
127
+ /** A FastAgent model spec, constrained to {@link SessionCapabilities.allowedModels}. Never a
128
+ * provider credential. */
129
+ model?: string;
130
+ /** A string because supported levels are MODEL-dependent — the set for this session's current
131
+ * model is {@link SessionState.availableThinkingLevels}. */
132
+ thinkingLevel?: string;
133
+ /** Move the session's active leaf: the write verb for the tree `entries()` publishes, and how
134
+ * sibling branches come to exist (the next turn hangs off it). Every entry `entries()` publishes
135
+ * is a legal target; anything else rejects `invalid_command`. A move to where the leaf already is
136
+ * writes nothing. There is no move to the ROOT — "start from nothing" is a new session, not an
137
+ * emptied one. */
138
+ leafEntryId?: string;
139
+ }
140
+ /** What {@link Session.update} can be asked to set. */
141
+ export type SessionUpdateField = keyof SessionUpdate;
142
+ /** Every field name, as a value — what an implementation checks a patch against, and what a
143
+ * transport rejects an unknown key by. The `satisfies` anchor keeps it exhaustive: a field added to
144
+ * {@link SessionUpdate} must be added here too, or this stops compiling. */
145
+ export declare const UPDATE_FIELDS: readonly ["name", "model", "thinkingLevel", "leafEntryId"];
146
+ /**
147
+ * The wire form of the run actions — what a transport carries for {@link Session.steer} and its
148
+ * siblings. Clients use the METHODS; this exists so a transport has one body shape to parse, and so
149
+ * an implementation can answer an unknown `type` as `invalid_command` rather than crashing.
150
+ */
151
+ export type SessionAction = {
152
+ type: "steer";
153
+ prompt: Prompt;
154
+ } | {
155
+ type: "follow_up";
156
+ prompt: Prompt;
157
+ } | {
158
+ type: "abort";
159
+ } | {
160
+ type: "compact";
161
+ instructions?: string;
162
+ };
31
163
  /**
32
- * STATIC support declaration — sessionless, so nothing here may depend on a session. Two kinds of flag:
33
- * - COMMAND GATES (`steering`, `followUp`, `manualCompaction`, `modelSelection`, `thinkingLevel`,
34
- * `navigate`):
35
- * clients MUST gate dispatch on them; an unsupported command is rejected before acceptance with
164
+ * STATIC support declaration — sessionless, so nothing here may depend on a session. Two kinds of
165
+ * flag, and the difference decides what a client does with them:
166
+ * - GATES (`steering`, `followUp`, `compaction`, `fork`, `delete`, `updatable`): a client MUST gate
167
+ * its controls on these; calling past one rejects before acceptance with
36
168
  * {@link UNSUPPORTED_CAPABILITY_CODE}.
37
- * - OBSERVATION-QUALITY flags (`toolProgress`, `usage`): whether those events/state fields appear
38
- * at all — nothing to dispatch, nothing to reject.
169
+ * - OBSERVATION QUALITY (`toolProgress`, `usage`): whether those events/state fields appear at all —
170
+ * nothing to call, nothing to reject.
39
171
  *
40
- * `modelSelection` may carry a list because the registry is a deployment fact; thinking levels
41
- * depend on the session's current model, so they live on {@link SessionState.availableThinkingLevels}.
172
+ * `allowedModels` may live here because the registry is a deployment fact; thinking LEVELS depend on
173
+ * the model a session is currently running, so they live on
174
+ * {@link SessionState.availableThinkingLevels} — a static list could only answer for one model.
42
175
  *
43
- * `state`/`entries`/`events` are mandatory (the reconnect contract) and deliberately absent here.
176
+ * `state`/`entries`/`events` and `sessions.list()` are mandatory (the reconnect contract and the
177
+ * conversation list) and deliberately absent here.
44
178
  */
45
179
  export interface SessionCapabilities {
46
180
  steering: boolean;
47
181
  followUp: boolean;
48
- manualCompaction: boolean;
49
- modelSelection: false | {
50
- allowedModels: string[];
51
- };
52
- /** Whether `set_thinking` is servable at all. WHICH levels is per-session see
53
- * {@link SessionState.availableThinkingLevels}. */
54
- thinkingLevel: boolean;
55
- /** Whether `navigate` is servable at all `false` both when the engine's sessions are linear and
56
- * when this deployment has no write path for them; either way the tree the contract publishes
57
- * (`SessionEntry.parentId` + `SessionEntries.leafEntryId`) is read-only here. Named after its COMMAND, unlike the older gates (`manualCompaction` gates
58
- * `compact`, `thinkingLevel` gates `set_thinking`): those already force a client to translate,
59
- * and a gate keyed by the command literal is the only naming a derived map could ever produce. */
60
- navigate: boolean;
182
+ compaction: boolean;
183
+ fork: boolean;
184
+ delete: boolean;
185
+ /** Which {@link SessionUpdate} fields this deployment accepts. A patch naming anything else
186
+ * rejects `unsupported_capability` a LIST rather than a flag per field, so a client reads the
187
+ * same names it writes. */
188
+ updatable: SessionUpdateField[];
189
+ /** The specs `update({ model })` accepts present iff `model` is updatable. */
190
+ allowedModels?: string[];
61
191
  toolProgress: boolean;
62
192
  usage: boolean;
63
193
  }
@@ -73,26 +203,28 @@ export interface AgentCommand {
73
203
  description?: string;
74
204
  source: string;
75
205
  }
76
- /** Stable `SessionResult.error.code` for a command the implementation does not support. */
206
+ /** Stable `SessionResult.error.code` for a call, or an update field, the implementation does not
207
+ * support — the answer to calling past a {@link SessionCapabilities} gate. */
77
208
  export declare const UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
78
- /** Stable `SessionResult.error.code` for a run-modulating command (`steer`/`follow_up`/`abort`)
79
- * dispatched while the session has no active run — and, for `abort`, no in-flight manual
80
- * compaction either (`abort` is also the door out of a `compacting` state; the outcome then
81
- * travels as `compaction_finished{aborted}`). `retryable: false` — re-dispatching as-is fails
82
- * again; re-dispatch only after `state()` shows an active run. */
209
+ /** Stable `SessionResult.error.code` for a run action
210
+ * (`steer`/`follow_up`/`abort`) called while the session has no active run — and, for `abort`, no
211
+ * in-flight compaction either (`abort` is also the door out of a `compacting` state; the outcome
212
+ * then travels as `compaction_finished{aborted}`). `retryable: false` — the same call fails again;
213
+ * call it after `state()` shows an active run. */
83
214
  export declare const NO_ACTIVE_RUN_CODE = "no_active_run";
84
- /** Stable `SessionResult.error.code` for a command whose PAYLOAD is invalid for this runtime — an
85
- * unknown model spec, an unsupported thinking level. Permanent for that payload; a different value
86
- * may succeed. Rejected before acceptance. */
215
+ /** Stable `SessionResult.error.code` for a PAYLOAD that is invalid for this runtime — an unknown
216
+ * model spec, an unsupported thinking level, an entry id that is not a position, a fork onto an id
217
+ * another history already holds. Permanent for that payload; a different value may succeed.
218
+ * Rejected before acceptance. */
87
219
  export declare const INVALID_COMMAND_CODE = "invalid_command";
88
- /** Stable `SessionResult.error.code` for a boundary mutation on a session that does not exist.
89
- * Sessions are created by the DATA plane (`invoke`), never by the control plane — a mutation on an
90
- * unknown id (a typo, a not-yet-started conversation) must not mint a ghost record. Rejected
91
- * before acceptance; retry after the session's first turn exists. */
220
+ /** Stable `SessionResult.error.code` for a write against a session that does not exist. Sessions are
221
+ * created by the DATA plane (`invoke`) or copied by `fork`, never minted by an update — a write on
222
+ * an unknown id (a typo, a not-yet-started conversation) must not create a ghost record. Rejected
223
+ * before acceptance; retry once the session's first turn exists. */
92
224
  export declare const NO_SUCH_SESSION_CODE = "no_such_session";
93
- /** Stable `SessionResult.error.code` for a boundary mutation rejected BEFORE acceptance with
94
- * nothing durable landed — a failed override append, or compact's admission failing (the harness
95
- * build, the local preparation). Acceptance sits where the work becomes asynchronous and
225
+ /** Stable `SessionResult.error.code` for a write rejected BEFORE acceptance with nothing durable
226
+ * landed — a failed property append, a fork whose copy could not be written, or compact's admission
227
+ * failing (binding the session, the local preparation). Acceptance sits where the work becomes asynchronous and
96
228
  * expensive: the model call — compact is accept-fast (holding the dispatch open for a full model
97
229
  * call would make acceptance = outcome), and post-acceptance outcomes travel as
98
230
  * `compaction_finished{summary|error|aborted}` events. `retryable: true` throughout: the same
@@ -101,52 +233,35 @@ export declare const NO_SUCH_SESSION_CODE = "no_such_session";
101
233
  export declare const BOUNDARY_COMMAND_FAILED_CODE = "boundary_command_failed";
102
234
  /** Stable `SessionResult.error.code` for `compact` on a session with no compactable history yet —
103
235
  * a no-op, not a failure, rejected before acceptance. The {@link NO_ACTIVE_RUN_CODE} pattern:
104
- * `retryable: false` (as-is retry fails now), re-dispatch once the session has grown. */
236
+ * `retryable: false` (as-is retry fails now), call it again once the session has grown. */
105
237
  export declare const NOTHING_TO_COMPACT_CODE = "nothing_to_compact";
106
- /** Stable `SessionResult.error.code` for a run command that reached an active run but could not
107
- * take effect because the run raced to settlement (or the engine refused it). Distinct from
108
- * {@link NO_ACTIVE_RUN_CODE}: the run existed — and TRANSIENT: the session's next run can be
109
- * dispatched to. Still pre-acceptance — nothing was queued — and `retryable: false`: the same
110
- * command as-is fails again. (A run registered without modulation controls is a capability
111
- * problem, not a run problem, and rejects with {@link UNSUPPORTED_CAPABILITY_CODE}.) */
238
+ /** Stable `SessionResult.error.code` for a run action that reached an active run but could not take
239
+ * effect because the run raced to settlement (or the engine refused it). Distinct from
240
+ * {@link NO_ACTIVE_RUN_CODE}: the run existed — and TRANSIENT: the session's next run can be acted
241
+ * on. Still pre-acceptance — nothing was queued — and `retryable: false`: the same call fails
242
+ * again. (A run registered without modulation controls is a capability problem, not a run problem,
243
+ * and rejects with {@link UNSUPPORTED_CAPABILITY_CODE}.) */
112
244
  export declare const RUN_COMMAND_FAILED_CODE = "run_command_failed";
113
- /** Seven commands; deliberately NO `prompt`starting work is the data plane's definition. */
114
- export type SessionCommand = {
115
- type: "steer";
116
- prompt: Prompt;
117
- } | {
118
- type: "follow_up";
119
- prompt: Prompt;
120
- } | {
121
- type: "abort";
122
- } | {
123
- type: "compact";
124
- instructions?: string;
125
- } | {
126
- type: "set_model";
127
- model: string;
128
- } | {
129
- type: "set_thinking";
130
- level: string;
131
- }
132
- /** Move the session's active leaf to `targetId`, an existing entry — the write verb for the tree
133
- * `entries()` already publishes (and how sibling branches come to exist: the next turn hangs off
134
- * the new leaf). Every entry `entries()` publishes is a legal target; a `targetId` that is not
135
- * one rejects `invalid_command`. A boundary mutation otherwise: same lease as a run. */
136
- | {
137
- type: "navigate";
138
- targetId: string;
139
- };
245
+ /** What {@link SessionCollection.list} rejects withthe only read that can (see it for why). Not a
246
+ * `SessionResult`: it REJECTS, and a transport carries this code in the error body of a non-2xx
247
+ * (design §13). `retryable: true` — the condition is the store's availability, not the request. */
248
+ export declare const SESSIONS_UNAVAILABLE_CODE = "sessions_unavailable";
249
+ /** Stable `SessionResult.error.code` for a multi-field {@link Session.update} that wrote some of its
250
+ * fields and then failed. It exists because {@link BOUNDARY_COMMAND_FAILED_CODE} promises the
251
+ * opposite — nothing durable landed — and an implementation cannot keep that promise across
252
+ * properties an engine records as separate journal entries. `retryable: false`: re-sending the same
253
+ * patch would re-apply what already landed, so a client reads `state()` (or the `state_changed`
254
+ * this emits first, which reports the record as it now is) and decides what is left to ask for. */
255
+ export declare const PARTIAL_UPDATE_CODE = "partial_update";
140
256
  /**
141
257
  * Acceptance is not outcome: `ok: true` means admitted or applied, never that the run ultimately
142
258
  * succeeded (outcomes are `run_settled` events / the invoke terminal). `ok: false` is guaranteed to
143
259
  * mean rejection BEFORE acceptance — nothing was queued or applied. ONE exception to "nothing took
144
260
  * effect": a rejected `abort` may still have attributed a concurrently-settling run as `aborted`
145
261
  * (the intent was live while the run resolved — see the guarantee boundary in the pi
146
- * implementation); the settlement is the truth. `error.retryable` means "re-dispatching the SAME
147
- * command as-is may succeed"; a `false` with a state-dependent code (e.g.
148
- * {@link NO_ACTIVE_RUN_CODE}) invites a re-dispatch only after `state()` shows the condition
149
- * changed.
262
+ * implementation); the settlement is the truth. `error.retryable` means "the SAME call as-is may
263
+ * succeed"; a `false` with a state-dependent code (e.g. {@link NO_ACTIVE_RUN_CODE}) invites another
264
+ * call only after `state()` shows the condition changed.
150
265
  */
151
266
  export type SessionResult = {
152
267
  ok: true;
@@ -159,7 +274,22 @@ export type SessionResult = {
159
274
  retryable: boolean;
160
275
  };
161
276
  };
277
+ /** One session in {@link SessionControl.sessions} — a conversation-list row, not a session's
278
+ * contents. `session` is the CALLER's id (the string a channel minted), never a storage name. */
279
+ export interface SessionSummary {
280
+ session: string;
281
+ /** Set by `update({ name })`; absent until then — a client showing a list falls back to `preview`. */
282
+ name?: string;
283
+ createdAt: number;
284
+ updatedAt: number;
285
+ messageCount: number;
286
+ /** First user message, truncated — enough for a list row, not a transcript. */
287
+ preview?: string;
288
+ }
162
289
  export interface SessionState {
290
+ /** Set by `update({ name })`, so a client that opens a session directly gets the same label the list
291
+ * showed. */
292
+ name?: string;
163
293
  /** `compacting` refers to Phase 2 MANUAL compaction at a session boundary. Automatic overflow
164
294
  * compaction happens inside a run's activity window and reports as `running`. */
165
295
  status: "idle" | "running" | "compacting";
@@ -169,7 +299,7 @@ export interface SessionState {
169
299
  * model cannot do is clamped). Absent where the implementation exposes no model control. */
170
300
  model?: string;
171
301
  thinkingLevel?: string;
172
- /** What `set_thinking` accepts for THIS session — re-read after a `set_model`. */
302
+ /** What `update({ thinkingLevel })` accepts for THIS session — re-read after a model change. */
173
303
  availableThinkingLevels?: string[];
174
304
  pending: {
175
305
  steering: number;
@@ -263,11 +393,15 @@ export type QueueChangedEvent = SessionEvent<"queue_changed", {
263
393
  }> & {
264
394
  runId: string;
265
395
  };
266
- /** A boundary mutation changed durable session state (L2; no runId — boundary mutations happen
267
- * between runs). `leafEntryId` reports a `navigate` a deliberate move of the branch head, which
268
- * a second attached client would otherwise have no signal for. It is NOT a general leaf feed:
269
- * every turn advances the leaf too, and that is read from `entries()`/`state()` after the run. */
396
+ /** An {@link Session.update} changed durable session state (L2; no runId — a property is set between
397
+ * runs). Carries what LANDED, read back from the record: a patch that set two fields reports both,
398
+ * and one that failed partway reports only what applied.
399
+ *
400
+ * `leafEntryId` reports a deliberate move of the branch head, which a second attached client would
401
+ * otherwise have no signal for. It is NOT a general leaf feed: every turn advances the leaf too,
402
+ * and that is read from `entries()`/`state()` after the run. */
270
403
  export type StateChangedEvent = SessionEvent<"state_changed", {
404
+ name?: string;
271
405
  model?: string;
272
406
  thinkingLevel?: string;
273
407
  leafEntryId?: string;
@@ -289,7 +423,9 @@ export type CompactionFinishedEvent = SessionEvent<"compaction_finished", {
289
423
  * the next event (message_*, `run_settled`, `compaction_finished`) is the closure, and the
290
424
  * engine's `retry_finished` carries no outcome to forward. */
291
425
  export type RetryScheduledEvent = SessionEvent<"retry_scheduled", {
292
- operation: "compaction" | "branch_summary";
426
+ /** "assistant" is an engine that retries the ANSWER request itself (pi's AgentSession does;
427
+ * pi's own session does; a summarization call is the other two). */
428
+ operation: "assistant" | "compaction" | "branch_summary";
293
429
  attempt: number;
294
430
  maxAttempts: number;
295
431
  delayMs: number;
package/dist/session.js CHANGED
@@ -1,23 +1,50 @@
1
- /** Stable `SessionResult.error.code` for a command the implementation does not support. */
1
+ /**
2
+ * Can this id be ADDRESSED by a client? A session id is an opaque Caller string, and the data plane
3
+ * takes any of it — but a control plane carries the id as a URL path segment, and three strings are
4
+ * not path segments: the empty one, `.` and `..`. URL normalisation eats them before any router
5
+ * sees them (`encodeURIComponent` does not help; the spec normalises `%2E` too), so a request for
6
+ * `.` arrives as a request for the collection and answers about something else entirely.
7
+ *
8
+ * The rule lives HERE, in the contract, because both sides enforce it and they must not drift: a
9
+ * transport rejects such an id rather than sending a request that will silently address its
10
+ * neighbour, and an implementation refuses to MINT one (a fork target nothing could open) — while a
11
+ * session a channel already created under one keeps running, and keeps appearing in `list()`, since
12
+ * hiding it would be the silent half of the same problem.
13
+ */
14
+ export function isAddressableSession(session) {
15
+ return session !== "" && session !== "." && session !== "..";
16
+ }
17
+ /** Every field name, as a value — what an implementation checks a patch against, and what a
18
+ * transport rejects an unknown key by. The `satisfies` anchor keeps it exhaustive: a field added to
19
+ * {@link SessionUpdate} must be added here too, or this stops compiling. */
20
+ export const UPDATE_FIELDS = [
21
+ "name",
22
+ "model",
23
+ "thinkingLevel",
24
+ "leafEntryId",
25
+ ];
26
+ /** Stable `SessionResult.error.code` for a call, or an update field, the implementation does not
27
+ * support — the answer to calling past a {@link SessionCapabilities} gate. */
2
28
  export const UNSUPPORTED_CAPABILITY_CODE = "unsupported_capability";
3
- /** Stable `SessionResult.error.code` for a run-modulating command (`steer`/`follow_up`/`abort`)
4
- * dispatched while the session has no active run — and, for `abort`, no in-flight manual
5
- * compaction either (`abort` is also the door out of a `compacting` state; the outcome then
6
- * travels as `compaction_finished{aborted}`). `retryable: false` — re-dispatching as-is fails
7
- * again; re-dispatch only after `state()` shows an active run. */
29
+ /** Stable `SessionResult.error.code` for a run action
30
+ * (`steer`/`follow_up`/`abort`) called while the session has no active run — and, for `abort`, no
31
+ * in-flight compaction either (`abort` is also the door out of a `compacting` state; the outcome
32
+ * then travels as `compaction_finished{aborted}`). `retryable: false` — the same call fails again;
33
+ * call it after `state()` shows an active run. */
8
34
  export const NO_ACTIVE_RUN_CODE = "no_active_run";
9
- /** Stable `SessionResult.error.code` for a command whose PAYLOAD is invalid for this runtime — an
10
- * unknown model spec, an unsupported thinking level. Permanent for that payload; a different value
11
- * may succeed. Rejected before acceptance. */
35
+ /** Stable `SessionResult.error.code` for a PAYLOAD that is invalid for this runtime — an unknown
36
+ * model spec, an unsupported thinking level, an entry id that is not a position, a fork onto an id
37
+ * another history already holds. Permanent for that payload; a different value may succeed.
38
+ * Rejected before acceptance. */
12
39
  export const INVALID_COMMAND_CODE = "invalid_command";
13
- /** Stable `SessionResult.error.code` for a boundary mutation on a session that does not exist.
14
- * Sessions are created by the DATA plane (`invoke`), never by the control plane — a mutation on an
15
- * unknown id (a typo, a not-yet-started conversation) must not mint a ghost record. Rejected
16
- * before acceptance; retry after the session's first turn exists. */
40
+ /** Stable `SessionResult.error.code` for a write against a session that does not exist. Sessions are
41
+ * created by the DATA plane (`invoke`) or copied by `fork`, never minted by an update — a write on
42
+ * an unknown id (a typo, a not-yet-started conversation) must not create a ghost record. Rejected
43
+ * before acceptance; retry once the session's first turn exists. */
17
44
  export const NO_SUCH_SESSION_CODE = "no_such_session";
18
- /** Stable `SessionResult.error.code` for a boundary mutation rejected BEFORE acceptance with
19
- * nothing durable landed — a failed override append, or compact's admission failing (the harness
20
- * build, the local preparation). Acceptance sits where the work becomes asynchronous and
45
+ /** Stable `SessionResult.error.code` for a write rejected BEFORE acceptance with nothing durable
46
+ * landed — a failed property append, a fork whose copy could not be written, or compact's admission
47
+ * failing (binding the session, the local preparation). Acceptance sits where the work becomes asynchronous and
21
48
  * expensive: the model call — compact is accept-fast (holding the dispatch open for a full model
22
49
  * call would make acceptance = outcome), and post-acceptance outcomes travel as
23
50
  * `compaction_finished{summary|error|aborted}` events. `retryable: true` throughout: the same
@@ -26,12 +53,23 @@ export const NO_SUCH_SESSION_CODE = "no_such_session";
26
53
  export const BOUNDARY_COMMAND_FAILED_CODE = "boundary_command_failed";
27
54
  /** Stable `SessionResult.error.code` for `compact` on a session with no compactable history yet —
28
55
  * a no-op, not a failure, rejected before acceptance. The {@link NO_ACTIVE_RUN_CODE} pattern:
29
- * `retryable: false` (as-is retry fails now), re-dispatch once the session has grown. */
56
+ * `retryable: false` (as-is retry fails now), call it again once the session has grown. */
30
57
  export const NOTHING_TO_COMPACT_CODE = "nothing_to_compact";
31
- /** Stable `SessionResult.error.code` for a run command that reached an active run but could not
32
- * take effect because the run raced to settlement (or the engine refused it). Distinct from
33
- * {@link NO_ACTIVE_RUN_CODE}: the run existed — and TRANSIENT: the session's next run can be
34
- * dispatched to. Still pre-acceptance — nothing was queued — and `retryable: false`: the same
35
- * command as-is fails again. (A run registered without modulation controls is a capability
36
- * problem, not a run problem, and rejects with {@link UNSUPPORTED_CAPABILITY_CODE}.) */
58
+ /** Stable `SessionResult.error.code` for a run action that reached an active run but could not take
59
+ * effect because the run raced to settlement (or the engine refused it). Distinct from
60
+ * {@link NO_ACTIVE_RUN_CODE}: the run existed — and TRANSIENT: the session's next run can be acted
61
+ * on. Still pre-acceptance — nothing was queued — and `retryable: false`: the same call fails
62
+ * again. (A run registered without modulation controls is a capability problem, not a run problem,
63
+ * and rejects with {@link UNSUPPORTED_CAPABILITY_CODE}.) */
37
64
  export const RUN_COMMAND_FAILED_CODE = "run_command_failed";
65
+ /** What {@link SessionCollection.list} rejects with — the only read that can (see it for why). Not a
66
+ * `SessionResult`: it REJECTS, and a transport carries this code in the error body of a non-2xx
67
+ * (design §13). `retryable: true` — the condition is the store's availability, not the request. */
68
+ export const SESSIONS_UNAVAILABLE_CODE = "sessions_unavailable";
69
+ /** Stable `SessionResult.error.code` for a multi-field {@link Session.update} that wrote some of its
70
+ * fields and then failed. It exists because {@link BOUNDARY_COMMAND_FAILED_CODE} promises the
71
+ * opposite — nothing durable landed — and an implementation cannot keep that promise across
72
+ * properties an engine records as separate journal entries. `retryable: false`: re-sending the same
73
+ * patch would re-apply what already landed, so a client reads `state()` (or the `state_changed`
74
+ * this emits first, which reports the record as it now is) and decides what is left to ask for. */
75
+ export const PARTIAL_UPDATE_CODE = "partial_update";
@@ -1,2 +1,2 @@
1
1
  /** `@fastagent-sh/fastagent/telegram` — the Telegram bot channel subpath export, kept off the root surface. */
2
- export { telegramChannel, defaultTelegramRoute, telegramEnvelope, type TelegramChannelOptions, type TelegramUpdate, type TelegramMessage, type TelegramRoute, type TelegramFailure, } from "./channels/telegram/telegram.ts";
2
+ export { telegramChannel, defaultTelegramRoute, telegramEnvelope, telegramStop, type TelegramChannelOptions, type TelegramUpdate, type TelegramMessage, type TelegramRoute, type TelegramFailure, } from "./channels/telegram/telegram.ts";
package/dist/telegram.js CHANGED
@@ -1,2 +1,2 @@
1
1
  /** `@fastagent-sh/fastagent/telegram` — the Telegram bot channel subpath export, kept off the root surface. */
2
- export { telegramChannel, defaultTelegramRoute, telegramEnvelope, } from "./channels/telegram/telegram.js";
2
+ export { telegramChannel, defaultTelegramRoute, telegramEnvelope, telegramStop, } from "./channels/telegram/telegram.js";
package/dist/tunnel.d.ts CHANGED
@@ -7,6 +7,8 @@
7
7
  * Process orchestration, not assembly — lives outside the engine, beside dev-supervisor.ts.
8
8
  */
9
9
  import { type ChildProcess } from "node:child_process";
10
+ import type { RegistrationOutcome } from "./channels/registration.ts";
11
+ import type { DeclaredChannel } from "./channels/discover.ts";
10
12
  export interface Tunnel {
11
13
  url: string;
12
14
  close(): void;
@@ -28,10 +30,23 @@ export declare function startCloudflareTunnel(port: number, spawnFn?: SpawnCloud
28
30
  * Print the public URL and wire up first-party webhook channels found under `dir` (the agent
29
31
  * ROOT): Telegram and Feishu/Lark use runtime credentials; onboarded Slack uses its owner-local config
30
32
  * token; GitHub and a manually scaffolded Slack app receive explicit console URLs.
33
+ *
34
+ * Returns what each registrar ANSWERED, because two kinds of caller need different things from a
35
+ * failure. `dev`/`start` are long-running: a webhook that did not register is a logged problem, not
36
+ * a reason to stop serving, and they void this. `deploy … --run` is a command that exits, and an
37
+ * exit 0 there tells its caller the deployment is reachable — so it feeds these through
38
+ * `registrationGate`, exactly as the fly/railway/agentcore runners feed their own registrar calls
39
+ * (docker used to be the one host that could not, because this returned nothing).
31
40
  */
32
- export declare function announceWebhooks(dir: string, baseUrl: string, opts?: {
41
+ export declare function announceWebhooks(dir: string, baseUrl: string,
42
+ /** Every declared channel with its ingress. Not a pre-filtered list: this used to accept "the route
43
+ * channels" and default to every basename in `channels/`, which pointed a webhook at a
44
+ * long-connection channel whenever a caller forgot to filter. {@link pointChannelsAt} filters. */
45
+ channels: readonly DeclaredChannel[], opts?: {
33
46
  openUrl?: (url: string) => void;
34
- routeChannels?: string[];
35
47
  stateRoot?: string;
36
- }): Promise<void>;
48
+ }): Promise<{
49
+ kind: string;
50
+ outcome: RegistrationOutcome;
51
+ }[]>;
37
52
  export {};