@stigmer/sdk 3.35.0 → 3.37.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.
Files changed (348) hide show
  1. package/activity.d.ts.map +1 -1
  2. package/activity.js.map +1 -1
  3. package/artifact-routing.d.ts.map +1 -1
  4. package/artifact-routing.js.map +1 -1
  5. package/authorization-config.d.ts.map +1 -1
  6. package/authorization-config.js.map +1 -1
  7. package/billing.d.ts.map +1 -1
  8. package/billing.js.map +1 -1
  9. package/config.d.ts.map +1 -1
  10. package/config.js.map +1 -1
  11. package/cursor-accounts.d.ts.map +1 -1
  12. package/cursor-accounts.js.map +1 -1
  13. package/ensure-identity-account.d.ts.map +1 -1
  14. package/ensure-identity-account.js.map +1 -1
  15. package/errors.d.ts.map +1 -1
  16. package/errors.js.map +1 -1
  17. package/execution/approval-provenance.d.ts.map +1 -1
  18. package/execution/approval-provenance.js.map +1 -1
  19. package/execution/conversation-rules.d.ts.map +1 -1
  20. package/execution/conversation-rules.js.map +1 -1
  21. package/execution/execution-phases.d.ts.map +1 -1
  22. package/execution/execution-phases.js.map +1 -1
  23. package/execution/file-review-fold.d.ts.map +1 -1
  24. package/execution/file-review-fold.js.map +1 -1
  25. package/execution/to-display-file-change.d.ts.map +1 -1
  26. package/execution/to-display-file-change.js.map +1 -1
  27. package/execution/tool-view.d.ts.map +1 -1
  28. package/execution/tool-view.js.map +1 -1
  29. package/execution/transcript.d.ts.map +1 -1
  30. package/execution/transcript.js.map +1 -1
  31. package/gen/agent.d.ts.map +1 -1
  32. package/gen/agent.js.map +1 -1
  33. package/gen/agentchannel.d.ts.map +1 -1
  34. package/gen/agentchannel.js.map +1 -1
  35. package/gen/agentexecution.d.ts.map +1 -1
  36. package/gen/agentexecution.js.map +1 -1
  37. package/gen/agentinstance.d.ts.map +1 -1
  38. package/gen/agentinstance.js.map +1 -1
  39. package/gen/agentshare.d.ts.map +1 -1
  40. package/gen/agentshare.js.map +1 -1
  41. package/gen/apikey.d.ts.map +1 -1
  42. package/gen/apikey.js.map +1 -1
  43. package/gen/artifact.d.ts.map +1 -1
  44. package/gen/artifact.js.map +1 -1
  45. package/gen/authorization-config.d.ts.map +1 -1
  46. package/gen/authorization-config.js +2 -2
  47. package/gen/authorization-config.js.map +1 -1
  48. package/gen/bidi-stream.d.ts.map +1 -1
  49. package/gen/bidi-stream.js.map +1 -1
  50. package/gen/channelapp.d.ts.map +1 -1
  51. package/gen/channelapp.js.map +1 -1
  52. package/gen/client.d.ts.map +1 -1
  53. package/gen/client.js.map +1 -1
  54. package/gen/environment.d.ts.map +1 -1
  55. package/gen/environment.js.map +1 -1
  56. package/gen/errors.d.ts.map +1 -1
  57. package/gen/errors.js.map +1 -1
  58. package/gen/executioncontext.d.ts.map +1 -1
  59. package/gen/executioncontext.js.map +1 -1
  60. package/gen/iampolicy.d.ts.map +1 -1
  61. package/gen/iampolicy.js.map +1 -1
  62. package/gen/identityaccount.d.ts.map +1 -1
  63. package/gen/identityaccount.js.map +1 -1
  64. package/gen/identityprovider.d.ts.map +1 -1
  65. package/gen/identityprovider.js.map +1 -1
  66. package/gen/invitation.d.ts.map +1 -1
  67. package/gen/invitation.js.map +1 -1
  68. package/gen/license.d.ts.map +1 -1
  69. package/gen/license.js.map +1 -1
  70. package/gen/mcpserver.d.ts.map +1 -1
  71. package/gen/mcpserver.js.map +1 -1
  72. package/gen/memory.d.ts.map +1 -1
  73. package/gen/memory.js.map +1 -1
  74. package/gen/oauthapp.d.ts.map +1 -1
  75. package/gen/oauthapp.js.map +1 -1
  76. package/gen/organization.d.ts.map +1 -1
  77. package/gen/organization.js.map +1 -1
  78. package/gen/plan.d.ts.map +1 -1
  79. package/gen/plan.js.map +1 -1
  80. package/gen/platformclient.d.ts.map +1 -1
  81. package/gen/platformclient.js.map +1 -1
  82. package/gen/plugin.d.ts.map +1 -1
  83. package/gen/plugin.js.map +1 -1
  84. package/gen/proto-utils.d.ts.map +1 -1
  85. package/gen/proto-utils.js.map +1 -1
  86. package/gen/resource-availability.d.ts.map +1 -1
  87. package/gen/resource-availability.js.map +1 -1
  88. package/gen/schedule.d.ts.map +1 -1
  89. package/gen/schedule.js.map +1 -1
  90. package/gen/session.d.ts.map +1 -1
  91. package/gen/session.js.map +1 -1
  92. package/gen/skill.d.ts.map +1 -1
  93. package/gen/skill.js.map +1 -1
  94. package/gen/subscription.d.ts.map +1 -1
  95. package/gen/subscription.js.map +1 -1
  96. package/gen/team.d.ts.map +1 -1
  97. package/gen/team.js.map +1 -1
  98. package/gen/types.d.ts.map +1 -1
  99. package/gen/types.js.map +1 -1
  100. package/gen/workflow.d.ts.map +1 -1
  101. package/gen/workflow.js.map +1 -1
  102. package/gen/workflowexecution.d.ts.map +1 -1
  103. package/gen/workflowexecution.js.map +1 -1
  104. package/gen/workflowinstance.d.ts.map +1 -1
  105. package/gen/workflowinstance.js.map +1 -1
  106. package/github.d.ts.map +1 -1
  107. package/github.js.map +1 -1
  108. package/guest-auth.d.ts.map +1 -1
  109. package/guest-auth.js.map +1 -1
  110. package/iam-principal.d.ts +6 -0
  111. package/iam-principal.d.ts.map +1 -1
  112. package/iam-principal.js +19 -0
  113. package/iam-principal.js.map +1 -1
  114. package/iam-role.d.ts.map +1 -1
  115. package/iam-role.js.map +1 -1
  116. package/index.d.ts +1 -1
  117. package/index.d.ts.map +1 -1
  118. package/index.js +1 -1
  119. package/index.js.map +1 -1
  120. package/internal/interceptors.d.ts.map +1 -1
  121. package/internal/interceptors.js.map +1 -1
  122. package/manifest/client.d.ts.map +1 -1
  123. package/manifest/client.js.map +1 -1
  124. package/manifest/document.d.ts.map +1 -1
  125. package/manifest/document.js.map +1 -1
  126. package/manifest/index.d.ts.map +1 -1
  127. package/manifest/index.js.map +1 -1
  128. package/manifest/parse.d.ts.map +1 -1
  129. package/manifest/parse.js.map +1 -1
  130. package/manifest/redaction.d.ts.map +1 -1
  131. package/manifest/redaction.js.map +1 -1
  132. package/manifest/registry.d.ts.map +1 -1
  133. package/manifest/registry.js.map +1 -1
  134. package/manifest/serialize.d.ts.map +1 -1
  135. package/manifest/serialize.js.map +1 -1
  136. package/mcpserver-connect.d.ts.map +1 -1
  137. package/mcpserver-connect.js.map +1 -1
  138. package/node.d.ts.map +1 -1
  139. package/node.js.map +1 -1
  140. package/package.json +2 -2
  141. package/platform-client-auth.d.ts.map +1 -1
  142. package/platform-client-auth.js.map +1 -1
  143. package/platform.d.ts.map +1 -1
  144. package/platform.js.map +1 -1
  145. package/plugin.d.ts.map +1 -1
  146. package/plugin.js.map +1 -1
  147. package/provider-standing.d.ts.map +1 -1
  148. package/provider-standing.js.map +1 -1
  149. package/resource-availability.d.ts.map +1 -1
  150. package/resource-availability.js.map +1 -1
  151. package/runner-adapter.d.ts.map +1 -1
  152. package/runner-adapter.js.map +1 -1
  153. package/search.d.ts.map +1 -1
  154. package/search.js.map +1 -1
  155. package/session.d.ts.map +1 -1
  156. package/session.js.map +1 -1
  157. package/sharing.d.ts.map +1 -1
  158. package/sharing.js.map +1 -1
  159. package/skill.d.ts.map +1 -1
  160. package/skill.js.map +1 -1
  161. package/src/gen/authorization-config.ts +2 -2
  162. package/src/iam-principal.ts +24 -0
  163. package/src/index.ts +1 -0
  164. package/stigmer.d.ts.map +1 -1
  165. package/stigmer.js.map +1 -1
  166. package/transport.d.ts.map +1 -1
  167. package/transport.js.map +1 -1
  168. package/__tests__/billing.test.d.ts +0 -2
  169. package/__tests__/billing.test.d.ts.map +0 -1
  170. package/__tests__/billing.test.js +0 -120
  171. package/__tests__/billing.test.js.map +0 -1
  172. package/__tests__/config.test.d.ts +0 -2
  173. package/__tests__/config.test.d.ts.map +0 -1
  174. package/__tests__/config.test.js +0 -35
  175. package/__tests__/config.test.js.map +0 -1
  176. package/__tests__/ensure-identity-account.test.d.ts +0 -2
  177. package/__tests__/ensure-identity-account.test.d.ts.map +0 -1
  178. package/__tests__/ensure-identity-account.test.js +0 -108
  179. package/__tests__/ensure-identity-account.test.js.map +0 -1
  180. package/__tests__/errors.test.d.ts +0 -2
  181. package/__tests__/errors.test.d.ts.map +0 -1
  182. package/__tests__/errors.test.js +0 -228
  183. package/__tests__/errors.test.js.map +0 -1
  184. package/__tests__/gen/errors.test.d.ts +0 -2
  185. package/__tests__/gen/errors.test.d.ts.map +0 -1
  186. package/__tests__/gen/errors.test.js +0 -97
  187. package/__tests__/gen/errors.test.js.map +0 -1
  188. package/__tests__/gen/invitation-client.test.d.ts +0 -2
  189. package/__tests__/gen/invitation-client.test.d.ts.map +0 -1
  190. package/__tests__/gen/invitation-client.test.js +0 -106
  191. package/__tests__/gen/invitation-client.test.js.map +0 -1
  192. package/__tests__/gen/proto-utils.test.d.ts +0 -2
  193. package/__tests__/gen/proto-utils.test.d.ts.map +0 -1
  194. package/__tests__/gen/proto-utils.test.js +0 -85
  195. package/__tests__/gen/proto-utils.test.js.map +0 -1
  196. package/__tests__/gen/session-client.test.d.ts +0 -2
  197. package/__tests__/gen/session-client.test.d.ts.map +0 -1
  198. package/__tests__/gen/session-client.test.js +0 -152
  199. package/__tests__/gen/session-client.test.js.map +0 -1
  200. package/__tests__/guest-auth.test.d.ts +0 -2
  201. package/__tests__/guest-auth.test.d.ts.map +0 -1
  202. package/__tests__/guest-auth.test.js +0 -223
  203. package/__tests__/guest-auth.test.js.map +0 -1
  204. package/__tests__/iam-principal.test.d.ts +0 -2
  205. package/__tests__/iam-principal.test.d.ts.map +0 -1
  206. package/__tests__/iam-principal.test.js +0 -65
  207. package/__tests__/iam-principal.test.js.map +0 -1
  208. package/__tests__/manifest.test.d.ts +0 -2
  209. package/__tests__/manifest.test.d.ts.map +0 -1
  210. package/__tests__/manifest.test.js +0 -306
  211. package/__tests__/manifest.test.js.map +0 -1
  212. package/__tests__/mcpserver-connect.test.d.ts +0 -2
  213. package/__tests__/mcpserver-connect.test.d.ts.map +0 -1
  214. package/__tests__/mcpserver-connect.test.js +0 -146
  215. package/__tests__/mcpserver-connect.test.js.map +0 -1
  216. package/__tests__/node.test.d.ts +0 -2
  217. package/__tests__/node.test.d.ts.map +0 -1
  218. package/__tests__/node.test.js +0 -67
  219. package/__tests__/node.test.js.map +0 -1
  220. package/__tests__/platform-client-auth.test.d.ts +0 -2
  221. package/__tests__/platform-client-auth.test.d.ts.map +0 -1
  222. package/__tests__/platform-client-auth.test.js +0 -59
  223. package/__tests__/platform-client-auth.test.js.map +0 -1
  224. package/__tests__/platform.test.d.ts +0 -2
  225. package/__tests__/platform.test.d.ts.map +0 -1
  226. package/__tests__/platform.test.js +0 -52
  227. package/__tests__/platform.test.js.map +0 -1
  228. package/__tests__/plugin.test.d.ts +0 -2
  229. package/__tests__/plugin.test.d.ts.map +0 -1
  230. package/__tests__/plugin.test.js +0 -74
  231. package/__tests__/plugin.test.js.map +0 -1
  232. package/__tests__/resource-availability.test.d.ts +0 -2
  233. package/__tests__/resource-availability.test.d.ts.map +0 -1
  234. package/__tests__/resource-availability.test.js +0 -80
  235. package/__tests__/resource-availability.test.js.map +0 -1
  236. package/__tests__/runner-adapter.test.d.ts +0 -2
  237. package/__tests__/runner-adapter.test.d.ts.map +0 -1
  238. package/__tests__/runner-adapter.test.js +0 -88
  239. package/__tests__/runner-adapter.test.js.map +0 -1
  240. package/__tests__/session.test.d.ts +0 -6
  241. package/__tests__/session.test.d.ts.map +0 -1
  242. package/__tests__/session.test.js +0 -50
  243. package/__tests__/session.test.js.map +0 -1
  244. package/__tests__/sharing.test.d.ts +0 -2
  245. package/__tests__/sharing.test.d.ts.map +0 -1
  246. package/__tests__/sharing.test.js +0 -106
  247. package/__tests__/sharing.test.js.map +0 -1
  248. package/__tests__/skill.test.d.ts +0 -2
  249. package/__tests__/skill.test.d.ts.map +0 -1
  250. package/__tests__/skill.test.js +0 -117
  251. package/__tests__/skill.test.js.map +0 -1
  252. package/__tests__/stigmer.test.d.ts +0 -2
  253. package/__tests__/stigmer.test.d.ts.map +0 -1
  254. package/__tests__/stigmer.test.js +0 -127
  255. package/__tests__/stigmer.test.js.map +0 -1
  256. package/__tests__/update-input-roundtrip.test.d.ts +0 -2
  257. package/__tests__/update-input-roundtrip.test.d.ts.map +0 -1
  258. package/__tests__/update-input-roundtrip.test.js +0 -775
  259. package/__tests__/update-input-roundtrip.test.js.map +0 -1
  260. package/__tests__/update-input.test.d.ts +0 -2
  261. package/__tests__/update-input.test.d.ts.map +0 -1
  262. package/__tests__/update-input.test.js +0 -188
  263. package/__tests__/update-input.test.js.map +0 -1
  264. package/execution/__tests__/approval-provenance.test.d.ts +0 -2
  265. package/execution/__tests__/approval-provenance.test.d.ts.map +0 -1
  266. package/execution/__tests__/approval-provenance.test.js +0 -42
  267. package/execution/__tests__/approval-provenance.test.js.map +0 -1
  268. package/execution/__tests__/file-review-fold.corpus.test.d.ts +0 -2
  269. package/execution/__tests__/file-review-fold.corpus.test.d.ts.map +0 -1
  270. package/execution/__tests__/file-review-fold.corpus.test.js +0 -82
  271. package/execution/__tests__/file-review-fold.corpus.test.js.map +0 -1
  272. package/execution/__tests__/file-review-fold.test.d.ts +0 -2
  273. package/execution/__tests__/file-review-fold.test.d.ts.map +0 -1
  274. package/execution/__tests__/file-review-fold.test.js +0 -184
  275. package/execution/__tests__/file-review-fold.test.js.map +0 -1
  276. package/execution/__tests__/to-display-file-change.test.d.ts +0 -2
  277. package/execution/__tests__/to-display-file-change.test.d.ts.map +0 -1
  278. package/execution/__tests__/to-display-file-change.test.js +0 -81
  279. package/execution/__tests__/to-display-file-change.test.js.map +0 -1
  280. package/execution/__tests__/tool-view.file-changes.test.d.ts +0 -2
  281. package/execution/__tests__/tool-view.file-changes.test.d.ts.map +0 -1
  282. package/execution/__tests__/tool-view.file-changes.test.js +0 -86
  283. package/execution/__tests__/tool-view.file-changes.test.js.map +0 -1
  284. package/execution/__tests__/tool-view.fixtures.test.d.ts +0 -2
  285. package/execution/__tests__/tool-view.fixtures.test.d.ts.map +0 -1
  286. package/execution/__tests__/tool-view.fixtures.test.js +0 -152
  287. package/execution/__tests__/tool-view.fixtures.test.js.map +0 -1
  288. package/execution/__tests__/tool-view.output-ref.test.d.ts +0 -2
  289. package/execution/__tests__/tool-view.output-ref.test.d.ts.map +0 -1
  290. package/execution/__tests__/tool-view.output-ref.test.js +0 -64
  291. package/execution/__tests__/tool-view.output-ref.test.js.map +0 -1
  292. package/execution/__tests__/tool-view.read.test.d.ts +0 -2
  293. package/execution/__tests__/tool-view.read.test.d.ts.map +0 -1
  294. package/execution/__tests__/tool-view.read.test.js +0 -56
  295. package/execution/__tests__/tool-view.read.test.js.map +0 -1
  296. package/execution/__tests__/tool-view.search.test.d.ts +0 -2
  297. package/execution/__tests__/tool-view.search.test.d.ts.map +0 -1
  298. package/execution/__tests__/tool-view.search.test.js +0 -200
  299. package/execution/__tests__/tool-view.search.test.js.map +0 -1
  300. package/execution/__tests__/tool-view.shell.test.d.ts +0 -2
  301. package/execution/__tests__/tool-view.shell.test.d.ts.map +0 -1
  302. package/execution/__tests__/tool-view.shell.test.js +0 -104
  303. package/execution/__tests__/tool-view.shell.test.js.map +0 -1
  304. package/execution/__tests__/transcript.test.d.ts +0 -2
  305. package/execution/__tests__/transcript.test.d.ts.map +0 -1
  306. package/execution/__tests__/transcript.test.js +0 -591
  307. package/execution/__tests__/transcript.test.js.map +0 -1
  308. package/node.test.d.ts +0 -2
  309. package/node.test.d.ts.map +0 -1
  310. package/node.test.js +0 -35
  311. package/node.test.js.map +0 -1
  312. package/src/__tests__/billing.test.ts +0 -146
  313. package/src/__tests__/config.test.ts +0 -52
  314. package/src/__tests__/ensure-identity-account.test.ts +0 -146
  315. package/src/__tests__/errors.test.ts +0 -349
  316. package/src/__tests__/gen/errors.test.ts +0 -138
  317. package/src/__tests__/gen/invitation-client.test.ts +0 -132
  318. package/src/__tests__/gen/proto-utils.test.ts +0 -99
  319. package/src/__tests__/gen/session-client.test.ts +0 -208
  320. package/src/__tests__/guest-auth.test.ts +0 -287
  321. package/src/__tests__/iam-principal.test.ts +0 -82
  322. package/src/__tests__/manifest.test.ts +0 -362
  323. package/src/__tests__/mcpserver-connect.test.ts +0 -181
  324. package/src/__tests__/node.test.ts +0 -74
  325. package/src/__tests__/platform-client-auth.test.ts +0 -76
  326. package/src/__tests__/platform.test.ts +0 -74
  327. package/src/__tests__/plugin.test.ts +0 -92
  328. package/src/__tests__/resource-availability.test.ts +0 -118
  329. package/src/__tests__/runner-adapter.test.ts +0 -122
  330. package/src/__tests__/session.test.ts +0 -66
  331. package/src/__tests__/sharing.test.ts +0 -159
  332. package/src/__tests__/skill.test.ts +0 -150
  333. package/src/__tests__/stigmer.test.ts +0 -170
  334. package/src/__tests__/update-input-roundtrip.test.ts +0 -1007
  335. package/src/__tests__/update-input.test.ts +0 -250
  336. package/src/execution/__tests__/approval-provenance.test.ts +0 -60
  337. package/src/execution/__tests__/file-review-fold.corpus.test.ts +0 -127
  338. package/src/execution/__tests__/file-review-fold.test.ts +0 -281
  339. package/src/execution/__tests__/to-display-file-change.test.ts +0 -106
  340. package/src/execution/__tests__/tool-view.file-changes.test.ts +0 -100
  341. package/src/execution/__tests__/tool-view.fixtures.test.ts +0 -225
  342. package/src/execution/__tests__/tool-view.output-ref.test.ts +0 -76
  343. package/src/execution/__tests__/tool-view.read.test.ts +0 -71
  344. package/src/execution/__tests__/tool-view.search.test.ts +0 -264
  345. package/src/execution/__tests__/tool-view.shell.test.ts +0 -127
  346. package/src/execution/__tests__/transcript.golden.md +0 -100
  347. package/src/execution/__tests__/transcript.test.ts +0 -697
  348. package/src/node.test.ts +0 -38
@@ -1,697 +0,0 @@
1
- // The canonical session transcript (stigmer/stigmer#814): assembly rules,
2
- // offload resolution, and the two serializations.
3
- //
4
- // The Markdown format is a pinned contract: transcript.golden.md freezes the
5
- // exact rendering of a transcript exercising every construct (thinking,
6
- // system, tool calls with args/results, offloaded outputs resolved and
7
- // noted, sub-agent nesting, build-from-plan and in-progress markers). A
8
- // deliberate format change regenerates the golden with
9
- // UPDATE_TRANSCRIPT_GOLDEN=1 npx vitest run src/execution/__tests__/transcript.test.ts
10
- // and reviews the diff; an accidental one fails here.
11
-
12
- import { readFileSync, writeFileSync } from "node:fs";
13
- import { fileURLToPath } from "node:url";
14
- import { dirname, resolve } from "node:path";
15
- import { describe, it, expect } from "vitest";
16
- import { create } from "@bufbuild/protobuf";
17
- import type { JsonObject } from "@bufbuild/protobuf";
18
- import {
19
- AgentExecutionSchema,
20
- type AgentExecution,
21
- } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/api_pb";
22
- import {
23
- ExecutionPhase,
24
- MessageType,
25
- ToolCallStatus,
26
- } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/enum_pb";
27
- import {
28
- AgentExecutionListSchema,
29
- GetArtifactContentResponseSchema,
30
- type GetArtifactContentRequest,
31
- type GetArtifactContentResponse,
32
- } from "@stigmer/protos/ai/stigmer/agentic/agentexecution/v1/io_pb";
33
- import { SessionSchema } from "@stigmer/protos/ai/stigmer/agentic/session/v1/api_pb";
34
- import {
35
- assembleSessionTranscript,
36
- fetchSessionTranscript,
37
- resolveOffloadedOutputs,
38
- transcriptToJson,
39
- transcriptToMarkdown,
40
- type ResolvedToolOutput,
41
- } from "../transcript";
42
-
43
- const here = dirname(fileURLToPath(import.meta.url));
44
-
45
- // ---------------------------------------------------------------------------
46
- // Fixture builders
47
- // ---------------------------------------------------------------------------
48
-
49
- function session() {
50
- return create(SessionSchema, {
51
- metadata: { id: "ses_01" },
52
- spec: { subject: "Fix the flaky test", agentInstanceId: "agi_01" },
53
- });
54
- }
55
-
56
- /** Turn 1: prompt echo dedupe, thinking, tool call with args + inline
57
- * result + duration, offloaded text output, image output, raw system. */
58
- function exec1(): AgentExecution {
59
- return create(AgentExecutionSchema, {
60
- metadata: { id: "aex_01a" },
61
- spec: { sessionId: "ses_01", message: "Why is CI red?" },
62
- status: {
63
- phase: ExecutionPhase.EXECUTION_COMPLETED,
64
- startedAt: "2026-08-20T10:00:00Z",
65
- completedAt: "2026-08-20T10:01:00Z",
66
- messages: [
67
- {
68
- type: MessageType.MESSAGE_HUMAN,
69
- content: "Why is CI red?",
70
- timestamp: "2026-08-20T10:00:01Z",
71
- },
72
- {
73
- type: MessageType.MESSAGE_THINKING,
74
- content: "The failure is in the retry loop.\nLet me check.",
75
- timestamp: "2026-08-20T10:00:02Z",
76
- },
77
- {
78
- type: MessageType.MESSAGE_AI,
79
- content: "Let me look.",
80
- timestamp: "2026-08-20T10:00:04Z",
81
- toolCalls: [
82
- {
83
- id: "tc_1",
84
- name: "shell_command",
85
- args: { command: "go test ./..." } as JsonObject,
86
- result: "FAIL: TestRetry",
87
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
88
- startedAt: "2026-08-20T10:00:05Z",
89
- completedAt: "2026-08-20T10:00:07Z",
90
- },
91
- ],
92
- },
93
- {
94
- type: MessageType.MESSAGE_AI,
95
- content: "",
96
- timestamp: "2026-08-20T10:00:10Z",
97
- toolCalls: [
98
- {
99
- id: "tc_2",
100
- name: "read_file",
101
- args: { path: "retry.go" } as JsonObject,
102
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
103
- outputRef: {
104
- storageKey: "artifacts/aex_01a/toolcalls/tc_2.txt",
105
- sizeBytes: 2048n,
106
- mimeType: "text/plain",
107
- truncatedPreview: "package retry…",
108
- },
109
- },
110
- {
111
- id: "tc_3",
112
- name: "screenshot",
113
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
114
- outputRef: {
115
- storageKey: "artifacts/aex_01a/toolcalls/tc_3.png",
116
- sizeBytes: 4096n,
117
- mimeType: "image/png",
118
- isImage: true,
119
- },
120
- },
121
- ],
122
- },
123
- {
124
- type: MessageType.MESSAGE_SYSTEM,
125
- content: "Approval received",
126
- timestamp: "2026-08-20T10:00:20Z",
127
- },
128
- ],
129
- },
130
- });
131
- }
132
-
133
- /** Superseded by exec3's edit-and-resubmit — excluded by default. */
134
- function exec2(): AgentExecution {
135
- return create(AgentExecutionSchema, {
136
- metadata: { id: "aex_01b" },
137
- spec: { sessionId: "ses_01", message: "old prompt" },
138
- status: { phase: ExecutionPhase.EXECUTION_COMPLETED },
139
- });
140
- }
141
-
142
- /** Turn 2: edit-and-resubmit successor with a sub-agent delegation. */
143
- function exec3(): AgentExecution {
144
- return create(AgentExecutionSchema, {
145
- metadata: { id: "aex_01c" },
146
- spec: {
147
- sessionId: "ses_01",
148
- message: "edited prompt",
149
- supersedesExecutionId: "aex_01b",
150
- },
151
- status: {
152
- phase: ExecutionPhase.EXECUTION_COMPLETED,
153
- startedAt: "2026-08-20T11:00:00Z",
154
- messages: [
155
- {
156
- type: MessageType.MESSAGE_AI,
157
- content: "Delegating.",
158
- toolCalls: [
159
- {
160
- id: "tc_sa",
161
- name: "task",
162
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
163
- },
164
- ],
165
- },
166
- ],
167
- subAgentExecutions: [
168
- {
169
- id: "tc_sa",
170
- name: "explore",
171
- subject: "Explore the repo",
172
- input: "find tests",
173
- output: "found 3",
174
- startedAt: "2026-08-20T11:00:01Z",
175
- completedAt: "2026-08-20T11:00:06Z",
176
- messages: [
177
- {
178
- type: MessageType.MESSAGE_AI,
179
- content: "Scanning.",
180
- toolCalls: [
181
- {
182
- id: "tc_sa_1",
183
- name: "grep",
184
- result: "3 matches",
185
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
186
- outputRef: {
187
- // Sub-agent outputs are stored under the PARENT
188
- // execution's id — the storage key is the record of it.
189
- storageKey: "artifacts/aex_01c/toolcalls/tc_sa_1.txt",
190
- sizeBytes: 64n,
191
- mimeType: "text/plain",
192
- truncatedPreview: "3 matches…",
193
- },
194
- },
195
- ],
196
- },
197
- ],
198
- },
199
- ],
200
- },
201
- });
202
- }
203
-
204
- /** Turn 3: an in-flight Build-from-plan turn. */
205
- function exec4(): AgentExecution {
206
- return create(AgentExecutionSchema, {
207
- metadata: { id: "aex_01d" },
208
- spec: {
209
- sessionId: "ses_01",
210
- message: "Build from plan",
211
- executionConfig: { buildFromPlan: true },
212
- },
213
- status: {
214
- phase: ExecutionPhase.EXECUTION_IN_PROGRESS,
215
- startedAt: "2026-08-20T12:00:00Z",
216
- messages: [{ type: MessageType.MESSAGE_AI, content: "Working on it." }],
217
- },
218
- });
219
- }
220
-
221
- function allExecutions(): AgentExecution[] {
222
- // Deliberately scrambled: assembly must restore ULID order.
223
- return [exec3(), exec1(), exec4(), exec2()];
224
- }
225
-
226
- const RESOLVED: Record<string, ResolvedToolOutput> = {
227
- "artifacts/aex_01a/toolcalls/tc_2.txt": {
228
- storageKey: "artifacts/aex_01a/toolcalls/tc_2.txt",
229
- content: "package retry\n\nfunc Do() {}",
230
- truncated: false,
231
- totalSizeBytes: 2048,
232
- mimeType: "text/plain",
233
- isImage: false,
234
- },
235
- "artifacts/aex_01a/toolcalls/tc_3.png": {
236
- storageKey: "artifacts/aex_01a/toolcalls/tc_3.png",
237
- truncated: false,
238
- totalSizeBytes: 4096,
239
- mimeType: "image/png",
240
- isImage: true,
241
- },
242
- "artifacts/aex_01c/toolcalls/tc_sa_1.txt": {
243
- storageKey: "artifacts/aex_01c/toolcalls/tc_sa_1.txt",
244
- content: "3 matches in test/",
245
- truncated: false,
246
- totalSizeBytes: 64,
247
- mimeType: "text/plain",
248
- isImage: false,
249
- },
250
- };
251
-
252
- // ---------------------------------------------------------------------------
253
- // Assembly
254
- // ---------------------------------------------------------------------------
255
-
256
- describe("assembleSessionTranscript", () => {
257
- it("orders turns chronologically by ULID regardless of input order", () => {
258
- const t = assembleSessionTranscript(session(), allExecutions());
259
- expect(t.turns.map((x) => x.execution.metadata?.id)).toEqual([
260
- "aex_01a",
261
- "aex_01c",
262
- "aex_01d",
263
- ]);
264
- });
265
-
266
- it("excludes superseded turns by default, matching the conversation view", () => {
267
- const t = assembleSessionTranscript(session(), allExecutions());
268
- expect(
269
- t.turns.some((x) => x.execution.metadata?.id === "aex_01b"),
270
- ).toBe(false);
271
- expect(t.includesSuperseded).toBe(false);
272
- });
273
-
274
- it("keeps superseded turns, marked, when includeSuperseded is set", () => {
275
- const t = assembleSessionTranscript(session(), allExecutions(), {
276
- includeSuperseded: true,
277
- });
278
- const ids = t.turns.map((x) => x.execution.metadata?.id);
279
- expect(ids).toEqual(["aex_01a", "aex_01b", "aex_01c", "aex_01d"]);
280
- expect(t.turns.map((x) => x.superseded)).toEqual([
281
- false,
282
- true,
283
- false,
284
- false,
285
- ]);
286
- });
287
-
288
- it("synthesizes user prompts by the shared rule", () => {
289
- const t = assembleSessionTranscript(session(), allExecutions());
290
- expect(t.turns[0].userPrompt).toBe("Why is CI red?");
291
- // Build-from-plan: machine label, no user prose.
292
- expect(t.turns[2].userPrompt).toBeNull();
293
- expect(t.turns[2].isBuildFromPlan).toBe(true);
294
- });
295
-
296
- it("suppresses the 'execute' placeholder prompt", () => {
297
- const exec = create(AgentExecutionSchema, {
298
- metadata: { id: "aex_x" },
299
- spec: { sessionId: "ses_01", message: "execute" },
300
- status: { phase: ExecutionPhase.EXECUTION_COMPLETED },
301
- });
302
- const t = assembleSessionTranscript(session(), [exec]);
303
- expect(t.turns[0].userPrompt).toBeNull();
304
- expect(t.turns[0].isBuildFromPlan).toBe(false);
305
- });
306
-
307
- it("marks non-terminal executions in progress", () => {
308
- const t = assembleSessionTranscript(session(), allExecutions());
309
- expect(t.turns.map((x) => x.inProgress)).toEqual([false, false, true]);
310
- });
311
- });
312
-
313
- // ---------------------------------------------------------------------------
314
- // Offload resolution
315
- // ---------------------------------------------------------------------------
316
-
317
- type ContentByKey = Record<
318
- string,
319
- { content: string; truncated?: boolean; totalSizeBytes?: number } | Error
320
- >;
321
-
322
- function fakeArtifactClient(contentByKey: ContentByKey) {
323
- const requests: GetArtifactContentRequest[] = [];
324
- return {
325
- requests,
326
- client: {
327
- agentExecution: {
328
- listBySession: () => Promise.reject(new Error("not under test")),
329
- getArtifactContent: (input: GetArtifactContentRequest) => {
330
- requests.push(input);
331
- const entry = contentByKey[input.storageKey];
332
- if (entry === undefined) {
333
- return Promise.reject(new Error(`no such key: ${input.storageKey}`));
334
- }
335
- if (entry instanceof Error) return Promise.reject(entry);
336
- return Promise.resolve(
337
- create(GetArtifactContentResponseSchema, {
338
- content: new TextEncoder().encode(entry.content),
339
- truncated: entry.truncated ?? false,
340
- totalSizeBytes: BigInt(entry.totalSizeBytes ?? entry.content.length),
341
- }),
342
- );
343
- },
344
- },
345
- },
346
- };
347
- }
348
-
349
- describe("resolveOffloadedOutputs", () => {
350
- it("resolves parent and sub-agent refs, deriving each execution id from the storage key", async () => {
351
- const { client, requests } = fakeArtifactClient({
352
- "artifacts/aex_01a/toolcalls/tc_2.txt": { content: "full file" },
353
- "artifacts/aex_01c/toolcalls/tc_sa_1.txt": { content: "3 matches in test/" },
354
- });
355
- const resolved = await resolveOffloadedOutputs(client, allExecutions());
356
-
357
- expect(resolved["artifacts/aex_01a/toolcalls/tc_2.txt"].content).toBe(
358
- "full file",
359
- );
360
- // The sub-agent's ref (nested in exec3's sub_agent_executions) resolved
361
- // under the PARENT execution's id, taken from the key itself.
362
- const subAgentRequest = requests.find(
363
- (r) => r.storageKey === "artifacts/aex_01c/toolcalls/tc_sa_1.txt",
364
- );
365
- expect(subAgentRequest?.executionId).toBe("aex_01c");
366
- });
367
-
368
- it("never fetches image refs, but records them for the serializers", async () => {
369
- const { client, requests } = fakeArtifactClient({
370
- "artifacts/aex_01a/toolcalls/tc_2.txt": { content: "full file" },
371
- "artifacts/aex_01c/toolcalls/tc_sa_1.txt": { content: "x" },
372
- });
373
- const resolved = await resolveOffloadedOutputs(client, allExecutions());
374
-
375
- const imageKey = "artifacts/aex_01a/toolcalls/tc_3.png";
376
- expect(requests.some((r) => r.storageKey === imageKey)).toBe(false);
377
- expect(resolved[imageKey]).toMatchObject({
378
- isImage: true,
379
- mimeType: "image/png",
380
- totalSizeBytes: 4096,
381
- });
382
- });
383
-
384
- it("tolerates individual fetch failures — the rest still resolve", async () => {
385
- const { client } = fakeArtifactClient({
386
- "artifacts/aex_01a/toolcalls/tc_2.txt": new Error("storage unavailable"),
387
- "artifacts/aex_01c/toolcalls/tc_sa_1.txt": { content: "3 matches in test/" },
388
- });
389
- const resolved = await resolveOffloadedOutputs(client, allExecutions());
390
-
391
- expect(resolved["artifacts/aex_01a/toolcalls/tc_2.txt"].error).toBe(
392
- "storage unavailable",
393
- );
394
- expect(resolved["artifacts/aex_01a/toolcalls/tc_2.txt"].content).toBeUndefined();
395
- expect(
396
- resolved["artifacts/aex_01c/toolcalls/tc_sa_1.txt"].content,
397
- ).toBe("3 matches in test/");
398
- });
399
-
400
- it("carries the server's truncation flag and true size", async () => {
401
- const { client } = fakeArtifactClient({
402
- "artifacts/aex_01a/toolcalls/tc_2.txt": {
403
- content: "first half…",
404
- truncated: true,
405
- totalSizeBytes: 1048576,
406
- },
407
- "artifacts/aex_01c/toolcalls/tc_sa_1.txt": { content: "x" },
408
- });
409
- const resolved = await resolveOffloadedOutputs(client, allExecutions());
410
- expect(resolved["artifacts/aex_01a/toolcalls/tc_2.txt"]).toMatchObject({
411
- truncated: true,
412
- totalSizeBytes: 1048576,
413
- });
414
- });
415
-
416
- it("holds at most `concurrency` fetches in flight and still resolves every ref", async () => {
417
- // Six text refs on one execution, a pool of two. The fake parks every
418
- // fetch on a deferred so the in-flight count is observable, then releases
419
- // them one at a time; the pool must never exceed two and must drain all six.
420
- const keys = Array.from({ length: 6 }, (_, i) => `artifacts/aex_pool/toolcalls/tc_${i}.txt`);
421
- const execution = create(AgentExecutionSchema, {
422
- metadata: { id: "aex_pool" },
423
- status: {
424
- messages: [
425
- {
426
- type: MessageType.MESSAGE_AI,
427
- toolCalls: keys.map((storageKey, i) => ({
428
- id: `tc_${i}`,
429
- name: "read_file",
430
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
431
- outputRef: { storageKey, mimeType: "text/plain" },
432
- })),
433
- },
434
- ],
435
- },
436
- });
437
-
438
- const releases: Array<() => void> = [];
439
- let inFlight = 0;
440
- let maxInFlight = 0;
441
- const client = {
442
- agentExecution: {
443
- listBySession: () => Promise.reject(new Error("not under test")),
444
- getArtifactContent: (input: GetArtifactContentRequest) => {
445
- inFlight++;
446
- maxInFlight = Math.max(maxInFlight, inFlight);
447
- return new Promise<GetArtifactContentResponse>((resolveFetch) => {
448
- releases.push(() => {
449
- inFlight--;
450
- resolveFetch(
451
- create(GetArtifactContentResponseSchema, {
452
- content: new TextEncoder().encode(input.storageKey),
453
- }),
454
- );
455
- });
456
- });
457
- },
458
- },
459
- };
460
-
461
- const resolving = resolveOffloadedOutputs(client, [execution], { concurrency: 2 });
462
- // Release the six fetches one at a time. A macrotask boundary between
463
- // releases lets the pool's microtask chain run to its next fetch, so the
464
- // observation is deterministic: no timers, no races.
465
- let released = 0;
466
- while (released < keys.length) {
467
- const release = releases.shift();
468
- if (release) {
469
- release();
470
- released++;
471
- } else {
472
- await new Promise((tick) => setTimeout(tick, 0));
473
- }
474
- }
475
- const resolved = await resolving;
476
-
477
- // Exactly two: never more (the bound holds) and never fewer (the pool is
478
- // genuinely parallel, not a serial loop wearing a `concurrency` option).
479
- expect(maxInFlight).toBe(2);
480
- for (const key of keys) {
481
- expect(resolved[key].content).toBe(key);
482
- }
483
- });
484
- });
485
-
486
- // ---------------------------------------------------------------------------
487
- // Fetch
488
- // ---------------------------------------------------------------------------
489
-
490
- describe("fetchSessionTranscript", () => {
491
- function fakeClient(overrides?: { totalPages?: number }) {
492
- const artifacts = fakeArtifactClient({
493
- "artifacts/aex_01a/toolcalls/tc_2.txt": { content: "full file" },
494
- "artifacts/aex_01c/toolcalls/tc_sa_1.txt": { content: "3 matches" },
495
- });
496
- return {
497
- session: { get: (id: string) => Promise.resolve(session()) },
498
- agentExecution: {
499
- ...artifacts.client.agentExecution,
500
- listBySession: () =>
501
- Promise.resolve(
502
- create(AgentExecutionListSchema, {
503
- totalPages: overrides?.totalPages ?? 1,
504
- entries: allExecutions(),
505
- }),
506
- ),
507
- },
508
- };
509
- }
510
-
511
- it("assembles the full transcript with outputs resolved", async () => {
512
- const t = await fetchSessionTranscript(fakeClient(), "ses_01");
513
- expect(t.turns).toHaveLength(3);
514
- expect(
515
- t.resolvedOutputs["artifacts/aex_01a/toolcalls/tc_2.txt"].content,
516
- ).toBe("full file");
517
- });
518
-
519
- it("skips output resolution when disabled", async () => {
520
- const t = await fetchSessionTranscript(fakeClient(), "ses_01", {
521
- resolveOutputs: false,
522
- });
523
- expect(Object.keys(t.resolvedOutputs)).toHaveLength(0);
524
- });
525
-
526
- it("refuses to export a silently truncated conversation if the server ever paginates", async () => {
527
- await expect(
528
- fetchSessionTranscript(fakeClient({ totalPages: 2 }), "ses_01"),
529
- ).rejects.toThrow(/2 pages .* single page/s);
530
- });
531
- });
532
-
533
- // ---------------------------------------------------------------------------
534
- // Markdown
535
- // ---------------------------------------------------------------------------
536
-
537
- describe("transcriptToMarkdown", () => {
538
- it("matches the pinned format contract (transcript.golden.md)", () => {
539
- const t = assembleSessionTranscript(session(), allExecutions(), {
540
- resolvedOutputs: RESOLVED,
541
- });
542
- const goldenPath = resolve(here, "transcript.golden.md");
543
- const actual = transcriptToMarkdown(t);
544
- if (process.env.UPDATE_TRANSCRIPT_GOLDEN) {
545
- writeFileSync(goldenPath, actual);
546
- }
547
- expect(actual).toBe(readFileSync(goldenPath, "utf8"));
548
- });
549
-
550
- it("stamps the export time only when provided", () => {
551
- const t = assembleSessionTranscript(session(), [exec1()]);
552
- expect(transcriptToMarkdown(t)).not.toContain("Exported:");
553
- expect(
554
- transcriptToMarkdown(t, { generatedAt: "2026-08-22T06:00:00Z" }),
555
- ).toContain("- Exported: 2026-08-22T06:00:00Z");
556
- });
557
-
558
- it("falls back to the ref's preview, with an honest note, when an output is unresolved", () => {
559
- const t = assembleSessionTranscript(session(), [exec1()]);
560
- const md = transcriptToMarkdown(t);
561
- expect(md).toContain("_Offloaded output not resolved — showing preview._");
562
- expect(md).toContain("package retry…");
563
- });
564
-
565
- it("notes the fetch failure when resolution was attempted and failed", () => {
566
- const t = assembleSessionTranscript(session(), [exec1()], {
567
- resolvedOutputs: {
568
- "artifacts/aex_01a/toolcalls/tc_2.txt": {
569
- storageKey: "artifacts/aex_01a/toolcalls/tc_2.txt",
570
- truncated: false,
571
- mimeType: "text/plain",
572
- isImage: false,
573
- error: "storage unavailable",
574
- },
575
- },
576
- });
577
- expect(transcriptToMarkdown(t)).toContain(
578
- "_Offloaded output unavailable (storage unavailable) — showing preview._",
579
- );
580
- });
581
-
582
- it("marks server-truncated outputs with the byte counts", () => {
583
- const t = assembleSessionTranscript(session(), [exec1()], {
584
- resolvedOutputs: {
585
- "artifacts/aex_01a/toolcalls/tc_2.txt": {
586
- storageKey: "artifacts/aex_01a/toolcalls/tc_2.txt",
587
- content: "0123456789",
588
- truncated: true,
589
- totalSizeBytes: 1048576,
590
- mimeType: "text/plain",
591
- isImage: false,
592
- },
593
- },
594
- });
595
- expect(transcriptToMarkdown(t)).toContain(
596
- "_Output truncated at 10 of 1048576 bytes (server content cap)._",
597
- );
598
- });
599
-
600
- it("sizes fences past backtick runs in the content", () => {
601
- const exec = create(AgentExecutionSchema, {
602
- metadata: { id: "aex_x" },
603
- spec: { sessionId: "ses_01", message: "prompt" },
604
- status: {
605
- phase: ExecutionPhase.EXECUTION_COMPLETED,
606
- messages: [
607
- {
608
- type: MessageType.MESSAGE_AI,
609
- content: "",
610
- toolCalls: [
611
- {
612
- id: "tc",
613
- name: "shell_command",
614
- result: "a fence: ```md\ninside\n```",
615
- status: ToolCallStatus.TOOL_CALL_COMPLETED,
616
- },
617
- ],
618
- },
619
- ],
620
- },
621
- });
622
- const md = transcriptToMarkdown(
623
- assembleSessionTranscript(session(), [exec]),
624
- );
625
- expect(md).toContain("````\na fence: ```md\ninside\n```\n````");
626
- });
627
-
628
- it("marks kept superseded turns", () => {
629
- const t = assembleSessionTranscript(session(), allExecutions(), {
630
- includeSuperseded: true,
631
- });
632
- const md = transcriptToMarkdown(t);
633
- expect(md).toContain("- Includes superseded (edited-and-resubmitted) turns");
634
- expect(md).toContain("_Superseded by an edited resubmission._");
635
- expect(md).toContain("old prompt");
636
- });
637
- });
638
-
639
- // ---------------------------------------------------------------------------
640
- // JSON
641
- // ---------------------------------------------------------------------------
642
-
643
- describe("transcriptToJson", () => {
644
- it("is JSON.stringify-safe despite bigint proto fields (protojson contract)", () => {
645
- const t = assembleSessionTranscript(session(), allExecutions(), {
646
- resolvedOutputs: RESOLVED,
647
- });
648
- // sizeBytes is int64 → bigint on the proto; a raw stringify of the
649
- // transcript would throw. The projection must not.
650
- const text = JSON.stringify(transcriptToJson(t), null, 2);
651
- const parsed = JSON.parse(text);
652
- expect(parsed.format).toBe("stigmer.ai/session-transcript/v1");
653
- expect(parsed.session.metadata.id).toBe("ses_01");
654
- expect(parsed.turns).toHaveLength(3);
655
- // protojson: snake_case field names, int64 as string.
656
- expect(
657
- parsed.turns[0].execution.status.messages[3].tool_calls[0].output_ref
658
- .size_bytes,
659
- ).toBe("2048");
660
- });
661
-
662
- it("carries the canonical-rule verdicts per turn", () => {
663
- const t = assembleSessionTranscript(session(), allExecutions(), {
664
- includeSuperseded: true,
665
- });
666
- const parsed = JSON.parse(JSON.stringify(transcriptToJson(t)));
667
- expect(parsed.includes_superseded).toBe(true);
668
- expect(parsed.turns[0].user_prompt).toBe("Why is CI red?");
669
- expect(parsed.turns[1].superseded).toBe(true);
670
- expect(parsed.turns[3].build_from_plan).toBe(true);
671
- expect(parsed.turns[3].in_progress).toBe(true);
672
- });
673
-
674
- it("strips the internal Temporal callback token from execution status", () => {
675
- const exec = exec1();
676
- exec.status!.callbackToken = new TextEncoder().encode("task-token");
677
- const t = assembleSessionTranscript(session(), [exec]);
678
- const parsed = JSON.parse(JSON.stringify(transcriptToJson(t)));
679
- expect(parsed.turns[0].execution.status.callback_token).toBeUndefined();
680
- // The strip is surgical — the rest of status is intact.
681
- expect(parsed.turns[0].execution.status.messages).toHaveLength(5);
682
- });
683
-
684
- it("keys resolved outputs by storage key with plain-JSON fields", () => {
685
- const t = assembleSessionTranscript(session(), allExecutions(), {
686
- resolvedOutputs: RESOLVED,
687
- });
688
- const parsed = JSON.parse(JSON.stringify(transcriptToJson(t)));
689
- expect(
690
- parsed.resolved_outputs["artifacts/aex_01a/toolcalls/tc_2.txt"],
691
- ).toMatchObject({
692
- content: "package retry\n\nfunc Do() {}",
693
- mime_type: "text/plain",
694
- total_size_bytes: 2048,
695
- });
696
- });
697
- });