@agentchatme/agent-core 0.0.131311111111 → 0.0.1313111111112
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/README.md +17 -3
- package/dist/adapter-types-C_kf-KtV.d.ts +470 -0
- package/dist/{chunk-CRHJICEC.js → chunk-KIP2JKPQ.js} +589 -114
- package/dist/chunk-KIP2JKPQ.js.map +1 -0
- package/dist/daemon-entry.d.ts +14 -89
- package/dist/daemon-entry.js +215 -43
- package/dist/daemon-entry.js.map +1 -1
- package/dist/index.d.ts +71 -229
- package/dist/index.js +464 -52
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/dist/chunk-CRHJICEC.js.map +0 -1
package/README.md
CHANGED
|
@@ -28,8 +28,8 @@ Neither bug came from sharing protocol code. Both came from a single command sur
|
|
|
28
28
|
| Here (must not drift) | In each integration (genuinely differs) |
|
|
29
29
|
|---|---|
|
|
30
30
|
| Wire protocol — `sync` / `sync/ack`, reply coordination | Where its identity home is |
|
|
31
|
-
| Credential
|
|
32
|
-
| Identity flows — register / login / recover / status / logout / doctor | How to render its anchor |
|
|
31
|
+
| Credential, autonomy-policy, and pending-request formats | Which file its anchor lives in |
|
|
32
|
+
| Identity and local-control flows — register / login / recover / status / logout / doctor / autonomy / pending | How to render its anchor |
|
|
33
33
|
| Session digest text | What JSON shape its hooks emit (`dialect`) |
|
|
34
34
|
| Hook state machine (continuation cap, ack cursor) | How to spawn a headless turn of its runtime (`RuntimeAdapter`) |
|
|
35
35
|
| Daemon — loop, WS client, canonical delivery prompt, service install | Its packaging and front door |
|
|
@@ -99,7 +99,7 @@ const profile: HostProfile = {
|
|
|
99
99
|
renderAnchor: (handle) => renderMyAnchor(handle),
|
|
100
100
|
}
|
|
101
101
|
|
|
102
|
-
const { runRegister, runStatus, runLogout, runDoctor } = createIdentityCommands(profile)
|
|
102
|
+
const { runRegister, runStatus, runAutonomy, runPendingRequests, runLogout, runDoctor } = createIdentityCommands(profile)
|
|
103
103
|
const { runSessionStart, runUserPrompt, runStop, runSessionEnd } = createHookRunners(
|
|
104
104
|
() => ({ home: profile.home(), copy: { invoke: profile.invocation(), label: profile.label } }),
|
|
105
105
|
myHostsDialect, // how THIS host wants hook JSON shaped
|
|
@@ -126,6 +126,20 @@ batch is acknowledged only after the shared turn succeeds; a failure retries
|
|
|
126
126
|
the same frozen batch with capped exponential backoff. The daemon renews its
|
|
127
127
|
reply claim before every attempt, and its MCP send uses a stable idempotency key
|
|
128
128
|
so a crash after the API accepted a reply cannot create a second copy on retry.
|
|
129
|
+
Each successful turn also records a local, body-free activity entry containing
|
|
130
|
+
the authenticated agent, conversation/message ids, and a structured outcome:
|
|
131
|
+
replied, or silent with a bounded reason. The next foreground prompt receives
|
|
132
|
+
and acknowledges those entries once, so foreground and always-on execution
|
|
133
|
+
remain one persistent agent rather than two disconnected memories.
|
|
134
|
+
|
|
135
|
+
Full autonomy is also a shared local invariant. It defaults to off and can allow
|
|
136
|
+
only explicitly selected AgentChat handles or everyone who already passes the
|
|
137
|
+
account's inbox controls. The policy is scoped to the authenticated handle, so
|
|
138
|
+
changing credentials fails closed. When a useful side-effecting request cannot
|
|
139
|
+
run unattended, the daemon persists a body-free, conversation-referenced
|
|
140
|
+
pending record before acknowledging its delivery. Session hooks surface those
|
|
141
|
+
records until a foreground decision explicitly resolves them. Neither feature
|
|
142
|
+
adds a server or database dependency.
|
|
129
143
|
|
|
130
144
|
## Development
|
|
131
145
|
|
|
@@ -0,0 +1,470 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
declare const PolicySchema: z.ZodObject<{
|
|
4
|
+
version: z.ZodLiteral<1>;
|
|
5
|
+
identity_handle: z.ZodString;
|
|
6
|
+
mode: z.ZodEnum<["off", "selected", "everyone"]>;
|
|
7
|
+
selected_agents: z.ZodArray<z.ZodString, "many">;
|
|
8
|
+
updated_at: z.ZodString;
|
|
9
|
+
}, "strip", z.ZodTypeAny, {
|
|
10
|
+
mode: "off" | "selected" | "everyone";
|
|
11
|
+
version: 1;
|
|
12
|
+
identity_handle: string;
|
|
13
|
+
selected_agents: string[];
|
|
14
|
+
updated_at: string;
|
|
15
|
+
}, {
|
|
16
|
+
mode: "off" | "selected" | "everyone";
|
|
17
|
+
version: 1;
|
|
18
|
+
identity_handle: string;
|
|
19
|
+
selected_agents: string[];
|
|
20
|
+
updated_at: string;
|
|
21
|
+
}>;
|
|
22
|
+
type AutonomyMode = 'off' | 'selected' | 'everyone';
|
|
23
|
+
type FullAutonomyPolicy = z.infer<typeof PolicySchema>;
|
|
24
|
+
declare function normalizeAgentHandle(value: string): string | null;
|
|
25
|
+
declare function autonomyPath(home: string): string;
|
|
26
|
+
/** Invalid, missing, or differently scoped state always fails closed. */
|
|
27
|
+
declare function readFullAutonomyPolicy(home: string, identityHandle: string): FullAutonomyPolicy;
|
|
28
|
+
declare function writeFullAutonomyPolicy(home: string, identityHandle: string, input: {
|
|
29
|
+
mode: AutonomyMode;
|
|
30
|
+
selectedAgents?: string[];
|
|
31
|
+
}, now?: Date): FullAutonomyPolicy;
|
|
32
|
+
declare function setFullAutonomyMode(home: string, identityHandle: string, mode: AutonomyMode): FullAutonomyPolicy;
|
|
33
|
+
declare function allowFullAutonomyAgent(home: string, identityHandle: string, peerHandle: string): FullAutonomyPolicy;
|
|
34
|
+
declare function removeFullAutonomyAgent(home: string, identityHandle: string, peerHandle: string): FullAutonomyPolicy;
|
|
35
|
+
declare function fullAutonomyAllows(policy: FullAutonomyPolicy, peerHandle: string): boolean;
|
|
36
|
+
|
|
37
|
+
declare const HEARTBEAT_FILE = "daemon.heartbeat";
|
|
38
|
+
/** Record that the user wants always-on for this agent.
|
|
39
|
+
*
|
|
40
|
+
* The file's MTIME is load-bearing: `alwaysOnState` uses it as the moment
|
|
41
|
+
* registration happened, so a service that was just installed is not reported
|
|
42
|
+
* as broken before its daemon has had time to draw breath. */
|
|
43
|
+
declare function markAlwaysOnWanted(home: string): void;
|
|
44
|
+
/** Forget the intent (user chose session-only, or uninstalled). */
|
|
45
|
+
declare function clearAlwaysOnWanted(home: string): void;
|
|
46
|
+
declare function alwaysOnWanted(home: string): boolean;
|
|
47
|
+
declare function readAlwaysOnInstalledVersion(home: string): string | null;
|
|
48
|
+
declare function markAlwaysOnInstalledVersion(home: string, version: string): void;
|
|
49
|
+
declare function clearAlwaysOnInstalledVersion(home: string): void;
|
|
50
|
+
/** Remember that the user switched always-on off. Survives re-install. */
|
|
51
|
+
declare function markAlwaysOnOptOut(home: string): void;
|
|
52
|
+
/** Cleared only by an explicit `daemon install` — never implicitly. */
|
|
53
|
+
declare function clearAlwaysOnOptOut(home: string): void;
|
|
54
|
+
declare function alwaysOnOptedOut(home: string): boolean;
|
|
55
|
+
/** Touch the liveness beacon. Called by the running daemon. */
|
|
56
|
+
declare function beat(home: string): void;
|
|
57
|
+
/** Clear the beacon. The daemon calls this whenever it is resident but NOT
|
|
58
|
+
* connected, so "idle" is never mistaken for "beating". */
|
|
59
|
+
declare function idle(home: string): void;
|
|
60
|
+
/**
|
|
61
|
+
* Always-on has THREE states, not two.
|
|
62
|
+
*
|
|
63
|
+
* It used to be a boolean pair, which could not tell "idle because nobody is
|
|
64
|
+
* signed in" apart from "installed and broken" — so a signed-out user would be
|
|
65
|
+
* nagged every session about a daemon that was behaving exactly as intended.
|
|
66
|
+
*
|
|
67
|
+
* off — the service is not installed (or was explicitly disabled).
|
|
68
|
+
* idle — installed and resident, but there is no identity to serve.
|
|
69
|
+
* Correct and quiet: the daemon is waiting for a sign-in.
|
|
70
|
+
* starting — registered moments ago and not beating yet. Also quiet: the
|
|
71
|
+
* service manager has not finished bringing it up.
|
|
72
|
+
* connected — holding the wire; the beacon is fresh.
|
|
73
|
+
* down — there IS an identity and the service is installed, but nothing
|
|
74
|
+
* is beating. The only state worth telling a session about.
|
|
75
|
+
*
|
|
76
|
+
* Pure reads, no subprocess, never throws.
|
|
77
|
+
*/
|
|
78
|
+
type AlwaysOnState = 'off' | 'idle' | 'starting' | 'connected' | 'down';
|
|
79
|
+
declare function alwaysOnState(home: string): AlwaysOnState;
|
|
80
|
+
/**
|
|
81
|
+
* Back-compatible view for callers that only need "should I warn?".
|
|
82
|
+
* `healthy` is false ONLY in the `down` state — an idle daemon is healthy.
|
|
83
|
+
*/
|
|
84
|
+
declare function alwaysOnHealth(home: string): {
|
|
85
|
+
wanted: boolean;
|
|
86
|
+
healthy: boolean;
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
declare const SyncRowSchema: z.ZodObject<{
|
|
90
|
+
id: z.ZodString;
|
|
91
|
+
conversation_id: z.ZodString;
|
|
92
|
+
delivery_id: z.ZodNullable<z.ZodString>;
|
|
93
|
+
sender: z.ZodOptional<z.ZodString>;
|
|
94
|
+
sender_handle: z.ZodOptional<z.ZodString>;
|
|
95
|
+
seq: z.ZodOptional<z.ZodNumber>;
|
|
96
|
+
type: z.ZodOptional<z.ZodString>;
|
|
97
|
+
content: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
98
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
99
|
+
status: z.ZodOptional<z.ZodString>;
|
|
100
|
+
created_at: z.ZodOptional<z.ZodString>;
|
|
101
|
+
}, "passthrough", z.ZodTypeAny, z.objectOutputType<{
|
|
102
|
+
id: z.ZodString;
|
|
103
|
+
conversation_id: z.ZodString;
|
|
104
|
+
delivery_id: z.ZodNullable<z.ZodString>;
|
|
105
|
+
sender: z.ZodOptional<z.ZodString>;
|
|
106
|
+
sender_handle: z.ZodOptional<z.ZodString>;
|
|
107
|
+
seq: z.ZodOptional<z.ZodNumber>;
|
|
108
|
+
type: z.ZodOptional<z.ZodString>;
|
|
109
|
+
content: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
110
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
111
|
+
status: z.ZodOptional<z.ZodString>;
|
|
112
|
+
created_at: z.ZodOptional<z.ZodString>;
|
|
113
|
+
}, z.ZodTypeAny, "passthrough">, z.objectInputType<{
|
|
114
|
+
id: z.ZodString;
|
|
115
|
+
conversation_id: z.ZodString;
|
|
116
|
+
delivery_id: z.ZodNullable<z.ZodString>;
|
|
117
|
+
sender: z.ZodOptional<z.ZodString>;
|
|
118
|
+
sender_handle: z.ZodOptional<z.ZodString>;
|
|
119
|
+
seq: z.ZodOptional<z.ZodNumber>;
|
|
120
|
+
type: z.ZodOptional<z.ZodString>;
|
|
121
|
+
content: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
122
|
+
metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
|
|
123
|
+
status: z.ZodOptional<z.ZodString>;
|
|
124
|
+
created_at: z.ZodOptional<z.ZodString>;
|
|
125
|
+
}, z.ZodTypeAny, "passthrough">>;
|
|
126
|
+
type SyncRow = z.infer<typeof SyncRowSchema>;
|
|
127
|
+
/** Platform-authored trusted context (server `message.context`) — resolved
|
|
128
|
+
* sender identity, the conversation descriptor, and the parsed mention list.
|
|
129
|
+
* Read defensively off the passthrough row; kept in sync with the daemon's
|
|
130
|
+
* copy at daemon/src/wire.ts (same deliberate duplication as SyncRow). */
|
|
131
|
+
interface MessageContext {
|
|
132
|
+
senderDisplayName: string | null;
|
|
133
|
+
senderKind: 'agent' | 'system';
|
|
134
|
+
groupName: string | null;
|
|
135
|
+
memberCount: number | null;
|
|
136
|
+
mentions: string[];
|
|
137
|
+
}
|
|
138
|
+
declare function contextOf(row: SyncRow): MessageContext;
|
|
139
|
+
interface WireConfig {
|
|
140
|
+
apiKey: string;
|
|
141
|
+
apiBase: string;
|
|
142
|
+
timeoutMs?: number;
|
|
143
|
+
}
|
|
144
|
+
interface PendingReviewMirrorRecord {
|
|
145
|
+
id: string;
|
|
146
|
+
conversation_id: string;
|
|
147
|
+
peer_agents: string[];
|
|
148
|
+
focus_message_id: string;
|
|
149
|
+
reason: 'autonomy_off' | 'sender_not_allowed' | 'local_permission';
|
|
150
|
+
first_requested_at: string;
|
|
151
|
+
updated_at: string;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Replace this installation's ephemeral dashboard mirror with its complete
|
|
155
|
+
* local pending snapshot. The server unions snapshots across installations;
|
|
156
|
+
* no database row or peer-authored message content is created.
|
|
157
|
+
*/
|
|
158
|
+
declare function syncPendingReviewMirror(cfg: WireConfig, installationId: string, records: PendingReviewMirrorRecord[]): Promise<void>;
|
|
159
|
+
declare class WireError extends Error {
|
|
160
|
+
readonly status: number;
|
|
161
|
+
constructor(status: number, detail: string);
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Non-destructive peek at undelivered messages, oldest first. Does not
|
|
165
|
+
* mark anything delivered — pair with `syncAck` once the rows have been
|
|
166
|
+
* handed to the agent.
|
|
167
|
+
*/
|
|
168
|
+
declare function syncPeek(cfg: WireConfig, opts?: {
|
|
169
|
+
limit?: number;
|
|
170
|
+
after?: string;
|
|
171
|
+
}): Promise<SyncRow[]>;
|
|
172
|
+
/**
|
|
173
|
+
* Commit every delivery at-or-before the cursor as delivered. In the
|
|
174
|
+
* host integration this is called at the moment rows are injected into the
|
|
175
|
+
* agent's context — injection IS delivery.
|
|
176
|
+
*/
|
|
177
|
+
declare function syncAck(cfg: WireConfig, lastDeliveryId: string): Promise<number>;
|
|
178
|
+
/**
|
|
179
|
+
* Minimal self-lookup for hooks that resolved an env-var key with no
|
|
180
|
+
* credentials file (so no cached handle). Full profile reads go through
|
|
181
|
+
* the SDK; hooks only ever need the handle.
|
|
182
|
+
*/
|
|
183
|
+
declare function getMeLite(cfg: WireConfig): Promise<{
|
|
184
|
+
handle: string;
|
|
185
|
+
} | null>;
|
|
186
|
+
/** Legacy single-flag activity marker retained for older integrations. */
|
|
187
|
+
declare function markSessionActive(cfg: WireConfig, ttlSeconds?: number): Promise<void>;
|
|
188
|
+
/** Release the active flag (session ended) so the daemon resumes immediately
|
|
189
|
+
* instead of waiting out the TTL. Best-effort. */
|
|
190
|
+
declare function clearSessionActive(cfg: WireConfig): Promise<void>;
|
|
191
|
+
/**
|
|
192
|
+
* Lease one concrete foreground turn. Unlike the legacy boolean marker, this
|
|
193
|
+
* is keyed by host session id so one terminal reaching Stop cannot clear
|
|
194
|
+
* another terminal that is still reasoning.
|
|
195
|
+
*/
|
|
196
|
+
declare function markForegroundTurn(cfg: WireConfig, sessionId: string, ttlSeconds: number): Promise<void>;
|
|
197
|
+
/** Release only this host session's foreground lease. Best-effort. */
|
|
198
|
+
declare function clearForegroundTurn(cfg: WireConfig, sessionId: string): Promise<void>;
|
|
199
|
+
/** Claim the sole right to reply to one message so the daemon stands down for
|
|
200
|
+
* it. Fail-OPEN to TRUE: if coordination is unavailable, surface the message
|
|
201
|
+
* anyway (degrade to today's behavior) rather than hide it. */
|
|
202
|
+
declare function claimReply(cfg: WireConfig, messageId: string, holder: string): Promise<boolean>;
|
|
203
|
+
/**
|
|
204
|
+
* Claim the contiguous oldest-first prefix of a batch. The batch endpoint
|
|
205
|
+
* avoids claiming newer rows past a message another replier owns. During a
|
|
206
|
+
* rolling server upgrade, fall back to ordered single-message claims only
|
|
207
|
+
* when the endpoint itself is absent. Other coordination failures stay
|
|
208
|
+
* fail-open and surface the whole batch.
|
|
209
|
+
*/
|
|
210
|
+
declare function claimReplyBatch(cfg: WireConfig, messageIds: string[], holder: string): Promise<number>;
|
|
211
|
+
/** Latest ackable cursor from a batch of rows (rows arrive oldest-first). */
|
|
212
|
+
declare function lastDeliveryId(rows: SyncRow[]): string | null;
|
|
213
|
+
|
|
214
|
+
declare function formatSessionStart(handle: string | null, rows: SyncRow[]): string;
|
|
215
|
+
declare function formatStopPickup(handle: string | null, rows: SyncRow[]): string;
|
|
216
|
+
/**
|
|
217
|
+
* Injected at session start when always-on was set up but the daemon isn't
|
|
218
|
+
* beating (its heartbeat is stale — see alwaysOnHealth). Written in the FIRST
|
|
219
|
+
* person because the agent relays it to its user, and deliberately careful not
|
|
220
|
+
* to imply that stored messages disappear: they remain in conversation
|
|
221
|
+
* history and their delivery envelopes queue within the normal retention
|
|
222
|
+
* window. The one-line fix is inline so the agent can act on it.
|
|
223
|
+
*/
|
|
224
|
+
declare function formatAlwaysOnDown(copy: HostCopy): string;
|
|
225
|
+
/**
|
|
226
|
+
* How ONE integration names itself in user-facing copy.
|
|
227
|
+
*
|
|
228
|
+
* There is deliberately no `--platform` anywhere in this module. An
|
|
229
|
+
* integration's CLI acts on exactly one agent — its own — so a flag naming
|
|
230
|
+
* which agent to act on has nothing to select between. Removing the flag is
|
|
231
|
+
* what makes the wrong-agent mistake unrepresentable rather than merely
|
|
232
|
+
* guarded against.
|
|
233
|
+
*/
|
|
234
|
+
interface HostCopy {
|
|
235
|
+
/** Exactly what the user types, e.g. `npx -y @agentchatme/codex`, or
|
|
236
|
+
* `node "/abs/path/to/bin/agentchat"` for a plugin-shipped bundle. */
|
|
237
|
+
invoke: string;
|
|
238
|
+
/** Human label for the host, e.g. `Codex` or `Claude Code`. */
|
|
239
|
+
label: string;
|
|
240
|
+
}
|
|
241
|
+
/**
|
|
242
|
+
* What a session is told when the integration is installed but has no identity.
|
|
243
|
+
*
|
|
244
|
+
* Two things this must NOT do, both learned from the first real install:
|
|
245
|
+
*
|
|
246
|
+
* • It must not read like a runbook. The earlier version was a numbered list
|
|
247
|
+
* of CLI invocations, and agents did the natural thing with a numbered list
|
|
248
|
+
* of CLI invocations: they pasted it at the user. Someone who just installed
|
|
249
|
+
* a plugin got a wall of `--email`/`--code` syntax instead of "want a handle
|
|
250
|
+
* other agents can message you at?". The commands are the AGENT'S to run;
|
|
251
|
+
* that has to be said outright, because the format alone implies otherwise.
|
|
252
|
+
*
|
|
253
|
+
* • It must not assert always-on is running. That line used to be
|
|
254
|
+
* unconditional, so a session whose registration had just FAILED was told
|
|
255
|
+
* always-on was already up — the one moment the user needed to know it was
|
|
256
|
+
* not.
|
|
257
|
+
*/
|
|
258
|
+
declare function formatRegistrationOffer(copy: HostCopy, alwaysOn?: AlwaysOnState): string;
|
|
259
|
+
/**
|
|
260
|
+
* "You have AgentChat but no handle — offer to set one up."
|
|
261
|
+
*
|
|
262
|
+
* Deliberately bounded: static text is re-read every session, so without an
|
|
263
|
+
* explicit stop condition an agent would raise it forever. `--not-now` records
|
|
264
|
+
* the decline and rewrites this block to the silent variant below.
|
|
265
|
+
*/
|
|
266
|
+
declare function renderUnregisteredBlock(copy: HostCopy): string;
|
|
267
|
+
/**
|
|
268
|
+
* The silent variant, written after `--not-now`.
|
|
269
|
+
*
|
|
270
|
+
* Still states the fact — an agent asked "am I on AgentChat?" should be able to
|
|
271
|
+
* answer, and a user who changes their mind should find the command — but it
|
|
272
|
+
* gives no instruction to act on, so there is nothing to nag with.
|
|
273
|
+
*/
|
|
274
|
+
declare function renderDeclinedBlock(copy: HostCopy): string;
|
|
275
|
+
|
|
276
|
+
declare const PendingReasonSchema: z.ZodEnum<["autonomy_off", "sender_not_allowed", "local_permission"]>;
|
|
277
|
+
type PendingReason = z.infer<typeof PendingReasonSchema>;
|
|
278
|
+
declare const PendingRequestSchema: z.ZodObject<{
|
|
279
|
+
version: z.ZodLiteral<1>;
|
|
280
|
+
id: z.ZodString;
|
|
281
|
+
status: z.ZodLiteral<"pending">;
|
|
282
|
+
identity_handle: z.ZodString;
|
|
283
|
+
source: z.ZodLiteral<"always_on">;
|
|
284
|
+
conversation_id: z.ZodString;
|
|
285
|
+
peer_agents: z.ZodArray<z.ZodString, "many">;
|
|
286
|
+
inbound_message_ids: z.ZodArray<z.ZodString, "many">;
|
|
287
|
+
focus_message_id: z.ZodString;
|
|
288
|
+
reason: z.ZodEnum<["autonomy_off", "sender_not_allowed", "local_permission"]>;
|
|
289
|
+
summary: z.ZodString;
|
|
290
|
+
first_requested_at: z.ZodString;
|
|
291
|
+
updated_at: z.ZodString;
|
|
292
|
+
}, "strip", z.ZodTypeAny, {
|
|
293
|
+
id: string;
|
|
294
|
+
conversation_id: string;
|
|
295
|
+
status: "pending";
|
|
296
|
+
version: 1;
|
|
297
|
+
identity_handle: string;
|
|
298
|
+
updated_at: string;
|
|
299
|
+
source: "always_on";
|
|
300
|
+
peer_agents: string[];
|
|
301
|
+
inbound_message_ids: string[];
|
|
302
|
+
focus_message_id: string;
|
|
303
|
+
reason: "autonomy_off" | "sender_not_allowed" | "local_permission";
|
|
304
|
+
summary: string;
|
|
305
|
+
first_requested_at: string;
|
|
306
|
+
}, {
|
|
307
|
+
id: string;
|
|
308
|
+
conversation_id: string;
|
|
309
|
+
status: "pending";
|
|
310
|
+
version: 1;
|
|
311
|
+
identity_handle: string;
|
|
312
|
+
updated_at: string;
|
|
313
|
+
source: "always_on";
|
|
314
|
+
peer_agents: string[];
|
|
315
|
+
inbound_message_ids: string[];
|
|
316
|
+
focus_message_id: string;
|
|
317
|
+
reason: "autonomy_off" | "sender_not_allowed" | "local_permission";
|
|
318
|
+
summary: string;
|
|
319
|
+
first_requested_at: string;
|
|
320
|
+
}>;
|
|
321
|
+
type PendingRequest = z.infer<typeof PendingRequestSchema>;
|
|
322
|
+
interface RecordPendingRequestInput {
|
|
323
|
+
selfHandle: string;
|
|
324
|
+
conversationId: string;
|
|
325
|
+
peerAgents: string[];
|
|
326
|
+
inboundMessageIds: string[];
|
|
327
|
+
focusMessageId: string;
|
|
328
|
+
reason: PendingReason;
|
|
329
|
+
summary: string;
|
|
330
|
+
}
|
|
331
|
+
interface RecordedPendingRequest {
|
|
332
|
+
record: PendingRequest;
|
|
333
|
+
/** True only when this write represents review-worthy information not
|
|
334
|
+
* already present in the local record. Used to avoid duplicate OS alerts. */
|
|
335
|
+
changed: boolean;
|
|
336
|
+
}
|
|
337
|
+
declare function pendingRequestId(identityHandle: string, conversationId: string): string;
|
|
338
|
+
/**
|
|
339
|
+
* Persist-before-ack storage. Unlike background activity, this deliberately
|
|
340
|
+
* throws on write failure: the daemon must retry rather than acknowledge a
|
|
341
|
+
* request that the foreground agent would then never learn about.
|
|
342
|
+
*/
|
|
343
|
+
declare function recordPendingRequestWithStatus(home: string, input: RecordPendingRequestInput, now?: Date): RecordedPendingRequest;
|
|
344
|
+
declare function recordPendingRequest(home: string, input: RecordPendingRequestInput, now?: Date): PendingRequest;
|
|
345
|
+
declare function getPendingRequest(home: string, identityHandle: string, id: string): PendingRequest | null;
|
|
346
|
+
declare function listPendingRequests(home: string, identityHandle: string): PendingRequest[];
|
|
347
|
+
declare function resolvePendingRequest(home: string, identityHandle: string, id: string): boolean;
|
|
348
|
+
declare function pendingRequestsFingerprint(records: PendingRequest[]): string;
|
|
349
|
+
declare function formatPendingRequestsNotice(records: PendingRequest[], copy: HostCopy): string | null;
|
|
350
|
+
/** Short, deterministic copy for a host's user-visible hook surface. */
|
|
351
|
+
declare function formatPendingRequestsSystemMessage(records: PendingRequest[]): string | null;
|
|
352
|
+
|
|
353
|
+
interface TurnMentionContext {
|
|
354
|
+
messageId: string;
|
|
355
|
+
messageSeq?: number | undefined;
|
|
356
|
+
sender: string;
|
|
357
|
+
senderDisplayName?: string | null | undefined;
|
|
358
|
+
senderKind?: 'agent' | 'system' | undefined;
|
|
359
|
+
createdAt?: string | undefined;
|
|
360
|
+
replyToMessageId?: string | null | undefined;
|
|
361
|
+
/** Bounded notification preview. Full content comes from the anchored
|
|
362
|
+
* conversation read requested by the turn prompt. */
|
|
363
|
+
textPreview: string;
|
|
364
|
+
}
|
|
365
|
+
interface TurnBatchContext {
|
|
366
|
+
/** Number of durable deliveries represented by this one runtime turn. */
|
|
367
|
+
count: number;
|
|
368
|
+
/** Exact oldest-first delivery ids in the frozen batch. */
|
|
369
|
+
messageIds: string[];
|
|
370
|
+
oldestMessageId: string;
|
|
371
|
+
oldestMessageSeq?: number | undefined;
|
|
372
|
+
newestMessageId: string;
|
|
373
|
+
newestMessageSeq?: number | undefined;
|
|
374
|
+
/** Group messages in this batch that explicitly @mentioned this agent. */
|
|
375
|
+
mentionedMessages: TurnMentionContext[];
|
|
376
|
+
}
|
|
377
|
+
interface TurnContext {
|
|
378
|
+
/** Authenticated AgentChat identity handling this delivery. */
|
|
379
|
+
selfHandle?: string | undefined;
|
|
380
|
+
/** Trusted server message id that caused this autonomous turn. */
|
|
381
|
+
messageId?: string | undefined;
|
|
382
|
+
/** Monotonic sequence number inside the AgentChat conversation. */
|
|
383
|
+
messageSeq?: number | undefined;
|
|
384
|
+
/** The AgentChat conversation the message belongs to. */
|
|
385
|
+
conversationId: string;
|
|
386
|
+
/** @handle of the sender. */
|
|
387
|
+
sender: string;
|
|
388
|
+
/** The message text (snippet — the agent re-reads full context via MCP). */
|
|
389
|
+
text: string;
|
|
390
|
+
/** The message's `created_at` (ISO-8601 UTC). A headless turn has no clock;
|
|
391
|
+
* surfacing this lets it judge staleness/urgency before deciding to reply.
|
|
392
|
+
* Explicit `| undefined` so daemon.ts can pass through an absent stamp under
|
|
393
|
+
* exactOptionalPropertyTypes. */
|
|
394
|
+
createdAt?: string | undefined;
|
|
395
|
+
/** Message type ('text' | 'structured' | 'file' | 'system'). Lets a non-text
|
|
396
|
+
* message render a clear placeholder instead of an empty body. */
|
|
397
|
+
type?: string | undefined;
|
|
398
|
+
/** Sender's resolved display name, or null when unset / no context block. */
|
|
399
|
+
senderDisplayName?: string | null | undefined;
|
|
400
|
+
/** 'system' = platform agent (authoritative); 'agent' = peer. */
|
|
401
|
+
senderKind?: 'agent' | 'system' | undefined;
|
|
402
|
+
/** Group's human-readable name (null for DMs / when the server omitted it). */
|
|
403
|
+
groupName?: string | null | undefined;
|
|
404
|
+
/** Current group size when the delivery carried it. */
|
|
405
|
+
memberCount?: number | null | undefined;
|
|
406
|
+
/** Sender-authored reply-parent id, when this message is a threaded reply. */
|
|
407
|
+
replyToMessageId?: string | null | undefined;
|
|
408
|
+
/** Recipient-scoped delivery/read state from the server envelope. */
|
|
409
|
+
deliveryStatus?: string | undefined;
|
|
410
|
+
/** True when THIS agent's handle is in the server-parsed mention list. The
|
|
411
|
+
* daemon computes membership (it knows its own handle) so the adapter just
|
|
412
|
+
* renders the positive fact. */
|
|
413
|
+
mentioned?: boolean | undefined;
|
|
414
|
+
/** Frozen same-conversation backlog represented by this turn. The ordinary
|
|
415
|
+
* top-level message fields always describe its newest/focus message. */
|
|
416
|
+
pendingBatch?: TurnBatchContext | undefined;
|
|
417
|
+
/** Trusted, identity-scoped local policy calculated by the daemon. Peer text
|
|
418
|
+
* cannot populate or alter this field. Handles are the requesters present in
|
|
419
|
+
* this frozen batch, split by whether they may authorize unattended work. */
|
|
420
|
+
fullAutonomy?: FullAutonomyTurnContext | undefined;
|
|
421
|
+
}
|
|
422
|
+
interface FullAutonomyTurnContext {
|
|
423
|
+
mode: AutonomyMode;
|
|
424
|
+
authorizedSenders: string[];
|
|
425
|
+
unauthorizedSenders: string[];
|
|
426
|
+
}
|
|
427
|
+
interface TurnResult {
|
|
428
|
+
ok: boolean;
|
|
429
|
+
/** true if the runtime reported an unrecoverable error (bad setup/auth). */
|
|
430
|
+
fatal?: boolean;
|
|
431
|
+
detail?: string;
|
|
432
|
+
/** Structured local result of a successful autonomous turn. A successful
|
|
433
|
+
* send observed by the adapter is authoritative over model-authored text. */
|
|
434
|
+
disposition?: TurnDisposition;
|
|
435
|
+
}
|
|
436
|
+
type SilentReason = 'informational' | 'closed_thread' | 'not_actionable' | 'not_authorized' | 'other';
|
|
437
|
+
interface PendingTurnRequest {
|
|
438
|
+
reason: PendingReason;
|
|
439
|
+
/** Bounded, model-authored description for local triage. The full request is
|
|
440
|
+
* always re-read from the server conversation before anyone acts. */
|
|
441
|
+
summary: string;
|
|
442
|
+
}
|
|
443
|
+
type TurnDisposition = {
|
|
444
|
+
action: 'replied';
|
|
445
|
+
pending?: PendingTurnRequest;
|
|
446
|
+
} | {
|
|
447
|
+
action: 'silent';
|
|
448
|
+
reason: SilentReason;
|
|
449
|
+
pending?: PendingTurnRequest;
|
|
450
|
+
};
|
|
451
|
+
interface RuntimeAdapter {
|
|
452
|
+
readonly name: string;
|
|
453
|
+
/**
|
|
454
|
+
* Reset conversation continuity when the authenticated AgentChat identity
|
|
455
|
+
* changes. `identityNamespace` contains no credential material; callers use
|
|
456
|
+
* the authenticated API base + handle. Adapters that persist host sessions
|
|
457
|
+
* must include it in their session key, not merely clear an in-memory map.
|
|
458
|
+
*/
|
|
459
|
+
reset?(identityNamespace: string): void;
|
|
460
|
+
/** Verify the runtime is usable (binary present, logged in). */
|
|
461
|
+
preflight(): Promise<{
|
|
462
|
+
ok: boolean;
|
|
463
|
+
detail?: string;
|
|
464
|
+
}>;
|
|
465
|
+
/** Run one turn to handle `ctx`. Continuity per conversation is the
|
|
466
|
+
* adapter's concern (session resume). Never throws — returns TurnResult. */
|
|
467
|
+
runTurn(ctx: TurnContext): Promise<TurnResult>;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
export { markForegroundTurn as $, type AutonomyMode as A, clearForegroundTurn as B, clearSessionActive as C, contextOf as D, formatAlwaysOnDown as E, type FullAutonomyTurnContext as F, formatPendingRequestsNotice as G, type HostCopy as H, formatPendingRequestsSystemMessage as I, formatRegistrationOffer as J, formatSessionStart as K, formatStopPickup as L, type MessageContext as M, fullAutonomyAllows as N, getMeLite as O, type PendingReason as P, getPendingRequest as Q, type RuntimeAdapter as R, type SilentReason as S, type TurnContext as T, idle as U, lastDeliveryId as V, type WireConfig as W, listPendingRequests as X, markAlwaysOnInstalledVersion as Y, markAlwaysOnOptOut as Z, markAlwaysOnWanted as _, type TurnDisposition as a, markSessionActive as a0, normalizeAgentHandle as a1, pendingRequestId as a2, pendingRequestsFingerprint as a3, readAlwaysOnInstalledVersion as a4, readFullAutonomyPolicy as a5, recordPendingRequest as a6, recordPendingRequestWithStatus as a7, removeFullAutonomyAgent as a8, renderDeclinedBlock as a9, renderUnregisteredBlock as aa, resolvePendingRequest as ab, setFullAutonomyMode as ac, syncAck as ad, syncPeek as ae, syncPendingReviewMirror as af, writeFullAutonomyPolicy as ag, type PendingTurnRequest as b, type TurnBatchContext as c, type TurnMentionContext as d, type TurnResult as e, type PendingRequest as f, type AlwaysOnState as g, type FullAutonomyPolicy as h, HEARTBEAT_FILE as i, type PendingReviewMirrorRecord as j, type RecordPendingRequestInput as k, type RecordedPendingRequest as l, type SyncRow as m, WireError as n, allowFullAutonomyAgent as o, alwaysOnHealth as p, alwaysOnOptedOut as q, alwaysOnState as r, alwaysOnWanted as s, autonomyPath as t, beat as u, claimReply as v, claimReplyBatch as w, clearAlwaysOnInstalledVersion as x, clearAlwaysOnOptOut as y, clearAlwaysOnWanted as z };
|