@openscout/protocol 0.2.37 → 0.2.39

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.
@@ -31,6 +31,8 @@ export interface AgentIdentityAlias {
31
31
  }
32
32
  export declare function normalizeAgentIdentitySegment(value: string): string;
33
33
  export declare const normalizeAgentSelectorSegment: typeof normalizeAgentIdentitySegment;
34
+ export declare const SCOUT_DISPATCHER_AGENT_ID = "scout";
35
+ export declare function isReservedAgentDefinitionId(value: string | null | undefined): boolean;
34
36
  export declare function parseAgentIdentity(value: string): AgentIdentity | null;
35
37
  export declare function formatAgentIdentity(input: AgentIdentityInput, options?: {
36
38
  includeSigil?: boolean;
@@ -45,6 +47,16 @@ export declare function extractAgentMentions(text: string): {
45
47
  };
46
48
  export declare function agentIdentityMatches(identity: AgentIdentity, candidate: AgentIdentityCandidate): boolean;
47
49
  export declare function resolveAgentIdentity<T extends AgentIdentityCandidate>(identity: AgentIdentity, candidates: T[]): T | null;
50
+ export type AgentIdentityDiagnosis<T extends AgentIdentityCandidate> = {
51
+ kind: "resolved";
52
+ match: T;
53
+ } | {
54
+ kind: "ambiguous";
55
+ candidates: T[];
56
+ } | {
57
+ kind: "unknown";
58
+ };
59
+ export declare function diagnoseAgentIdentity<T extends AgentIdentityCandidate>(identity: AgentIdentity, candidates: T[]): AgentIdentityDiagnosis<T>;
48
60
  export declare function constructAgentAlias(input: {
49
61
  alias: string;
50
62
  target: AgentIdentityInput;
@@ -24,6 +24,15 @@ export function normalizeAgentIdentitySegment(value) {
24
24
  .replace(/^-+|-+$/g, "");
25
25
  }
26
26
  export const normalizeAgentSelectorSegment = normalizeAgentIdentitySegment;
27
+ export const SCOUT_DISPATCHER_AGENT_ID = "scout";
28
+ const RESERVED_AGENT_DEFINITION_IDS = new Set([
29
+ SCOUT_DISPATCHER_AGENT_ID,
30
+ ]);
31
+ export function isReservedAgentDefinitionId(value) {
32
+ if (!value)
33
+ return false;
34
+ return RESERVED_AGENT_DEFINITION_IDS.has(normalizeAgentIdentitySegment(value));
35
+ }
27
36
  function normalizeDimensionKey(value) {
28
37
  return DIMENSION_ALIASES[normalizeAgentIdentitySegment(value)] ?? null;
29
38
  }
@@ -277,27 +286,36 @@ export function agentIdentityMatches(identity, candidate) {
277
286
  return true;
278
287
  }
279
288
  export function resolveAgentIdentity(identity, candidates) {
289
+ const diagnosis = diagnoseAgentIdentity(identity, candidates);
290
+ return diagnosis.kind === "resolved" ? diagnosis.match : null;
291
+ }
292
+ export function diagnoseAgentIdentity(identity, candidates) {
280
293
  const aliasKeys = identityAliasKeys(identity);
281
294
  const exactAliasMatches = candidates.filter((candidate) => {
282
295
  const candidateAliasKeys = explicitCandidateAliases(candidate).map(canonicalizeAliasValue);
283
296
  return aliasKeys.some((key) => candidateAliasKeys.includes(key));
284
297
  });
285
298
  if (exactAliasMatches.length === 1) {
286
- return exactAliasMatches[0];
299
+ return { kind: "resolved", match: exactAliasMatches[0] };
287
300
  }
288
301
  if (exactAliasMatches.length > 1) {
289
- return null;
302
+ return { kind: "ambiguous", candidates: exactAliasMatches };
290
303
  }
291
304
  const matches = candidates.filter((candidate) => agentIdentityMatches(identity, candidate));
292
305
  if (matches.length === 1) {
293
- return matches[0];
306
+ return { kind: "resolved", match: matches[0] };
307
+ }
308
+ if (matches.length === 0) {
309
+ return { kind: "unknown" };
294
310
  }
295
311
  if (!identity.nodeQualifier && !identity.workspaceQualifier && !identity.profile && !identity.harness) {
296
- return matches.find((candidate) => normalizeAgentIdentitySegment(candidate.agentId) === identity.definitionId)
297
- ?? matches[0]
298
- ?? null;
312
+ const exactIdMatch = matches.find((candidate) => normalizeAgentIdentitySegment(candidate.agentId) === identity.definitionId);
313
+ if (exactIdMatch) {
314
+ return { kind: "resolved", match: exactIdMatch };
315
+ }
316
+ return { kind: "ambiguous", candidates: matches };
299
317
  }
300
- return null;
318
+ return { kind: "ambiguous", candidates: matches };
301
319
  }
302
320
  export function constructAgentAlias(input) {
303
321
  const alias = normalizeAgentIdentitySegment(trimIdentityPrefix(input.alias));
package/dist/common.d.ts CHANGED
@@ -2,7 +2,8 @@ export type ScoutId = string;
2
2
  export type ActorKind = "person" | "helper" | "agent" | "system" | "bridge" | "device";
3
3
  export type AgentState = "offline" | "idle" | "active" | "waiting";
4
4
  export type VisibilityScope = "private" | "workspace" | "public" | "system";
5
- export type DeliveryStatus = "pending" | "leased" | "sent" | "acknowledged" | "failed" | "cancelled";
5
+ export type DeliveryStatus = "accepted" | "peer_acked" | "running" | "completed" | "deferred" | "failed" | "cancelled" | "pending" | "leased" | "sent" | "acknowledged";
6
+ export type DeliveryFailureReason = "peer_unreachable" | "peer_rejected" | "agent_offline" | "timeout" | "harness_error" | "dispatch" | "cancelled";
6
7
  export type DeliveryPolicy = "best_effort" | "must_ack" | "durable" | "ephemeral";
7
8
  export type DeliveryTargetKind = "participant" | "agent" | "bridge" | "device" | "voice_session" | "webhook";
8
9
  export type DeliveryTransport = "local_socket" | "websocket" | "peer_broker" | "http" | "webhook" | "telegram" | "discord" | "sms" | "email" | "tts" | "native_voice" | "claude_stream_json" | "codex_app_server" | "codex_exec" | "claude_resume" | "tmux";
package/dist/events.d.ts CHANGED
@@ -6,6 +6,7 @@ import type { FlightRecord, InvocationRequest } from "./invocations.js";
6
6
  import type { MessageRecord } from "./messages.js";
7
7
  import type { AgentDefinition, AgentEndpoint, ActorIdentity } from "./actors.js";
8
8
  import type { CollaborationEvent, CollaborationRecord } from "./collaboration.js";
9
+ import type { ScoutDispatchRecord } from "./scout-dispatch.js";
9
10
  export interface ControlEventBase<K extends string, P> {
10
11
  id: ScoutId;
11
12
  kind: K;
@@ -47,10 +48,17 @@ export type DeliveryPlannedEvent = ControlEventBase<"delivery.planned", {
47
48
  export type DeliveryAttemptedEvent = ControlEventBase<"delivery.attempted", {
48
49
  attempt: DeliveryAttempt;
49
50
  }>;
51
+ export type DeliveryStateChangedEvent = ControlEventBase<"delivery.state.changed", {
52
+ delivery: DeliveryIntent;
53
+ previousStatus?: DeliveryIntent["status"];
54
+ }>;
50
55
  export type CollaborationUpsertedEvent = ControlEventBase<"collaboration.upserted", {
51
56
  record: CollaborationRecord;
52
57
  }>;
53
58
  export type CollaborationEventAppendedEvent = ControlEventBase<"collaboration.event.appended", {
54
59
  event: CollaborationEvent;
55
60
  }>;
56
- export type ControlEvent = NodeUpsertedEvent | ActorRegisteredEvent | AgentRegisteredEvent | AgentEndpointUpsertedEvent | ConversationUpsertedEvent | BindingUpsertedEvent | MessagePostedEvent | InvocationRequestedEvent | FlightUpdatedEvent | DeliveryPlannedEvent | DeliveryAttemptedEvent | CollaborationUpsertedEvent | CollaborationEventAppendedEvent;
61
+ export type ScoutDispatchedEvent = ControlEventBase<"scout.dispatched", {
62
+ dispatch: ScoutDispatchRecord;
63
+ }>;
64
+ export type ControlEvent = NodeUpsertedEvent | ActorRegisteredEvent | AgentRegisteredEvent | AgentEndpointUpsertedEvent | ConversationUpsertedEvent | BindingUpsertedEvent | MessagePostedEvent | InvocationRequestedEvent | FlightUpdatedEvent | DeliveryPlannedEvent | DeliveryAttemptedEvent | DeliveryStateChangedEvent | CollaborationUpsertedEvent | CollaborationEventAppendedEvent | ScoutDispatchedEvent;
package/dist/index.d.ts CHANGED
@@ -9,6 +9,7 @@ export * from "./conversations.js";
9
9
  export * from "./collaboration.js";
10
10
  export * from "./messages.js";
11
11
  export * from "./invocations.js";
12
+ export * from "./scout-dispatch.js";
12
13
  export * from "./deliveries.js";
13
14
  export * from "./transports.js";
14
15
  export * from "./events.js";
package/dist/index.js CHANGED
@@ -9,6 +9,7 @@ export * from "./conversations.js";
9
9
  export * from "./collaboration.js";
10
10
  export * from "./messages.js";
11
11
  export * from "./invocations.js";
12
+ export * from "./scout-dispatch.js";
12
13
  export * from "./deliveries.js";
13
14
  export * from "./transports.js";
14
15
  export * from "./events.js";
@@ -0,0 +1,31 @@
1
+ import type { AdvertiseScope, DeliveryTransport, ScoutId } from "./common.js";
2
+ export type ScoutDispatchKind = "ambiguous" | "unknown" | "unparseable";
3
+ export type ScoutCandidateEndpointState = "online" | "offline" | "unknown";
4
+ export interface ScoutDispatchCandidate {
5
+ agentId: ScoutId;
6
+ displayName: string;
7
+ authorityNodeId?: ScoutId;
8
+ homeNodeId?: ScoutId;
9
+ advertiseScope?: AdvertiseScope;
10
+ selector?: string | null;
11
+ defaultSelector?: string | null;
12
+ workspace?: string | null;
13
+ node?: string | null;
14
+ projectRoot?: string | null;
15
+ endpointState: ScoutCandidateEndpointState;
16
+ transport?: DeliveryTransport | null;
17
+ }
18
+ export interface ScoutDispatchEnvelope {
19
+ kind: ScoutDispatchKind;
20
+ askedLabel: string;
21
+ detail: string;
22
+ candidates: ScoutDispatchCandidate[];
23
+ dispatchedAt: number;
24
+ dispatcherNodeId: ScoutId;
25
+ }
26
+ export interface ScoutDispatchRecord extends ScoutDispatchEnvelope {
27
+ id: ScoutId;
28
+ invocationId?: ScoutId;
29
+ conversationId?: ScoutId;
30
+ requesterId?: ScoutId;
31
+ }
@@ -0,0 +1 @@
1
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openscout/protocol",
3
- "version": "0.2.37",
3
+ "version": "0.2.39",
4
4
  "description": "Typed protocol for the OpenScout local control plane",
5
5
  "type": "module",
6
6
  "exports": {
@@ -3,15 +3,18 @@ import { describe, expect, test } from "bun:test";
3
3
  import {
4
4
  constructAgentAlias,
5
5
  constructAgentIdentity,
6
+ diagnoseAgentIdentity,
6
7
  extractAgentIdentities,
7
8
  formatAgentAlias,
8
9
  formatAgentIdentity,
9
10
  formatMinimalAgentIdentity,
11
+ isReservedAgentDefinitionId,
10
12
  parseAgentIdentity,
11
13
  parseAgentSelector,
12
14
  resolveAgentAlias,
13
15
  resolveAgentIdentity,
14
16
  resolveAgentSelector,
17
+ SCOUT_DISPATCHER_AGENT_ID,
15
18
  } from "./agent-identity.js";
16
19
 
17
20
  describe("agent identity grammar", () => {
@@ -271,3 +274,75 @@ describe("agent identity resolution", () => {
271
274
  expect(formatMinimalAgentIdentity(candidates[5], candidates)).toBe("@hudson.node:backup-mac-mini");
272
275
  });
273
276
  });
277
+
278
+ describe("scout dispatcher reservation", () => {
279
+ test("reserves the scout definition id", () => {
280
+ expect(SCOUT_DISPATCHER_AGENT_ID).toBe("scout");
281
+ expect(isReservedAgentDefinitionId("scout")).toBe(true);
282
+ expect(isReservedAgentDefinitionId("Scout")).toBe(true);
283
+ expect(isReservedAgentDefinitionId("SCOUT ")).toBe(true);
284
+ expect(isReservedAgentDefinitionId("scoutie")).toBe(false);
285
+ expect(isReservedAgentDefinitionId("scout-ie")).toBe(false);
286
+ expect(isReservedAgentDefinitionId("")).toBe(false);
287
+ expect(isReservedAgentDefinitionId(null)).toBe(false);
288
+ expect(isReservedAgentDefinitionId(undefined)).toBe(false);
289
+ });
290
+ });
291
+
292
+ describe("agent identity diagnosis", () => {
293
+ const scoutieMiniMain = {
294
+ agentId: "scoutie.mini.main",
295
+ definitionId: "scoutie",
296
+ nodeQualifier: "mini",
297
+ workspaceQualifier: "main",
298
+ aliases: ["@scoutie.main.node:mini", "@scoutie"],
299
+ };
300
+ const scoutieMainMini = {
301
+ agentId: "scoutie.main.mini",
302
+ definitionId: "scoutie",
303
+ nodeQualifier: "mini",
304
+ workspaceQualifier: "main",
305
+ aliases: ["@scoutie.main.node:mini", "@scoutie"],
306
+ };
307
+ const arachMini = {
308
+ agentId: "arach.mini",
309
+ definitionId: "arach",
310
+ nodeQualifier: "mini",
311
+ aliases: ["@arach.node:mini", "@arach"],
312
+ };
313
+
314
+ test("returns resolved when exactly one candidate matches", () => {
315
+ const identity = parseAgentIdentity("@arach");
316
+ expect(identity).not.toBeNull();
317
+ const result = diagnoseAgentIdentity(identity!, [scoutieMiniMain, arachMini]);
318
+ expect(result.kind).toBe("resolved");
319
+ if (result.kind === "resolved") {
320
+ expect(result.match.agentId).toBe("arach.mini");
321
+ }
322
+ });
323
+
324
+ test("returns ambiguous when multiple exact alias matches exist", () => {
325
+ const identity = parseAgentIdentity("@scoutie");
326
+ expect(identity).not.toBeNull();
327
+ const result = diagnoseAgentIdentity(identity!, [scoutieMiniMain, scoutieMainMini, arachMini]);
328
+ expect(result.kind).toBe("ambiguous");
329
+ if (result.kind === "ambiguous") {
330
+ expect(result.candidates.map((c) => c.agentId).sort()).toEqual([
331
+ "scoutie.main.mini",
332
+ "scoutie.mini.main",
333
+ ]);
334
+ }
335
+ });
336
+
337
+ test("returns unknown when no candidate matches", () => {
338
+ const identity = parseAgentIdentity("@nonexistent");
339
+ expect(identity).not.toBeNull();
340
+ const result = diagnoseAgentIdentity(identity!, [scoutieMiniMain, arachMini]);
341
+ expect(result.kind).toBe("unknown");
342
+ });
343
+
344
+ test("resolveAgentIdentity returns null on ambiguity (back-compat)", () => {
345
+ const identity = parseAgentIdentity("@scoutie");
346
+ expect(resolveAgentIdentity(identity!, [scoutieMiniMain, scoutieMainMini])).toBeNull();
347
+ });
348
+ });
@@ -65,6 +65,17 @@ export function normalizeAgentIdentitySegment(value: string): string {
65
65
 
66
66
  export const normalizeAgentSelectorSegment = normalizeAgentIdentitySegment;
67
67
 
68
+ export const SCOUT_DISPATCHER_AGENT_ID = "scout";
69
+
70
+ const RESERVED_AGENT_DEFINITION_IDS: ReadonlySet<string> = new Set([
71
+ SCOUT_DISPATCHER_AGENT_ID,
72
+ ]);
73
+
74
+ export function isReservedAgentDefinitionId(value: string | null | undefined): boolean {
75
+ if (!value) return false;
76
+ return RESERVED_AGENT_DEFINITION_IDS.has(normalizeAgentIdentitySegment(value));
77
+ }
78
+
68
79
  function normalizeDimensionKey(value: string): AgentIdentityDimension | null {
69
80
  return DIMENSION_ALIASES[normalizeAgentIdentitySegment(value)] ?? null;
70
81
  }
@@ -363,30 +374,50 @@ export function resolveAgentIdentity<T extends AgentIdentityCandidate>(
363
374
  identity: AgentIdentity,
364
375
  candidates: T[],
365
376
  ): T | null {
377
+ const diagnosis = diagnoseAgentIdentity(identity, candidates);
378
+ return diagnosis.kind === "resolved" ? diagnosis.match : null;
379
+ }
380
+
381
+ export type AgentIdentityDiagnosis<T extends AgentIdentityCandidate> =
382
+ | { kind: "resolved"; match: T }
383
+ | { kind: "ambiguous"; candidates: T[] }
384
+ | { kind: "unknown" };
385
+
386
+ export function diagnoseAgentIdentity<T extends AgentIdentityCandidate>(
387
+ identity: AgentIdentity,
388
+ candidates: T[],
389
+ ): AgentIdentityDiagnosis<T> {
366
390
  const aliasKeys = identityAliasKeys(identity);
367
391
  const exactAliasMatches = candidates.filter((candidate) => {
368
392
  const candidateAliasKeys = explicitCandidateAliases(candidate).map(canonicalizeAliasValue);
369
393
  return aliasKeys.some((key) => candidateAliasKeys.includes(key));
370
394
  });
371
395
  if (exactAliasMatches.length === 1) {
372
- return exactAliasMatches[0];
396
+ return { kind: "resolved", match: exactAliasMatches[0] };
373
397
  }
374
398
  if (exactAliasMatches.length > 1) {
375
- return null;
399
+ return { kind: "ambiguous", candidates: exactAliasMatches };
376
400
  }
377
401
 
378
402
  const matches = candidates.filter((candidate) => agentIdentityMatches(identity, candidate));
379
403
  if (matches.length === 1) {
380
- return matches[0];
404
+ return { kind: "resolved", match: matches[0] };
405
+ }
406
+ if (matches.length === 0) {
407
+ return { kind: "unknown" };
381
408
  }
382
409
 
383
410
  if (!identity.nodeQualifier && !identity.workspaceQualifier && !identity.profile && !identity.harness) {
384
- return matches.find((candidate) => normalizeAgentIdentitySegment(candidate.agentId) === identity.definitionId)
385
- ?? matches[0]
386
- ?? null;
411
+ const exactIdMatch = matches.find(
412
+ (candidate) => normalizeAgentIdentitySegment(candidate.agentId) === identity.definitionId,
413
+ );
414
+ if (exactIdMatch) {
415
+ return { kind: "resolved", match: exactIdMatch };
416
+ }
417
+ return { kind: "ambiguous", candidates: matches };
387
418
  }
388
419
 
389
- return null;
420
+ return { kind: "ambiguous", candidates: matches };
390
421
  }
391
422
 
392
423
  export function constructAgentAlias(input: {
package/src/common.ts CHANGED
@@ -17,11 +17,27 @@ export type AgentState =
17
17
  export type VisibilityScope = "private" | "workspace" | "public" | "system";
18
18
 
19
19
  export type DeliveryStatus =
20
+ // Outbox lifecycle (Issue 3 of broker-three-contracts)
21
+ | "accepted" // local journal write done, awaiting forward
22
+ | "peer_acked" // peer broker journaled the envelope
23
+ | "running" // target agent claimed the flight
24
+ | "completed" // terminal success
25
+ | "deferred" // within retry window — see metadata.nextAttemptAt
26
+ | "failed" // terminal failure — see metadata.failureReason
27
+ | "cancelled"
28
+ // Legacy values kept for backwards-compatible journal replay
20
29
  | "pending"
21
30
  | "leased"
22
31
  | "sent"
23
- | "acknowledged"
24
- | "failed"
32
+ | "acknowledged";
33
+
34
+ export type DeliveryFailureReason =
35
+ | "peer_unreachable" // TCP/network failure — retry-able
36
+ | "peer_rejected" // peer broker explicitly refused — not retried
37
+ | "agent_offline" // peer ACK'd but target agent never claimed
38
+ | "timeout"
39
+ | "harness_error"
40
+ | "dispatch" // ambiguous label — see metadata.scoutDispatch
25
41
  | "cancelled";
26
42
 
27
43
  export type DeliveryPolicy = "best_effort" | "must_ack" | "durable" | "ephemeral";
package/src/events.ts CHANGED
@@ -6,6 +6,7 @@ import type { FlightRecord, InvocationRequest } from "./invocations.js";
6
6
  import type { MessageRecord } from "./messages.js";
7
7
  import type { AgentDefinition, AgentEndpoint, ActorIdentity } from "./actors.js";
8
8
  import type { CollaborationEvent, CollaborationRecord } from "./collaboration.js";
9
+ import type { ScoutDispatchRecord } from "./scout-dispatch.js";
9
10
 
10
11
  export interface ControlEventBase<K extends string, P> {
11
12
  id: ScoutId;
@@ -60,6 +61,11 @@ export type DeliveryAttemptedEvent = ControlEventBase<"delivery.attempted", {
60
61
  attempt: DeliveryAttempt;
61
62
  }>;
62
63
 
64
+ export type DeliveryStateChangedEvent = ControlEventBase<"delivery.state.changed", {
65
+ delivery: DeliveryIntent;
66
+ previousStatus?: DeliveryIntent["status"];
67
+ }>;
68
+
63
69
  export type CollaborationUpsertedEvent = ControlEventBase<"collaboration.upserted", {
64
70
  record: CollaborationRecord;
65
71
  }>;
@@ -68,6 +74,10 @@ export type CollaborationEventAppendedEvent = ControlEventBase<"collaboration.ev
68
74
  event: CollaborationEvent;
69
75
  }>;
70
76
 
77
+ export type ScoutDispatchedEvent = ControlEventBase<"scout.dispatched", {
78
+ dispatch: ScoutDispatchRecord;
79
+ }>;
80
+
71
81
  export type ControlEvent =
72
82
  | NodeUpsertedEvent
73
83
  | ActorRegisteredEvent
@@ -80,5 +90,7 @@ export type ControlEvent =
80
90
  | FlightUpdatedEvent
81
91
  | DeliveryPlannedEvent
82
92
  | DeliveryAttemptedEvent
93
+ | DeliveryStateChangedEvent
83
94
  | CollaborationUpsertedEvent
84
- | CollaborationEventAppendedEvent;
95
+ | CollaborationEventAppendedEvent
96
+ | ScoutDispatchedEvent;
package/src/index.ts CHANGED
@@ -9,6 +9,7 @@ export * from "./conversations.js";
9
9
  export * from "./collaboration.js";
10
10
  export * from "./messages.js";
11
11
  export * from "./invocations.js";
12
+ export * from "./scout-dispatch.js";
12
13
  export * from "./deliveries.js";
13
14
  export * from "./transports.js";
14
15
  export * from "./events.js";
@@ -0,0 +1,36 @@
1
+ import type { AdvertiseScope, DeliveryTransport, ScoutId } from "./common.js";
2
+
3
+ export type ScoutDispatchKind = "ambiguous" | "unknown" | "unparseable";
4
+
5
+ export type ScoutCandidateEndpointState = "online" | "offline" | "unknown";
6
+
7
+ export interface ScoutDispatchCandidate {
8
+ agentId: ScoutId;
9
+ displayName: string;
10
+ authorityNodeId?: ScoutId;
11
+ homeNodeId?: ScoutId;
12
+ advertiseScope?: AdvertiseScope;
13
+ selector?: string | null;
14
+ defaultSelector?: string | null;
15
+ workspace?: string | null;
16
+ node?: string | null;
17
+ projectRoot?: string | null;
18
+ endpointState: ScoutCandidateEndpointState;
19
+ transport?: DeliveryTransport | null;
20
+ }
21
+
22
+ export interface ScoutDispatchEnvelope {
23
+ kind: ScoutDispatchKind;
24
+ askedLabel: string;
25
+ detail: string;
26
+ candidates: ScoutDispatchCandidate[];
27
+ dispatchedAt: number;
28
+ dispatcherNodeId: ScoutId;
29
+ }
30
+
31
+ export interface ScoutDispatchRecord extends ScoutDispatchEnvelope {
32
+ id: ScoutId;
33
+ invocationId?: ScoutId;
34
+ conversationId?: ScoutId;
35
+ requesterId?: ScoutId;
36
+ }