@gajae-code/coding-agent 0.6.5 → 0.7.1
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/CHANGELOG.md +38 -0
- package/dist/types/async/job-manager.d.ts +3 -1
- package/dist/types/cli/daemon-cli.d.ts +25 -0
- package/dist/types/cli/notify-cli.d.ts +23 -0
- package/dist/types/cli/setup-cli.d.ts +20 -1
- package/dist/types/commands/daemon.d.ts +41 -0
- package/dist/types/commands/notify.d.ts +41 -0
- package/dist/types/config/model-profile-activation.d.ts +12 -0
- package/dist/types/config/model-profiles.d.ts +2 -1
- package/dist/types/config/model-registry.d.ts +3 -3
- package/dist/types/config/models-config-schema.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +38 -0
- package/dist/types/coordinator/contract.d.ts +1 -1
- package/dist/types/daemon/builtin.d.ts +20 -0
- package/dist/types/daemon/control-types.d.ts +57 -0
- package/dist/types/daemon/runtime.d.ts +25 -0
- package/dist/types/extensibility/extensions/types.d.ts +8 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +2 -0
- package/dist/types/gjc-runtime/tmux-common.d.ts +3 -0
- package/dist/types/gjc-runtime/tmux-sessions.d.ts +2 -0
- package/dist/types/gjc-runtime/ultragoal-guard.d.ts +15 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +14 -0
- package/dist/types/modes/components/oauth-selector.d.ts +2 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -2
- package/dist/types/modes/interactive-mode.d.ts +1 -1
- package/dist/types/modes/shared/agent-wire/unattended-session.d.ts +10 -0
- package/dist/types/modes/types.d.ts +7 -1
- package/dist/types/notifications/config-commands.d.ts +26 -0
- package/dist/types/notifications/config.d.ts +61 -0
- package/dist/types/notifications/helpers.d.ts +55 -0
- package/dist/types/notifications/html-format.d.ts +62 -0
- package/dist/types/notifications/index.d.ts +28 -0
- package/dist/types/notifications/rate-limit-pool.d.ts +93 -0
- package/dist/types/notifications/telegram-cli.d.ts +19 -0
- package/dist/types/notifications/telegram-daemon-cli.d.ts +11 -0
- package/dist/types/notifications/telegram-daemon-control.d.ts +56 -0
- package/dist/types/notifications/telegram-daemon.d.ts +276 -0
- package/dist/types/notifications/telegram-reference.d.ts +111 -0
- package/dist/types/notifications/threaded-inbound.d.ts +58 -0
- package/dist/types/notifications/threaded-render.d.ts +66 -0
- package/dist/types/notifications/topic-registry.d.ts +67 -0
- package/dist/types/rlm/index.d.ts +12 -0
- package/dist/types/session/agent-session.d.ts +39 -2
- package/dist/types/session/auth-storage.d.ts +1 -1
- package/dist/types/setup/credential-auto-import.d.ts +63 -0
- package/dist/types/setup/credential-import.d.ts +3 -0
- package/dist/types/setup/host-plugin-setup.d.ts +39 -0
- package/dist/types/tools/ask-answer-registry.d.ts +13 -0
- package/dist/types/tools/index.d.ts +18 -0
- package/dist/types/tools/subagent.d.ts +3 -0
- package/package.json +7 -7
- package/scripts/build-binary.ts +3 -0
- package/src/async/job-manager.ts +5 -1
- package/src/cli/daemon-cli.ts +122 -0
- package/src/cli/notify-cli.ts +274 -0
- package/src/cli/setup-cli.ts +173 -84
- package/src/cli.ts +3 -3
- package/src/commands/daemon.ts +47 -0
- package/src/commands/notify.ts +61 -0
- package/src/commands/setup.ts +11 -1
- package/src/config/model-profile-activation.ts +74 -5
- package/src/config/model-profiles.ts +7 -4
- package/src/config/model-registry.ts +6 -3
- package/src/config/models-config-schema.ts +1 -1
- package/src/config/settings-schema.ts +29 -0
- package/src/coordinator/contract.ts +3 -0
- package/src/coordinator-mcp/server.ts +270 -1
- package/src/daemon/builtin.ts +46 -0
- package/src/daemon/control-types.ts +65 -0
- package/src/daemon/runtime.ts +51 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +16 -0
- package/src/edit/modes/replace.ts +1 -1
- package/src/extensibility/extensions/runner.ts +4 -0
- package/src/extensibility/extensions/types.ts +8 -0
- package/src/gjc-runtime/deep-interview-recorder.ts +12 -4
- package/src/gjc-runtime/launch-tmux.ts +10 -2
- package/src/gjc-runtime/state-runtime.ts +18 -4
- package/src/gjc-runtime/state-writer.ts +8 -8
- package/src/gjc-runtime/tmux-common.ts +8 -0
- package/src/gjc-runtime/tmux-sessions.ts +8 -1
- package/src/gjc-runtime/ultragoal-guard.ts +57 -2
- package/src/gjc-runtime/ultragoal-runtime.ts +105 -19
- package/src/gjc-runtime/workflow-manifest.generated.json +27 -2
- package/src/gjc-runtime/workflow-manifest.ts +11 -1
- package/src/goals/tools/goal-tool.ts +11 -2
- package/src/hashline/hash.ts +1 -1
- package/src/internal-urls/docs-index.generated.ts +9 -7
- package/src/main.ts +30 -0
- package/src/modes/acp/acp-event-mapper.ts +1 -0
- package/src/modes/components/hook-editor.ts +7 -2
- package/src/modes/components/oauth-selector.ts +19 -0
- package/src/modes/controllers/event-controller.ts +20 -0
- package/src/modes/controllers/selector-controller.ts +80 -17
- package/src/modes/interactive-mode.ts +6 -2
- package/src/modes/runtime-init.ts +1 -0
- package/src/modes/shared/agent-wire/event-contract.ts +1 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +1 -0
- package/src/modes/shared/agent-wire/event-observation.ts +16 -0
- package/src/modes/shared/agent-wire/unattended-session.ts +22 -0
- package/src/modes/types.ts +7 -1
- package/src/modes/utils/ui-helpers.ts +23 -0
- package/src/notifications/config-commands.ts +50 -0
- package/src/notifications/config.ts +107 -0
- package/src/notifications/helpers.ts +135 -0
- package/src/notifications/html-format.ts +389 -0
- package/src/notifications/index.ts +700 -0
- package/src/notifications/rate-limit-pool.ts +179 -0
- package/src/notifications/telegram-cli.ts +194 -0
- package/src/notifications/telegram-daemon-cli.ts +74 -0
- package/src/notifications/telegram-daemon-control.ts +370 -0
- package/src/notifications/telegram-daemon.ts +1370 -0
- package/src/notifications/telegram-reference.ts +335 -0
- package/src/notifications/threaded-inbound.ts +80 -0
- package/src/notifications/threaded-render.ts +155 -0
- package/src/notifications/topic-registry.ts +133 -0
- package/src/rlm/index.ts +19 -0
- package/src/sdk.ts +16 -0
- package/src/session/agent-session.ts +113 -3
- package/src/session/auth-storage.ts +3 -0
- package/src/session/session-dump-format.ts +43 -2
- package/src/session/session-manager.ts +39 -5
- package/src/setup/credential-auto-import.ts +258 -0
- package/src/setup/credential-import.ts +17 -0
- package/src/setup/hermes/templates/operator-instructions.v1.md +10 -0
- package/src/setup/host-plugin-setup.ts +142 -0
- package/src/slash-commands/builtin-registry.ts +4 -1
- package/src/task/executor.ts +5 -1
- package/src/tools/ask-answer-registry.ts +25 -0
- package/src/tools/ask.ts +77 -6
- package/src/tools/image-gen.ts +5 -8
- package/src/tools/index.ts +19 -0
- package/src/tools/inspect-image.ts +16 -11
- package/src/tools/subagent-render.ts +7 -0
- package/src/tools/subagent.ts +38 -7
|
@@ -0,0 +1,276 @@
|
|
|
1
|
+
import * as fs from "node:fs";
|
|
2
|
+
import type { Settings } from "../config/settings";
|
|
3
|
+
import type { DaemonRuntimeInfo } from "../daemon/control-types";
|
|
4
|
+
import { type AliasTable, type CallbackRoute, type PendingAsk } from "./telegram-reference";
|
|
5
|
+
export type EnsureDaemonResult = "owner_spawned" | "attached" | "disabled";
|
|
6
|
+
export interface DaemonState {
|
|
7
|
+
pid: number;
|
|
8
|
+
ownerId: string;
|
|
9
|
+
tokenFingerprint: string;
|
|
10
|
+
chatId: string;
|
|
11
|
+
startedAt: number;
|
|
12
|
+
heartbeatAt: number;
|
|
13
|
+
roots: string[];
|
|
14
|
+
version: 1;
|
|
15
|
+
stoppedAt?: number;
|
|
16
|
+
}
|
|
17
|
+
export interface DaemonPaths {
|
|
18
|
+
dir: string;
|
|
19
|
+
lock: string;
|
|
20
|
+
state: string;
|
|
21
|
+
roots: string;
|
|
22
|
+
steal: string;
|
|
23
|
+
aliases: string;
|
|
24
|
+
}
|
|
25
|
+
export interface TelegramDaemonFs {
|
|
26
|
+
mkdir(path: string, opts?: fs.MakeDirectoryOptions): Promise<void>;
|
|
27
|
+
readFile(path: string, encoding: BufferEncoding): Promise<string>;
|
|
28
|
+
writeFile(path: string, data: string, opts?: fs.WriteFileOptions): Promise<void>;
|
|
29
|
+
rename(oldPath: string, newPath: string): Promise<void>;
|
|
30
|
+
unlink(path: string): Promise<void>;
|
|
31
|
+
open(path: string, flags: string, mode?: number): Promise<{
|
|
32
|
+
close(): Promise<void>;
|
|
33
|
+
}>;
|
|
34
|
+
readdir(path: string): Promise<string[]>;
|
|
35
|
+
chmod(path: string, mode: number): Promise<void>;
|
|
36
|
+
}
|
|
37
|
+
export interface SpawnResult {
|
|
38
|
+
unref?: () => void;
|
|
39
|
+
}
|
|
40
|
+
export interface TelegramDaemonDeps {
|
|
41
|
+
fs?: TelegramDaemonFs;
|
|
42
|
+
now?: () => number;
|
|
43
|
+
pid?: number;
|
|
44
|
+
pidAlive?: (pid: number) => boolean;
|
|
45
|
+
spawn?: (command: string, args: string[], opts: {
|
|
46
|
+
detached: boolean;
|
|
47
|
+
stdio: "ignore";
|
|
48
|
+
logPath?: string;
|
|
49
|
+
}) => SpawnResult;
|
|
50
|
+
execPath?: string;
|
|
51
|
+
randomId?: () => string;
|
|
52
|
+
}
|
|
53
|
+
export declare const HEARTBEAT_INTERVAL_MS = 5000;
|
|
54
|
+
export declare const HEARTBEAT_TTL_MS = 20000;
|
|
55
|
+
export declare const DAEMON_VERSION = 1;
|
|
56
|
+
/** Capability token advertised when the server supports app-level ping/pong. */
|
|
57
|
+
export declare const CLIENT_PING_PONG_CAPABILITY = "client_ping_pong";
|
|
58
|
+
/** Protocol version the daemon advertises in its ClientHello. */
|
|
59
|
+
export declare const NOTIFICATION_PROTOCOL_VERSION = 2;
|
|
60
|
+
export declare function daemonPaths(agentDir: string): DaemonPaths;
|
|
61
|
+
export declare function registerNotificationRoot(input: {
|
|
62
|
+
settings: Settings;
|
|
63
|
+
cwd: string;
|
|
64
|
+
sessionId: string;
|
|
65
|
+
fs?: TelegramDaemonFs;
|
|
66
|
+
}): Promise<string>;
|
|
67
|
+
export declare function isFreshLiveOwner(input: {
|
|
68
|
+
state: DaemonState | undefined;
|
|
69
|
+
now: number;
|
|
70
|
+
tokenFingerprint: string;
|
|
71
|
+
chatId: string;
|
|
72
|
+
pidAlive: (pid: number) => boolean;
|
|
73
|
+
}): boolean;
|
|
74
|
+
export declare function acquireDaemonOwnership(input: {
|
|
75
|
+
settings: Settings;
|
|
76
|
+
roots?: string[];
|
|
77
|
+
tokenFingerprint: string;
|
|
78
|
+
chatId: string;
|
|
79
|
+
fs?: TelegramDaemonFs;
|
|
80
|
+
now?: () => number;
|
|
81
|
+
pid?: number;
|
|
82
|
+
pidAlive?: (pid: number) => boolean;
|
|
83
|
+
randomId?: () => string;
|
|
84
|
+
}): Promise<{
|
|
85
|
+
acquired: boolean;
|
|
86
|
+
ownerId?: string;
|
|
87
|
+
attached?: boolean;
|
|
88
|
+
}>;
|
|
89
|
+
export declare function renewDaemonHeartbeat(input: {
|
|
90
|
+
settings: Settings;
|
|
91
|
+
ownerId: string;
|
|
92
|
+
fs?: TelegramDaemonFs;
|
|
93
|
+
now?: () => number;
|
|
94
|
+
pid?: number;
|
|
95
|
+
}): Promise<boolean>;
|
|
96
|
+
export declare function releaseDaemonOwnership(input: {
|
|
97
|
+
settings: Settings;
|
|
98
|
+
ownerId: string;
|
|
99
|
+
fs?: TelegramDaemonFs;
|
|
100
|
+
now?: () => number;
|
|
101
|
+
}): Promise<void>;
|
|
102
|
+
/** Read the persisted daemon ownership state (or undefined when absent). */
|
|
103
|
+
export declare function readDaemonState(settings: Settings, fs?: TelegramDaemonFs): Promise<DaemonState | undefined>;
|
|
104
|
+
/** Read the persisted notification roots list. */
|
|
105
|
+
export declare function readDaemonRoots(settings: Settings, fs?: TelegramDaemonFs): Promise<string[]>;
|
|
106
|
+
export interface TelegramSpawnOwnerInput {
|
|
107
|
+
settings: Settings;
|
|
108
|
+
roots?: string[];
|
|
109
|
+
tokenFingerprint: string;
|
|
110
|
+
chatId: string;
|
|
111
|
+
}
|
|
112
|
+
export interface TelegramSpawnOwnerResult {
|
|
113
|
+
result: EnsureDaemonResult;
|
|
114
|
+
ownerId?: string;
|
|
115
|
+
runtime: DaemonRuntimeInfo;
|
|
116
|
+
warnings: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Build the detached spawn command/args for the daemon-internal entrypoint.
|
|
120
|
+
* Source mode prepends the entry script so the respawn loads edited source;
|
|
121
|
+
* a compiled binary self-spawns its own subcommand directly.
|
|
122
|
+
*/
|
|
123
|
+
export declare function buildTelegramDaemonSpawnArgs(input: {
|
|
124
|
+
execPath?: string;
|
|
125
|
+
ownerId: string;
|
|
126
|
+
agentDir: string;
|
|
127
|
+
}): {
|
|
128
|
+
command: string;
|
|
129
|
+
args: string[];
|
|
130
|
+
runtime: DaemonRuntimeInfo;
|
|
131
|
+
};
|
|
132
|
+
/**
|
|
133
|
+
* Acquire ownership for the given Telegram identity and, if acquired, spawn a
|
|
134
|
+
* fresh detached daemon process. Does NOT register notification roots; callers
|
|
135
|
+
* that own a session (autostart) register roots separately, while reload reuses
|
|
136
|
+
* already-persisted roots.
|
|
137
|
+
*/
|
|
138
|
+
export declare function spawnTelegramDaemonOwner(input: TelegramSpawnOwnerInput, deps?: TelegramDaemonDeps): Promise<TelegramSpawnOwnerResult>;
|
|
139
|
+
export declare function ensureTelegramDaemonRunning(input: {
|
|
140
|
+
settings: Settings;
|
|
141
|
+
cwd: string;
|
|
142
|
+
sessionId: string;
|
|
143
|
+
}, deps?: TelegramDaemonDeps): Promise<EnsureDaemonResult>;
|
|
144
|
+
export interface BotApi {
|
|
145
|
+
call(method: string, body: unknown, opts?: {
|
|
146
|
+
signal?: AbortSignal;
|
|
147
|
+
}): Promise<unknown>;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Cooperative control seam for the daemon run loop. Implemented by the
|
|
151
|
+
* daemon-internal CLI / controller against the owner-scoped control-request
|
|
152
|
+
* file so the daemon does not import the control module directly.
|
|
153
|
+
*/
|
|
154
|
+
export interface DaemonControlHooks {
|
|
155
|
+
/** Returns true when a stop/reload has been requested for this owner. */
|
|
156
|
+
shouldStop(ownerId: string): Promise<boolean>;
|
|
157
|
+
/** Clear a consumed control request (best-effort). */
|
|
158
|
+
clear?(ownerId: string): Promise<void>;
|
|
159
|
+
}
|
|
160
|
+
export interface TelegramDaemonOptions {
|
|
161
|
+
settings: Settings;
|
|
162
|
+
ownerId: string;
|
|
163
|
+
botToken: string;
|
|
164
|
+
chatId: string;
|
|
165
|
+
apiBase?: string;
|
|
166
|
+
fetchImpl?: typeof fetch;
|
|
167
|
+
fs?: TelegramDaemonFs;
|
|
168
|
+
WebSocketImpl?: typeof WebSocket;
|
|
169
|
+
now?: () => number;
|
|
170
|
+
setTimeoutImpl?: typeof setTimeout;
|
|
171
|
+
clearTimeoutImpl?: typeof clearTimeout;
|
|
172
|
+
setIntervalImpl?: typeof setInterval;
|
|
173
|
+
clearIntervalImpl?: typeof clearInterval;
|
|
174
|
+
idleTimeoutMs?: number;
|
|
175
|
+
scanIntervalMs?: number;
|
|
176
|
+
pid?: number;
|
|
177
|
+
botApi?: BotApi;
|
|
178
|
+
control?: DaemonControlHooks;
|
|
179
|
+
}
|
|
180
|
+
interface SessionSocket {
|
|
181
|
+
sessionId: string;
|
|
182
|
+
token: string;
|
|
183
|
+
ws: WebSocket;
|
|
184
|
+
pending: Map<string, {
|
|
185
|
+
sessionId: string;
|
|
186
|
+
actionId: string;
|
|
187
|
+
}>;
|
|
188
|
+
/** True once the server advertised the `client_ping_pong` capability. */
|
|
189
|
+
capable: boolean;
|
|
190
|
+
/** Timestamp (via opts.now) of the last received pong; seeds the TTL window. */
|
|
191
|
+
lastPongAt: number;
|
|
192
|
+
/** Nonce of the most recent in-flight ping, if any. */
|
|
193
|
+
awaitingNonce: string | undefined;
|
|
194
|
+
/** Per-session liveness interval handle (only set for capable sessions). */
|
|
195
|
+
pingTimer: ReturnType<typeof setInterval> | undefined;
|
|
196
|
+
}
|
|
197
|
+
export declare class TelegramNotificationDaemon {
|
|
198
|
+
private readonly opts;
|
|
199
|
+
readonly aliasTable: AliasTable;
|
|
200
|
+
readonly messageRoutes: Map<string | number, CallbackRoute | Omit<CallbackRoute, "answer">>;
|
|
201
|
+
readonly sessions: Map<string, SessionSocket>;
|
|
202
|
+
private running;
|
|
203
|
+
private offset;
|
|
204
|
+
private readonly fsImpl;
|
|
205
|
+
private readonly botApi;
|
|
206
|
+
private readonly topics;
|
|
207
|
+
private readonly pool;
|
|
208
|
+
private readonly seenUpdateIds;
|
|
209
|
+
private flushTimer;
|
|
210
|
+
private scanTimer;
|
|
211
|
+
private scanning;
|
|
212
|
+
private typingTimer;
|
|
213
|
+
/** Sessions whose agent loop is currently busy (drives the typing indicator). */
|
|
214
|
+
private readonly busy;
|
|
215
|
+
/** Inbound update id → originating Telegram message, for delivery reactions. */
|
|
216
|
+
private readonly inboundReactions;
|
|
217
|
+
/** AbortController for the in-flight long poll; aborted by requestStop() to wake the loop. */
|
|
218
|
+
private activePoll;
|
|
219
|
+
/** Set when a cooperative stop has been requested (signal or control request). */
|
|
220
|
+
private stopRequested;
|
|
221
|
+
/** Current bounded backoff after a Telegram getUpdates 409 conflict (0 when healthy). */
|
|
222
|
+
private pollConflictBackoffMs;
|
|
223
|
+
/**
|
|
224
|
+
* Cooperatively stop the daemon: set the stop flag and abort the in-flight
|
|
225
|
+
* long poll so the run loop wakes immediately instead of waiting out the
|
|
226
|
+
* ~25s getUpdates timeout. Safe to call from a signal handler.
|
|
227
|
+
*/
|
|
228
|
+
requestStop(_reason?: "reload" | "stop" | "signal"): void;
|
|
229
|
+
constructor(opts: TelegramDaemonOptions);
|
|
230
|
+
loadAliases(): Promise<void>;
|
|
231
|
+
persistAliases(): Promise<void>;
|
|
232
|
+
scanRoots(): Promise<void>;
|
|
233
|
+
connectSession(sessionId: string, url: string, token: string): void;
|
|
234
|
+
/**
|
|
235
|
+
* Start ack-based liveness for a session whose server advertised the
|
|
236
|
+
* `client_ping_pong` capability. Each interval drops the session when no pong
|
|
237
|
+
* has arrived within the TTL (the half-open case the socket never signals via
|
|
238
|
+
* `close`), otherwise sends a fresh application-level ping. The timer is bound
|
|
239
|
+
* to this exact session object.
|
|
240
|
+
*/
|
|
241
|
+
private startLiveness;
|
|
242
|
+
/**
|
|
243
|
+
* Idempotent, identity-guarded session teardown. Clears the liveness timer,
|
|
244
|
+
* removes the map entry only when it still points at this exact session object
|
|
245
|
+
* (so a delayed old close cannot delete a replacement), and best-effort closes
|
|
246
|
+
* the socket. `scanRoots()` then reconnects the session.
|
|
247
|
+
*/
|
|
248
|
+
private dropSession;
|
|
249
|
+
private static readonly THREADED_FRAMES;
|
|
250
|
+
private topicNameFor;
|
|
251
|
+
private ensureTopic;
|
|
252
|
+
private persistTopics;
|
|
253
|
+
loadTopics(): Promise<void>;
|
|
254
|
+
private flushPool;
|
|
255
|
+
private startFlushTimer;
|
|
256
|
+
private stopFlushTimer;
|
|
257
|
+
private runScan;
|
|
258
|
+
private startScanTimer;
|
|
259
|
+
private stopScanTimer;
|
|
260
|
+
private sendTyping;
|
|
261
|
+
private setReaction;
|
|
262
|
+
private startTypingTimer;
|
|
263
|
+
private stopTypingTimer;
|
|
264
|
+
handleSessionMessage(session: SessionSocket, msg: any): Promise<void>;
|
|
265
|
+
pendingBySession: (sessionId?: string) => PendingAsk[];
|
|
266
|
+
private sendStaleGuidance;
|
|
267
|
+
handleTelegramUpdate(update: unknown): Promise<void>;
|
|
268
|
+
pollOnce(signal?: AbortSignal): Promise<number>;
|
|
269
|
+
/** Abortable sleep honoring the injected timer; resolves early on abort. */
|
|
270
|
+
private sleep;
|
|
271
|
+
/** Sync the bot's Telegram command menu to what the daemon actually handles. */
|
|
272
|
+
registerBotCommands(): Promise<void>;
|
|
273
|
+
run(): Promise<void>;
|
|
274
|
+
private controlStopRequested;
|
|
275
|
+
}
|
|
276
|
+
export {};
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Telegram **reference** client for the notifications SDK.
|
|
3
|
+
*
|
|
4
|
+
* This is an example/template, NOT an upstream-owned integration: it implements
|
|
5
|
+
* the documented WS protocol (see `docs/notifications-sdk.md`) so you can copy it
|
|
6
|
+
* to build Discord/Slack/etc. clients with zero upstream changes. The Bot API
|
|
7
|
+
* transport shape is salvaged from the removed `telegram-remote` package.
|
|
8
|
+
*
|
|
9
|
+
* Flow: read the endpoint discovery file -> connect to the session WS -> render
|
|
10
|
+
* `action_needed` to a Telegram chat (inline keyboard for options) -> map button
|
|
11
|
+
* taps / text replies to `reply` frames -> reflect `action_resolved` /
|
|
12
|
+
* `reply_rejected`.
|
|
13
|
+
*
|
|
14
|
+
* Dependency-free: uses global `fetch` and `WebSocket` (Bun/Node 22+).
|
|
15
|
+
*/
|
|
16
|
+
/** One inline-keyboard button. */
|
|
17
|
+
export interface InlineButton {
|
|
18
|
+
text: string;
|
|
19
|
+
callback_data: string;
|
|
20
|
+
}
|
|
21
|
+
/** A rendered Telegram message for an `action_needed`. */
|
|
22
|
+
export interface RenderedMessage {
|
|
23
|
+
text: string;
|
|
24
|
+
inline_keyboard?: InlineButton[][];
|
|
25
|
+
}
|
|
26
|
+
/** Encode `actionId` + option `index` into Telegram callback_data (<=64 bytes). */
|
|
27
|
+
export declare function encodeCallbackData(actionId: string, index: number): string;
|
|
28
|
+
/** Decode callback_data produced by {@link encodeCallbackData}. */
|
|
29
|
+
export declare function decodeCallbackData(data: string): {
|
|
30
|
+
id: string;
|
|
31
|
+
index: number;
|
|
32
|
+
} | null;
|
|
33
|
+
export interface CallbackRoute {
|
|
34
|
+
sessionId: string;
|
|
35
|
+
actionId: string;
|
|
36
|
+
answer: number | string;
|
|
37
|
+
}
|
|
38
|
+
export interface SerializedAliasTable {
|
|
39
|
+
version: 1;
|
|
40
|
+
next: number;
|
|
41
|
+
routes: Record<string, CallbackRoute>;
|
|
42
|
+
}
|
|
43
|
+
export interface AliasTable {
|
|
44
|
+
put(route: CallbackRoute): string;
|
|
45
|
+
get(alias: string): CallbackRoute | undefined;
|
|
46
|
+
delete(alias: string): boolean;
|
|
47
|
+
serialize(): SerializedAliasTable;
|
|
48
|
+
load(json: unknown): void;
|
|
49
|
+
entries(): Array<[string, CallbackRoute]>;
|
|
50
|
+
}
|
|
51
|
+
/** Create a compact, durable callback alias table. Serialized data contains routing ids only. */
|
|
52
|
+
export declare function createAliasTable(): AliasTable;
|
|
53
|
+
/** Render an `action_needed` payload into a Telegram message. */
|
|
54
|
+
export declare function buildActionMessage(action: {
|
|
55
|
+
kind: "ask" | "idle";
|
|
56
|
+
id: string;
|
|
57
|
+
question?: string;
|
|
58
|
+
options?: string[];
|
|
59
|
+
summary?: string;
|
|
60
|
+
}): RenderedMessage;
|
|
61
|
+
/** A protocol `reply` frame the client should send to the server. */
|
|
62
|
+
export interface ReplyFrame {
|
|
63
|
+
type: "reply";
|
|
64
|
+
id: string;
|
|
65
|
+
answer: number | string;
|
|
66
|
+
token: string;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Map a Telegram update into a reply frame, given the most recent pending ask id
|
|
70
|
+
* (for free-text replies). Returns `null` when the update is not actionable.
|
|
71
|
+
*/
|
|
72
|
+
export declare function telegramUpdateToReply(update: unknown, token: string, latestPendingAskId: string | undefined): ReplyFrame | null;
|
|
73
|
+
export type RouteDecision = ({
|
|
74
|
+
kind: "reply";
|
|
75
|
+
} & CallbackRoute) | {
|
|
76
|
+
kind: "stale";
|
|
77
|
+
reason: string;
|
|
78
|
+
} | {
|
|
79
|
+
kind: "ignore";
|
|
80
|
+
};
|
|
81
|
+
export interface PendingAsk {
|
|
82
|
+
sessionId: string;
|
|
83
|
+
actionId: string;
|
|
84
|
+
}
|
|
85
|
+
export interface RouteInboundContext {
|
|
86
|
+
aliasTable: Pick<AliasTable, "get">;
|
|
87
|
+
messageRoutes: Map<string | number, CallbackRoute | Omit<CallbackRoute, "answer">>;
|
|
88
|
+
pendingBySession: (sessionId?: string) => PendingAsk[];
|
|
89
|
+
pairedChatId: string;
|
|
90
|
+
}
|
|
91
|
+
/** Route a Telegram update to a session/action without I/O. Fail closed under ambiguity. */
|
|
92
|
+
export declare function routeInboundUpdate(update: unknown, ctx: RouteInboundContext): RouteDecision;
|
|
93
|
+
/** Read `{url, token}` from an endpoint discovery file. */
|
|
94
|
+
export declare function readEndpoint(path: string): {
|
|
95
|
+
url: string;
|
|
96
|
+
token: string;
|
|
97
|
+
};
|
|
98
|
+
/** Options for {@link runTelegramReferenceClient}. */
|
|
99
|
+
export interface TelegramReferenceOptions {
|
|
100
|
+
botToken: string;
|
|
101
|
+
chatId: string;
|
|
102
|
+
endpointFile: string;
|
|
103
|
+
apiBase?: string;
|
|
104
|
+
fetchImpl?: typeof fetch;
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Run the reference bridge until the WebSocket closes. Sends `action_needed` to
|
|
108
|
+
* the chat and forwards taps/text as replies. This is a minimal example loop;
|
|
109
|
+
* production clients add reconnection, multi-chat routing, and persistence.
|
|
110
|
+
*/
|
|
111
|
+
export declare function runTelegramReferenceClient(opts: TelegramReferenceOptions): Promise<void>;
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fail-closed routing for inbound Telegram updates in threaded session mode.
|
|
3
|
+
*
|
|
4
|
+
* In the threaded surface, a free-text reply inside a session's forum topic
|
|
5
|
+
* injects a new user turn into that session (steering it at any time). That is
|
|
6
|
+
* remote control of the agent, so every inbound path must fail closed:
|
|
7
|
+
*
|
|
8
|
+
* - the update must come from the single paired chat id;
|
|
9
|
+
* - it must carry a `message_thread_id` (topic) that maps to a KNOWN session;
|
|
10
|
+
* - its `update_id` must not have been seen before (idempotency / replay guard);
|
|
11
|
+
* - the text must be non-empty.
|
|
12
|
+
*
|
|
13
|
+
* Anything ambiguous or unmapped is ignored with a reason rather than guessed.
|
|
14
|
+
* This module is pure (the dedupe set and topic map are injected) so the
|
|
15
|
+
* security rules are exhaustively unit-testable without a live Bot API.
|
|
16
|
+
*/
|
|
17
|
+
/** Minimal shape of the inbound Telegram message we route on. */
|
|
18
|
+
export interface InboundUpdate {
|
|
19
|
+
update_id?: unknown;
|
|
20
|
+
message?: {
|
|
21
|
+
message_id?: unknown;
|
|
22
|
+
text?: unknown;
|
|
23
|
+
chat?: {
|
|
24
|
+
id?: unknown;
|
|
25
|
+
};
|
|
26
|
+
message_thread_id?: unknown;
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/** Context for {@link decideThreadedInbound}. All lookups are injected. */
|
|
30
|
+
export interface ThreadedInboundCtx {
|
|
31
|
+
/** The single paired chat id (string-compared). */
|
|
32
|
+
pairedChatId: string;
|
|
33
|
+
/** Resolve a topic/thread id to its owning session id, or undefined. */
|
|
34
|
+
topicToSession: (threadId: string) => string | undefined;
|
|
35
|
+
/** Whether this `update_id` has already been processed. */
|
|
36
|
+
isDuplicate: (updateId: number) => boolean;
|
|
37
|
+
}
|
|
38
|
+
/** Outcome of routing an inbound update. */
|
|
39
|
+
export type ThreadedInboundDecision = {
|
|
40
|
+
kind: "inject";
|
|
41
|
+
sessionId: string;
|
|
42
|
+
text: string;
|
|
43
|
+
updateId: number;
|
|
44
|
+
threadId: string;
|
|
45
|
+
messageId?: number;
|
|
46
|
+
} | {
|
|
47
|
+
kind: "duplicate";
|
|
48
|
+
updateId: number;
|
|
49
|
+
} | {
|
|
50
|
+
kind: "ignore";
|
|
51
|
+
reason: string;
|
|
52
|
+
};
|
|
53
|
+
/**
|
|
54
|
+
* Decide whether an inbound update should inject a user turn. Fail-closed:
|
|
55
|
+
* returns `ignore` (with a reason) or `duplicate` for anything that is not an
|
|
56
|
+
* unambiguous, first-seen, paired-chat, known-topic text message.
|
|
57
|
+
*/
|
|
58
|
+
export declare function decideThreadedInbound(update: InboundUpdate, ctx: ThreadedInboundCtx): ThreadedInboundDecision;
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pure rendering of threaded-session frames into Telegram send specs.
|
|
3
|
+
*
|
|
4
|
+
* The daemon receives the additive `ServerMessage` frames (identity_header,
|
|
5
|
+
* context_update, turn_stream, image_attachment, config_update) over the session
|
|
6
|
+
* WS and must turn each into a Bot API call scoped to the session's forum topic
|
|
7
|
+
* (`message_thread_id`), throttled through the shared rate-limit pool. This
|
|
8
|
+
* module is the pure frame→send mapping (including the priority lane and live-
|
|
9
|
+
* edit coalesce key), so rendering is unit-testable without a live Bot API.
|
|
10
|
+
*/
|
|
11
|
+
import type { RateLimitLane } from "./rate-limit-pool";
|
|
12
|
+
/** A Telegram send derived from a threaded frame (topic id is applied by the daemon). */
|
|
13
|
+
export interface ThreadedSend {
|
|
14
|
+
method: "sendMessage" | "sendPhoto";
|
|
15
|
+
/** Rate-limit lane for prioritisation/fairness. */
|
|
16
|
+
lane: RateLimitLane;
|
|
17
|
+
/** Message text (sendMessage) or photo caption (sendPhoto). */
|
|
18
|
+
text?: string;
|
|
19
|
+
/** Base64 image bytes for sendPhoto. */
|
|
20
|
+
photoBase64?: string;
|
|
21
|
+
/** Image MIME type for sendPhoto. */
|
|
22
|
+
mime?: string;
|
|
23
|
+
/** Coalesce key for live edits (same key collapses to the latest). */
|
|
24
|
+
coalesceKey?: string;
|
|
25
|
+
/** True for the one-time identity header (the daemon pins it once). */
|
|
26
|
+
identity?: boolean;
|
|
27
|
+
}
|
|
28
|
+
interface ThreadedFrame {
|
|
29
|
+
type?: unknown;
|
|
30
|
+
sessionId?: unknown;
|
|
31
|
+
repo?: unknown;
|
|
32
|
+
branch?: unknown;
|
|
33
|
+
machine?: unknown;
|
|
34
|
+
title?: unknown;
|
|
35
|
+
lastMessage?: unknown;
|
|
36
|
+
task?: unknown;
|
|
37
|
+
goal?: unknown;
|
|
38
|
+
tokenUsage?: unknown;
|
|
39
|
+
model?: unknown;
|
|
40
|
+
diff?: unknown;
|
|
41
|
+
phase?: unknown;
|
|
42
|
+
text?: unknown;
|
|
43
|
+
messageRef?: unknown;
|
|
44
|
+
source?: unknown;
|
|
45
|
+
data?: unknown;
|
|
46
|
+
mime?: unknown;
|
|
47
|
+
caption?: unknown;
|
|
48
|
+
verbosity?: unknown;
|
|
49
|
+
redact?: unknown;
|
|
50
|
+
}
|
|
51
|
+
/** Format the one-time identity header as pinned bullets. */
|
|
52
|
+
export declare function formatIdentityHeader(frame: {
|
|
53
|
+
repo?: unknown;
|
|
54
|
+
branch?: unknown;
|
|
55
|
+
machine?: unknown;
|
|
56
|
+
sessionId?: unknown;
|
|
57
|
+
title?: unknown;
|
|
58
|
+
}): string;
|
|
59
|
+
/** Format a streamed context update into a compact block (omitting empty fields). */
|
|
60
|
+
export declare function formatContextUpdate(frame: ThreadedFrame): string | undefined;
|
|
61
|
+
/**
|
|
62
|
+
* Map a threaded frame to a Telegram send spec, or `undefined` when there is
|
|
63
|
+
* nothing to send (e.g. an empty context update or an unknown frame type).
|
|
64
|
+
*/
|
|
65
|
+
export declare function renderThreadedFrame(frame: ThreadedFrame): ThreadedSend | undefined;
|
|
66
|
+
export {};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Per-session forum-topic registry for the threaded session surface.
|
|
3
|
+
*
|
|
4
|
+
* Each GJC session owns exactly one Telegram forum topic in the paired private
|
|
5
|
+
* DM. The topic is created once (via `createForumTopic`) and REUSED on resume,
|
|
6
|
+
* keyed by session id, so a resumed session streams back into its existing
|
|
7
|
+
* thread/history. The registry also tracks whether the one-time identity header
|
|
8
|
+
* has already been pinned, so it is sent exactly once per topic even across
|
|
9
|
+
* reconnects.
|
|
10
|
+
*
|
|
11
|
+
* State is a plain serialisable map persisted beside the daemon state files;
|
|
12
|
+
* topic creation is injected so this module is pure and unit-testable without a
|
|
13
|
+
* live Bot API.
|
|
14
|
+
*/
|
|
15
|
+
/** Persisted record for one session's topic. */
|
|
16
|
+
export interface TopicRecord {
|
|
17
|
+
/** Telegram forum topic id (message_thread_id). */
|
|
18
|
+
topicId: string;
|
|
19
|
+
/** Whether the one-time identity header has been sent/pinned. */
|
|
20
|
+
identitySent: boolean;
|
|
21
|
+
/** Creation timestamp (ms epoch). */
|
|
22
|
+
createdAt: number;
|
|
23
|
+
/** Last applied topic title (for rename detection). */
|
|
24
|
+
name?: string;
|
|
25
|
+
}
|
|
26
|
+
/** Serialisable shape persisted to disk. */
|
|
27
|
+
export interface TopicRegistryState {
|
|
28
|
+
/** sessionId -> record. */
|
|
29
|
+
topics: Record<string, TopicRecord>;
|
|
30
|
+
}
|
|
31
|
+
export declare function emptyTopicRegistryState(): TopicRegistryState;
|
|
32
|
+
/**
|
|
33
|
+
* In-memory registry over a serialisable state. Topic creation is injected via
|
|
34
|
+
* `getOrCreateTopic`'s `create` callback (the daemon supplies a real
|
|
35
|
+
* `createForumTopic` call); reuse-on-resume is automatic when a record exists.
|
|
36
|
+
*/
|
|
37
|
+
export declare class TopicRegistry {
|
|
38
|
+
private readonly topics;
|
|
39
|
+
/** Maps topicId -> sessionId for fast inbound routing. */
|
|
40
|
+
private readonly byTopic;
|
|
41
|
+
/** In-flight create promises, keyed by session, to dedupe concurrent creates. */
|
|
42
|
+
private readonly inflight;
|
|
43
|
+
constructor(state?: TopicRegistryState);
|
|
44
|
+
/** Merge a serialized state into this registry, preserving all persisted fields. */
|
|
45
|
+
load(state: TopicRegistryState): void;
|
|
46
|
+
/** Resolve the owning session for a topic id (for fail-closed inbound routing). */
|
|
47
|
+
sessionForTopic(topicId: string): string | undefined;
|
|
48
|
+
/** The existing topic record for a session, if any. */
|
|
49
|
+
get(sessionId: string): TopicRecord | undefined;
|
|
50
|
+
/**
|
|
51
|
+
* Return the existing topic for `sessionId`, or create one via `create`
|
|
52
|
+
* (called only on first use). Reuse-on-resume: an existing record is
|
|
53
|
+
* returned without invoking `create`.
|
|
54
|
+
*/
|
|
55
|
+
getOrCreateTopic(sessionId: string, create: () => Promise<string>, now?: () => number): Promise<TopicRecord>;
|
|
56
|
+
/** Mark the identity header as sent for a session. Idempotent. */
|
|
57
|
+
markIdentitySent(sessionId: string): void;
|
|
58
|
+
/** Whether the identity header still needs sending for this session. */
|
|
59
|
+
needsIdentity(sessionId: string): boolean;
|
|
60
|
+
/**
|
|
61
|
+
* Record the topic's applied title. Returns `true` when it changed (so the
|
|
62
|
+
* caller should `editForumTopic`), `false` when already current or unknown.
|
|
63
|
+
*/
|
|
64
|
+
applyName(sessionId: string, name: string): boolean;
|
|
65
|
+
/** Serialise for atomic persistence beside the daemon state. */
|
|
66
|
+
serialize(): TopicRegistryState;
|
|
67
|
+
}
|
|
@@ -31,5 +31,17 @@ export declare function buildRlmGoalObjective(input: {
|
|
|
31
31
|
}): string;
|
|
32
32
|
export declare function isRlmAutonomousRun(parsed: Pick<Args, "print" | "mode" | "messages">, pipedStdin: boolean): boolean;
|
|
33
33
|
export declare function prepareRlmLaunchMode(parsed: Args, pipedStdin: boolean): boolean;
|
|
34
|
+
/**
|
|
35
|
+
* RLM artifacts are scoped under a GJC session directory and resolving their
|
|
36
|
+
* paths is a *write* (it must pick a concrete session). When `gjc rlm` runs
|
|
37
|
+
* standalone — no parent agent, no `GJC_SESSION_ID` in the environment — there is
|
|
38
|
+
* no session to resolve and `resolveGjcSessionForWrite` throws
|
|
39
|
+
* `missing_for_write`. Establish a dedicated GJC session id in that case and pin
|
|
40
|
+
* it into the environment so artifact-path resolution, the per-session activity
|
|
41
|
+
* marker, and the child agent's workflow state all share one writable session.
|
|
42
|
+
*
|
|
43
|
+
* Returns the resolved (existing or freshly generated) GJC session id.
|
|
44
|
+
*/
|
|
45
|
+
export declare function ensureRlmGjcSessionId(): string;
|
|
34
46
|
export declare function runRlmCommand(argv: string[]): Promise<void>;
|
|
35
47
|
export {};
|
|
@@ -71,7 +71,7 @@ import { type AgentRegistry } from "../registry/agent-registry";
|
|
|
71
71
|
import { type DiscoverableMCPSearchIndex, type DiscoverableMCPTool } from "../runtime-mcp/discoverable-tool-metadata";
|
|
72
72
|
import { type SecretObfuscator } from "../secrets/obfuscator";
|
|
73
73
|
import { type DiscoverableTool, type DiscoverableToolSearchIndex } from "../tool-discovery/tool-index";
|
|
74
|
-
import type { ToolSession } from "../tools";
|
|
74
|
+
import type { AskAnswerSource, ToolSession } from "../tools";
|
|
75
75
|
import type { CheckpointState } from "../tools/checkpoint";
|
|
76
76
|
import { type TodoItem, type TodoPhase } from "../tools/todo-write";
|
|
77
77
|
import type { ClientBridge } from "./client-bridge";
|
|
@@ -128,6 +128,9 @@ export type AgentSessionEvent = AgentEvent | {
|
|
|
128
128
|
} | {
|
|
129
129
|
type: "irc_message";
|
|
130
130
|
message: CustomMessage;
|
|
131
|
+
} | {
|
|
132
|
+
type: "subagent_steer_message";
|
|
133
|
+
message: CustomMessage;
|
|
131
134
|
} | {
|
|
132
135
|
type: "notice";
|
|
133
136
|
level: "info" | "warning" | "error";
|
|
@@ -558,6 +561,7 @@ export declare class AgentSession {
|
|
|
558
561
|
getGoalModeState(): GoalModeState | undefined;
|
|
559
562
|
setGoalModeState(state: GoalModeState | undefined): void;
|
|
560
563
|
getWorkflowGateEmitter(): WorkflowGateEmitter | undefined;
|
|
564
|
+
getAskAnswerSource(): AskAnswerSource | undefined;
|
|
561
565
|
setWorkflowGateEmitter(emitter: WorkflowGateEmitter | undefined): void;
|
|
562
566
|
get goalRuntime(): GoalRuntime;
|
|
563
567
|
markPlanReferenceSent(): void;
|
|
@@ -713,12 +717,38 @@ export declare class AgentSession {
|
|
|
713
717
|
}): Promise<void>;
|
|
714
718
|
setActiveModelProfile(name: string | undefined): void;
|
|
715
719
|
getActiveModelProfile(): string | undefined;
|
|
720
|
+
/**
|
|
721
|
+
* The model selector ("provider/id") that resume restores as the session
|
|
722
|
+
* default — the latest session-log `model_change` with role="default".
|
|
723
|
+
* Model-profile activation snapshots this before mutating the session so a
|
|
724
|
+
* failed-activation rollback can restore the pre-activation resume default
|
|
725
|
+
* instead of promoting a transient runtime model to the resume default.
|
|
726
|
+
*/
|
|
727
|
+
getSessionDefaultModelSelector(): string | undefined;
|
|
728
|
+
/**
|
|
729
|
+
* Re-assert the session resume default ("provider/id") in the session log
|
|
730
|
+
* WITHOUT touching the live runtime model. Appends a `model_change` with
|
|
731
|
+
* role="default"; never writes to global settings (apply-for-this-session
|
|
732
|
+
* semantics). Used by model-profile activation rollback to neutralize the
|
|
733
|
+
* profile main model the failed activation already recorded as the default.
|
|
734
|
+
*/
|
|
735
|
+
recordResumeDefaultModel(selector: string): void;
|
|
716
736
|
/**
|
|
717
737
|
* Set model temporarily (for this session only).
|
|
718
738
|
* Validates API key, saves to session log but NOT to settings.
|
|
739
|
+
*
|
|
740
|
+
* The change is recorded in the session log as `role: "temporary"` by
|
|
741
|
+
* default, which means it is NOT restored as the session default on resume —
|
|
742
|
+
* transient retry/fallback/context-promotion/plan switches must not clobber
|
|
743
|
+
* the user's explicit pick (issue #849). Model-profile activation passes
|
|
744
|
+
* `persistAsSessionDefault: true` so the profile's main model becomes the
|
|
745
|
+
* session default and survives resume, while still not being written to
|
|
746
|
+
* global settings (new sessions keep the global default).
|
|
719
747
|
* @throws Error if no API key available for the model
|
|
720
748
|
*/
|
|
721
|
-
setModelTemporary(model: Model, thinkingLevel?: ThinkingLevel
|
|
749
|
+
setModelTemporary(model: Model, thinkingLevel?: ThinkingLevel, options?: {
|
|
750
|
+
persistAsSessionDefault?: boolean;
|
|
751
|
+
}): Promise<void>;
|
|
722
752
|
/**
|
|
723
753
|
* Cycle to next/previous model.
|
|
724
754
|
* Uses scoped models (from --models flag) if available, otherwise all available models.
|
|
@@ -946,6 +976,13 @@ export declare class AgentSession {
|
|
|
946
976
|
* Does not persist the record to history. Public so other sessions can forward.
|
|
947
977
|
*/
|
|
948
978
|
emitIrcRelayObservation(record: CustomMessage): void;
|
|
979
|
+
emitSubagentSteerObservation(args: {
|
|
980
|
+
from: string;
|
|
981
|
+
to: string;
|
|
982
|
+
body: string;
|
|
983
|
+
timestamp?: number;
|
|
984
|
+
}): void;
|
|
985
|
+
emitSubagentSteerRelayObservation(record: CustomMessage): void;
|
|
949
986
|
/**
|
|
950
987
|
* Run a single ephemeral side-channel turn against this session's current
|
|
951
988
|
* model + system prompt + history. No tools are used; the side request
|
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Re-exports from @gajae-code/ai.
|
|
3
3
|
* All credential storage types and the AuthStorage class now live in the ai package.
|
|
4
4
|
*/
|
|
5
|
-
export type { ApiKeyCredential, AuthCredential, AuthCredentialEntry, AuthCredentialStore, AuthStorageData, AuthStorageOptions, OAuthCredential, SerializedAuthStorage, StoredAuthCredential, } from "@gajae-code/ai";
|
|
5
|
+
export type { ApiKeyCredential, AuthCredential, AuthCredentialEntry, AuthCredentialIfAbsentReason, AuthCredentialIfAbsentResult, AuthCredentialIfAbsentSnapshotResult, AuthCredentialStore, AuthStorageData, AuthStorageOptions, OAuthCredential, SerializedAuthStorage, StoredAuthCredential, } from "@gajae-code/ai";
|
|
6
6
|
export { AuthBrokerClient, AuthStorage, REMOTE_REFRESH_SENTINEL, RemoteAuthCredentialStore, SqliteAuthCredentialStore, } from "@gajae-code/ai";
|