@zooid/transport-matrix 0.12.0 → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +164 -5
- package/dist/index.js +946 -101
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
- package/src/context-provider.test.ts +178 -3
- package/src/context-provider.ts +62 -5
- package/src/event-encoders.test.ts +69 -1
- package/src/event-encoders.ts +41 -1
- package/src/index.ts +23 -3
- package/src/invocation-registry.test.ts +22 -0
- package/src/invocation-registry.ts +32 -0
- package/src/matrix-client.ts +58 -34
- package/src/router.test.ts +129 -10
- package/src/router.ts +78 -2
- package/src/task-completion.test.ts +23 -0
- package/src/task-completion.ts +37 -0
- package/src/task-dispatch.test.ts +53 -0
- package/src/task-dispatch.ts +68 -0
- package/src/task-envelope.test.ts +27 -0
- package/src/task-registry.test.ts +50 -0
- package/src/task-registry.ts +152 -0
- package/src/transport.test.ts +520 -111
- package/src/transport.ts +760 -116
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TransportContextProvider, HistoryOptions, HistoryPage, ThreadOverviewPage, Member,
|
|
1
|
+
import { TransportContextProvider, RoomBinding, HistoryOptions, HistoryPage, ThreadOverviewPage, Member, RoomInfo, SendMessageInput as SendMessageInput$1, SendMessageResult, AcpRegistry, ApprovalCorrelator, PendingInputRegistry, TaskActions, InvocationRecord, ThreadCompletion, ThreadStartContent } from '@zooid/core';
|
|
2
2
|
import * as hono_types from 'hono/types';
|
|
3
3
|
import { Hono } from 'hono';
|
|
4
4
|
|
|
@@ -16,12 +16,14 @@ interface SendMessageInput {
|
|
|
16
16
|
[k: string]: unknown;
|
|
17
17
|
};
|
|
18
18
|
threadRoot?: string;
|
|
19
|
+
txnId?: string;
|
|
19
20
|
}
|
|
20
21
|
interface SendCustomEventInput {
|
|
21
22
|
roomId: string;
|
|
22
23
|
asUserId: string;
|
|
23
24
|
eventType: string;
|
|
24
25
|
content: Record<string, unknown>;
|
|
26
|
+
txnId?: string;
|
|
25
27
|
}
|
|
26
28
|
interface SetTypingInput {
|
|
27
29
|
roomId: string;
|
|
@@ -177,10 +179,30 @@ declare class MatrixClient {
|
|
|
177
179
|
|
|
178
180
|
interface MatrixContextProviderOpts {
|
|
179
181
|
client: MatrixClient;
|
|
180
|
-
/**
|
|
182
|
+
/**
|
|
183
|
+
* The **agent's own** Matrix user (`@{workstation}.{name}:server`), which
|
|
184
|
+
* every read is impersonated as via `?user_id=`. Not the AS bot: that would
|
|
185
|
+
* read every room on the homeserver and make this class the only thing
|
|
186
|
+
* standing between an agent and someone else's conversation.
|
|
187
|
+
*
|
|
188
|
+
* This is load-bearing. It is what makes the homeserver — not our own
|
|
189
|
+
* bookkeeping — the authorization boundary for context reads, so a room or
|
|
190
|
+
* thread the agent is not in fails at Matrix with 403/404. Anything that
|
|
191
|
+
* widens who can name a room (a CLI, a new tool parameter) is safe only
|
|
192
|
+
* while this holds.
|
|
193
|
+
*/
|
|
181
194
|
asUserId: string;
|
|
182
195
|
/** Map of Matrix user IDs → agent names, for is_agent / agent_name flags. */
|
|
183
196
|
agentBots: Map<string, string>;
|
|
197
|
+
/**
|
|
198
|
+
* This agent's own room bindings — the live array `BotPool.bootstrap`
|
|
199
|
+
* rewrites `.alias` on in place, so reads through this field after
|
|
200
|
+
* bootstrap see canonical room IDs. Backs `getRooms()` and the
|
|
201
|
+
* `sendMessage()` authorization check. Absent/empty = no rooms known
|
|
202
|
+
* (context providers built before this field existed, or in tests that
|
|
203
|
+
* don't exercise either method).
|
|
204
|
+
*/
|
|
205
|
+
rooms?: RoomBinding[];
|
|
184
206
|
}
|
|
185
207
|
declare class MatrixContextProvider implements TransportContextProvider {
|
|
186
208
|
private readonly opts;
|
|
@@ -190,7 +212,9 @@ declare class MatrixContextProvider implements TransportContextProvider {
|
|
|
190
212
|
getThreadHistory(channelId: string, threadId: string, hopts: HistoryOptions): Promise<HistoryPage>;
|
|
191
213
|
private toMessage;
|
|
192
214
|
getChannelMembers(channelId: string): Promise<Member[]>;
|
|
193
|
-
|
|
215
|
+
getRoomInfo(channelId: string): Promise<RoomInfo>;
|
|
216
|
+
getRooms(): Promise<RoomInfo[]>;
|
|
217
|
+
sendMessage(input: SendMessageInput$1): Promise<SendMessageResult>;
|
|
194
218
|
}
|
|
195
219
|
|
|
196
220
|
interface MatrixTransportConfig {
|
|
@@ -279,6 +303,10 @@ interface ThreadState {
|
|
|
279
303
|
*/
|
|
280
304
|
handoffs: Record<string, string[]>;
|
|
281
305
|
}
|
|
306
|
+
interface TaskThreadContext {
|
|
307
|
+
assignee: string;
|
|
308
|
+
isRoot: boolean;
|
|
309
|
+
}
|
|
282
310
|
interface MaybeEvent {
|
|
283
311
|
type?: string;
|
|
284
312
|
room_id?: string;
|
|
@@ -292,7 +320,7 @@ interface MaybeEvent {
|
|
|
292
320
|
};
|
|
293
321
|
}
|
|
294
322
|
type RouteMatch = AgentBinding;
|
|
295
|
-
declare function route(event: MaybeEvent, agents: AgentBinding[], threadStates?: Map<string, ThreadState
|
|
323
|
+
declare function route(event: MaybeEvent, agents: AgentBinding[], threadStates?: Map<string, ThreadState>, task?: TaskThreadContext): RouteMatch[];
|
|
296
324
|
|
|
297
325
|
interface BootstrapOpts {
|
|
298
326
|
/** Invited to any newly-created room; absent = no invite. */
|
|
@@ -367,6 +395,69 @@ declare class SyncLoop {
|
|
|
367
395
|
stop(): void;
|
|
368
396
|
}
|
|
369
397
|
|
|
398
|
+
declare const MAX_OPEN_TASKS_PER_ROOM = 5;
|
|
399
|
+
type TaskPhase = 'reserved' | 'uncertain' | 'open' | 'closed';
|
|
400
|
+
interface TaskRecord {
|
|
401
|
+
taskId: string;
|
|
402
|
+
attemptId: string;
|
|
403
|
+
roomId: string;
|
|
404
|
+
assignee: string;
|
|
405
|
+
notify: 'caller' | 'none';
|
|
406
|
+
parent: {
|
|
407
|
+
agent: string;
|
|
408
|
+
threadRoot: string;
|
|
409
|
+
sessionKey: string;
|
|
410
|
+
generation: number;
|
|
411
|
+
};
|
|
412
|
+
phase: TaskPhase;
|
|
413
|
+
threadRoot?: string;
|
|
414
|
+
summary?: string;
|
|
415
|
+
runId?: string;
|
|
416
|
+
closedAt?: string;
|
|
417
|
+
}
|
|
418
|
+
interface PersistedTask extends Required<Pick<TaskRecord, 'taskId' | 'attemptId' | 'roomId' | 'assignee' | 'notify' | 'parent' | 'phase'>> {
|
|
419
|
+
threadRoot?: string;
|
|
420
|
+
summary?: string;
|
|
421
|
+
runId: string;
|
|
422
|
+
closedAt?: string;
|
|
423
|
+
}
|
|
424
|
+
interface TaskJournal {
|
|
425
|
+
load(): PersistedTask[];
|
|
426
|
+
save(tasks: PersistedTask[]): void;
|
|
427
|
+
}
|
|
428
|
+
declare class TaskRegistry {
|
|
429
|
+
private readonly opts;
|
|
430
|
+
private readonly tasks;
|
|
431
|
+
private readonly byRoot;
|
|
432
|
+
private readonly generations;
|
|
433
|
+
private readonly runIdValue;
|
|
434
|
+
constructor(opts?: {
|
|
435
|
+
maxOpenPerRoom?: number;
|
|
436
|
+
newId?: () => string;
|
|
437
|
+
journal?: TaskJournal;
|
|
438
|
+
runId?: string;
|
|
439
|
+
maxClosedRecords?: number;
|
|
440
|
+
});
|
|
441
|
+
private get max();
|
|
442
|
+
private get runId();
|
|
443
|
+
private save;
|
|
444
|
+
openCount(roomId: string): number;
|
|
445
|
+
reserve(input: Omit<TaskRecord, 'taskId' | 'attemptId' | 'phase' | 'threadRoot' | 'summary'>): TaskRecord | undefined;
|
|
446
|
+
activate(taskId: string, threadRoot: string): void;
|
|
447
|
+
abandon(taskId: string): void;
|
|
448
|
+
markUncertain(taskId: string): void;
|
|
449
|
+
adopt(attemptId: string, threadRoot: string): TaskRecord | undefined;
|
|
450
|
+
taskForRoot(threadRoot: string): TaskRecord | undefined;
|
|
451
|
+
openTaskFor(agent: string, root: string): TaskRecord | undefined;
|
|
452
|
+
recordSummary(id: string, summary: string): "recorded" | "already_recorded";
|
|
453
|
+
clearSummary(id: string): void;
|
|
454
|
+
close(id: string): boolean;
|
|
455
|
+
/** Reconcile records from a prior daemon run and retain closed roots for trust checks. */
|
|
456
|
+
restore(): TaskRecord[];
|
|
457
|
+
generationOf(agent: string, session: string): number;
|
|
458
|
+
bumpGeneration(agent: string, session: string): void;
|
|
459
|
+
}
|
|
460
|
+
|
|
370
461
|
interface MediaClientLike {
|
|
371
462
|
download(input: {
|
|
372
463
|
mxcUri: string;
|
|
@@ -417,9 +508,16 @@ interface CreateMatrixTransportOptions {
|
|
|
417
508
|
loadSince?: (agentUserId: string) => string | null;
|
|
418
509
|
/** Pull mode: persist the `since` cursor after each sync poll. */
|
|
419
510
|
saveSince?: (agentUserId: string, since: string) => void;
|
|
511
|
+
/** Durable lifecycle state; supplied by the daemon when it has a data directory. */
|
|
512
|
+
taskJournal?: TaskJournal;
|
|
513
|
+
taskRunId?: string;
|
|
514
|
+
pendingInput?: PendingInputRegistry;
|
|
515
|
+
/** Deferred-return fallback window. Defaults to `RETURN_GRACE_MS`. */
|
|
516
|
+
returnGraceMs?: number;
|
|
420
517
|
}
|
|
421
518
|
declare function createMatrixTransport(opts: CreateMatrixTransportOptions): {
|
|
422
519
|
app: Hono<hono_types.BlankEnv, hono_types.BlankSchema, "/">;
|
|
520
|
+
taskActions: TaskActions;
|
|
423
521
|
syncLoops: SyncLoop[] | undefined;
|
|
424
522
|
bootstrap: (bootstrapOpts?: {
|
|
425
523
|
spaceRoomId?: string;
|
|
@@ -565,4 +663,65 @@ declare class PendingMediaStore {
|
|
|
565
663
|
drain(roomId: string, threadKey: string | undefined, sender: string): PendingMediaItem[];
|
|
566
664
|
}
|
|
567
665
|
|
|
568
|
-
|
|
666
|
+
declare class InvocationRegistry {
|
|
667
|
+
private readonly opts;
|
|
668
|
+
private readonly records;
|
|
669
|
+
private readonly byCallee;
|
|
670
|
+
private readonly byEvent;
|
|
671
|
+
constructor(opts?: {
|
|
672
|
+
newId?: () => string;
|
|
673
|
+
});
|
|
674
|
+
open(input: Omit<InvocationRecord, 'invocationId' | 'state'>): InvocationRecord;
|
|
675
|
+
attachCallEvent(id: string, eventId: string, sessionKey: string): void;
|
|
676
|
+
get(id: string): InvocationRecord | undefined;
|
|
677
|
+
byCallEvent(eventId: string): InvocationRecord | undefined;
|
|
678
|
+
forCalleeSession(session: string): InvocationRecord | undefined;
|
|
679
|
+
outstandingFor(session: string): InvocationRecord[];
|
|
680
|
+
outstandingForTask(taskId: string): InvocationRecord[];
|
|
681
|
+
resolve(id: string): InvocationRecord | undefined;
|
|
682
|
+
cancelForTask(taskId: string): InvocationRecord[];
|
|
683
|
+
ancestorAgents(session: string): string[];
|
|
684
|
+
isOutstandingAncestor(session: string, agent: string): boolean;
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
/** ACP's stable prompt termination values (kept local to avoid an SDK runtime dep). */
|
|
688
|
+
type StopReason = 'end_turn' | 'max_tokens' | 'max_turn_requests' | 'refusal' | 'cancelled';
|
|
689
|
+
interface CompletionInputs {
|
|
690
|
+
agent: string;
|
|
691
|
+
threadId: string;
|
|
692
|
+
stopReason?: StopReason;
|
|
693
|
+
error?: unknown;
|
|
694
|
+
summary?: string;
|
|
695
|
+
prose?: string;
|
|
696
|
+
outstanding: number;
|
|
697
|
+
awaitingHuman: number;
|
|
698
|
+
}
|
|
699
|
+
type CompletionDecision = {
|
|
700
|
+
decision: 'stay_open';
|
|
701
|
+
reason: 'outstanding_handoff' | 'awaiting_human';
|
|
702
|
+
} | {
|
|
703
|
+
decision: 'finish';
|
|
704
|
+
completion: ThreadCompletion;
|
|
705
|
+
};
|
|
706
|
+
declare function evaluateCompletion(input: CompletionInputs): CompletionDecision;
|
|
707
|
+
|
|
708
|
+
type Admission = {
|
|
709
|
+
ok: true;
|
|
710
|
+
} | {
|
|
711
|
+
ok: false;
|
|
712
|
+
reason: string;
|
|
713
|
+
};
|
|
714
|
+
declare function checkDelegable(agentName: string, roomId: string, bindings: AgentBinding[]): Admission;
|
|
715
|
+
declare function buildAssignmentContent(input: {
|
|
716
|
+
assigneeUserId: string;
|
|
717
|
+
prompt: string;
|
|
718
|
+
start: ThreadStartContent;
|
|
719
|
+
}): {
|
|
720
|
+
msgtype: string;
|
|
721
|
+
body: string;
|
|
722
|
+
[key: string]: unknown;
|
|
723
|
+
};
|
|
724
|
+
declare function renderCompletionPrompt(c: ThreadCompletion): string;
|
|
725
|
+
declare function renderInvocationReturn(c: ThreadCompletion): string;
|
|
726
|
+
|
|
727
|
+
export { AGENT_KEY_RE, type AgentBinding, BotPool, type CompletionDecision, type CompletionInputs, type CreateMatrixTransportOptions, type EnsureDefaultChannelOpts, type EnsureSpaceOpts, INLINE_IMAGE_MIMES, InvocationRegistry, MAX_DOWNLOAD_BYTES, MAX_INLINE_IMAGE_BYTES, MAX_MEDIA_PER_TURN, MAX_OPEN_TASKS_PER_ROOM, MEDIA_MSGTYPES, MatrixClient, type MatrixClientOptions, MatrixContextProvider, type MatrixContextProviderOpts, type MatrixTransportConfig, type MaybeMessage, MediaClient, type MediaClientLike, type MediaClientOptions, type PendingMediaItem, PendingMediaStore, type PersistedTask, type PublishOpts, type PublisherHandle, type RouteMatch, SLUG_RE, type SendCustomEventInput, type SendMessageInput, type StartOpts as StartWorkforcePublisherOpts, type StopReason, type SyncClient, SyncLoop, type SyncLoopOptions, type SyncResponse, type TaskJournal, type TaskPhase, type TaskRecord, TaskRegistry, type WorkforceRoster, type WriteAttachmentInput, agentMxid, buildAssignmentContent, buildWorkforceRoster, checkDelegable, createMatrixTransport, ensureDefaultChannel, ensureWorkforceSpace, evaluateCompletion, extractMentions, isMediaMsgtype, isValidAgentKey, isValidWorkstation, parseMxcUri, publishWorkforce, renderCompletionPrompt, renderInvocationReturn, renderRegistration, route, serverNameFromMxid, splitAgentLocalpart, startWorkforcePublisher, workstationUserNamespace, writeAttachment };
|