@nylorun/runtime 0.23.0-beta → 0.25.0-beta

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 (301) hide show
  1. package/CHANGELOG.md +252 -0
  2. package/README.md +87 -28
  3. package/dist/adapters/execution/restate.js +1 -1
  4. package/dist/adapters/replication/pgoutput.d.ts +2 -0
  5. package/dist/adapters/replication/pgoutput.js +6 -3
  6. package/dist/adapters/sandbox/local.d.ts +9 -1
  7. package/dist/adapters/sandbox/local.js +16 -4
  8. package/dist/adapters/sandbox/virtual.js +4 -1
  9. package/dist/api/a2a/card.d.ts +11 -1
  10. package/dist/api/a2a/card.js +26 -2
  11. package/dist/api/a2a/endpoint.js +9 -3
  12. package/dist/api/a2a/protocol.d.ts +25 -2
  13. package/dist/api/a2a/protocol.js +20 -3
  14. package/dist/api/a2a/routes.d.ts +6 -1
  15. package/dist/api/a2a/routes.js +67 -9
  16. package/dist/api/a2a/tasks.js +2 -1
  17. package/dist/api/ag-ui/endpoint.js +8 -3
  18. package/dist/api/ag-ui/history.d.ts +6 -1
  19. package/dist/api/ag-ui/history.js +39 -3
  20. package/dist/api/ag-ui/routes.d.ts +4 -1
  21. package/dist/api/ag-ui/routes.js +63 -20
  22. package/dist/api/ag-ui/translate.js +3 -2
  23. package/dist/api/components.d.ts +5327 -1091
  24. package/dist/api/components.js +40 -16
  25. package/dist/api/gate/keys.d.ts +2 -1
  26. package/dist/api/gate/keys.js +14 -1
  27. package/dist/api/gate/routes.d.ts +6 -0
  28. package/dist/api/gate/routes.js +52 -3
  29. package/dist/api/http/app.js +17 -6
  30. package/dist/api/http/body.d.ts +3 -3
  31. package/dist/api/http/body.js +7 -7
  32. package/dist/api/http/define.d.ts +6 -0
  33. package/dist/api/http/define.js +13 -1
  34. package/dist/api/http/respond.js +1 -1
  35. package/dist/api/http/routes/artifacts.js +35 -8
  36. package/dist/api/http/routes/coverage.d.ts +9 -0
  37. package/dist/api/http/routes/coverage.js +34 -0
  38. package/dist/api/http/routes/environment-manifests.d.ts +9 -0
  39. package/dist/api/http/routes/environment-manifests.js +118 -0
  40. package/dist/api/http/routes/environments.d.ts +11 -0
  41. package/dist/api/http/routes/environments.js +332 -0
  42. package/dist/api/http/routes/mcp.d.ts +1 -1
  43. package/dist/api/http/routes/mcp.js +2 -2
  44. package/dist/api/http/routes/me.js +1 -1
  45. package/dist/api/http/routes/reads.d.ts +94 -9
  46. package/dist/api/http/routes/reads.js +54 -5
  47. package/dist/api/http/routes/sessions.js +24 -9
  48. package/dist/api/http/routes/tenant.js +65 -15
  49. package/dist/api/inbound-files.d.ts +65 -0
  50. package/dist/api/inbound-files.js +115 -0
  51. package/dist/api/openapi.js +48 -28
  52. package/dist/artifacts/disk.d.ts +59 -0
  53. package/dist/artifacts/disk.js +569 -0
  54. package/dist/artifacts/export.d.ts +1 -1
  55. package/dist/artifacts/export.js +2 -3
  56. package/dist/artifacts/folders.d.ts +6 -3
  57. package/dist/artifacts/folders.js +17 -12
  58. package/dist/artifacts/media-types.d.ts +15 -0
  59. package/dist/artifacts/media-types.js +56 -4
  60. package/dist/artifacts/parts.d.ts +12 -3
  61. package/dist/artifacts/parts.js +15 -4
  62. package/dist/artifacts/service.d.ts +2 -1
  63. package/dist/artifacts/service.js +6 -1
  64. package/dist/artifacts/workspace.d.ts +5 -5
  65. package/dist/artifacts/workspace.js +7 -19
  66. package/dist/core/flow-host.d.ts +3 -4
  67. package/dist/core/flow-host.js +5 -2
  68. package/dist/core/provider.d.ts +3 -2
  69. package/dist/core/provider.js +5 -37
  70. package/dist/core/sandbox-routes.d.ts +2 -21
  71. package/dist/core/sandbox-routes.js +11 -44
  72. package/dist/core/turn-manifest.d.ts +3 -2
  73. package/dist/core/turn-manifest.js +29 -5
  74. package/dist/execution/types.d.ts +1 -1
  75. package/dist/gates/contract.d.ts +3 -24
  76. package/dist/gates/contract.js +1 -36
  77. package/dist/gates/egress-credentials.d.ts +9 -0
  78. package/dist/gates/egress-credentials.js +11 -4
  79. package/dist/gates/egress.d.ts +22 -1
  80. package/dist/gates/egress.js +116 -10
  81. package/dist/gates/fixture-model.d.ts +28 -0
  82. package/dist/gates/fixture-model.js +92 -0
  83. package/dist/gates/handler.js +4 -4
  84. package/dist/gates/http-tool.d.ts +9 -6
  85. package/dist/gates/http-tool.js +11 -17
  86. package/dist/gates/in-process.d.ts +5 -0
  87. package/dist/gates/in-process.js +12 -1
  88. package/dist/gates/journal.d.ts +30 -0
  89. package/dist/gates/journal.js +51 -0
  90. package/dist/gates/mcp-handler.d.ts +4 -0
  91. package/dist/gates/mcp-handler.js +7 -4
  92. package/dist/gates/meter.d.ts +10 -2
  93. package/dist/gates/meter.js +20 -5
  94. package/dist/gates/policy.d.ts +49 -0
  95. package/dist/gates/policy.js +132 -0
  96. package/dist/gates/tenant-vaults.d.ts +7 -7
  97. package/dist/gates/tenant-vaults.js +5 -5
  98. package/dist/gates/tool-calls.d.ts +10 -5
  99. package/dist/gates/tool-calls.js +28 -10
  100. package/dist/gates/tool-client.d.ts +8 -0
  101. package/dist/gates/tool-client.js +27 -11
  102. package/dist/gates/tool-contract.d.ts +11 -69
  103. package/dist/gates/tool-contract.js +1 -85
  104. package/dist/gates/tool-gate.d.ts +1 -1
  105. package/dist/harness/calls.d.ts +14 -7
  106. package/dist/harness/calls.js +30 -24
  107. package/dist/harness/executors.js +12 -9
  108. package/dist/harness/main.js +24 -5
  109. package/dist/harness/pod.d.ts +39 -0
  110. package/dist/harness/pod.js +46 -0
  111. package/dist/harness/service.d.ts +0 -1
  112. package/dist/harness/service.js +17 -9
  113. package/dist/harness/setup.d.ts +29 -0
  114. package/dist/harness/setup.js +174 -0
  115. package/dist/harness/ws-client.js +3 -2
  116. package/dist/harness/ws-port.d.ts +1 -5
  117. package/dist/harness/ws-port.js +1 -5
  118. package/dist/harness-api/in-process.js +3 -3
  119. package/dist/harness-api/record.d.ts +15 -1
  120. package/dist/harness-api/record.js +180 -50
  121. package/dist/harness-api/redact.d.ts +3 -0
  122. package/dist/harness-api/redact.js +45 -0
  123. package/dist/harness-api/server.d.ts +35 -4
  124. package/dist/harness-api/server.js +130 -17
  125. package/dist/harness-api/start.d.ts +10 -3
  126. package/dist/harness-api/start.js +40 -10
  127. package/dist/harness-api/tool-journal.d.ts +105 -0
  128. package/dist/harness-api/tool-journal.js +132 -0
  129. package/dist/harness-api/tool-status.d.ts +13 -0
  130. package/dist/harness-api/tool-status.js +26 -0
  131. package/dist/harness-api/workspace.d.ts +12 -7
  132. package/dist/harness-api/workspace.js +47 -25
  133. package/dist/harness-api/ws-server.d.ts +11 -3
  134. package/dist/harness-api/ws-server.js +94 -15
  135. package/dist/host/gates.d.ts +2 -1
  136. package/dist/host/gates.js +10 -2
  137. package/dist/host/main.js +54 -5
  138. package/dist/host/operate.js +67 -5
  139. package/dist/host/stack-config.d.ts +64 -0
  140. package/dist/host/stack-config.js +62 -2
  141. package/dist/keys/client.js +4 -1
  142. package/dist/keys/keys.d.ts +13 -6
  143. package/dist/keys/keys.js +9 -8
  144. package/dist/management-openapi.json +1264 -2171
  145. package/dist/mcp/connect.d.ts +26 -22
  146. package/dist/mcp/connect.js +30 -34
  147. package/dist/mcp/pool.d.ts +3 -6
  148. package/dist/mcp/pool.js +14 -28
  149. package/dist/mcp/preview.d.ts +3 -3
  150. package/dist/mcp/preview.js +10 -21
  151. package/dist/mcp/snapshot.d.ts +16 -24
  152. package/dist/mcp/snapshot.js +33 -45
  153. package/dist/model/capabilities.d.ts +26 -0
  154. package/dist/model/capabilities.js +44 -0
  155. package/dist/model/catalog.d.ts +34 -3
  156. package/dist/model/catalog.js +38 -2
  157. package/dist/model/models.d.ts +2 -0
  158. package/dist/model/models.js +1 -1
  159. package/dist/model/native-blocks.d.ts +35 -0
  160. package/dist/model/native-blocks.js +170 -0
  161. package/dist/model/pi-model.js +114 -94
  162. package/dist/openapi.json +12822 -3943
  163. package/dist/reads/types.d.ts +16 -3
  164. package/dist/record/append.d.ts +3 -1
  165. package/dist/record/append.js +1 -0
  166. package/dist/record/envelope.d.ts +5 -1
  167. package/dist/record/envelope.js +7 -3
  168. package/dist/record/environment.d.ts +25 -0
  169. package/dist/record/environment.js +44 -0
  170. package/dist/record/index.d.ts +1 -1
  171. package/dist/record/index.js +1 -1
  172. package/dist/sandbox/disk-fs.d.ts +95 -0
  173. package/dist/sandbox/disk-fs.js +206 -0
  174. package/dist/sandbox/join.d.ts +17 -18
  175. package/dist/sandbox/join.js +46 -15
  176. package/dist/sandbox/manager.d.ts +47 -21
  177. package/dist/sandbox/manager.js +162 -107
  178. package/dist/sandbox/placement.d.ts +14 -13
  179. package/dist/sandbox/placement.js +31 -14
  180. package/dist/sandbox/pods/client.d.ts +9 -2
  181. package/dist/sandbox/pods/lifecycle.d.ts +36 -27
  182. package/dist/sandbox/pods/lifecycle.js +29 -26
  183. package/dist/sandbox/pods/reconcile.js +18 -12
  184. package/dist/sandbox/pods/spec.d.ts +15 -13
  185. package/dist/sandbox/pods/spec.js +17 -20
  186. package/dist/sandbox/records.d.ts +2 -2
  187. package/dist/sandbox/records.js +3 -3
  188. package/dist/sandbox/resolve.d.ts +37 -27
  189. package/dist/sandbox/resolve.js +73 -41
  190. package/dist/sandbox/runtime-tools.d.ts +9 -0
  191. package/dist/sandbox/runtime-tools.js +16 -0
  192. package/dist/sandbox/session-sandbox.d.ts +4 -6
  193. package/dist/sandbox/session-sandbox.js +47 -94
  194. package/dist/sandbox/setup.d.ts +64 -0
  195. package/dist/sandbox/setup.js +160 -0
  196. package/dist/sandbox/share.d.ts +21 -26
  197. package/dist/sandbox/share.js +36 -63
  198. package/dist/sandbox/skills.d.ts +8 -6
  199. package/dist/sandbox/skills.js +24 -23
  200. package/dist/sandbox/tenant-config.d.ts +12 -14
  201. package/dist/sandbox/tenant-config.js +12 -17
  202. package/dist/sandbox/types.d.ts +6 -0
  203. package/dist/store/postgres/drizzle/0020_environments.sql +63 -0
  204. package/dist/store/postgres/drizzle/0021_disk_versions.sql +7 -0
  205. package/dist/store/postgres/drizzle/0022_model_usage_timing.sql +5 -0
  206. package/dist/store/postgres/drizzle/0023_artifact_pages.sql +1 -0
  207. package/dist/store/postgres/drizzle/0024_flat_manifest.sql +7 -0
  208. package/dist/store/postgres/drizzle/0025_environment_manifests.sql +14 -0
  209. package/dist/store/postgres/drizzle/0026_environment_forks.sql +1 -0
  210. package/dist/store/postgres/drizzle/0027_environment_image_digest.sql +1 -0
  211. package/dist/store/postgres/drizzle/meta/_journal.json +56 -0
  212. package/dist/store/postgres/reads.js +123 -17
  213. package/dist/store/postgres/record-writer.d.ts +4 -4
  214. package/dist/store/postgres/record-writer.js +9 -9
  215. package/dist/store/postgres/record.d.ts +7 -0
  216. package/dist/store/postgres/record.js +23 -2
  217. package/dist/store/postgres/schema.d.ts +1126 -736
  218. package/dist/store/postgres/schema.js +136 -73
  219. package/dist/store/postgres/store.js +195 -67
  220. package/dist/store/types.d.ts +165 -50
  221. package/dist/tenant/advance.d.ts +7 -6
  222. package/dist/tenant/advance.js +118 -42
  223. package/dist/tenant/artifact-tool.d.ts +1 -1
  224. package/dist/tenant/artifact-tool.js +46 -26
  225. package/dist/tenant/commands.d.ts +15 -2
  226. package/dist/tenant/commands.js +115 -14
  227. package/dist/tenant/context.d.ts +56 -24
  228. package/dist/tenant/context.js +4 -15
  229. package/dist/tenant/effects.d.ts +1 -1
  230. package/dist/tenant/effects.js +44 -29
  231. package/dist/tenant/environment-manifests.d.ts +57 -0
  232. package/dist/tenant/environment-manifests.js +200 -0
  233. package/dist/tenant/environments.d.ts +174 -0
  234. package/dist/tenant/environments.js +1044 -0
  235. package/dist/tenant/harness-tokens.d.ts +21 -0
  236. package/dist/tenant/harness-tokens.js +61 -0
  237. package/dist/tenant/host-token.d.ts +1 -1
  238. package/dist/tenant/host-token.js +2 -4
  239. package/dist/tenant/identity-file.d.ts +4 -4
  240. package/dist/tenant/identity-file.js +17 -8
  241. package/dist/tenant/issuers.js +3 -3
  242. package/dist/tenant/model-setting.d.ts +14 -0
  243. package/dist/tenant/model-setting.js +51 -0
  244. package/dist/tenant/principals.js +1 -1
  245. package/dist/tenant/reset.js +3 -3
  246. package/dist/tenant/runtime.d.ts +6 -1
  247. package/dist/tenant/runtime.js +7 -1
  248. package/dist/tenant/session.d.ts +3 -3
  249. package/dist/tenant/session.js +0 -14
  250. package/dist/tenant/sessions.d.ts +18 -14
  251. package/dist/tenant/sessions.js +99 -143
  252. package/dist/tenant/signing-keys.d.ts +5 -1
  253. package/dist/tenant/skill-tool.d.ts +3 -3
  254. package/dist/tenant/skill-tool.js +6 -11
  255. package/dist/tenant/status.js +3 -3
  256. package/dist/tenant/sweep.js +13 -7
  257. package/dist/tenant/tool-results.js +1 -1
  258. package/dist/tenant/tool-search.d.ts +7 -11
  259. package/dist/tenant/tool-search.js +8 -5
  260. package/dist/tenant/transcript.d.ts +245 -36
  261. package/dist/tenant/transcript.js +64 -12
  262. package/dist/tenant/turn-timing.d.ts +43 -0
  263. package/dist/tenant/turn-timing.js +39 -0
  264. package/dist/tenant/types.d.ts +2 -0
  265. package/dist/traces/ids.d.ts +41 -0
  266. package/dist/traces/ids.js +81 -0
  267. package/dist/traces/key.d.ts +6 -0
  268. package/dist/traces/key.js +37 -0
  269. package/dist/traces/map.d.ts +113 -0
  270. package/dist/traces/map.js +289 -0
  271. package/dist/traces/options.d.ts +7 -0
  272. package/dist/traces/options.js +1 -0
  273. package/dist/traces/otlp.d.ts +42 -0
  274. package/dist/traces/otlp.js +84 -0
  275. package/dist/traces/projector.d.ts +58 -0
  276. package/dist/traces/projector.js +200 -0
  277. package/dist/traces/read.d.ts +23 -0
  278. package/dist/traces/read.js +16 -0
  279. package/dist/vault/coverage.d.ts +26 -0
  280. package/dist/vault/coverage.js +62 -0
  281. package/dist/vault/error.d.ts +11 -1
  282. package/dist/vault/error.js +5 -1
  283. package/dist/vault/host-model.d.ts +4 -1
  284. package/dist/vault/host-model.js +10 -2
  285. package/dist/vault/service.d.ts +92 -48
  286. package/dist/vault/service.js +462 -376
  287. package/dist/vault/sources.d.ts +5 -16
  288. package/dist/vault/sources.js +6 -8
  289. package/dist/version.d.ts +1 -1
  290. package/dist/version.js +2 -2
  291. package/package.json +13 -13
  292. package/dist/api/http/routes/sandboxes.d.ts +0 -9
  293. package/dist/api/http/routes/sandboxes.js +0 -153
  294. package/dist/api/http/routes/vaults.d.ts +0 -10
  295. package/dist/api/http/routes/vaults.js +0 -139
  296. package/dist/record/sandbox.d.ts +0 -25
  297. package/dist/record/sandbox.js +0 -43
  298. package/dist/sandbox/capability.d.ts +0 -3
  299. package/dist/sandbox/capability.js +0 -10
  300. package/dist/tenant/sandboxes.d.ts +0 -123
  301. package/dist/tenant/sandboxes.js +0 -566
@@ -4,6 +4,10 @@
4
4
  * Payload schemas: `@nylorun/core/contracts` (`parseTranscriptEvent`).
5
5
  */
6
6
  import type { HostEffect } from "@nylorun/harness/run";
7
+ import type { PluginLabel } from "@nylorun/core/define";
8
+ import type { TOOL_CALL_KINDS, TOOL_CALL_STATUSES } from "@nylorun/core/contracts";
9
+ export type ToolCallStatus = (typeof TOOL_CALL_STATUSES)[number];
10
+ export type ToolCallKind = (typeof TOOL_CALL_KINDS)[number];
7
11
  /** The model's tool call id and the harness invocation, for tool effects. */
8
12
  export declare function toolIds(context: unknown): {
9
13
  callId: string;
@@ -11,7 +15,9 @@ export declare function toolIds(context: unknown): {
11
15
  } | Record<string, never>;
12
16
  /**
13
17
  * `message.assistant` for a completed model effect: the step's text and tool calls. The
14
- * provider returns a `ModelCandidate` or a bare string; anything else writes no event.
18
+ * provider returns a `ModelCandidate` or a bare string. A step that said nothing (no text, no
19
+ * tool calls; a structured answer) is still one event, with `text: ""` (R7.1): every model call
20
+ * has its outcome row. Readers that build a conversation skip it (`isEmptyAssistantMessage`).
15
21
  */
16
22
  export declare function assistantMessage(request: HostEffect, value: unknown): {
17
23
  agent: import("@nylorun/core/define").AgentRef;
@@ -46,7 +52,8 @@ export declare function assistantMessage(request: HostEffect, value: unknown): {
46
52
  } | undefined;
47
53
  /**
48
54
  * `context.compacted` for a model effect that summarized history (Model Calls §8): the
49
- * engine replaced the older transcript with that summary.
55
+ * engine replaced the older transcript with that summary. A partial summary (one call of
56
+ * several) is marked `partial: true` (R7.1): only the last call's event replaced the history.
50
57
  */
51
58
  export declare function contextCompacted(request: HostEffect, value: unknown): {
52
59
  agent: import("@nylorun/core/define").AgentRef;
@@ -54,12 +61,14 @@ export declare function contextCompacted(request: HostEffect, value: unknown): {
54
61
  trigger: "overflow" | "threshold";
55
62
  tokensBefore: number;
56
63
  tokensAfter: number;
64
+ partial?: true | undefined;
57
65
  } | {
58
66
  agent?: undefined;
59
67
  invocationId?: string | undefined;
60
68
  trigger: "overflow" | "threshold";
61
69
  tokensBefore: number;
62
70
  tokensAfter: number;
71
+ partial?: true | undefined;
63
72
  } | undefined;
64
73
  /** `model.failed` for a model effect that completed with a failure outcome (Model Calls §6.4). */
65
74
  export declare function modelFailed(request: HostEffect, value: unknown): {
@@ -75,87 +84,219 @@ export declare function modelFailed(request: HostEffect, value: unknown): {
75
84
  message: string;
76
85
  retryable: boolean;
77
86
  } | undefined;
78
- /** `tool.completed` for a tool the Runtime ran: its output, or the tool error it reported. */
79
- export declare function toolCompleted(request: HostEffect, value: unknown): {
87
+ /** A gate's own start and end of a call (R7.1). */
88
+ export interface GateTimes {
89
+ readonly startedAt: string;
90
+ readonly endedAt: string;
91
+ }
92
+ /** What the usage ledger holds for a model call (R7.1): its `model_usage` row's columns. */
93
+ export interface MeteredCall {
94
+ readonly startedAt: string | null;
95
+ readonly endedAt: string | null;
96
+ readonly firstTokenMs: number | null;
97
+ readonly inputTokens: number;
98
+ readonly outputTokens: number;
99
+ readonly totalTokens: number;
100
+ readonly cachedTokens: number;
101
+ readonly costUsd: number;
102
+ }
103
+ /** From `startedAt` to `endedAt` in whole milliseconds; undefined unless both are times. */
104
+ export declare function durationBetween(startedAt: string | undefined, endedAt: string | undefined): number | undefined;
105
+ /**
106
+ * The timing a model call's outcome event carries (R7.1): its effect id, the journal's window
107
+ * (`startedAt` on the row to `settledAt`), and, when the gate metered the call (`metered`), the
108
+ * gate's own start and end, the first token's time and the metered usage.
109
+ */
110
+ export declare function modelOutcomeFacts(effectId: string, window: {
111
+ startedAt?: string;
112
+ settledAt?: string;
113
+ }, metered: MeteredCall | undefined): {
114
+ effectId: string;
115
+ durationMs?: number | undefined;
116
+ gate?: {
117
+ startedAt: string;
118
+ endedAt: string;
119
+ } | undefined;
120
+ firstTokenMs?: number | undefined;
121
+ meteredUsage?: {
122
+ inputTokens: number;
123
+ outputTokens: number;
124
+ totalTokens: number;
125
+ cachedTokens?: number | undefined;
126
+ costUsd?: number | undefined;
127
+ } | undefined;
128
+ };
129
+ /** What the Tenant's tool policy did with a call, when it did more than allow it (R7.1). */
130
+ export interface ToolPolicyFact {
131
+ readonly decision: "ask" | "deny";
132
+ readonly reason: string;
133
+ readonly approvedBy?: string;
134
+ }
135
+ /** What the journal knows of a tool call when it ends (R5.1, R7.1), for its `tool.completed`. */
136
+ export interface ToolCallFacts {
137
+ readonly status: ToolCallStatus;
138
+ readonly kind?: ToolCallKind;
139
+ readonly server?: string;
140
+ readonly skill?: string;
141
+ readonly plugin?: PluginLabel;
142
+ readonly attempts?: number;
143
+ readonly durationMs?: number;
144
+ readonly effectId?: string;
145
+ readonly gate?: GateTimes;
146
+ readonly policy?: ToolPolicyFact;
147
+ }
148
+ /**
149
+ * `tool.completed` for a tool call that ended: its output, or the tool error it reported, and
150
+ * how it ended (R5.1).
151
+ */
152
+ export declare function toolCompleted(request: HostEffect, value: unknown, facts?: ToolCallFacts): {
80
153
  agent: import("@nylorun/core/define").AgentRef;
81
154
  error: {
82
155
  code: string;
83
156
  message: string;
84
157
  server?: string | undefined;
85
- vault?: string | undefined;
86
158
  retryable?: boolean | undefined;
87
159
  };
88
160
  output?: undefined;
89
161
  redacted: number;
90
- capabilityId: string;
91
162
  toolName: string;
163
+ status?: "cancelled" | "completed" | "failed" | undefined;
164
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
165
+ server?: string | undefined;
166
+ skill?: string | undefined;
167
+ plugin?: PluginLabel | undefined;
168
+ attempts?: number | undefined;
169
+ durationMs?: number | undefined;
170
+ effectId?: string | undefined;
171
+ gate?: GateTimes | undefined;
172
+ policy?: ToolPolicyFact | undefined;
92
173
  } | {
93
174
  agent?: undefined;
94
175
  error: {
95
176
  code: string;
96
177
  message: string;
97
178
  server?: string | undefined;
98
- vault?: string | undefined;
99
179
  retryable?: boolean | undefined;
100
180
  };
101
181
  output?: undefined;
102
182
  redacted: number;
103
- capabilityId: string;
104
183
  toolName: string;
184
+ status?: "cancelled" | "completed" | "failed" | undefined;
185
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
186
+ server?: string | undefined;
187
+ skill?: string | undefined;
188
+ plugin?: PluginLabel | undefined;
189
+ attempts?: number | undefined;
190
+ durationMs?: number | undefined;
191
+ effectId?: string | undefined;
192
+ gate?: GateTimes | undefined;
193
+ policy?: ToolPolicyFact | undefined;
105
194
  } | {
106
- redacted?: undefined;
107
195
  agent: import("@nylorun/core/define").AgentRef;
108
196
  error: {
109
197
  code: string;
110
198
  message: string;
111
199
  server?: string | undefined;
112
- vault?: string | undefined;
113
200
  retryable?: boolean | undefined;
114
201
  };
115
202
  output?: undefined;
116
- capabilityId: string;
203
+ redacted?: undefined;
117
204
  toolName: string;
205
+ status?: "cancelled" | "completed" | "failed" | undefined;
206
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
207
+ server?: string | undefined;
208
+ skill?: string | undefined;
209
+ plugin?: PluginLabel | undefined;
210
+ attempts?: number | undefined;
211
+ durationMs?: number | undefined;
212
+ effectId?: string | undefined;
213
+ gate?: GateTimes | undefined;
214
+ policy?: ToolPolicyFact | undefined;
118
215
  } | {
119
- redacted?: undefined;
120
216
  agent?: undefined;
121
217
  error: {
122
218
  code: string;
123
219
  message: string;
124
220
  server?: string | undefined;
125
- vault?: string | undefined;
126
221
  retryable?: boolean | undefined;
127
222
  };
128
223
  output?: undefined;
129
- capabilityId: string;
224
+ redacted?: undefined;
130
225
  toolName: string;
226
+ status?: "cancelled" | "completed" | "failed" | undefined;
227
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
228
+ server?: string | undefined;
229
+ skill?: string | undefined;
230
+ plugin?: PluginLabel | undefined;
231
+ attempts?: number | undefined;
232
+ durationMs?: number | undefined;
233
+ effectId?: string | undefined;
234
+ gate?: GateTimes | undefined;
235
+ policy?: ToolPolicyFact | undefined;
131
236
  } | {
132
237
  agent: import("@nylorun/core/define").AgentRef;
133
238
  error?: undefined;
134
239
  output: unknown;
135
240
  redacted: number;
136
- capabilityId: string;
137
241
  toolName: string;
242
+ status?: "cancelled" | "completed" | "failed" | undefined;
243
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
244
+ server?: string | undefined;
245
+ skill?: string | undefined;
246
+ plugin?: PluginLabel | undefined;
247
+ attempts?: number | undefined;
248
+ durationMs?: number | undefined;
249
+ effectId?: string | undefined;
250
+ gate?: GateTimes | undefined;
251
+ policy?: ToolPolicyFact | undefined;
138
252
  } | {
139
253
  agent?: undefined;
140
254
  error?: undefined;
141
255
  output: unknown;
142
256
  redacted: number;
143
- capabilityId: string;
144
257
  toolName: string;
258
+ status?: "cancelled" | "completed" | "failed" | undefined;
259
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
260
+ server?: string | undefined;
261
+ skill?: string | undefined;
262
+ plugin?: PluginLabel | undefined;
263
+ attempts?: number | undefined;
264
+ durationMs?: number | undefined;
265
+ effectId?: string | undefined;
266
+ gate?: GateTimes | undefined;
267
+ policy?: ToolPolicyFact | undefined;
145
268
  } | {
146
- redacted?: undefined;
147
269
  agent: import("@nylorun/core/define").AgentRef;
148
270
  error?: undefined;
149
271
  output: unknown;
150
- capabilityId: string;
272
+ redacted?: undefined;
151
273
  toolName: string;
274
+ status?: "cancelled" | "completed" | "failed" | undefined;
275
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
276
+ server?: string | undefined;
277
+ skill?: string | undefined;
278
+ plugin?: PluginLabel | undefined;
279
+ attempts?: number | undefined;
280
+ durationMs?: number | undefined;
281
+ effectId?: string | undefined;
282
+ gate?: GateTimes | undefined;
283
+ policy?: ToolPolicyFact | undefined;
152
284
  } | {
153
- redacted?: undefined;
154
285
  agent?: undefined;
155
286
  error?: undefined;
156
287
  output: unknown;
157
- capabilityId: string;
288
+ redacted?: undefined;
158
289
  toolName: string;
290
+ status?: "cancelled" | "completed" | "failed" | undefined;
291
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
292
+ server?: string | undefined;
293
+ skill?: string | undefined;
294
+ plugin?: PluginLabel | undefined;
295
+ attempts?: number | undefined;
296
+ durationMs?: number | undefined;
297
+ effectId?: string | undefined;
298
+ gate?: GateTimes | undefined;
299
+ policy?: ToolPolicyFact | undefined;
159
300
  } | {
160
301
  callId: string;
161
302
  invocationId: string;
@@ -164,13 +305,21 @@ export declare function toolCompleted(request: HostEffect, value: unknown): {
164
305
  code: string;
165
306
  message: string;
166
307
  server?: string | undefined;
167
- vault?: string | undefined;
168
308
  retryable?: boolean | undefined;
169
309
  };
170
310
  output?: undefined;
171
311
  redacted: number;
172
- capabilityId: string;
173
312
  toolName: string;
313
+ status?: "cancelled" | "completed" | "failed" | undefined;
314
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
315
+ server?: string | undefined;
316
+ skill?: string | undefined;
317
+ plugin?: PluginLabel | undefined;
318
+ attempts?: number | undefined;
319
+ durationMs?: number | undefined;
320
+ effectId?: string | undefined;
321
+ gate?: GateTimes | undefined;
322
+ policy?: ToolPolicyFact | undefined;
174
323
  } | {
175
324
  callId: string;
176
325
  invocationId: string;
@@ -179,15 +328,22 @@ export declare function toolCompleted(request: HostEffect, value: unknown): {
179
328
  code: string;
180
329
  message: string;
181
330
  server?: string | undefined;
182
- vault?: string | undefined;
183
331
  retryable?: boolean | undefined;
184
332
  };
185
333
  output?: undefined;
186
334
  redacted: number;
187
- capabilityId: string;
188
335
  toolName: string;
336
+ status?: "cancelled" | "completed" | "failed" | undefined;
337
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
338
+ server?: string | undefined;
339
+ skill?: string | undefined;
340
+ plugin?: PluginLabel | undefined;
341
+ attempts?: number | undefined;
342
+ durationMs?: number | undefined;
343
+ effectId?: string | undefined;
344
+ gate?: GateTimes | undefined;
345
+ policy?: ToolPolicyFact | undefined;
189
346
  } | {
190
- redacted?: undefined;
191
347
  callId: string;
192
348
  invocationId: string;
193
349
  agent: import("@nylorun/core/define").AgentRef;
@@ -195,14 +351,22 @@ export declare function toolCompleted(request: HostEffect, value: unknown): {
195
351
  code: string;
196
352
  message: string;
197
353
  server?: string | undefined;
198
- vault?: string | undefined;
199
354
  retryable?: boolean | undefined;
200
355
  };
201
356
  output?: undefined;
202
- capabilityId: string;
357
+ redacted?: undefined;
203
358
  toolName: string;
359
+ status?: "cancelled" | "completed" | "failed" | undefined;
360
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
361
+ server?: string | undefined;
362
+ skill?: string | undefined;
363
+ plugin?: PluginLabel | undefined;
364
+ attempts?: number | undefined;
365
+ durationMs?: number | undefined;
366
+ effectId?: string | undefined;
367
+ gate?: GateTimes | undefined;
368
+ policy?: ToolPolicyFact | undefined;
204
369
  } | {
205
- redacted?: undefined;
206
370
  callId: string;
207
371
  invocationId: string;
208
372
  agent?: undefined;
@@ -210,12 +374,21 @@ export declare function toolCompleted(request: HostEffect, value: unknown): {
210
374
  code: string;
211
375
  message: string;
212
376
  server?: string | undefined;
213
- vault?: string | undefined;
214
377
  retryable?: boolean | undefined;
215
378
  };
216
379
  output?: undefined;
217
- capabilityId: string;
380
+ redacted?: undefined;
218
381
  toolName: string;
382
+ status?: "cancelled" | "completed" | "failed" | undefined;
383
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
384
+ server?: string | undefined;
385
+ skill?: string | undefined;
386
+ plugin?: PluginLabel | undefined;
387
+ attempts?: number | undefined;
388
+ durationMs?: number | undefined;
389
+ effectId?: string | undefined;
390
+ gate?: GateTimes | undefined;
391
+ policy?: ToolPolicyFact | undefined;
219
392
  } | {
220
393
  callId: string;
221
394
  invocationId: string;
@@ -223,8 +396,17 @@ export declare function toolCompleted(request: HostEffect, value: unknown): {
223
396
  error?: undefined;
224
397
  output: unknown;
225
398
  redacted: number;
226
- capabilityId: string;
227
399
  toolName: string;
400
+ status?: "cancelled" | "completed" | "failed" | undefined;
401
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
402
+ server?: string | undefined;
403
+ skill?: string | undefined;
404
+ plugin?: PluginLabel | undefined;
405
+ attempts?: number | undefined;
406
+ durationMs?: number | undefined;
407
+ effectId?: string | undefined;
408
+ gate?: GateTimes | undefined;
409
+ policy?: ToolPolicyFact | undefined;
228
410
  } | {
229
411
  callId: string;
230
412
  invocationId: string;
@@ -232,24 +414,51 @@ export declare function toolCompleted(request: HostEffect, value: unknown): {
232
414
  error?: undefined;
233
415
  output: unknown;
234
416
  redacted: number;
235
- capabilityId: string;
236
417
  toolName: string;
418
+ status?: "cancelled" | "completed" | "failed" | undefined;
419
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
420
+ server?: string | undefined;
421
+ skill?: string | undefined;
422
+ plugin?: PluginLabel | undefined;
423
+ attempts?: number | undefined;
424
+ durationMs?: number | undefined;
425
+ effectId?: string | undefined;
426
+ gate?: GateTimes | undefined;
427
+ policy?: ToolPolicyFact | undefined;
237
428
  } | {
238
- redacted?: undefined;
239
429
  callId: string;
240
430
  invocationId: string;
241
431
  agent: import("@nylorun/core/define").AgentRef;
242
432
  error?: undefined;
243
433
  output: unknown;
244
- capabilityId: string;
434
+ redacted?: undefined;
245
435
  toolName: string;
436
+ status?: "cancelled" | "completed" | "failed" | undefined;
437
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
438
+ server?: string | undefined;
439
+ skill?: string | undefined;
440
+ plugin?: PluginLabel | undefined;
441
+ attempts?: number | undefined;
442
+ durationMs?: number | undefined;
443
+ effectId?: string | undefined;
444
+ gate?: GateTimes | undefined;
445
+ policy?: ToolPolicyFact | undefined;
246
446
  } | {
247
- redacted?: undefined;
248
447
  callId: string;
249
448
  invocationId: string;
250
449
  agent?: undefined;
251
450
  error?: undefined;
252
451
  output: unknown;
253
- capabilityId: string;
452
+ redacted?: undefined;
254
453
  toolName: string;
454
+ status?: "cancelled" | "completed" | "failed" | undefined;
455
+ kind?: "harness" | "http" | "mcp" | "platform" | "sandbox" | undefined;
456
+ server?: string | undefined;
457
+ skill?: string | undefined;
458
+ plugin?: PluginLabel | undefined;
459
+ attempts?: number | undefined;
460
+ durationMs?: number | undefined;
461
+ effectId?: string | undefined;
462
+ gate?: GateTimes | undefined;
463
+ policy?: ToolPolicyFact | undefined;
255
464
  } | undefined;
@@ -9,7 +9,9 @@ export function toolIds(context) {
9
9
  const agentOf = (request) => request.agent ? { agent: request.agent } : {};
10
10
  /**
11
11
  * `message.assistant` for a completed model effect: the step's text and tool calls. The
12
- * provider returns a `ModelCandidate` or a bare string; anything else writes no event.
12
+ * provider returns a `ModelCandidate` or a bare string. A step that said nothing (no text, no
13
+ * tool calls; a structured answer) is still one event, with `text: ""` (R7.1): every model call
14
+ * has its outcome row. Readers that build a conversation skip it (`isEmptyAssistantMessage`).
13
15
  */
14
16
  export function assistantMessage(request, value) {
15
17
  const invocationId = request.context
@@ -31,8 +33,6 @@ export function assistantMessage(request, value) {
31
33
  typeof block.name === "string")
32
34
  toolCalls.push({ callId: block.id, name: block.name, input: block.args });
33
35
  }
34
- if (!text && toolCalls.length === 0)
35
- return undefined;
36
36
  const candidate = (typeof value === "object" && value !== null ? value : {});
37
37
  const producer = candidate.evidence?.extras?.producer;
38
38
  return {
@@ -53,11 +53,12 @@ export function assistantMessage(request, value) {
53
53
  }
54
54
  /**
55
55
  * `context.compacted` for a model effect that summarized history (Model Calls §8): the
56
- * engine replaced the older transcript with that summary.
56
+ * engine replaced the older transcript with that summary. A partial summary (one call of
57
+ * several) is marked `partial: true` (R7.1): only the last call's event replaced the history.
57
58
  */
58
59
  export function contextCompacted(request, value) {
59
60
  const compaction = request.context?.compaction;
60
- if (!compaction || compaction.partial || isModelFailureOutcome(value))
61
+ if (!compaction || isModelFailureOutcome(value))
61
62
  return undefined;
62
63
  const summary = typeof value === "string"
63
64
  ? value
@@ -74,6 +75,7 @@ export function contextCompacted(request, value) {
74
75
  trigger: compaction.trigger === "overflow" ? "overflow" : "threshold",
75
76
  tokensBefore,
76
77
  tokensAfter: keptTokens + Math.ceil(summary.trim().length / 4),
78
+ ...(compaction.partial ? { partial: true } : {}),
77
79
  ...agentOf(request),
78
80
  };
79
81
  }
@@ -91,8 +93,48 @@ export function modelFailed(request, value) {
91
93
  ...agentOf(request),
92
94
  };
93
95
  }
94
- /** `tool.completed` for a tool the Runtime ran: its output, or the tool error it reported. */
95
- export function toolCompleted(request, value) {
96
+ /** From `startedAt` to `endedAt` in whole milliseconds; undefined unless both are times. */
97
+ export function durationBetween(startedAt, endedAt) {
98
+ const started = startedAt ? Date.parse(startedAt) : NaN;
99
+ const ended = endedAt ? Date.parse(endedAt) : NaN;
100
+ if (!Number.isFinite(started) || !Number.isFinite(ended))
101
+ return undefined;
102
+ return Math.max(0, Math.round(ended - started));
103
+ }
104
+ /**
105
+ * The timing a model call's outcome event carries (R7.1): its effect id, the journal's window
106
+ * (`startedAt` on the row to `settledAt`), and, when the gate metered the call (`metered`), the
107
+ * gate's own start and end, the first token's time and the metered usage.
108
+ */
109
+ export function modelOutcomeFacts(effectId, window, metered) {
110
+ const durationMs = durationBetween(window.startedAt, window.settledAt);
111
+ return {
112
+ effectId,
113
+ ...(durationMs === undefined ? {} : { durationMs }),
114
+ ...(metered?.startedAt && metered.endedAt
115
+ ? { gate: { startedAt: metered.startedAt, endedAt: metered.endedAt } }
116
+ : {}),
117
+ ...(metered?.firstTokenMs !== null && metered?.firstTokenMs !== undefined
118
+ ? { firstTokenMs: metered.firstTokenMs }
119
+ : {}),
120
+ ...(metered
121
+ ? {
122
+ meteredUsage: {
123
+ inputTokens: metered.inputTokens,
124
+ outputTokens: metered.outputTokens,
125
+ totalTokens: metered.totalTokens,
126
+ ...(metered.cachedTokens > 0 ? { cachedTokens: metered.cachedTokens } : {}),
127
+ ...(metered.costUsd > 0 ? { costUsd: metered.costUsd } : {}),
128
+ },
129
+ }
130
+ : {}),
131
+ };
132
+ }
133
+ /**
134
+ * `tool.completed` for a tool call that ended: its output, or the tool error it reported, and
135
+ * how it ended (R5.1).
136
+ */
137
+ export function toolCompleted(request, value, facts) {
96
138
  const ids = toolIds(request.context);
97
139
  if (!("callId" in ids))
98
140
  return undefined;
@@ -102,11 +144,8 @@ export function toolCompleted(request, value) {
102
144
  error: {
103
145
  code: String(outcome.code ?? "tool.failed"),
104
146
  message: String(outcome.message ?? ""),
105
- // `credential_rejected` (R2b C1): which server, and which vault's credential.
147
+ // `credential_rejected` (R2b C1): which server.
106
148
  ...(typeof outcome.server === "string" ? { server: outcome.server } : {}),
107
- ...(outcome.vault === "installation" || outcome.vault === "user"
108
- ? { vault: outcome.vault }
109
- : {}),
110
149
  ...(typeof outcome.retryable === "boolean" ? { retryable: outcome.retryable } : {}),
111
150
  },
112
151
  }
@@ -119,8 +158,21 @@ export function toolCompleted(request, value) {
119
158
  : {};
120
159
  return {
121
160
  ...ids,
122
- capabilityId: request.capabilityId,
123
161
  toolName: request.toolName,
162
+ ...(facts
163
+ ? {
164
+ status: facts.status,
165
+ ...(facts.kind === undefined ? {} : { kind: facts.kind }),
166
+ ...(facts.server === undefined ? {} : { server: facts.server }),
167
+ ...(facts.skill === undefined ? {} : { skill: facts.skill }),
168
+ ...(facts.plugin === undefined ? {} : { plugin: facts.plugin }),
169
+ ...(facts.attempts === undefined ? {} : { attempts: facts.attempts }),
170
+ ...(facts.durationMs === undefined ? {} : { durationMs: facts.durationMs }),
171
+ ...(facts.effectId === undefined ? {} : { effectId: facts.effectId }),
172
+ ...(facts.gate === undefined ? {} : { gate: facts.gate }),
173
+ ...(facts.policy === undefined ? {} : { policy: facts.policy }),
174
+ }
175
+ : {}),
124
176
  ...result,
125
177
  ...redacted,
126
178
  ...agentOf(request),
@@ -0,0 +1,43 @@
1
+ /**
2
+ * A turn's timing and totals (R7.1), so the event that ends it is its span. The session body
3
+ * keeps when its active turn started (`turnStartedAt`, set beside `activeTurnId`), how long it
4
+ * has waited paused for a person (`pausedMs`), and since when it waits (`pausedAt`, while
5
+ * paused). `turn.completed`, `turn.failed` and `turn.cancelled` carry `endTurn`'s facts.
6
+ *
7
+ * A turn started before the Runtime recorded these has no `turnStartedAt`: its end carries no
8
+ * `durationMs`.
9
+ */
10
+ import type { Tx } from "../store/types.js";
11
+ /** The turn timing a session body keeps. */
12
+ export interface TurnTiming {
13
+ turnStartedAt?: string;
14
+ /** The trace context the turn's message arrived with (R7.4); it ends with the turn. */
15
+ turnTrace?: unknown;
16
+ pausedMs?: number;
17
+ pausedAt?: string;
18
+ }
19
+ /** A new turn starts now. Mutates `s`. */
20
+ export declare function startTurn(s: TurnTiming, now?: Date): void;
21
+ /** The turn waits for a person from now, unless it already does. Mutates `s`. */
22
+ export declare function pauseTurn(s: TurnTiming, now?: Date): void;
23
+ /** A paused turn goes on: its wait is added to `pausedMs`. No-op when it was not paused. */
24
+ export declare function resumeTurn(s: TurnTiming, now?: Date): void;
25
+ /**
26
+ * The facts the event that ends turn `turnId` carries: `durationMs` from its start to now, waits
27
+ * included, so the turn's span holds every crossing in it; `pausedMs`, how long it waited paused
28
+ * (a wait still open ends now, as for a cancel); the session's agent;
29
+ * and the turn's totals from the usage ledger (one read, as `/v1/tenant/usage` totals a turn;
30
+ * `steps` are the model calls the gate metered). Clears the turn's timing from `s`.
31
+ */
32
+ export declare function endTurn(t: Tx, s: TurnTiming & {
33
+ agentId: string;
34
+ }, turnId: string | null, now?: Date): Promise<{
35
+ durationMs?: number;
36
+ pausedMs?: number;
37
+ agentId: string;
38
+ totals?: {
39
+ steps: number;
40
+ tokens: number;
41
+ costUsd: number;
42
+ };
43
+ }>;
@@ -0,0 +1,39 @@
1
+ import { durationBetween } from "./transcript.js";
2
+ /** A new turn starts now. Mutates `s`. */
3
+ export function startTurn(s, now = new Date()) {
4
+ s.turnStartedAt = now.toISOString();
5
+ s.pausedMs = 0;
6
+ delete s.pausedAt;
7
+ }
8
+ /** The turn waits for a person from now, unless it already does. Mutates `s`. */
9
+ export function pauseTurn(s, now = new Date()) {
10
+ s.pausedAt ??= now.toISOString();
11
+ }
12
+ /** A paused turn goes on: its wait is added to `pausedMs`. No-op when it was not paused. */
13
+ export function resumeTurn(s, now = new Date()) {
14
+ if (s.pausedAt === undefined)
15
+ return;
16
+ s.pausedMs = (s.pausedMs ?? 0) + (durationBetween(s.pausedAt, now.toISOString()) ?? 0);
17
+ delete s.pausedAt;
18
+ }
19
+ /**
20
+ * The facts the event that ends turn `turnId` carries: `durationMs` from its start to now, waits
21
+ * included, so the turn's span holds every crossing in it; `pausedMs`, how long it waited paused
22
+ * (a wait still open ends now, as for a cancel); the session's agent;
23
+ * and the turn's totals from the usage ledger (one read, as `/v1/tenant/usage` totals a turn;
24
+ * `steps` are the model calls the gate metered). Clears the turn's timing from `s`.
25
+ */
26
+ export async function endTurn(t, s, turnId, now = new Date()) {
27
+ resumeTurn(s, now);
28
+ const elapsed = durationBetween(s.turnStartedAt, now.toISOString());
29
+ const totals = turnId ? await t.modelUsageTotals({ scope: "turn", id: turnId }) : undefined;
30
+ const facts = {
31
+ ...(elapsed === undefined ? {} : { durationMs: Math.max(0, elapsed), pausedMs: s.pausedMs ?? 0 }),
32
+ agentId: s.agentId,
33
+ ...(totals ? { totals: { steps: totals.calls, tokens: totals.tokens, costUsd: totals.costUsd } } : {}),
34
+ };
35
+ delete s.turnStartedAt;
36
+ delete s.pausedMs;
37
+ delete s.turnTrace;
38
+ return facts;
39
+ }
@@ -119,6 +119,8 @@ export interface TenantHandle {
119
119
  attachHarness?(channel: HarnessChannel, peer: HarnessPeer): () => void;
120
120
  /** The Tenant's side of a sandbox pod's join (F7.2); absent without sandbox pods. */
121
121
  hostAuthority?(): HostAuthority | undefined;
122
+ /** The custom harness a per-harness token is for (R4.1), or undefined. */
123
+ harnessOfToken?(token: string): Promise<string | undefined>;
122
124
  /** The Tenant's harnesses (F6.2), for `/ready`. */
123
125
  harnessStatus?(): HarnessStatus;
124
126
  }