@pinet/broker-core 0.2.2 → 0.2.6
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/dist/agent-messaging.d.ts +27 -4
- package/dist/hibernation-commands.d.ts +123 -0
- package/dist/hibernation-commands.js +287 -0
- package/dist/hibernation-orchestrator.d.ts +327 -0
- package/dist/hibernation-orchestrator.js +1096 -0
- package/dist/hibernation-projection.d.ts +20 -0
- package/dist/hibernation-projection.js +60 -0
- package/dist/hibernation-status.d.ts +141 -0
- package/dist/hibernation-status.js +390 -0
- package/dist/hibernation-telemetry.d.ts +54 -0
- package/dist/hibernation-telemetry.js +119 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/leader.d.ts +134 -5
- package/dist/leader.js +359 -26
- package/dist/lifecycle.d.ts +5 -0
- package/dist/lifecycle.js +59 -0
- package/dist/mail-classification.d.ts +6 -1
- package/dist/message-send.d.ts +4 -3
- package/dist/router.d.ts +14 -1
- package/dist/router.js +15 -0
- package/dist/schema.d.ts +181 -2
- package/dist/schema.js +1243 -17
- package/dist/types.d.ts +288 -1
- package/dist/types.js +6 -0
- package/package.json +5 -5
package/dist/schema.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { DatabaseSync } from "node:sqlite";
|
|
2
2
|
import type { PinetMailClass } from "./mail-classification.js";
|
|
3
|
-
import type { AgentInfo, ThreadInfo, BrokerMessage, InboxEntry, InboxReadOptions, InboxReadResult, InboxThreadUnreadSummary, DeliveredInboundMessageResult, BacklogEntry, BrokerDBInterface, InboundMessage, ChannelAssignment, TaskAssignmentInfo, TaskAssignmentKind, TaskAssignmentStatus, ScheduledWakeupInfo, ScheduledWakeupDelivery, PortLeaseAcquireInput, PortLeaseInfo, PortLeaseListOptions, PortLeaseReleaseInput, PortLeaseRenewInput, AgentSessionSearchInfo, AgentSessionSearchOptions, PinetLaneInfo, PinetLaneListOptions, PinetLaneParticipantInfo, PinetLaneParticipantUpsertInput, PinetLaneUpsertInput } from "./types.js";
|
|
3
|
+
import type { AgentInfo, ThreadInfo, BrokerMessage, InboxEntry, InboxReadOptions, InboxReadResult, InboxThreadUnreadSummary, DeliveredInboundMessageResult, BacklogEntry, BrokerDBInterface, InboundMessage, ChannelAssignment, TaskAssignmentInfo, TaskAssignmentKind, TaskAssignmentStatus, ScheduledWakeupInfo, ScheduledWakeupDelivery, PortLeaseAcquireInput, PortLeaseInfo, PortLeaseListOptions, PortLeaseReleaseInput, PortLeaseRenewInput, AgentSessionSearchInfo, AgentSessionSearchOptions, PinetLaneInfo, PinetLaneListOptions, PinetLaneParticipantInfo, PinetLaneParticipantUpsertInput, PinetLaneUpsertInput, AgentHibernatePolicy, AgentLifecycleLease, AgentLifecycleOperation, AgentLifecycleTransitionInput, AgentLifecycleRetentionInfo, AgentRuntimeSpec, AgentRuntimeSpecInput, AgentCheckpointReceipt, AgentCheckpointReceiptInput, AgentWakeReservation, AgentWakeAcceptanceReceipt, AcceptRuntimeGenerationInput, RuntimeGenerationAcceptance, AgentWakeQueueEntry, EnqueueWakeInput, AgentLifecycleEvent, AgentLifecycleEventInput } from "./types.js";
|
|
4
4
|
export interface TaskAssignmentAwaitingReplyInfo {
|
|
5
5
|
id: number;
|
|
6
6
|
agentId: string;
|
|
@@ -12,7 +12,7 @@ export interface TaskAssignmentAwaitingReplyInfo {
|
|
|
12
12
|
export declare function defaultDbPath(): string;
|
|
13
13
|
export declare const DEFAULT_RESUMABLE_WINDOW_MS = 15000;
|
|
14
14
|
export declare const DEFAULT_DISCONNECTED_PURGE_GRACE_MS: number;
|
|
15
|
-
export declare const CURRENT_BROKER_SCHEMA_VERSION =
|
|
15
|
+
export declare const CURRENT_BROKER_SCHEMA_VERSION = 24;
|
|
16
16
|
export declare class BrokerDB implements BrokerDBInterface {
|
|
17
17
|
private db;
|
|
18
18
|
private readonly dbPath;
|
|
@@ -28,6 +28,185 @@ export declare class BrokerDB implements BrokerDBInterface {
|
|
|
28
28
|
close(): void;
|
|
29
29
|
registerAgent(id: string, name: string, emoji: string, pid: number, metadata?: Record<string, unknown>, stableId?: string): AgentInfo;
|
|
30
30
|
private resolveAgentHierarchy;
|
|
31
|
+
transitionAgentLifecycle(input: AgentLifecycleTransitionInput): AgentInfo;
|
|
32
|
+
/**
|
|
33
|
+
* Append an audit-only lifecycle event (a refusal, fenced stale attempt, or
|
|
34
|
+
* duplicate-launch prevention) without changing the agent's lifecycle state.
|
|
35
|
+
*/
|
|
36
|
+
recordAgentLifecycleEvent(input: AgentLifecycleEventInput): void;
|
|
37
|
+
private insertLifecycleEventRow;
|
|
38
|
+
getRecentAgentLifecycleEvents(agentId?: string, limit?: number): AgentLifecycleEvent[];
|
|
39
|
+
getAgentLifecycleRetentionInfo(): AgentLifecycleRetentionInfo;
|
|
40
|
+
acquireAgentLifecycleLease(input: {
|
|
41
|
+
agentId: string;
|
|
42
|
+
operation: AgentLifecycleOperation;
|
|
43
|
+
ownerBrokerInstanceId: string;
|
|
44
|
+
leaseId: string;
|
|
45
|
+
ttlMs: number;
|
|
46
|
+
triggerMessageId?: number | null;
|
|
47
|
+
now?: number;
|
|
48
|
+
}): AgentLifecycleLease | null;
|
|
49
|
+
releaseAgentLifecycleLease(agentId: string, leaseId: string, fenceToken: number): boolean;
|
|
50
|
+
/**
|
|
51
|
+
* Extend an already-held, still-valid lease's expiry WITHOUT bumping the
|
|
52
|
+
* fence, so a legitimately long-running operation (e.g. a wake that waits on
|
|
53
|
+
* process launch + runtime registration across several attempts) keeps a valid
|
|
54
|
+
* lease across adapter waits and can still complete its fenced forward
|
|
55
|
+
* transition. The fence is preserved so revival fencing is unaffected.
|
|
56
|
+
*
|
|
57
|
+
* Renewal only succeeds while the lease is still unexpired and held by this
|
|
58
|
+
* exact owner (matching `leaseId` + `fenceToken`); this preserves the takeover
|
|
59
|
+
* guarantee (a stalled owner past expiry cannot reclaim a lease another broker
|
|
60
|
+
* may take over). Returns the refreshed lease, or null when ownership was lost
|
|
61
|
+
* (expired, released, or the fence moved) — a null result means the caller
|
|
62
|
+
* must fail closed rather than continue driving forward transitions.
|
|
63
|
+
*/
|
|
64
|
+
renewAgentLifecycleLease(input: {
|
|
65
|
+
agentId: string;
|
|
66
|
+
leaseId: string;
|
|
67
|
+
fenceToken: number;
|
|
68
|
+
ttlMs: number;
|
|
69
|
+
now?: number;
|
|
70
|
+
}): AgentLifecycleLease | null;
|
|
71
|
+
/** Set the opt-in hibernation policy for an agent (auto | manual | never). */
|
|
72
|
+
setAgentHibernatePolicy(agentId: string, policy: AgentHibernatePolicy): void;
|
|
73
|
+
/** Record grace/idle eligibility timestamps used by the auto-hibernation scheduler. */
|
|
74
|
+
setAgentHibernationSchedule(agentId: string, schedule: {
|
|
75
|
+
graceUntil?: string | null;
|
|
76
|
+
idleEligibleAt?: string | null;
|
|
77
|
+
}): void;
|
|
78
|
+
getAgentLifecycleLease(agentId: string): AgentLifecycleLease | null;
|
|
79
|
+
upsertAgentRuntimeSpec(input: AgentRuntimeSpecInput): AgentRuntimeSpec;
|
|
80
|
+
getAgentRuntimeSpec(agentId: string): AgentRuntimeSpec | null;
|
|
81
|
+
deleteAgentRuntimeSpec(agentId: string): void;
|
|
82
|
+
recordAgentCheckpointReceipt(input: AgentCheckpointReceiptInput): AgentCheckpointReceipt;
|
|
83
|
+
getLatestAgentCheckpointReceipt(agentId: string): AgentCheckpointReceipt | null;
|
|
84
|
+
/**
|
|
85
|
+
* Reserve the exact runtime generation the broker will accept for a wake.
|
|
86
|
+
* Requires an unexpired wake lease held with the given fence token. Exactly
|
|
87
|
+
* one reservation may exist per agent (PK). The reserved generation is the
|
|
88
|
+
* agent's current runtime_generation + 1, so any older runtime is fenced out.
|
|
89
|
+
*/
|
|
90
|
+
reserveWakeGeneration(input: {
|
|
91
|
+
agentId: string;
|
|
92
|
+
wakeLeaseId: string;
|
|
93
|
+
fenceToken: number;
|
|
94
|
+
correlationId: string;
|
|
95
|
+
/** Optional injected nonce (tests); production mints a fresh UUID. */
|
|
96
|
+
reservationNonce?: string;
|
|
97
|
+
now?: number;
|
|
98
|
+
}): AgentWakeReservation;
|
|
99
|
+
getAgentWakeReservation(agentId: string): AgentWakeReservation | null;
|
|
100
|
+
clearAgentWakeReservation(agentId: string): void;
|
|
101
|
+
/**
|
|
102
|
+
* Record the EXACT wake fence that just accepted a generation, so a runtime
|
|
103
|
+
* whose register RPC response was lost to a crash can replay its single-use
|
|
104
|
+
* fence and be re-bound idempotently. Called INSIDE the acceptance transaction
|
|
105
|
+
* (via {@link acceptRuntimeGeneration} / {@link registerAgentWithGenerationAcceptance})
|
|
106
|
+
* so the receipt is atomic with the generation advance. The stable id is read
|
|
107
|
+
* from the just-registered row so the receipt binds to the durable identity.
|
|
108
|
+
*/
|
|
109
|
+
private writeWakeAcceptanceReceipt;
|
|
110
|
+
getAgentWakeAcceptanceReceipt(agentId: string): AgentWakeAcceptanceReceipt | null;
|
|
111
|
+
/**
|
|
112
|
+
* Accept exactly one runtime generation for a waking agent. The registration
|
|
113
|
+
* must present the same wake lease id, fence token, and reserved generation,
|
|
114
|
+
* AND the bound lease must still be an unexpired `wake` lease while the agent
|
|
115
|
+
* is still in the `waking` lifecycle state. A stale, expired, wrong-operation,
|
|
116
|
+
* wrong-state, or duplicate registration returns `{ accepted: false }` without
|
|
117
|
+
* mutating state. On success the agent's runtime_generation is advanced and
|
|
118
|
+
* the reservation is consumed. `now` (epoch ms) is injectable for tests.
|
|
119
|
+
*/
|
|
120
|
+
/**
|
|
121
|
+
* Non-mutating validation shared by {@link acceptRuntimeGeneration} and
|
|
122
|
+
* {@link checkRuntimeGenerationAcceptable}. Returns a `{ accepted: false }`
|
|
123
|
+
* rejection when the fence does not bind, or `null` when acceptance is legal.
|
|
124
|
+
* Never advances the generation or consumes the reservation.
|
|
125
|
+
*/
|
|
126
|
+
private validateRuntimeGenerationAcceptance;
|
|
127
|
+
acceptRuntimeGeneration(input: AcceptRuntimeGenerationInput): RuntimeGenerationAcceptance;
|
|
128
|
+
/**
|
|
129
|
+
* Atomically settle a wake attempt against the acceptance boundary BEFORE the
|
|
130
|
+
* orchestrator stops or quarantines a launched-but-unaccepted runtime. This
|
|
131
|
+
* closes the timeout-boundary race: the socket layer accepts a generation
|
|
132
|
+
* atomically, so an acceptance can land in the window between the
|
|
133
|
+
* orchestrator's last waiter read and its decision to stop the attempt. In one
|
|
134
|
+
* transaction:
|
|
135
|
+
*
|
|
136
|
+
* - If the reserved generation was ALREADY accepted (the agent's
|
|
137
|
+
* `runtime_generation` reached `reservedGeneration` — the socket won the
|
|
138
|
+
* race), report `{ accepted: true }` and leave the accepted runtime and its
|
|
139
|
+
* (already consumed) reservation untouched. The caller must then treat the
|
|
140
|
+
* attempt as the live runtime and NEVER stop it.
|
|
141
|
+
* - Otherwise, consume ONLY this attempt's exact-nonce reservation, so any
|
|
142
|
+
* later registration by the launched runtime can no longer be accepted
|
|
143
|
+
* (`no_reservation`). This makes the caller's subsequent prove-stop safe:
|
|
144
|
+
* once this returns `{ accepted: false }` the launched runtime can never
|
|
145
|
+
* become live. A reservation minted by a superseded/newer attempt (a
|
|
146
|
+
* different nonce) is left intact.
|
|
147
|
+
*
|
|
148
|
+
* `runtime_generation === reservedGeneration` uniquely identifies acceptance of
|
|
149
|
+
* THIS attempt because reserved generations are `current_generation + 1` at
|
|
150
|
+
* reserve time and only advance on acceptance.
|
|
151
|
+
*/
|
|
152
|
+
finalizeWakeAttempt(input: {
|
|
153
|
+
agentId: string;
|
|
154
|
+
reservedGeneration: number;
|
|
155
|
+
reservationNonce: string;
|
|
156
|
+
}): {
|
|
157
|
+
accepted: boolean;
|
|
158
|
+
};
|
|
159
|
+
/**
|
|
160
|
+
* Atomically revive a hibernated identity: perform the agent registration
|
|
161
|
+
* mutation AND accept the reserved runtime generation in ONE transaction, so a
|
|
162
|
+
* rejected acceptance rolls the registration mutation back. This closes the
|
|
163
|
+
* window where a revival whose wake lease expires between the socket-layer
|
|
164
|
+
* preflight and acceptance would otherwise leave the durable row with a
|
|
165
|
+
* mutated pid/metadata/connectivity even though the socket is refused and
|
|
166
|
+
* unbound. On rejection the transaction is rolled back and `agent` is null.
|
|
167
|
+
*/
|
|
168
|
+
registerAgentWithGenerationAcceptance(input: {
|
|
169
|
+
registration: {
|
|
170
|
+
id: string;
|
|
171
|
+
name: string;
|
|
172
|
+
emoji: string;
|
|
173
|
+
pid: number;
|
|
174
|
+
metadata?: NonNullable<AgentInfo["metadata"]>;
|
|
175
|
+
stableId?: string;
|
|
176
|
+
};
|
|
177
|
+
accept: AcceptRuntimeGenerationInput;
|
|
178
|
+
}): {
|
|
179
|
+
agent: AgentInfo | null;
|
|
180
|
+
acceptance: RuntimeGenerationAcceptance;
|
|
181
|
+
};
|
|
182
|
+
/**
|
|
183
|
+
* Non-mutating preflight for {@link acceptRuntimeGeneration}: runs the exact
|
|
184
|
+
* same fence validation without advancing the generation or consuming the
|
|
185
|
+
* reservation. The socket layer uses this to validate a wake fence BEFORE
|
|
186
|
+
* committing the agent registration, and only accepts the generation once
|
|
187
|
+
* registration has succeeded. Because broker registration is synchronous, a
|
|
188
|
+
* passing preflight followed immediately by `acceptRuntimeGeneration` cannot
|
|
189
|
+
* be interleaved by another connection, so this closes the window where a
|
|
190
|
+
* generation was advanced for a runtime whose registration then failed.
|
|
191
|
+
*/
|
|
192
|
+
checkRuntimeGenerationAcceptable(input: AcceptRuntimeGenerationInput): RuntimeGenerationAcceptance;
|
|
193
|
+
/**
|
|
194
|
+
* Idempotently enqueue a wake trigger. If an active (queued/dispatching)
|
|
195
|
+
* entry already exists for the agent it is returned unchanged except that the
|
|
196
|
+
* effective priority is lowered to the strongest (smallest) trigger and the
|
|
197
|
+
* trigger message id is preserved when still unset. Never fans out.
|
|
198
|
+
*/
|
|
199
|
+
enqueueWake(input: EnqueueWakeInput): AgentWakeQueueEntry;
|
|
200
|
+
private getActiveWakeQueueEntry;
|
|
201
|
+
private getWakeQueueEntryById;
|
|
202
|
+
listWakeQueue(status?: AgentWakeQueueEntry["status"]): AgentWakeQueueEntry[];
|
|
203
|
+
countInflightWakes(repoRoot?: string | null): number;
|
|
204
|
+
markWakeDispatching(id: number): AgentWakeQueueEntry | null;
|
|
205
|
+
requeueWake(id: number): AgentWakeQueueEntry | null;
|
|
206
|
+
completeWakeQueueEntry(id: number, status?: "done" | "cancelled"): void;
|
|
207
|
+
cancelWake(agentId: string): void;
|
|
208
|
+
/** Mark any active wake-queue entry for an agent as completed (idempotent). */
|
|
209
|
+
completeWakeForAgent(agentId: string): void;
|
|
31
210
|
unregisterAgent(id: string): void;
|
|
32
211
|
disconnectAgent(id: string, resumableForMs?: number): void;
|
|
33
212
|
private getDirectChildren;
|