@pinet/broker-core 0.1.2 → 0.2.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/dist/agent-messaging.d.ts +1 -0
- package/dist/agent-messaging.js +50 -1
- package/dist/maintenance.js +6 -2
- package/dist/message-send.d.ts +2 -1
- package/dist/message-send.js +1 -0
- package/dist/schema.d.ts +8 -1
- package/dist/schema.js +340 -10
- package/dist/types.d.ts +11 -1
- package/package.json +2 -2
package/dist/agent-messaging.js
CHANGED
|
@@ -128,17 +128,66 @@ export function resolveDirectAgentTarget(agents, target) {
|
|
|
128
128
|
agents.find((agent) => agent.name === target) ??
|
|
129
129
|
null);
|
|
130
130
|
}
|
|
131
|
+
function isDescendantOf(agents, descendantId, ancestorId) {
|
|
132
|
+
let current = agents.find((agent) => agent.id === descendantId) ?? null;
|
|
133
|
+
const seen = new Set();
|
|
134
|
+
while (current?.parentAgentId) {
|
|
135
|
+
if (current.parentAgentId === ancestorId)
|
|
136
|
+
return true;
|
|
137
|
+
if (seen.has(current.parentAgentId))
|
|
138
|
+
return false;
|
|
139
|
+
seen.add(current.parentAgentId);
|
|
140
|
+
current = agents.find((agent) => agent.id === current?.parentAgentId) ?? null;
|
|
141
|
+
}
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
function canDispatchDirectAgentMessage(agents, sender, target, metadata) {
|
|
145
|
+
if (!sender)
|
|
146
|
+
return false;
|
|
147
|
+
if (!target.parentAgentId &&
|
|
148
|
+
target.supervisionState !== "supervised" &&
|
|
149
|
+
target.supervisionState !== "orphaned" &&
|
|
150
|
+
target.supervisionState !== "stopping") {
|
|
151
|
+
return true;
|
|
152
|
+
}
|
|
153
|
+
if (sender.id === metadata?.trustedBrokerAgentId) {
|
|
154
|
+
return metadata.emergency === true || metadata.targetScope === "subtree";
|
|
155
|
+
}
|
|
156
|
+
if (target.parentAgentId === sender.id)
|
|
157
|
+
return true;
|
|
158
|
+
if (sender.parentAgentId === target.id)
|
|
159
|
+
return true;
|
|
160
|
+
if (isDescendantOf(agents, target.id, sender.id))
|
|
161
|
+
return true;
|
|
162
|
+
if (isDescendantOf(agents, sender.id, target.id))
|
|
163
|
+
return true;
|
|
164
|
+
return false;
|
|
165
|
+
}
|
|
131
166
|
export function resolveBroadcastTargets(agents, senderAgentId, channel) {
|
|
132
167
|
return agents
|
|
133
168
|
.filter((agent) => agent.id !== senderAgentId)
|
|
169
|
+
.filter((agent) => !agent.parentAgentId &&
|
|
170
|
+
agent.supervisionState !== "supervised" &&
|
|
171
|
+
agent.supervisionState !== "orphaned" &&
|
|
172
|
+
agent.supervisionState !== "stopping")
|
|
134
173
|
.filter((agent) => agentSubscribesToBroadcastChannel(agent, channel))
|
|
135
174
|
.sort((left, right) => left.name.localeCompare(right.name));
|
|
136
175
|
}
|
|
137
176
|
export function dispatchDirectAgentMessage(storage, input, onDispatch) {
|
|
138
|
-
const
|
|
177
|
+
const agents = storage.getAgents();
|
|
178
|
+
const target = resolveDirectAgentTarget(agents, input.target);
|
|
139
179
|
if (!target) {
|
|
140
180
|
throw new Error(`Agent not found: ${input.target}`);
|
|
141
181
|
}
|
|
182
|
+
const sender = agents.find((agent) => agent.id === input.senderAgentId) ?? null;
|
|
183
|
+
const policyMetadata = { ...(input.metadata ?? {}) };
|
|
184
|
+
delete policyMetadata.trustedBrokerAgentId;
|
|
185
|
+
if (input.trustedBrokerAgentId) {
|
|
186
|
+
policyMetadata.trustedBrokerAgentId = input.trustedBrokerAgentId;
|
|
187
|
+
}
|
|
188
|
+
if (!canDispatchDirectAgentMessage(agents, sender, target, policyMetadata)) {
|
|
189
|
+
throw new Error(`Agent ${input.senderAgentId} cannot message supervised agent ${target.id} without parent/subtree visibility or an explicit broker emergency override.`);
|
|
190
|
+
}
|
|
142
191
|
const resolvedTarget = { id: target.id, name: target.name };
|
|
143
192
|
const metadata = buildAgentMessageMetadata(input.senderAgentName, input.body, input.metadata);
|
|
144
193
|
const { threadId, messageId } = deliverAgentMessage(storage, input.senderAgentId, resolvedTarget, input.body, metadata, onDispatch);
|
package/dist/maintenance.js
CHANGED
|
@@ -32,7 +32,11 @@ export function runBrokerMaintenancePass(db, options) {
|
|
|
32
32
|
const agents = db
|
|
33
33
|
.getAgents()
|
|
34
34
|
.filter((agent) => agent.id !== brokerAgentId)
|
|
35
|
-
.filter((agent) => agent.metadata?.role !== "broker")
|
|
35
|
+
.filter((agent) => agent.metadata?.role !== "broker")
|
|
36
|
+
.filter((agent) => !agent.parentAgentId &&
|
|
37
|
+
agent.supervisionState !== "supervised" &&
|
|
38
|
+
agent.supervisionState !== "orphaned" &&
|
|
39
|
+
agent.supervisionState !== "stopping");
|
|
36
40
|
const agentLoads = agents.map((agent) => ({
|
|
37
41
|
agent,
|
|
38
42
|
pendingInboxCount: db.getPendingInboxCount(agent.id),
|
|
@@ -53,7 +57,7 @@ export function runBrokerMaintenancePass(db, options) {
|
|
|
53
57
|
continue;
|
|
54
58
|
}
|
|
55
59
|
const preferredAgent = backlog.preferredAgentId
|
|
56
|
-
? (
|
|
60
|
+
? (db.getAgents().find((agent) => agent.id === backlog.preferredAgentId) ?? null)
|
|
57
61
|
: null;
|
|
58
62
|
if (backlog.preferredAgentId && !preferredAgent) {
|
|
59
63
|
const knownPreferredAgent = db.getAgentById(backlog.preferredAgentId);
|
package/dist/message-send.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BrokerMessage, MessageAdapter, NormalizedMessageContent, ThreadInfo } from "./types.js";
|
|
1
|
+
import type { BrokerMessage, MessageAdapter, NormalizedMessageContent, OutboundAttachmentFile, ThreadInfo } from "./types.js";
|
|
2
2
|
export interface BrokerMessageSenderDb {
|
|
3
3
|
getThread(threadId: string): ThreadInfo | null;
|
|
4
4
|
createThread(threadId: string, source: string, channel: string, ownerAgent: string | null): ThreadInfo;
|
|
@@ -18,6 +18,7 @@ export interface SendBrokerMessageInput {
|
|
|
18
18
|
channel?: string;
|
|
19
19
|
content?: NormalizedMessageContent;
|
|
20
20
|
blocks?: ReadonlyArray<Record<string, unknown>>;
|
|
21
|
+
files?: ReadonlyArray<OutboundAttachmentFile>;
|
|
21
22
|
agentName?: string;
|
|
22
23
|
agentEmoji?: string;
|
|
23
24
|
agentOwnerToken?: string;
|
package/dist/message-send.js
CHANGED
|
@@ -60,6 +60,7 @@ export async function sendBrokerMessage(deps, input) {
|
|
|
60
60
|
text: messageBody,
|
|
61
61
|
...(content ? { content } : {}),
|
|
62
62
|
...(input.blocks && input.blocks.length > 0 ? { blocks: input.blocks } : {}),
|
|
63
|
+
...(input.files && input.files.length > 0 ? { files: input.files } : {}),
|
|
63
64
|
...(input.agentName ? { agentName: input.agentName } : {}),
|
|
64
65
|
...(input.agentEmoji ? { agentEmoji: input.agentEmoji } : {}),
|
|
65
66
|
...(input.agentOwnerToken ? { agentOwnerToken: input.agentOwnerToken } : {}),
|
package/dist/schema.d.ts
CHANGED
|
@@ -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 = 18;
|
|
16
16
|
export declare class BrokerDB implements BrokerDBInterface {
|
|
17
17
|
private db;
|
|
18
18
|
private readonly dbPath;
|
|
@@ -27,8 +27,14 @@ export declare class BrokerDB implements BrokerDBInterface {
|
|
|
27
27
|
reconcileStartupAgents(resumableForMs?: number): void;
|
|
28
28
|
close(): void;
|
|
29
29
|
registerAgent(id: string, name: string, emoji: string, pid: number, metadata?: Record<string, unknown>, stableId?: string): AgentInfo;
|
|
30
|
+
private resolveAgentHierarchy;
|
|
30
31
|
unregisterAgent(id: string): void;
|
|
31
32
|
disconnectAgent(id: string, resumableForMs?: number): void;
|
|
33
|
+
private getDirectChildren;
|
|
34
|
+
getAgentDescendants(parentAgentId: string, includeDisconnected?: boolean): AgentInfo[];
|
|
35
|
+
isAgentAncestor(ancestorAgentId: string, descendantAgentId: string): boolean;
|
|
36
|
+
private notifyParentOfChildExit;
|
|
37
|
+
private markDescendantsOrphaned;
|
|
32
38
|
getAgentById(id: string): AgentInfo | null;
|
|
33
39
|
private getCurrentSessionOutboundCount;
|
|
34
40
|
private rowToAgentWithCurrentSessionOutboundCount;
|
|
@@ -127,6 +133,7 @@ export declare class BrokerDB implements BrokerDBInterface {
|
|
|
127
133
|
private getExistingMessageIdForIdentity;
|
|
128
134
|
private getMessageByExternalId;
|
|
129
135
|
private getMessageById;
|
|
136
|
+
private dropStaleSlackDeliveryRows;
|
|
130
137
|
private dropStaleTransportInboxRows;
|
|
131
138
|
getInbox(agentId: string, limit?: number): {
|
|
132
139
|
entry: InboxEntry;
|
package/dist/schema.js
CHANGED
|
@@ -28,6 +28,14 @@ function rowToAgent(row) {
|
|
|
28
28
|
lastHeartbeat: row.last_heartbeat,
|
|
29
29
|
metadata: row.metadata ? JSON.parse(row.metadata) : null,
|
|
30
30
|
status: row.status === "working" ? "working" : "idle",
|
|
31
|
+
parentAgentId: row.parent_agent_id,
|
|
32
|
+
rootAgentId: row.root_agent_id,
|
|
33
|
+
treeDepth: row.tree_depth ?? 0,
|
|
34
|
+
spawnedByAgentId: row.spawned_by_agent_id,
|
|
35
|
+
supervisionState: normalizeAgentSupervisionState(row.supervision_state),
|
|
36
|
+
launchId: row.launch_id,
|
|
37
|
+
subtreeRole: row.subtree_role,
|
|
38
|
+
laneId: row.lane_id,
|
|
31
39
|
disconnectedAt: row.disconnected_at,
|
|
32
40
|
resumableUntil: row.resumable_until,
|
|
33
41
|
idleSince: row.idle_since,
|
|
@@ -78,6 +86,30 @@ function getStringMetadataValue(metadata, keys) {
|
|
|
78
86
|
return null;
|
|
79
87
|
}
|
|
80
88
|
const INTERNAL_AGENT_SOURCE = "agent";
|
|
89
|
+
const STALE_SLACK_MESSAGE_MAX_AGE_MS = 15 * 60 * 1000;
|
|
90
|
+
// Slack ts values are epoch seconds. Small fixture/sentinel values are treated
|
|
91
|
+
// as ambiguous instead of stale so replay filtering only applies to plausible
|
|
92
|
+
// real Slack event timestamps.
|
|
93
|
+
const MIN_PLAUSIBLE_SLACK_TIMESTAMP_SECONDS = 1_000_000_000;
|
|
94
|
+
function parseSlackTimestampMs(timestamp) {
|
|
95
|
+
if (!timestamp)
|
|
96
|
+
return null;
|
|
97
|
+
const seconds = Number(timestamp);
|
|
98
|
+
if (!Number.isFinite(seconds) || seconds < MIN_PLAUSIBLE_SLACK_TIMESTAMP_SECONDS) {
|
|
99
|
+
return null;
|
|
100
|
+
}
|
|
101
|
+
return Math.trunc(seconds * 1000);
|
|
102
|
+
}
|
|
103
|
+
function getSlackMessageAgeMs(source, timestamp, nowMs = Date.now()) {
|
|
104
|
+
if (source !== "slack")
|
|
105
|
+
return null;
|
|
106
|
+
const timestampMs = parseSlackTimestampMs(timestamp);
|
|
107
|
+
return timestampMs === null ? null : nowMs - timestampMs;
|
|
108
|
+
}
|
|
109
|
+
function isStaleSlackMessageTimestamp(source, timestamp, nowMs = Date.now()) {
|
|
110
|
+
const ageMs = getSlackMessageAgeMs(source, timestamp, nowMs);
|
|
111
|
+
return ageMs !== null && ageMs > STALE_SLACK_MESSAGE_MAX_AGE_MS;
|
|
112
|
+
}
|
|
81
113
|
function isExternalTransportSource(source) {
|
|
82
114
|
return source.trim().length > 0 && source !== INTERNAL_AGENT_SOURCE;
|
|
83
115
|
}
|
|
@@ -263,6 +295,26 @@ function parseMetadataJson(value) {
|
|
|
263
295
|
return null;
|
|
264
296
|
}
|
|
265
297
|
}
|
|
298
|
+
const AGENT_SUPERVISION_STATES = new Set([
|
|
299
|
+
"root",
|
|
300
|
+
"supervised",
|
|
301
|
+
"orphaned",
|
|
302
|
+
"stopping",
|
|
303
|
+
]);
|
|
304
|
+
function normalizeAgentSupervisionState(value) {
|
|
305
|
+
return typeof value === "string" && AGENT_SUPERVISION_STATES.has(value)
|
|
306
|
+
? value
|
|
307
|
+
: "root";
|
|
308
|
+
}
|
|
309
|
+
function getOptionalMetadataString(metadata, keys) {
|
|
310
|
+
for (const key of keys) {
|
|
311
|
+
const value = metadata?.[key];
|
|
312
|
+
if (typeof value === "string" && value.trim().length > 0) {
|
|
313
|
+
return value.trim();
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
266
318
|
function rowToPinetLaneParticipant(row) {
|
|
267
319
|
return {
|
|
268
320
|
laneId: row.lane_id,
|
|
@@ -406,7 +458,7 @@ export function defaultDbPath() {
|
|
|
406
458
|
}
|
|
407
459
|
export const DEFAULT_RESUMABLE_WINDOW_MS = 15_000;
|
|
408
460
|
export const DEFAULT_DISCONNECTED_PURGE_GRACE_MS = 60 * 60_000;
|
|
409
|
-
export const CURRENT_BROKER_SCHEMA_VERSION =
|
|
461
|
+
export const CURRENT_BROKER_SCHEMA_VERSION = 18;
|
|
410
462
|
const REQUIRED_AGENT_LIFECYCLE_COLUMNS = [
|
|
411
463
|
"stable_id",
|
|
412
464
|
"metadata",
|
|
@@ -575,6 +627,31 @@ function addObservabilityColumns(db) {
|
|
|
575
627
|
WHERE status = 'idle' AND idle_since IS NULL;
|
|
576
628
|
`);
|
|
577
629
|
}
|
|
630
|
+
function addAgentHierarchyColumns(db) {
|
|
631
|
+
ensureColumn(db, "agents", "parent_agent_id", "ALTER TABLE agents ADD COLUMN parent_agent_id TEXT");
|
|
632
|
+
ensureColumn(db, "agents", "root_agent_id", "ALTER TABLE agents ADD COLUMN root_agent_id TEXT");
|
|
633
|
+
ensureColumn(db, "agents", "tree_depth", "ALTER TABLE agents ADD COLUMN tree_depth INTEGER NOT NULL DEFAULT 0");
|
|
634
|
+
ensureColumn(db, "agents", "spawned_by_agent_id", "ALTER TABLE agents ADD COLUMN spawned_by_agent_id TEXT");
|
|
635
|
+
ensureColumn(db, "agents", "supervision_state", "ALTER TABLE agents ADD COLUMN supervision_state TEXT NOT NULL DEFAULT 'root'");
|
|
636
|
+
ensureColumn(db, "agents", "launch_id", "ALTER TABLE agents ADD COLUMN launch_id TEXT");
|
|
637
|
+
ensureColumn(db, "agents", "subtree_role", "ALTER TABLE agents ADD COLUMN subtree_role TEXT");
|
|
638
|
+
ensureColumn(db, "agents", "lane_id", "ALTER TABLE agents ADD COLUMN lane_id TEXT");
|
|
639
|
+
db.exec(`
|
|
640
|
+
UPDATE agents
|
|
641
|
+
SET tree_depth = COALESCE(tree_depth, 0),
|
|
642
|
+
supervision_state = COALESCE(supervision_state, 'root')
|
|
643
|
+
WHERE tree_depth IS NULL OR supervision_state IS NULL;
|
|
644
|
+
|
|
645
|
+
CREATE INDEX IF NOT EXISTS idx_agents_parent_agent_id
|
|
646
|
+
ON agents(parent_agent_id);
|
|
647
|
+
CREATE INDEX IF NOT EXISTS idx_agents_root_agent_id
|
|
648
|
+
ON agents(root_agent_id);
|
|
649
|
+
CREATE INDEX IF NOT EXISTS idx_agents_supervision_state
|
|
650
|
+
ON agents(supervision_state, parent_agent_id);
|
|
651
|
+
CREATE INDEX IF NOT EXISTS idx_agents_lane_id
|
|
652
|
+
ON agents(lane_id);
|
|
653
|
+
`);
|
|
654
|
+
}
|
|
578
655
|
function addThreadOwnershipBindingColumn(db) {
|
|
579
656
|
createCoreTables(db);
|
|
580
657
|
ensureColumn(db, "threads", "owner_binding", "ALTER TABLE threads ADD COLUMN owner_binding TEXT");
|
|
@@ -1058,6 +1135,9 @@ function runSchemaMigrations(db) {
|
|
|
1058
1135
|
case 17:
|
|
1059
1136
|
migrateTaskAssignmentsToRepoScopedTracking(db);
|
|
1060
1137
|
break;
|
|
1138
|
+
case 18:
|
|
1139
|
+
addAgentHierarchyColumns(db);
|
|
1140
|
+
break;
|
|
1061
1141
|
default:
|
|
1062
1142
|
throw new Error(`Unsupported broker schema migration target: ${nextVersion}`);
|
|
1063
1143
|
}
|
|
@@ -1153,13 +1233,16 @@ export class BrokerDB {
|
|
|
1153
1233
|
? JSON.parse(existingRow.metadata)
|
|
1154
1234
|
: undefined);
|
|
1155
1235
|
const meta = finalMetadata ? JSON.stringify(finalMetadata) : null;
|
|
1236
|
+
const hierarchy = this.resolveAgentHierarchy(agentId, finalMetadata, existingRow);
|
|
1156
1237
|
db.prepare(`INSERT INTO agents (
|
|
1157
1238
|
id, stable_id, name, emoji, pid,
|
|
1158
1239
|
connected_at, last_seen, last_heartbeat,
|
|
1159
|
-
metadata, status,
|
|
1160
|
-
|
|
1240
|
+
metadata, status,
|
|
1241
|
+
parent_agent_id, root_agent_id, tree_depth, spawned_by_agent_id,
|
|
1242
|
+
supervision_state, launch_id, subtree_role, lane_id,
|
|
1243
|
+
disconnected_at, resumable_until, idle_since, last_activity
|
|
1161
1244
|
)
|
|
1162
|
-
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'idle', NULL, NULL, ?, NULL)
|
|
1245
|
+
VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, 'idle', ?, ?, ?, ?, ?, ?, ?, ?, NULL, NULL, ?, NULL)
|
|
1163
1246
|
ON CONFLICT(id) DO UPDATE SET
|
|
1164
1247
|
stable_id = COALESCE(excluded.stable_id, agents.stable_id),
|
|
1165
1248
|
name = excluded.name,
|
|
@@ -1170,12 +1253,21 @@ export class BrokerDB {
|
|
|
1170
1253
|
last_heartbeat = excluded.last_heartbeat,
|
|
1171
1254
|
metadata = excluded.metadata,
|
|
1172
1255
|
status = 'idle',
|
|
1256
|
+
parent_agent_id = excluded.parent_agent_id,
|
|
1257
|
+
root_agent_id = excluded.root_agent_id,
|
|
1258
|
+
tree_depth = excluded.tree_depth,
|
|
1259
|
+
spawned_by_agent_id = excluded.spawned_by_agent_id,
|
|
1260
|
+
supervision_state = excluded.supervision_state,
|
|
1261
|
+
launch_id = excluded.launch_id,
|
|
1262
|
+
subtree_role = excluded.subtree_role,
|
|
1263
|
+
lane_id = excluded.lane_id,
|
|
1173
1264
|
disconnected_at = NULL,
|
|
1174
1265
|
resumable_until = NULL,
|
|
1175
1266
|
idle_since = excluded.idle_since,
|
|
1176
|
-
last_activity = NULL`).run(agentId, persistedStableId, finalName, finalEmoji, pid, now, now, now, meta, now);
|
|
1267
|
+
last_activity = NULL`).run(agentId, persistedStableId, finalName, finalEmoji, pid, now, now, now, meta, hierarchy.parentAgentId, hierarchy.rootAgentId, hierarchy.treeDepth, hierarchy.spawnedByAgentId, hierarchy.supervisionState, hierarchy.launchId, hierarchy.subtreeRole, hierarchy.laneId, now);
|
|
1177
1268
|
return {
|
|
1178
1269
|
id: agentId,
|
|
1270
|
+
stableId: persistedStableId,
|
|
1179
1271
|
name: finalName,
|
|
1180
1272
|
emoji: finalEmoji,
|
|
1181
1273
|
pid,
|
|
@@ -1184,18 +1276,76 @@ export class BrokerDB {
|
|
|
1184
1276
|
lastHeartbeat: now,
|
|
1185
1277
|
metadata: finalMetadata ?? null,
|
|
1186
1278
|
status: "idle",
|
|
1279
|
+
parentAgentId: hierarchy.parentAgentId,
|
|
1280
|
+
rootAgentId: hierarchy.rootAgentId,
|
|
1281
|
+
treeDepth: hierarchy.treeDepth,
|
|
1282
|
+
spawnedByAgentId: hierarchy.spawnedByAgentId,
|
|
1283
|
+
supervisionState: hierarchy.supervisionState,
|
|
1284
|
+
launchId: hierarchy.launchId,
|
|
1285
|
+
subtreeRole: hierarchy.subtreeRole,
|
|
1286
|
+
laneId: hierarchy.laneId,
|
|
1187
1287
|
idleSince: now,
|
|
1188
1288
|
lastActivity: null,
|
|
1189
1289
|
};
|
|
1190
1290
|
}
|
|
1291
|
+
resolveAgentHierarchy(agentId, metadata, existingRow) {
|
|
1292
|
+
const requestedParentId = getOptionalMetadataString(metadata, [
|
|
1293
|
+
"parentAgentId",
|
|
1294
|
+
"pinetParentAgentId",
|
|
1295
|
+
]);
|
|
1296
|
+
const parentId = requestedParentId ?? existingRow?.parent_agent_id ?? null;
|
|
1297
|
+
const parent = parentId ? this.getAgentById(parentId) : null;
|
|
1298
|
+
if (parentId && (!parent || parent.disconnectedAt)) {
|
|
1299
|
+
throw new Error(`Cannot register supervised Pinet agent; parent ${parentId} is not live.`);
|
|
1300
|
+
}
|
|
1301
|
+
if (parent && parent.id === agentId) {
|
|
1302
|
+
throw new Error("Cannot register a Pinet agent as its own parent.");
|
|
1303
|
+
}
|
|
1304
|
+
if (parent && this.isAgentAncestor(agentId, parent.id)) {
|
|
1305
|
+
throw new Error("Cannot register a Pinet agent under one of its descendants.");
|
|
1306
|
+
}
|
|
1307
|
+
const supervisionState = parent
|
|
1308
|
+
? "supervised"
|
|
1309
|
+
: normalizeAgentSupervisionState(getOptionalMetadataString(metadata, ["supervisionState", "pinetSupervisionState"]) ??
|
|
1310
|
+
existingRow?.supervision_state);
|
|
1311
|
+
const rootAgentId = parent
|
|
1312
|
+
? (parent.rootAgentId ?? parent.id)
|
|
1313
|
+
: (getOptionalMetadataString(metadata, ["rootAgentId", "pinetRootAgentId"]) ??
|
|
1314
|
+
existingRow?.root_agent_id ??
|
|
1315
|
+
null);
|
|
1316
|
+
const treeDepth = parent ? (parent.treeDepth ?? 0) + 1 : (existingRow?.tree_depth ?? 0);
|
|
1317
|
+
const spawnedByAgentId = getOptionalMetadataString(metadata, ["spawnedByAgentId", "pinetSpawnedByAgentId"]) ??
|
|
1318
|
+
(parent ? parent.id : (existingRow?.spawned_by_agent_id ?? null));
|
|
1319
|
+
return {
|
|
1320
|
+
parentAgentId: parent?.id ?? null,
|
|
1321
|
+
rootAgentId,
|
|
1322
|
+
treeDepth,
|
|
1323
|
+
spawnedByAgentId,
|
|
1324
|
+
supervisionState,
|
|
1325
|
+
launchId: getOptionalMetadataString(metadata, ["launchId", "pinetLaunchId"]) ??
|
|
1326
|
+
existingRow?.launch_id ??
|
|
1327
|
+
null,
|
|
1328
|
+
subtreeRole: getOptionalMetadataString(metadata, ["subtreeRole", "pinetSubtreeRole"]) ??
|
|
1329
|
+
existingRow?.subtree_role ??
|
|
1330
|
+
null,
|
|
1331
|
+
laneId: getOptionalMetadataString(metadata, ["laneId", "pinetLaneId"]) ??
|
|
1332
|
+
existingRow?.lane_id ??
|
|
1333
|
+
null,
|
|
1334
|
+
};
|
|
1335
|
+
}
|
|
1191
1336
|
unregisterAgent(id) {
|
|
1192
1337
|
const db = this.getDb();
|
|
1193
1338
|
const now = new Date().toISOString();
|
|
1194
1339
|
this.withTransaction(() => {
|
|
1340
|
+
const agent = this.getAgentById(id);
|
|
1195
1341
|
this.requeueUndeliveredMessagesInternal(id, "agent_disconnected");
|
|
1196
1342
|
db.prepare("DELETE FROM inbox WHERE agent_id = ?").run(id);
|
|
1197
1343
|
db.prepare("UPDATE agents SET disconnected_at = ?, resumable_until = NULL WHERE id = ?").run(now, id);
|
|
1198
1344
|
db.prepare("UPDATE threads SET owner_agent = NULL WHERE owner_agent = ?").run(id);
|
|
1345
|
+
if (agent?.parentAgentId) {
|
|
1346
|
+
this.notifyParentOfChildExit(agent, "unregistered");
|
|
1347
|
+
}
|
|
1348
|
+
this.markDescendantsOrphaned(id, "parent_unregistered");
|
|
1199
1349
|
});
|
|
1200
1350
|
}
|
|
1201
1351
|
disconnectAgent(id, resumableForMs = DEFAULT_RESUMABLE_WINDOW_MS) {
|
|
@@ -1204,6 +1354,85 @@ export class BrokerDB {
|
|
|
1204
1354
|
const resumableUntil = new Date(now.getTime() + resumableForMs).toISOString();
|
|
1205
1355
|
db.prepare("UPDATE agents SET disconnected_at = ?, resumable_until = ? WHERE id = ?").run(now.toISOString(), resumableUntil, id);
|
|
1206
1356
|
}
|
|
1357
|
+
getDirectChildren(parentAgentId) {
|
|
1358
|
+
const rows = this.getDb()
|
|
1359
|
+
.prepare("SELECT * FROM agents WHERE parent_agent_id = ? ORDER BY connected_at ASC")
|
|
1360
|
+
.all(parentAgentId);
|
|
1361
|
+
return rows.map(rowToAgent);
|
|
1362
|
+
}
|
|
1363
|
+
getAgentDescendants(parentAgentId, includeDisconnected = false) {
|
|
1364
|
+
const descendants = [];
|
|
1365
|
+
const seen = new Set();
|
|
1366
|
+
const queue = this.getDirectChildren(parentAgentId);
|
|
1367
|
+
while (queue.length > 0) {
|
|
1368
|
+
const child = queue.shift();
|
|
1369
|
+
if (!child || seen.has(child.id))
|
|
1370
|
+
continue;
|
|
1371
|
+
seen.add(child.id);
|
|
1372
|
+
if (includeDisconnected || !child.disconnectedAt) {
|
|
1373
|
+
descendants.push(child);
|
|
1374
|
+
}
|
|
1375
|
+
queue.push(...this.getDirectChildren(child.id));
|
|
1376
|
+
}
|
|
1377
|
+
return descendants;
|
|
1378
|
+
}
|
|
1379
|
+
isAgentAncestor(ancestorAgentId, descendantAgentId) {
|
|
1380
|
+
let current = this.getAgentById(descendantAgentId);
|
|
1381
|
+
const seen = new Set();
|
|
1382
|
+
while (current?.parentAgentId) {
|
|
1383
|
+
if (current.parentAgentId === ancestorAgentId)
|
|
1384
|
+
return true;
|
|
1385
|
+
if (seen.has(current.parentAgentId))
|
|
1386
|
+
return false;
|
|
1387
|
+
seen.add(current.parentAgentId);
|
|
1388
|
+
current = this.getAgentById(current.parentAgentId);
|
|
1389
|
+
}
|
|
1390
|
+
return false;
|
|
1391
|
+
}
|
|
1392
|
+
notifyParentOfChildExit(agent, reason) {
|
|
1393
|
+
const parentId = agent.parentAgentId;
|
|
1394
|
+
if (!parentId)
|
|
1395
|
+
return;
|
|
1396
|
+
const parent = this.getAgentById(parentId);
|
|
1397
|
+
if (!parent || parent.disconnectedAt)
|
|
1398
|
+
return;
|
|
1399
|
+
const threadId = `a2a:${agent.id}:${parentId}`;
|
|
1400
|
+
this.createThread(threadId, "agent", `agent:${parentId}`, parentId);
|
|
1401
|
+
this.insertMessage(threadId, "agent", "inbound", agent.id, `Child worker ${agent.name} (${agent.id}) exited: ${reason}.`, [parentId], {
|
|
1402
|
+
a2a: true,
|
|
1403
|
+
senderAgent: agent.name,
|
|
1404
|
+
pinetMailClass: "fwup",
|
|
1405
|
+
subtree: true,
|
|
1406
|
+
childAgentId: agent.id,
|
|
1407
|
+
parentAgentId: parentId,
|
|
1408
|
+
lifecycle: "child_exit",
|
|
1409
|
+
reason,
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
markDescendantsOrphaned(parentAgentId, reason) {
|
|
1413
|
+
const descendants = this.getAgentDescendants(parentAgentId, true);
|
|
1414
|
+
if (descendants.length === 0)
|
|
1415
|
+
return;
|
|
1416
|
+
const db = this.getDb();
|
|
1417
|
+
const update = db.prepare("UPDATE agents SET supervision_state = 'orphaned', parent_agent_id = NULL WHERE id = ?");
|
|
1418
|
+
for (const child of descendants) {
|
|
1419
|
+
update.run(child.id);
|
|
1420
|
+
if (!child.disconnectedAt) {
|
|
1421
|
+
const threadId = `a2a:${parentAgentId}:${child.id}`;
|
|
1422
|
+
this.createThread(threadId, "agent", `agent:${child.id}`, child.id);
|
|
1423
|
+
this.insertMessage(threadId, "agent", "inbound", parentAgentId, `Parent worker ${parentAgentId} is no longer supervising this subtree (${reason}); this worker is now orphaned and should stop or await broker recovery instructions.`, [child.id], {
|
|
1424
|
+
a2a: true,
|
|
1425
|
+
senderAgent: "Pinet lifecycle",
|
|
1426
|
+
pinetMailClass: "steering",
|
|
1427
|
+
subtree: true,
|
|
1428
|
+
parentAgentId,
|
|
1429
|
+
childAgentId: child.id,
|
|
1430
|
+
lifecycle: "parent_orphaned_child",
|
|
1431
|
+
reason,
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1207
1436
|
getAgentById(id) {
|
|
1208
1437
|
const row = this.getAgentRowById(id);
|
|
1209
1438
|
return row ? rowToAgent(row) : null;
|
|
@@ -1469,7 +1698,7 @@ export class BrokerDB {
|
|
|
1469
1698
|
const now = new Date().toISOString();
|
|
1470
1699
|
return this.withTransaction(() => {
|
|
1471
1700
|
const staleRows = db
|
|
1472
|
-
.prepare(`SELECT
|
|
1701
|
+
.prepare(`SELECT * FROM agents
|
|
1473
1702
|
WHERE (disconnected_at IS NULL AND last_heartbeat <= ?)
|
|
1474
1703
|
OR (disconnected_at IS NOT NULL AND resumable_until IS NOT NULL AND resumable_until <= ?)`)
|
|
1475
1704
|
.all(cutoff, now);
|
|
@@ -1479,9 +1708,14 @@ export class BrokerDB {
|
|
|
1479
1708
|
const disconnectAgent = db.prepare("UPDATE agents SET disconnected_at = COALESCE(disconnected_at, ?), resumable_until = NULL WHERE id = ?");
|
|
1480
1709
|
const releaseClaims = db.prepare("UPDATE threads SET owner_agent = NULL WHERE owner_agent = ?");
|
|
1481
1710
|
for (const row of staleRows) {
|
|
1711
|
+
const agent = rowToAgent(row);
|
|
1482
1712
|
this.requeueUndeliveredMessagesInternal(row.id, "agent_disconnected");
|
|
1483
1713
|
disconnectAgent.run(now, row.id);
|
|
1484
1714
|
releaseClaims.run(row.id);
|
|
1715
|
+
if (agent.parentAgentId) {
|
|
1716
|
+
this.notifyParentOfChildExit(agent, "stale_heartbeat");
|
|
1717
|
+
}
|
|
1718
|
+
this.markDescendantsOrphaned(row.id, "parent_stale");
|
|
1485
1719
|
}
|
|
1486
1720
|
return staleRows.map((row) => row.id);
|
|
1487
1721
|
});
|
|
@@ -1493,7 +1727,7 @@ export class BrokerDB {
|
|
|
1493
1727
|
const cutoff = new Date(now - graceMs).toISOString();
|
|
1494
1728
|
return this.withTransaction(() => {
|
|
1495
1729
|
const rows = db
|
|
1496
|
-
.prepare(`SELECT
|
|
1730
|
+
.prepare(`SELECT * FROM agents
|
|
1497
1731
|
WHERE disconnected_at IS NOT NULL
|
|
1498
1732
|
AND disconnected_at <= ?
|
|
1499
1733
|
AND (resumable_until IS NULL OR resumable_until <= ?)`)
|
|
@@ -1504,12 +1738,17 @@ export class BrokerDB {
|
|
|
1504
1738
|
const releaseThreads = db.prepare("UPDATE threads SET owner_agent = NULL WHERE owner_agent = ?");
|
|
1505
1739
|
const deleteInbox = db.prepare("DELETE FROM inbox WHERE agent_id = ?");
|
|
1506
1740
|
for (const row of rows) {
|
|
1741
|
+
const agent = rowToAgent(row);
|
|
1507
1742
|
// Requeue undelivered messages to the backlog
|
|
1508
1743
|
this.requeueUndeliveredMessagesInternal(row.id, "agent_disconnected");
|
|
1509
1744
|
// Release thread ownership for the purged agent
|
|
1510
1745
|
releaseThreads.run(row.id);
|
|
1511
1746
|
// Clean up all inbox entries (both delivered and undelivered) for the agent
|
|
1512
1747
|
deleteInbox.run(row.id);
|
|
1748
|
+
if (agent.parentAgentId) {
|
|
1749
|
+
this.notifyParentOfChildExit(agent, "purged");
|
|
1750
|
+
}
|
|
1751
|
+
this.markDescendantsOrphaned(row.id, "parent_purged");
|
|
1513
1752
|
}
|
|
1514
1753
|
db.prepare(`DELETE FROM agents
|
|
1515
1754
|
WHERE disconnected_at IS NOT NULL
|
|
@@ -1779,6 +2018,7 @@ export class BrokerDB {
|
|
|
1779
2018
|
return rows.map(rowToThread);
|
|
1780
2019
|
}
|
|
1781
2020
|
getPendingBacklog(limit = 50) {
|
|
2021
|
+
this.dropStaleSlackDeliveryRows();
|
|
1782
2022
|
const db = this.getDb();
|
|
1783
2023
|
const rows = db
|
|
1784
2024
|
.prepare(`SELECT * FROM unrouted_backlog
|
|
@@ -1789,6 +2029,9 @@ export class BrokerDB {
|
|
|
1789
2029
|
return rows.map(rowToBacklog);
|
|
1790
2030
|
}
|
|
1791
2031
|
getBacklogCount(status = "pending") {
|
|
2032
|
+
if (status === "pending") {
|
|
2033
|
+
this.dropStaleSlackDeliveryRows();
|
|
2034
|
+
}
|
|
1792
2035
|
const db = this.getDb();
|
|
1793
2036
|
const row = db
|
|
1794
2037
|
.prepare("SELECT COUNT(*) AS count FROM unrouted_backlog WHERE status = ?")
|
|
@@ -1825,6 +2068,7 @@ export class BrokerDB {
|
|
|
1825
2068
|
assignBacklogEntry(id, agentId) {
|
|
1826
2069
|
const db = this.getDb();
|
|
1827
2070
|
return this.withTransaction(() => {
|
|
2071
|
+
this.dropStaleSlackDeliveryRows(agentId);
|
|
1828
2072
|
const row = db
|
|
1829
2073
|
.prepare("SELECT * FROM unrouted_backlog WHERE id = ? AND status = 'pending'")
|
|
1830
2074
|
.get(id);
|
|
@@ -1861,6 +2105,7 @@ export class BrokerDB {
|
|
|
1861
2105
|
});
|
|
1862
2106
|
}
|
|
1863
2107
|
recoverPendingTargetedBacklog(agentId) {
|
|
2108
|
+
this.dropStaleSlackDeliveryRows(agentId);
|
|
1864
2109
|
const agent = this.getAgentRowById(agentId);
|
|
1865
2110
|
if (!agent || agent.disconnected_at) {
|
|
1866
2111
|
return 0;
|
|
@@ -2607,7 +2852,75 @@ export class BrokerDB {
|
|
|
2607
2852
|
.get(messageId);
|
|
2608
2853
|
return row ? rowToBrokerMessage(row) : null;
|
|
2609
2854
|
}
|
|
2855
|
+
dropStaleSlackDeliveryRows(agentId) {
|
|
2856
|
+
const db = this.getDb();
|
|
2857
|
+
const nowMs = Date.now();
|
|
2858
|
+
const now = new Date(nowMs).toISOString();
|
|
2859
|
+
const agentClause = agentId ? " AND i.agent_id = ?" : "";
|
|
2860
|
+
const inboxRows = db
|
|
2861
|
+
.prepare(`SELECT i.id AS inbox_id,
|
|
2862
|
+
i.agent_id AS agent_id,
|
|
2863
|
+
i.message_id AS message_id,
|
|
2864
|
+
m.source AS source,
|
|
2865
|
+
m.metadata AS metadata,
|
|
2866
|
+
m.external_ts AS external_ts
|
|
2867
|
+
FROM inbox i
|
|
2868
|
+
JOIN messages m ON m.id = i.message_id
|
|
2869
|
+
WHERE (i.delivered = 0 OR i.read_at IS NULL)
|
|
2870
|
+
AND m.direction = 'inbound'
|
|
2871
|
+
AND m.source = 'slack'${agentClause}`)
|
|
2872
|
+
.all(...(agentId ? [agentId] : []));
|
|
2873
|
+
const staleInboxRows = inboxRows.filter((row) => {
|
|
2874
|
+
const metadata = parseJsonMetadata(row.metadata);
|
|
2875
|
+
const timestamp = getStringMetadataValue(metadata, ["timestamp", "ts", "externalTs", "external_ts"]) ??
|
|
2876
|
+
row.external_ts;
|
|
2877
|
+
return isStaleSlackMessageTimestamp(row.source, timestamp, nowMs);
|
|
2878
|
+
});
|
|
2879
|
+
const markInboxStale = db.prepare("UPDATE inbox SET delivered = 1, read_at = COALESCE(read_at, ?) WHERE id = ?");
|
|
2880
|
+
for (const row of staleInboxRows) {
|
|
2881
|
+
markInboxStale.run(now, row.inbox_id);
|
|
2882
|
+
this.completeTargetedBacklogAssignment(row.message_id, row.agent_id);
|
|
2883
|
+
}
|
|
2884
|
+
const backlogRows = tableExists(db, "unrouted_backlog")
|
|
2885
|
+
? db
|
|
2886
|
+
.prepare(`SELECT b.id AS backlog_id,
|
|
2887
|
+
m.source AS source,
|
|
2888
|
+
m.metadata AS metadata,
|
|
2889
|
+
m.external_ts AS external_ts
|
|
2890
|
+
FROM unrouted_backlog b
|
|
2891
|
+
JOIN messages m ON m.id = b.message_id
|
|
2892
|
+
WHERE b.status = 'pending'
|
|
2893
|
+
AND m.direction = 'inbound'
|
|
2894
|
+
AND m.source = 'slack'`)
|
|
2895
|
+
.all()
|
|
2896
|
+
: [];
|
|
2897
|
+
const staleBacklogIds = backlogRows
|
|
2898
|
+
.filter((row) => {
|
|
2899
|
+
const metadata = parseJsonMetadata(row.metadata);
|
|
2900
|
+
const timestamp = getStringMetadataValue(metadata, ["timestamp", "ts", "externalTs", "external_ts"]) ??
|
|
2901
|
+
row.external_ts;
|
|
2902
|
+
return isStaleSlackMessageTimestamp(row.source, timestamp, nowMs);
|
|
2903
|
+
})
|
|
2904
|
+
.map((row) => row.backlog_id);
|
|
2905
|
+
if (staleBacklogIds.length > 0) {
|
|
2906
|
+
const dropBacklog = db.prepare(`UPDATE unrouted_backlog
|
|
2907
|
+
SET status = 'dropped',
|
|
2908
|
+
reason = 'stale_slack_message',
|
|
2909
|
+
assigned_agent_id = NULL,
|
|
2910
|
+
updated_at = ?
|
|
2911
|
+
WHERE id = ?
|
|
2912
|
+
AND status = 'pending'`);
|
|
2913
|
+
for (const id of staleBacklogIds) {
|
|
2914
|
+
dropBacklog.run(now, id);
|
|
2915
|
+
}
|
|
2916
|
+
}
|
|
2917
|
+
if (staleInboxRows.length > 0 || staleBacklogIds.length > 0) {
|
|
2918
|
+
console.info(`[broker-core] skipped stale Slack delivery rows older than 15m: inbox=${staleInboxRows.length} backlog=${staleBacklogIds.length}`);
|
|
2919
|
+
}
|
|
2920
|
+
return { inboxCount: staleInboxRows.length, backlogCount: staleBacklogIds.length };
|
|
2921
|
+
}
|
|
2610
2922
|
dropStaleTransportInboxRows(agentId) {
|
|
2923
|
+
this.dropStaleSlackDeliveryRows(agentId);
|
|
2611
2924
|
const db = this.getDb();
|
|
2612
2925
|
const rows = db
|
|
2613
2926
|
.prepare(`SELECT i.id AS inbox_id,
|
|
@@ -2952,7 +3265,8 @@ export class BrokerDB {
|
|
|
2952
3265
|
m.id AS message_id,
|
|
2953
3266
|
m.thread_id AS thread_id,
|
|
2954
3267
|
m.source AS source,
|
|
2955
|
-
m.metadata AS metadata
|
|
3268
|
+
m.metadata AS metadata,
|
|
3269
|
+
m.external_ts AS external_ts
|
|
2956
3270
|
FROM inbox i
|
|
2957
3271
|
JOIN messages m ON m.id = i.message_id
|
|
2958
3272
|
WHERE i.agent_id = ?
|
|
@@ -2963,14 +3277,30 @@ export class BrokerDB {
|
|
|
2963
3277
|
return 0;
|
|
2964
3278
|
}
|
|
2965
3279
|
const markDelivered = db.prepare("UPDATE inbox SET delivered = 1 WHERE id = ?");
|
|
3280
|
+
const markStaleRead = db.prepare("UPDATE inbox SET delivered = 1, read_at = COALESCE(read_at, ?) WHERE id = ?");
|
|
3281
|
+
const nowMs = Date.now();
|
|
3282
|
+
const now = new Date(nowMs).toISOString();
|
|
3283
|
+
let requeuedCount = 0;
|
|
3284
|
+
let staleCount = 0;
|
|
2966
3285
|
for (const row of rows) {
|
|
2967
3286
|
const metadata = row.metadata ? JSON.parse(row.metadata) : {};
|
|
3287
|
+
const timestamp = getStringMetadataValue(metadata, ["timestamp", "ts", "externalTs", "external_ts"]) ??
|
|
3288
|
+
row.external_ts;
|
|
3289
|
+
if (isStaleSlackMessageTimestamp(row.source, timestamp, nowMs)) {
|
|
3290
|
+
markStaleRead.run(now, row.inbox_id);
|
|
3291
|
+
staleCount += 1;
|
|
3292
|
+
continue;
|
|
3293
|
+
}
|
|
2968
3294
|
const channel = typeof metadata.channel === "string" ? metadata.channel : "";
|
|
2969
|
-
const preferredAgentId = row.
|
|
3295
|
+
const preferredAgentId = row.target_agent_id || null;
|
|
2970
3296
|
this.upsertBacklogEntry(row.message_id, row.thread_id, channel, reason, "pending", preferredAgentId, null);
|
|
2971
3297
|
markDelivered.run(row.inbox_id);
|
|
3298
|
+
requeuedCount += 1;
|
|
3299
|
+
}
|
|
3300
|
+
if (staleCount > 0) {
|
|
3301
|
+
console.info(`[broker-core] skipped stale Slack requeue rows older than 15m: inbox=${staleCount}`);
|
|
2972
3302
|
}
|
|
2973
|
-
return
|
|
3303
|
+
return requeuedCount;
|
|
2974
3304
|
}
|
|
2975
3305
|
getBacklogById(id) {
|
|
2976
3306
|
const db = this.getDb();
|
package/dist/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { PinetMailClass } from "./mail-classification.js";
|
|
2
2
|
export declare const DEFAULT_EXTERNAL_THREAD_SOURCE = "external";
|
|
3
|
+
export type AgentSupervisionState = "root" | "supervised" | "orphaned" | "stopping";
|
|
3
4
|
export interface AgentInfo {
|
|
4
5
|
id: string;
|
|
5
6
|
stableId?: string | null;
|
|
@@ -11,6 +12,14 @@ export interface AgentInfo {
|
|
|
11
12
|
lastHeartbeat: string;
|
|
12
13
|
metadata: Record<string, unknown> | null;
|
|
13
14
|
status: "working" | "idle";
|
|
15
|
+
parentAgentId?: string | null;
|
|
16
|
+
rootAgentId?: string | null;
|
|
17
|
+
treeDepth?: number;
|
|
18
|
+
spawnedByAgentId?: string | null;
|
|
19
|
+
supervisionState?: AgentSupervisionState;
|
|
20
|
+
launchId?: string | null;
|
|
21
|
+
subtreeRole?: string | null;
|
|
22
|
+
laneId?: string | null;
|
|
14
23
|
disconnectedAt?: string | null;
|
|
15
24
|
resumableUntil?: string | null;
|
|
16
25
|
idleSince?: string | null;
|
|
@@ -266,9 +275,10 @@ export declare const RPC_AUTH_REQUIRED = -32001;
|
|
|
266
275
|
export declare const RPC_AGENT_NAME_CONFLICT = -32002;
|
|
267
276
|
export declare const RPC_AGENT_STABLE_ID_CONFLICT = -32003;
|
|
268
277
|
import { buildCompatibilityInstanceScope as _buildCompatibilityInstanceScope, buildCompatibilityWorkspaceScope as _buildCompatibilityWorkspaceScope, buildRuntimeScopeCarrier as _buildRuntimeScopeCarrier } from "@pinet/transport-core";
|
|
269
|
-
import type { InboundMessage as _InboundMessage, NormalizedMessageContent as _NormalizedMessageContent, OutboundMessage as _OutboundMessage, AdapterCapabilityRequest as _AdapterCapabilityRequest, AdapterCapabilityResult as _AdapterCapabilityResult, AdapterCapabilityEffects as _AdapterCapabilityEffects, AdapterThreadClaimEffect as _AdapterThreadClaimEffect, MessageAdapter as _MessageAdapter, RuntimeScopeCarrier as _RuntimeScopeCarrier, WorkspaceInstallScopeCarrier as _WorkspaceInstallScopeCarrier, InstanceScopeCarrier as _InstanceScopeCarrier } from "@pinet/transport-core";
|
|
278
|
+
import type { InboundMessage as _InboundMessage, NormalizedMessageContent as _NormalizedMessageContent, OutboundAttachmentFile as _OutboundAttachmentFile, OutboundMessage as _OutboundMessage, AdapterCapabilityRequest as _AdapterCapabilityRequest, AdapterCapabilityResult as _AdapterCapabilityResult, AdapterCapabilityEffects as _AdapterCapabilityEffects, AdapterThreadClaimEffect as _AdapterThreadClaimEffect, MessageAdapter as _MessageAdapter, RuntimeScopeCarrier as _RuntimeScopeCarrier, WorkspaceInstallScopeCarrier as _WorkspaceInstallScopeCarrier, InstanceScopeCarrier as _InstanceScopeCarrier } from "@pinet/transport-core";
|
|
270
279
|
export type InboundMessage = _InboundMessage;
|
|
271
280
|
export type NormalizedMessageContent = _NormalizedMessageContent;
|
|
281
|
+
export type OutboundAttachmentFile = _OutboundAttachmentFile;
|
|
272
282
|
export type OutboundMessage = _OutboundMessage;
|
|
273
283
|
export type AdapterCapabilityRequest = _AdapterCapabilityRequest;
|
|
274
284
|
export type AdapterCapabilityResult = _AdapterCapabilityResult;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pinet/broker-core",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Transport-neutral broker kernel primitives for pi transports",
|
|
6
6
|
"author": "Will Porcellini <5994936+gugu91@users.noreply.github.com>",
|
|
@@ -43,7 +43,7 @@
|
|
|
43
43
|
"test": "vitest run *.test.ts"
|
|
44
44
|
},
|
|
45
45
|
"dependencies": {
|
|
46
|
-
"@pinet/transport-core": "0.1
|
|
46
|
+
"@pinet/transport-core": "0.2.1"
|
|
47
47
|
},
|
|
48
48
|
"types": "./dist/index.d.ts"
|
|
49
49
|
}
|