agent-relay-server 0.121.5 → 0.122.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.
Files changed (179) hide show
  1. package/docs/openapi.json +1 -1
  2. package/package.json +6 -6
  3. package/public/assets/{MessageBubble-CLqxCG9b.js → MessageBubble-DRdUD-kW.js} +2 -2
  4. package/public/assets/{MessageBubble-CLqxCG9b.js.map → MessageBubble-DRdUD-kW.js.map} +1 -1
  5. package/public/assets/{PlanGraphPanel-BkkToFEb.js → PlanGraphPanel-siKMPCln.js} +2 -2
  6. package/public/assets/{PlanGraphPanel-BkkToFEb.js.map → PlanGraphPanel-siKMPCln.js.map} +1 -1
  7. package/public/assets/{activity-D-ocGQGs.js → activity-D3MNcSaV.js} +2 -2
  8. package/public/assets/{activity-D-ocGQGs.js.map → activity-D3MNcSaV.js.map} +1 -1
  9. package/public/assets/{agent-profiles-CRPgYTyb.js → agent-profiles-CKzttq6G.js} +2 -2
  10. package/public/assets/{agent-profiles-CRPgYTyb.js.map → agent-profiles-CKzttq6G.js.map} +1 -1
  11. package/public/assets/{agent-type-icon-CeEoMouY.js → agent-type-icon-0ZJRP1Vy.js} +2 -2
  12. package/public/assets/{agent-type-icon-CeEoMouY.js.map → agent-type-icon-0ZJRP1Vy.js.map} +1 -1
  13. package/public/assets/{agents-Chw5E_2q.js → agents-CuVj_rfG.js} +2 -2
  14. package/public/assets/{agents-Chw5E_2q.js.map → agents-CuVj_rfG.js.map} +1 -1
  15. package/public/assets/{analytics-BmNDG0hR.js → analytics-iob6C27d.js} +2 -2
  16. package/public/assets/{analytics-BmNDG0hR.js.map → analytics-iob6C27d.js.map} +1 -1
  17. package/public/assets/{automation-D7g90kTv.js → automation-B2ixxs4q.js} +2 -2
  18. package/public/assets/{automation-D7g90kTv.js.map → automation-B2ixxs4q.js.map} +1 -1
  19. package/public/assets/{branch-state-badge-Bv7DhLBZ.js → branch-state-badge-CafBJWKo.js} +2 -2
  20. package/public/assets/{branch-state-badge-Bv7DhLBZ.js.map → branch-state-badge-CafBJWKo.js.map} +1 -1
  21. package/public/assets/{channels-CLwPeEPi.js → channels-C-WsbL2H.js} +2 -2
  22. package/public/assets/{channels-CLwPeEPi.js.map → channels-C-WsbL2H.js.map} +1 -1
  23. package/public/assets/{chat-Cgj7VKzc.js → chat-DeoVTVob.js} +2 -2
  24. package/public/assets/{chat-Cgj7VKzc.js.map → chat-DeoVTVob.js.map} +1 -1
  25. package/public/assets/{connectors-Br6fiTny.js → connectors-C2Ac03LJ.js} +2 -2
  26. package/public/assets/{connectors-Br6fiTny.js.map → connectors-C2Ac03LJ.js.map} +1 -1
  27. package/public/assets/display-CJzSoTMq.js +3 -0
  28. package/public/assets/display-CJzSoTMq.js.map +1 -0
  29. package/public/assets/{formatted-body-CmkuD23M.js → formatted-body-35XBOY5L.js} +3 -3
  30. package/public/assets/{formatted-body-CmkuD23M.js.map → formatted-body-35XBOY5L.js.map} +1 -1
  31. package/public/assets/{formatted-body-impl-DbdFmbwW.js → formatted-body-impl-RmDxI5Ux.js} +2 -2
  32. package/public/assets/{formatted-body-impl-DbdFmbwW.js.map → formatted-body-impl-RmDxI5Ux.js.map} +1 -1
  33. package/public/assets/index-D0xMQQb_.js +25 -0
  34. package/public/assets/{index-D9OogaB5.js.map → index-D0xMQQb_.js.map} +1 -1
  35. package/public/assets/{insights-qvaPqWCV.js → insights-B643SFvm.js} +2 -2
  36. package/public/assets/{insights-qvaPqWCV.js.map → insights-B643SFvm.js.map} +1 -1
  37. package/public/assets/{integrations-DYEGSqq_.js → integrations-hFIHeCF4.js} +2 -2
  38. package/public/assets/{integrations-DYEGSqq_.js.map → integrations-hFIHeCF4.js.map} +1 -1
  39. package/public/assets/{maintenance-C0HIEB-J.js → maintenance-CURvdp_Z.js} +2 -2
  40. package/public/assets/{maintenance-C0HIEB-J.js.map → maintenance-CURvdp_Z.js.map} +1 -1
  41. package/public/assets/{managed-agents-DdS7aI38.js → managed-agents-DrZtdlSn.js} +2 -2
  42. package/public/assets/{managed-agents-DdS7aI38.js.map → managed-agents-DrZtdlSn.js.map} +1 -1
  43. package/public/assets/{markdown-preview-impl-BnXMH1z1.js → markdown-preview-impl-CVDO--ek.js} +2 -2
  44. package/public/assets/{markdown-preview-impl-BnXMH1z1.js.map → markdown-preview-impl-CVDO--ek.js.map} +1 -1
  45. package/public/assets/{memory-CSwx7bz8.js → memory-Bm7dt_Qf.js} +2 -2
  46. package/public/assets/{memory-CSwx7bz8.js.map → memory-Bm7dt_Qf.js.map} +1 -1
  47. package/public/assets/{messages-Be9CmvDv.js → messages-DTq4i2KZ.js} +2 -2
  48. package/public/assets/{messages-Be9CmvDv.js.map → messages-DTq4i2KZ.js.map} +1 -1
  49. package/public/assets/{orchestrators-BgtvvHvo.js → orchestrators-Dra318Ap.js} +2 -2
  50. package/public/assets/{orchestrators-BgtvvHvo.js.map → orchestrators-Dra318Ap.js.map} +1 -1
  51. package/public/assets/{overview-BvhbPWtF.js → overview-yr1Vmk64.js} +2 -2
  52. package/public/assets/{overview-BvhbPWtF.js.map → overview-yr1Vmk64.js.map} +1 -1
  53. package/public/assets/{pairs-CpXSOMx0.js → pairs-mnlKDBGp.js} +2 -2
  54. package/public/assets/{pairs-CpXSOMx0.js.map → pairs-mnlKDBGp.js.map} +1 -1
  55. package/public/assets/projects-Dzdf-gkK.js +2 -0
  56. package/public/assets/{projects-DdPNPFJI.js.map → projects-Dzdf-gkK.js.map} +1 -1
  57. package/public/assets/prompt-settings-ByL8SNCi.js +2 -0
  58. package/public/assets/{prompt-settings-BpZse7-X.js.map → prompt-settings-ByL8SNCi.js.map} +1 -1
  59. package/public/assets/{registry-pb1gTZEg.js → registry-CXWyOtpr.js} +2 -2
  60. package/public/assets/{registry-pb1gTZEg.js.map → registry-CXWyOtpr.js.map} +1 -1
  61. package/public/assets/{security-BgcX1n9D.js → security-0SBsc_4W.js} +2 -2
  62. package/public/assets/{security-BgcX1n9D.js.map → security-0SBsc_4W.js.map} +1 -1
  63. package/public/assets/{select-DZPVpKPv.js → select-Bw5z2KJ_.js} +2 -2
  64. package/public/assets/{select-DZPVpKPv.js.map → select-Bw5z2KJ_.js.map} +1 -1
  65. package/public/assets/{settings-hd5kzdRB.js → settings-78Cyq_tA.js} +4 -4
  66. package/public/assets/{settings-hd5kzdRB.js.map → settings-78Cyq_tA.js.map} +1 -1
  67. package/public/assets/{store-DKTLubBT.js → store-BPrVuKiv.js} +4 -4
  68. package/public/assets/store-BPrVuKiv.js.map +1 -0
  69. package/public/assets/{tasks-C5d2LU5E.js → tasks-Cg2MMeri.js} +2 -2
  70. package/public/assets/{tasks-C5d2LU5E.js.map → tasks-Cg2MMeri.js.map} +1 -1
  71. package/public/assets/teams-DWv6UwFV.js +2 -0
  72. package/public/assets/{teams-B8f2pGJe.js.map → teams-DWv6UwFV.js.map} +1 -1
  73. package/public/assets/{terminal-viewer-impl-CxAscH0U.js → terminal-viewer-impl-DBLDjbIg.js} +2 -2
  74. package/public/assets/{terminal-viewer-impl-CxAscH0U.js.map → terminal-viewer-impl-DBLDjbIg.js.map} +1 -1
  75. package/public/assets/{types-uVOXgvMT.js → types-BeJUSfDj.js} +2 -2
  76. package/public/assets/types-BeJUSfDj.js.map +1 -0
  77. package/public/assets/{user-avatar-Dw6mzWhv.js → user-avatar-BsOLyVJj.js} +2 -2
  78. package/public/assets/{user-avatar-Dw6mzWhv.js.map → user-avatar-BsOLyVJj.js.map} +1 -1
  79. package/public/assets/{work-queue-9imc7aNK.js → work-queue-DmwvnF6F.js} +2 -2
  80. package/public/assets/{work-queue-9imc7aNK.js.map → work-queue-DmwvnF6F.js.map} +1 -1
  81. package/public/assets/{workspaces-CLYc3yF3.js → workspaces-dIBivJN8.js} +2 -2
  82. package/public/assets/{workspaces-CLYc3yF3.js.map → workspaces-dIBivJN8.js.map} +1 -1
  83. package/public/index.html +6 -6
  84. package/runner/plugins/claude/.claude-plugin/plugin.json +1 -1
  85. package/runner/plugins/claude/monitors/relay-monitor.provisioned.mjs +44 -938
  86. package/runner/src/adapter.ts +53 -18
  87. package/runner/src/adapters/claude-delivery.ts +127 -0
  88. package/runner/src/adapters/claude-quota-harvest.ts +92 -0
  89. package/runner/src/adapters/claude-session-probe.ts +225 -0
  90. package/runner/src/adapters/claude-status-detectors.ts +147 -0
  91. package/runner/src/adapters/claude-transcript-tail.ts +128 -0
  92. package/runner/src/adapters/claude-transcript.ts +414 -0
  93. package/runner/src/adapters/claude.ts +672 -0
  94. package/runner/src/adapters/codex-agent-message-capture.ts +139 -0
  95. package/runner/src/adapters/codex-client.ts +279 -0
  96. package/runner/src/adapters/codex.ts +1345 -0
  97. package/runner/src/attachment-cache.ts +189 -0
  98. package/runner/src/busy-reconciler.ts +102 -0
  99. package/runner/src/claim-tracker.ts +140 -0
  100. package/runner/src/claude-prompt-gates.ts +268 -0
  101. package/runner/src/config.ts +1 -4
  102. package/runner/src/context-probe-state.ts +6 -0
  103. package/runner/src/continuation-archive.ts +179 -0
  104. package/runner/src/control-server.ts +639 -0
  105. package/runner/src/index.ts +396 -0
  106. package/runner/src/launch-assembly.ts +508 -0
  107. package/runner/src/liveness.ts +50 -0
  108. package/runner/src/logger.ts +99 -0
  109. package/runner/src/mcp-outbox.ts +120 -0
  110. package/runner/src/message-body-config/config.ts +3 -0
  111. package/runner/src/message-body-config.ts +1 -0
  112. package/runner/src/native-self-resume.ts +202 -0
  113. package/runner/src/outbox.ts +342 -0
  114. package/runner/src/process-meta.ts +9 -0
  115. package/runner/src/profile-home.ts +260 -0
  116. package/runner/src/profile-projection.ts +305 -0
  117. package/runner/src/providers.ts +20 -0
  118. package/runner/src/provisioning.ts +314 -0
  119. package/runner/src/quota.ts +40 -0
  120. package/runner/src/rate-limit.ts +189 -0
  121. package/runner/src/relay-injection-events.ts +102 -0
  122. package/runner/src/relay-instructions.ts +60 -0
  123. package/runner/src/relay-mcp-proxy.ts +383 -0
  124. package/runner/src/relay-mcp.ts +156 -0
  125. package/runner/src/reply-obligation-cache.ts +136 -0
  126. package/runner/src/response-capture-report.ts +63 -0
  127. package/runner/src/runner-core.ts +2409 -0
  128. package/runner/src/runner-helpers.ts +435 -0
  129. package/runner/src/runner-insights.ts +105 -0
  130. package/runner/src/runner.ts +14 -0
  131. package/runner/src/session-destroy.ts +22 -0
  132. package/runner/src/session-insights.ts +118 -0
  133. package/runner/src/session-scratch.ts +271 -0
  134. package/runner/src/template-resolver.ts +29 -0
  135. package/runner/src/version.ts +43 -0
  136. package/src/agent-card-projection.ts +5 -1
  137. package/src/agent-command-activity.ts +39 -0
  138. package/src/automations/reconcile.ts +2 -2
  139. package/src/cli/workspace.ts +3 -1
  140. package/src/config.ts +10 -1
  141. package/src/db/agents.ts +118 -37
  142. package/src/db/message-reads.ts +50 -0
  143. package/src/db/messages.ts +48 -9
  144. package/src/db/migrations.ts +54 -0
  145. package/src/db/provider-quota-burn.ts +96 -67
  146. package/src/db/provider-quotas.ts +29 -7
  147. package/src/db/scheduled-timers.ts +21 -0
  148. package/src/db/schema.ts +1 -0
  149. package/src/db/tasks.ts +33 -3
  150. package/src/db/work-evidence.ts +10 -7
  151. package/src/event-loop-lag.ts +15 -0
  152. package/src/gate-resolver.ts +19 -1
  153. package/src/maintenance/jobs.ts +23 -6
  154. package/src/managed-policy.ts +5 -12
  155. package/src/mcp-plan-tools.ts +13 -1
  156. package/src/project-instructions.ts +36 -2
  157. package/src/quota-advisory.ts +6 -4
  158. package/src/quota-band-transition.ts +23 -14
  159. package/src/routes/agent-sessions.ts +39 -7
  160. package/src/routes/agents.ts +3 -2
  161. package/src/routes/tasks.ts +16 -4
  162. package/src/routes/workspaces.ts +35 -10
  163. package/src/services/plan-graph.ts +27 -9
  164. package/src/services/register-agent.ts +12 -12
  165. package/src/services/send-message.ts +43 -15
  166. package/src/services/spawn-agent.ts +3 -0
  167. package/src/spawn-command.ts +8 -0
  168. package/src/spawn-targets.ts +19 -34
  169. package/src/sse.ts +25 -3
  170. package/src/workspace-merge.ts +25 -5
  171. package/src/workspace-orphans.ts +13 -6
  172. package/public/assets/display-exQDWum3.js +0 -3
  173. package/public/assets/display-exQDWum3.js.map +0 -1
  174. package/public/assets/index-D9OogaB5.js +0 -25
  175. package/public/assets/projects-DdPNPFJI.js +0 -2
  176. package/public/assets/prompt-settings-BpZse7-X.js +0 -2
  177. package/public/assets/store-DKTLubBT.js.map +0 -1
  178. package/public/assets/teams-B8f2pGJe.js +0 -2
  179. package/public/assets/types-uVOXgvMT.js.map +0 -1
@@ -6,6 +6,7 @@ import { DEFAULT_RELAY_URL, RELAY_TOKEN_HEADER, errMessage, stringValue } from "
6
6
  import type { SettingEntry, WorkspaceMetadata } from "agent-relay-sdk";
7
7
  import { sanitizeFsName } from "agent-relay-sdk/fs-name";
8
8
  import { getManifest } from "agent-relay-providers";
9
+ export { messageBodyMaxCharsFromEnv } from "./message-body-config";
9
10
 
10
11
  interface ProviderConfig {
11
12
  command: string;
@@ -241,10 +242,6 @@ export function providerHomeRootFromEnv(): string {
241
242
  return process.env.AGENT_RELAY_PROVIDER_HOME_ROOT || join(homedir(), ".agent-relay", "provider-homes");
242
243
  }
243
244
 
244
- export function messageBodyMaxCharsFromEnv(): string | undefined {
245
- return process.env.AGENT_RELAY_MESSAGE_BODY_MAX_CHARS;
246
- }
247
-
248
245
  export function loadProviderConfig(provider: string, home = agentRelayHome()): LoadedProviderConfig {
249
246
  const path = join(providersDir(home), `${provider}.json`);
250
247
  const raw = readJson(path);
@@ -0,0 +1,6 @@
1
+ import { readContextProbeState } from "agent-relay-sdk/context-probe";
2
+ import { contextStateDirFromEnv } from "./config";
3
+
4
+ export function readRunnerContextProbeState(agentId: string) {
5
+ return readContextProbeState(agentId, contextStateDirFromEnv());
6
+ }
@@ -0,0 +1,179 @@
1
+ import type { RelayHttpClient } from "agent-relay-sdk";
2
+ import type { OutboxRecord } from "./outbox";
3
+
4
+ const CONTINUATION_ARCHIVE_MAX_POST_BODY_BYTES = 64 * 1024;
5
+ const CONTINUATION_ARCHIVE_CHUNK_TARGET_BYTES = 56 * 1024;
6
+ const CONTINUATION_ARCHIVE_MAX_GENERATION_BYTES = 8 * 1024 * 1024;
7
+ const encoder = new TextEncoder();
8
+ const fatalUtf8Decoder = new TextDecoder("utf-8", { fatal: true });
9
+
10
+ interface ContinuationArchiveOutboxPayload {
11
+ agentId: string;
12
+ segment: string;
13
+ generation?: number;
14
+ deliveredChunks?: number;
15
+ totalChunks?: number;
16
+ }
17
+
18
+ interface ContinuationArchiveResponse {
19
+ archive?: { generation?: unknown };
20
+ }
21
+
22
+ export function boundContinuationArchiveSegment(segment: string): { segment: string; keptBytes: number; droppedBytes: number } {
23
+ const encoded = encoder.encode(segment);
24
+ const bytes = encoded.byteLength;
25
+ if (bytes <= CONTINUATION_ARCHIVE_MAX_GENERATION_BYTES) {
26
+ return { segment, keptBytes: bytes, droppedBytes: 0 };
27
+ }
28
+ const bounded = decodeUtf8Prefix(encoded, CONTINUATION_ARCHIVE_MAX_GENERATION_BYTES);
29
+ const keptBytes = utf8Bytes(bounded);
30
+ return { segment: bounded.trimEnd(), keptBytes, droppedBytes: bytes - keptBytes };
31
+ }
32
+
33
+ export async function deliverContinuationArchiveRecord(input: {
34
+ record: OutboxRecord;
35
+ http: Pick<RelayHttpClient, "recordContinuationArchive">;
36
+ updatePayload: (seq: number, payload: unknown) => void;
37
+ sessionLog: (message: string) => void;
38
+ }): Promise<void> {
39
+ const payload = input.record.payload as ContinuationArchiveOutboxPayload;
40
+ let segment = payload.segment;
41
+ if (!payload.agentId || typeof segment !== "string") throw new Error("invalid continuation archive outbox payload");
42
+
43
+ const bounded = boundContinuationArchiveSegment(segment);
44
+ if (bounded.droppedBytes > 0) {
45
+ segment = bounded.segment;
46
+ input.sessionLog(`continuation archive truncated at ${bounded.keptBytes} bytes; dropped ${bounded.droppedBytes} bytes before delivery`);
47
+ input.updatePayload(input.record.seq, { ...payload, segment, deliveredChunks: 0, totalChunks: undefined, generation: undefined });
48
+ }
49
+
50
+ const chunks = splitContinuationArchiveSegment({
51
+ agentId: payload.agentId,
52
+ segment,
53
+ occurredAt: input.record.occurredAt,
54
+ });
55
+ const knownGeneration = Number.isSafeInteger(payload.generation) ? payload.generation : undefined;
56
+ const deliveredChunks = knownGeneration === undefined ? 0 : Math.max(0, Math.min(payload.deliveredChunks ?? 0, chunks.length));
57
+ let generation = knownGeneration;
58
+
59
+ for (let index = deliveredChunks; index < chunks.length; index += 1) {
60
+ const request = {
61
+ agentId: payload.agentId,
62
+ segment: chunks[index]!,
63
+ occurredAt: input.record.occurredAt,
64
+ ...(generation !== undefined ? { generation } : {}),
65
+ };
66
+ assertContinuationArchivePostFits(request);
67
+ const response = await input.http.recordContinuationArchive(request) as ContinuationArchiveResponse;
68
+ const returnedGeneration = archiveGeneration(response);
69
+ if (generation === undefined) {
70
+ if (returnedGeneration === undefined) throw new Error("continuation archive response missing generation");
71
+ generation = returnedGeneration;
72
+ } else if (returnedGeneration !== undefined && returnedGeneration !== generation) {
73
+ throw new Error(`continuation archive generation mismatch: expected ${generation}, got ${returnedGeneration}`);
74
+ }
75
+ input.updatePayload(input.record.seq, {
76
+ ...payload,
77
+ segment,
78
+ generation,
79
+ deliveredChunks: index + 1,
80
+ totalChunks: chunks.length,
81
+ } satisfies ContinuationArchiveOutboxPayload);
82
+ }
83
+ }
84
+
85
+ function splitContinuationArchiveSegment(input: { agentId: string; segment: string; occurredAt: number }): string[] {
86
+ const chunks: string[] = [];
87
+ let current = "";
88
+ for (const line of transcriptLines(input.segment)) {
89
+ if (!line) continue;
90
+ if (fitsContinuationArchiveChunk(input.agentId, line, input.occurredAt)) {
91
+ const next = current ? current + line : line;
92
+ if (utf8Bytes(next) <= CONTINUATION_ARCHIVE_CHUNK_TARGET_BYTES && fitsContinuationArchiveChunk(input.agentId, next, input.occurredAt)) {
93
+ current = next;
94
+ continue;
95
+ }
96
+ if (current) chunks.push(current.trimEnd());
97
+ current = line;
98
+ continue;
99
+ }
100
+ if (current) {
101
+ chunks.push(current.trimEnd());
102
+ current = "";
103
+ }
104
+ chunks.push(...splitLongContinuationArchiveLine(input.agentId, line, input.occurredAt));
105
+ }
106
+ if (current) chunks.push(current.trimEnd());
107
+ return chunks.filter((chunk) => chunk.length > 0);
108
+ }
109
+
110
+ function transcriptLines(segment: string): string[] {
111
+ const lines = segment.match(/[^\n]*(?:\n|$)/g) ?? [segment];
112
+ return lines.filter((line) => line.length > 0);
113
+ }
114
+
115
+ function splitLongContinuationArchiveLine(agentId: string, line: string, occurredAt: number): string[] {
116
+ const chars = Array.from(line);
117
+ const chunks: string[] = [];
118
+ let offset = 0;
119
+ while (offset < chars.length) {
120
+ let low = 1;
121
+ let high = chars.length - offset;
122
+ let best = 0;
123
+ while (low <= high) {
124
+ const mid = Math.floor((low + high) / 2);
125
+ const candidate = chars.slice(offset, offset + mid).join("");
126
+ if (utf8Bytes(candidate) <= CONTINUATION_ARCHIVE_CHUNK_TARGET_BYTES && fitsContinuationArchiveChunk(agentId, candidate, occurredAt)) {
127
+ best = mid;
128
+ low = mid + 1;
129
+ } else {
130
+ high = mid - 1;
131
+ }
132
+ }
133
+ if (best === 0) throw new Error("continuation archive chunk budget cannot fit one character");
134
+ chunks.push(chars.slice(offset, offset + best).join(""));
135
+ offset += best;
136
+ }
137
+ return chunks;
138
+ }
139
+
140
+ function fitsContinuationArchiveChunk(agentId: string, segment: string, occurredAt: number): boolean {
141
+ return continuationArchivePostBytes({
142
+ agentId,
143
+ segment,
144
+ occurredAt,
145
+ generation: Number.MAX_SAFE_INTEGER,
146
+ }) < CONTINUATION_ARCHIVE_MAX_POST_BODY_BYTES;
147
+ }
148
+
149
+ function assertContinuationArchivePostFits(input: { agentId: string; segment: string; occurredAt: number; generation?: number }): void {
150
+ const bytes = continuationArchivePostBytes(input);
151
+ if (bytes >= CONTINUATION_ARCHIVE_MAX_POST_BODY_BYTES) {
152
+ throw new Error(`continuation archive chunk JSON body is ${bytes} bytes; max is ${CONTINUATION_ARCHIVE_MAX_POST_BODY_BYTES - 1}`);
153
+ }
154
+ }
155
+
156
+ function continuationArchivePostBytes(input: { agentId: string; segment: string; occurredAt: number; generation?: number }): number {
157
+ return utf8Bytes(JSON.stringify(input));
158
+ }
159
+
160
+ function archiveGeneration(response: ContinuationArchiveResponse): number | undefined {
161
+ const generation = response.archive?.generation;
162
+ return typeof generation === "number" && Number.isSafeInteger(generation) && generation >= 0 ? generation : undefined;
163
+ }
164
+
165
+ function decodeUtf8Prefix(bytes: Uint8Array, maxBytes: number): string {
166
+ let end = Math.min(maxBytes, bytes.byteLength);
167
+ while (end > 0) {
168
+ try {
169
+ return fatalUtf8Decoder.decode(bytes.subarray(0, end));
170
+ } catch {
171
+ end -= 1;
172
+ }
173
+ }
174
+ return "";
175
+ }
176
+
177
+ function utf8Bytes(value: string): number {
178
+ return encoder.encode(value).byteLength;
179
+ }