@namzu/sdk 0.2.0 → 0.3.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 (297) hide show
  1. package/CHANGELOG.md +53 -2
  2. package/dist/agents/ReactiveAgent.d.ts.map +1 -1
  3. package/dist/agents/ReactiveAgent.js +3 -2
  4. package/dist/agents/ReactiveAgent.js.map +1 -1
  5. package/dist/agents/SupervisorAgent.d.ts.map +1 -1
  6. package/dist/agents/SupervisorAgent.js +5 -2
  7. package/dist/agents/SupervisorAgent.js.map +1 -1
  8. package/dist/bridge/a2a/index.d.ts +1 -1
  9. package/dist/bridge/a2a/index.d.ts.map +1 -1
  10. package/dist/bridge/a2a/index.js +1 -1
  11. package/dist/bridge/a2a/index.js.map +1 -1
  12. package/dist/bridge/a2a/message.d.ts +0 -2
  13. package/dist/bridge/a2a/message.d.ts.map +1 -1
  14. package/dist/bridge/a2a/message.js +0 -26
  15. package/dist/bridge/a2a/message.js.map +1 -1
  16. package/dist/bridge/a2a/task.d.ts +4 -3
  17. package/dist/bridge/a2a/task.d.ts.map +1 -1
  18. package/dist/bridge/a2a/task.js +4 -4
  19. package/dist/bridge/a2a/task.js.map +1 -1
  20. package/dist/contracts/api.d.ts +6 -38
  21. package/dist/contracts/api.d.ts.map +1 -1
  22. package/dist/contracts/ids.d.ts +1 -1
  23. package/dist/contracts/ids.d.ts.map +1 -1
  24. package/dist/contracts/index.d.ts +3 -5
  25. package/dist/contracts/index.d.ts.map +1 -1
  26. package/dist/contracts/index.js +1 -1
  27. package/dist/contracts/index.js.map +1 -1
  28. package/dist/contracts/schemas.d.ts +1 -31
  29. package/dist/contracts/schemas.d.ts.map +1 -1
  30. package/dist/contracts/schemas.js +1 -7
  31. package/dist/contracts/schemas.js.map +1 -1
  32. package/dist/index.d.ts +2 -3
  33. package/dist/index.d.ts.map +1 -1
  34. package/dist/index.js +2 -3
  35. package/dist/index.js.map +1 -1
  36. package/dist/manager/agent/__tests__/lifecycle.test.js +27 -13
  37. package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -1
  38. package/dist/manager/agent/lifecycle.d.ts +9 -0
  39. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  40. package/dist/manager/agent/lifecycle.js +93 -31
  41. package/dist/manager/agent/lifecycle.js.map +1 -1
  42. package/dist/manager/index.d.ts +2 -0
  43. package/dist/manager/index.d.ts.map +1 -1
  44. package/dist/manager/index.js +1 -0
  45. package/dist/manager/index.js.map +1 -1
  46. package/dist/manager/run/persistence.d.ts +3 -1
  47. package/dist/manager/run/persistence.d.ts.map +1 -1
  48. package/dist/manager/run/persistence.js +5 -0
  49. package/dist/manager/run/persistence.js.map +1 -1
  50. package/dist/manager/thread/__tests__/lifecycle.test.d.ts +2 -0
  51. package/dist/manager/thread/__tests__/lifecycle.test.d.ts.map +1 -0
  52. package/dist/manager/thread/__tests__/lifecycle.test.js +216 -0
  53. package/dist/manager/thread/__tests__/lifecycle.test.js.map +1 -0
  54. package/dist/manager/thread/lifecycle.d.ts +105 -0
  55. package/dist/manager/thread/lifecycle.d.ts.map +1 -0
  56. package/dist/manager/thread/lifecycle.js +186 -0
  57. package/dist/manager/thread/lifecycle.js.map +1 -0
  58. package/dist/rag/retriever.js +2 -2
  59. package/dist/runtime/query/__tests__/context.test.js +8 -7
  60. package/dist/runtime/query/__tests__/context.test.js.map +1 -1
  61. package/dist/runtime/query/context-cache.d.ts +3 -3
  62. package/dist/runtime/query/context-cache.d.ts.map +1 -1
  63. package/dist/runtime/query/context-cache.js +2 -2
  64. package/dist/runtime/query/context-cache.js.map +1 -1
  65. package/dist/runtime/query/context.d.ts +12 -21
  66. package/dist/runtime/query/context.d.ts.map +1 -1
  67. package/dist/runtime/query/context.js +3 -1
  68. package/dist/runtime/query/context.js.map +1 -1
  69. package/dist/runtime/query/index.d.ts +13 -15
  70. package/dist/runtime/query/index.d.ts.map +1 -1
  71. package/dist/runtime/query/index.js +1 -0
  72. package/dist/runtime/query/index.js.map +1 -1
  73. package/dist/session/__tests__/integration/_fixtures.d.ts +11 -4
  74. package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -1
  75. package/dist/session/__tests__/integration/_fixtures.js +23 -6
  76. package/dist/session/__tests__/integration/_fixtures.js.map +1 -1
  77. package/dist/session/__tests__/integration/archive-gate.test.d.ts +15 -0
  78. package/dist/session/__tests__/integration/archive-gate.test.d.ts.map +1 -0
  79. package/dist/session/__tests__/integration/archive-gate.test.js +214 -0
  80. package/dist/session/__tests__/integration/archive-gate.test.js.map +1 -0
  81. package/dist/session/__tests__/integration/capacity-caps.test.js +13 -6
  82. package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -1
  83. package/dist/session/__tests__/integration/e2e-spawn.test.js +14 -2
  84. package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -1
  85. package/dist/session/__tests__/integration/event-stream-ordering.test.js +14 -7
  86. package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -1
  87. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +26 -14
  88. package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -1
  89. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +30 -20
  90. package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -1
  91. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +25 -9
  92. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -1
  93. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +11 -10
  94. package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -1
  95. package/dist/session/__tests__/integration/prev-artifact-dag.test.js +5 -4
  96. package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -1
  97. package/dist/session/__tests__/integration/retention-archive.test.js +3 -2
  98. package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -1
  99. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts +26 -0
  100. package/dist/session/__tests__/integration/spawn-rollback.test.d.ts.map +1 -0
  101. package/dist/session/__tests__/integration/spawn-rollback.test.js +236 -0
  102. package/dist/session/__tests__/integration/spawn-rollback.test.js.map +1 -0
  103. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +2 -1
  104. package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -1
  105. package/dist/session/__tests__/integration/tenant-isolation.test.js +14 -5
  106. package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -1
  107. package/dist/session/errors.d.ts +79 -0
  108. package/dist/session/errors.d.ts.map +1 -1
  109. package/dist/session/errors.js +57 -0
  110. package/dist/session/errors.js.map +1 -1
  111. package/dist/session/handoff/__tests__/broadcast.test.js +49 -31
  112. package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -1
  113. package/dist/session/handoff/__tests__/capacity.test.js +21 -18
  114. package/dist/session/handoff/__tests__/capacity.test.js.map +1 -1
  115. package/dist/session/handoff/__tests__/single.test.js +39 -30
  116. package/dist/session/handoff/__tests__/single.test.js.map +1 -1
  117. package/dist/session/handoff/assignment.d.ts +13 -1
  118. package/dist/session/handoff/assignment.d.ts.map +1 -1
  119. package/dist/session/handoff/broadcast.d.ts +7 -0
  120. package/dist/session/handoff/broadcast.d.ts.map +1 -1
  121. package/dist/session/handoff/broadcast.js +16 -1
  122. package/dist/session/handoff/broadcast.js.map +1 -1
  123. package/dist/session/handoff/single.d.ts +7 -0
  124. package/dist/session/handoff/single.d.ts.map +1 -1
  125. package/dist/session/handoff/single.js +13 -1
  126. package/dist/session/handoff/single.js.map +1 -1
  127. package/dist/session/hierarchy/__tests__/session.test.js +2 -0
  128. package/dist/session/hierarchy/__tests__/session.test.js.map +1 -1
  129. package/dist/session/hierarchy/index.d.ts +1 -0
  130. package/dist/session/hierarchy/index.d.ts.map +1 -1
  131. package/dist/session/hierarchy/index.js.map +1 -1
  132. package/dist/session/hierarchy/session.d.ts +15 -3
  133. package/dist/session/hierarchy/session.d.ts.map +1 -1
  134. package/dist/session/hierarchy/session.js.map +1 -1
  135. package/dist/session/hierarchy/thread.d.ts +54 -0
  136. package/dist/session/hierarchy/thread.d.ts.map +1 -0
  137. package/dist/session/hierarchy/thread.js +2 -0
  138. package/dist/session/hierarchy/thread.js.map +1 -0
  139. package/dist/session/migration/id-prefix.d.ts +8 -13
  140. package/dist/session/migration/id-prefix.d.ts.map +1 -1
  141. package/dist/session/migration/id-prefix.js +8 -13
  142. package/dist/session/migration/id-prefix.js.map +1 -1
  143. package/dist/session/retention/__tests__/archive.test.js +3 -2
  144. package/dist/session/retention/__tests__/archive.test.js.map +1 -1
  145. package/dist/session/summary/__tests__/materialize.test.js +4 -3
  146. package/dist/session/summary/__tests__/materialize.test.js.map +1 -1
  147. package/dist/store/index.d.ts +0 -2
  148. package/dist/store/index.d.ts.map +1 -1
  149. package/dist/store/index.js +0 -1
  150. package/dist/store/index.js.map +1 -1
  151. package/dist/store/session/__tests__/disk.test.js +32 -5
  152. package/dist/store/session/__tests__/disk.test.js.map +1 -1
  153. package/dist/store/session/__tests__/memory.test.js +50 -9
  154. package/dist/store/session/__tests__/memory.test.js.map +1 -1
  155. package/dist/store/session/disk.d.ts +2 -1
  156. package/dist/store/session/disk.d.ts.map +1 -1
  157. package/dist/store/session/disk.js +61 -0
  158. package/dist/store/session/disk.js.map +1 -1
  159. package/dist/store/session/index.d.ts.map +1 -1
  160. package/dist/store/session/index.js +3 -4
  161. package/dist/store/session/index.js.map +1 -1
  162. package/dist/store/session/memory.d.ts +2 -1
  163. package/dist/store/session/memory.d.ts.map +1 -1
  164. package/dist/store/session/memory.js +13 -0
  165. package/dist/store/session/memory.js.map +1 -1
  166. package/dist/store/thread/disk.d.ts +41 -0
  167. package/dist/store/thread/disk.d.ts.map +1 -0
  168. package/dist/store/thread/disk.js +229 -0
  169. package/dist/store/thread/disk.js.map +1 -0
  170. package/dist/store/thread/index.d.ts +4 -0
  171. package/dist/store/thread/index.d.ts.map +1 -0
  172. package/dist/store/thread/index.js +6 -0
  173. package/dist/store/thread/index.js.map +1 -0
  174. package/dist/store/thread/memory.d.ts +23 -0
  175. package/dist/store/thread/memory.d.ts.map +1 -0
  176. package/dist/store/thread/memory.js +90 -0
  177. package/dist/store/thread/memory.js.map +1 -0
  178. package/dist/types/agent/base.d.ts +17 -21
  179. package/dist/types/agent/base.d.ts.map +1 -1
  180. package/dist/types/agent/factory.d.ts +8 -2
  181. package/dist/types/agent/factory.d.ts.map +1 -1
  182. package/dist/types/agent/task.d.ts +18 -11
  183. package/dist/types/agent/task.d.ts.map +1 -1
  184. package/dist/types/ids/index.d.ts +5 -9
  185. package/dist/types/ids/index.d.ts.map +1 -1
  186. package/dist/types/ids/index.js +4 -4
  187. package/dist/types/ids/index.js.map +1 -1
  188. package/dist/types/rag/retrieval.d.ts +4 -3
  189. package/dist/types/rag/retrieval.d.ts.map +1 -1
  190. package/dist/types/run/config.d.ts +6 -5
  191. package/dist/types/run/config.d.ts.map +1 -1
  192. package/dist/types/run/metadata.d.ts +5 -18
  193. package/dist/types/run/metadata.d.ts.map +1 -1
  194. package/dist/types/session/ids.d.ts +4 -13
  195. package/dist/types/session/ids.d.ts.map +1 -1
  196. package/dist/types/session/ids.js +3 -6
  197. package/dist/types/session/ids.js.map +1 -1
  198. package/dist/types/session/index.d.ts +1 -1
  199. package/dist/types/session/index.d.ts.map +1 -1
  200. package/dist/types/session/store.d.ts +32 -10
  201. package/dist/types/session/store.d.ts.map +1 -1
  202. package/dist/types/session/store.js +3 -8
  203. package/dist/types/session/store.js.map +1 -1
  204. package/dist/types/thread/index.d.ts +2 -0
  205. package/dist/types/thread/index.d.ts.map +1 -0
  206. package/dist/types/thread/index.js +5 -0
  207. package/dist/types/thread/index.js.map +1 -0
  208. package/dist/types/thread/store.d.ts +86 -0
  209. package/dist/types/thread/store.d.ts.map +1 -0
  210. package/dist/types/thread/store.js +22 -0
  211. package/dist/types/thread/store.js.map +1 -0
  212. package/dist/utils/id.d.ts +1 -12
  213. package/dist/utils/id.d.ts.map +1 -1
  214. package/dist/utils/id.js +3 -23
  215. package/dist/utils/id.js.map +1 -1
  216. package/package.json +6 -11
  217. package/src/agents/ReactiveAgent.ts +3 -2
  218. package/src/agents/SupervisorAgent.ts +5 -2
  219. package/src/bridge/a2a/index.ts +0 -1
  220. package/src/bridge/a2a/message.ts +0 -32
  221. package/src/bridge/a2a/task.ts +8 -7
  222. package/src/contracts/api.ts +6 -42
  223. package/src/contracts/ids.ts +1 -1
  224. package/src/contracts/index.ts +2 -8
  225. package/src/contracts/schemas.ts +1 -8
  226. package/src/index.ts +0 -4
  227. package/src/manager/agent/__tests__/lifecycle.test.ts +34 -13
  228. package/src/manager/agent/lifecycle.ts +114 -35
  229. package/src/manager/index.ts +3 -0
  230. package/src/manager/run/persistence.ts +7 -1
  231. package/src/manager/thread/__tests__/lifecycle.test.ts +286 -0
  232. package/src/manager/thread/lifecycle.ts +217 -0
  233. package/src/rag/retriever.ts +2 -2
  234. package/src/runtime/query/__tests__/context.test.ts +9 -8
  235. package/src/runtime/query/context-cache.ts +4 -4
  236. package/src/runtime/query/context.ts +15 -22
  237. package/src/runtime/query/index.ts +15 -16
  238. package/src/session/__tests__/integration/_fixtures.ts +36 -8
  239. package/src/session/__tests__/integration/archive-gate.test.ts +288 -0
  240. package/src/session/__tests__/integration/capacity-caps.test.ts +13 -6
  241. package/src/session/__tests__/integration/e2e-spawn.test.ts +20 -2
  242. package/src/session/__tests__/integration/event-stream-ordering.test.ts +14 -7
  243. package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +39 -13
  244. package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +54 -19
  245. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +40 -9
  246. package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +13 -10
  247. package/src/session/__tests__/integration/prev-artifact-dag.test.ts +12 -5
  248. package/src/session/__tests__/integration/retention-archive.test.ts +5 -3
  249. package/src/session/__tests__/integration/spawn-rollback.test.ts +313 -0
  250. package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +4 -2
  251. package/src/session/__tests__/integration/tenant-isolation.test.ts +16 -6
  252. package/src/session/errors.ts +89 -0
  253. package/src/session/handoff/__tests__/broadcast.test.ts +56 -28
  254. package/src/session/handoff/__tests__/capacity.test.ts +26 -20
  255. package/src/session/handoff/__tests__/single.test.ts +45 -28
  256. package/src/session/handoff/assignment.ts +13 -1
  257. package/src/session/handoff/broadcast.ts +26 -1
  258. package/src/session/handoff/single.ts +23 -1
  259. package/src/session/hierarchy/__tests__/session.test.ts +9 -1
  260. package/src/session/hierarchy/index.ts +1 -0
  261. package/src/session/hierarchy/session.ts +15 -3
  262. package/src/session/hierarchy/thread.ts +55 -0
  263. package/src/session/migration/id-prefix.ts +8 -13
  264. package/src/session/retention/__tests__/archive.test.ts +5 -3
  265. package/src/session/summary/__tests__/materialize.test.ts +6 -4
  266. package/src/store/index.ts +0 -3
  267. package/src/store/session/__tests__/disk.test.ts +57 -6
  268. package/src/store/session/__tests__/memory.test.ts +84 -9
  269. package/src/store/session/disk.ts +57 -1
  270. package/src/store/session/index.ts +3 -4
  271. package/src/store/session/memory.ts +13 -1
  272. package/src/store/thread/disk.ts +261 -0
  273. package/src/store/thread/index.ts +7 -0
  274. package/src/store/thread/memory.ts +104 -0
  275. package/src/types/agent/base.ts +17 -21
  276. package/src/types/agent/factory.ts +8 -3
  277. package/src/types/agent/task.ts +19 -11
  278. package/src/types/ids/index.ts +8 -15
  279. package/src/types/rag/retrieval.ts +4 -3
  280. package/src/types/run/config.ts +6 -5
  281. package/src/types/run/metadata.ts +5 -18
  282. package/src/types/session/ids.ts +4 -15
  283. package/src/types/session/index.ts +1 -2
  284. package/src/types/session/store.ts +34 -11
  285. package/src/types/thread/index.ts +5 -0
  286. package/src/types/thread/store.ts +92 -0
  287. package/src/utils/id.ts +3 -24
  288. package/dist/store/conversation/memory.d.ts +0 -43
  289. package/dist/store/conversation/memory.d.ts.map +0 -1
  290. package/dist/store/conversation/memory.js +0 -108
  291. package/dist/store/conversation/memory.js.map +0 -1
  292. package/dist/types/conversation/index.d.ts +0 -14
  293. package/dist/types/conversation/index.d.ts.map +0 -1
  294. package/dist/types/conversation/index.js +0 -2
  295. package/dist/types/conversation/index.js.map +0 -1
  296. package/src/store/conversation/memory.ts +0 -144
  297. package/src/types/conversation/index.ts +0 -15
@@ -0,0 +1,104 @@
1
+ /**
2
+ * InMemoryThreadStore — reference in-memory implementation of
3
+ * {@link ThreadStore}.
4
+ *
5
+ * Mirrors the write-time CAS contract of the disk store: every
6
+ * `updateThread` compares the supplied `ownerVersion` against the persisted
7
+ * copy and rejects with `StaleThreadError` on mismatch. Convention #17:
8
+ * cross-tenant access throws `TenantIsolationError` with no fallback.
9
+ */
10
+
11
+ import { StaleThreadError, TenantIsolationError } from '../../session/errors.js'
12
+ import type { Thread } from '../../session/hierarchy/thread.js'
13
+ import type { TenantId } from '../../types/ids/index.js'
14
+ import type { ProjectId, ThreadId } from '../../types/session/ids.js'
15
+ import type { CreateThreadParams, ThreadStore } from '../../types/thread/store.js'
16
+ import { generateThreadId } from '../../utils/id.js'
17
+
18
+ interface ThreadRecord {
19
+ tenantId: TenantId
20
+ thread: Thread
21
+ }
22
+
23
+ export class InMemoryThreadStore implements ThreadStore {
24
+ private readonly threads = new Map<ThreadId, ThreadRecord>()
25
+
26
+ async createThread(params: CreateThreadParams, tenantId: TenantId): Promise<Thread> {
27
+ const now = new Date()
28
+ const thread: Thread = {
29
+ id: generateThreadId(),
30
+ projectId: params.projectId,
31
+ tenantId,
32
+ title: params.title,
33
+ status: 'open',
34
+ ownerVersion: 0,
35
+ createdAt: now,
36
+ updatedAt: now,
37
+ }
38
+ this.threads.set(thread.id, { tenantId, thread })
39
+ return thread
40
+ }
41
+
42
+ async getThread(threadId: ThreadId, tenantId: TenantId): Promise<Thread | null> {
43
+ const record = this.threads.get(threadId)
44
+ if (!record) return null
45
+ this.assertTenant(record.tenantId, tenantId, `thread(${threadId})`)
46
+ return record.thread
47
+ }
48
+
49
+ async updateThread(thread: Thread, tenantId: TenantId): Promise<void> {
50
+ if (thread.tenantId !== tenantId) {
51
+ throw new TenantIsolationError({
52
+ requested: tenantId,
53
+ resource: `thread(${thread.id}) payload`,
54
+ })
55
+ }
56
+ const existing = this.threads.get(thread.id)
57
+ if (!existing) {
58
+ throw new Error(`Thread ${thread.id} not found`)
59
+ }
60
+ this.assertTenant(existing.tenantId, tenantId, `thread(${thread.id})`)
61
+
62
+ // CAS on ownerVersion — supplied version must match persisted exactly.
63
+ // Any drift means another writer already advanced the record; the caller
64
+ // must re-read + re-apply + retry.
65
+ if (thread.ownerVersion !== existing.thread.ownerVersion) {
66
+ throw new StaleThreadError({
67
+ threadId: thread.id,
68
+ expectedVersion: thread.ownerVersion,
69
+ actualVersion: existing.thread.ownerVersion,
70
+ })
71
+ }
72
+
73
+ const updated: Thread = {
74
+ ...thread,
75
+ ownerVersion: existing.thread.ownerVersion + 1,
76
+ updatedAt: new Date(),
77
+ }
78
+ this.threads.set(thread.id, { tenantId, thread: updated })
79
+ }
80
+
81
+ async deleteThread(threadId: ThreadId, tenantId: TenantId): Promise<void> {
82
+ const record = this.threads.get(threadId)
83
+ if (!record) return // Idempotent: missing = no-op.
84
+ this.assertTenant(record.tenantId, tenantId, `thread(${threadId})`)
85
+ this.threads.delete(threadId)
86
+ }
87
+
88
+ async listThreads(projectId: ProjectId, tenantId: TenantId): Promise<readonly Thread[]> {
89
+ const matches: Thread[] = []
90
+ for (const { tenantId: ownerTenant, thread } of this.threads.values()) {
91
+ if (ownerTenant !== tenantId) continue
92
+ if (thread.projectId !== projectId) continue
93
+ matches.push(thread)
94
+ }
95
+ matches.sort((a, b) => a.createdAt.getTime() - b.createdAt.getTime())
96
+ return matches
97
+ }
98
+
99
+ private assertTenant(owning: TenantId, requested: TenantId, resource: string): void {
100
+ if (owning !== requested) {
101
+ throw new TenantIsolationError({ requested, resource })
102
+ }
103
+ }
104
+ }
@@ -1,10 +1,10 @@
1
1
  import type { AgentStatus, CostInfo, TokenUsage } from '../common/index.js'
2
- import type { RunId, SessionId, TenantId, ThreadId } from '../ids/index.js'
2
+ import type { RunId, SessionId, TenantId } from '../ids/index.js'
3
3
  import type { InvocationState } from '../invocation/index.js'
4
4
  import type { Message } from '../message/index.js'
5
5
  import type { PermissionMode } from '../permission/index.js'
6
6
  import type { StopReason } from '../run/stop-reason.js'
7
- import type { ProjectId } from '../session/ids.js'
7
+ import type { ProjectId, ThreadId } from '../session/ids.js'
8
8
  import type { TaskStore } from '../task/index.js'
9
9
  import type { ToolAvailability } from '../tool/index.js'
10
10
 
@@ -24,29 +24,25 @@ export interface BaseAgentConfig {
24
24
  env?: Record<string, string>
25
25
 
26
26
  /**
27
- * @deprecated Use `projectId`. Kept as a migration-window mirror; when both
28
- * are present `projectId` wins. See session-hierarchy.md §13.1.
27
+ * Long-lived goal scope for the run. Required at runtime — agents reject
28
+ * configs missing this (`'X requires sessionId, projectId, and tenantId
29
+ * in config'`).
30
+ *
31
+ * Kept optional at the TYPE level because {@link AgentManager} stamps
32
+ * this field AFTER `configBuilder` returns (manager/agent/lifecycle.ts).
33
+ * Tightening to required is a separate task alongside
34
+ * `AgentFactoryOptions` carrying the triple.
29
35
  */
30
- threadId?: ThreadId
36
+ projectId?: ProjectId
31
37
 
32
38
  /**
33
- * Long-lived goal scope for the run. Required at runtime in 0.2.0 per
34
- * session-hierarchy.md §12.1`{@link ReactiveAgent}`, `{@link
35
- * SupervisorAgent}`, etc. reject configs missing this (`'X requires
36
- * sessionId, projectId, and tenantId in config (§12.1)'`).
37
- *
38
- * Kept optional at the TYPE level during the 0.2.x migration window
39
- * because {@link AgentManager} stamps this field AFTER `configBuilder`
40
- * returns (manager/agent/lifecycle.ts:228–230). That stamping path is
41
- * how every `@namzu/agents` configBuilder currently gets its tenant /
42
- * session / project triple; flipping the type to required without first
43
- * updating every {@link AgentFactoryOptions} consumer (which does not
44
- * carry these fields) would be a gratuitous downstream break.
45
- *
46
- * Tightening to required is Phase 9 Known Delta #6. The type-level flip
47
- * lands in 0.3.0 alongside `AgentFactoryOptions` gaining the triple.
39
+ * Topic the run belongs to. Optional at the TYPE level for the same
40
+ * reason as `projectId` — {@link AgentManager} stamps this field after
41
+ * `configBuilder` returns so `configBuilder` implementations do not
42
+ * need to be updated before this tightens. Tightening to required
43
+ * lands with the `AgentFactoryOptions` triple refactor.
48
44
  */
49
- projectId?: ProjectId
45
+ threadId?: ThreadId
50
46
 
51
47
  /** Session under which the run executes. See `projectId` for the tightening plan. */
52
48
  sessionId?: SessionId
@@ -14,7 +14,14 @@ export interface AgentDefinition {
14
14
  }
15
15
 
16
16
  export interface AgentFactoryOptions {
17
- apiKey: string
17
+ /**
18
+ * API key for providers that authenticate via key (OpenAI, Anthropic,
19
+ * OpenRouter). Optional because BYO-provider flows (Bedrock IAM, custom
20
+ * `ProviderRegistry.create(...)`) resolve credentials outside this object.
21
+ * `configBuilder` implementations should treat an absent `apiKey` as the
22
+ * BYO signal and use the provider passed via the agent config instead.
23
+ */
24
+ apiKey?: string
18
25
  model?: string
19
26
  workingDirectory?: string
20
27
  tokenBudget?: number
@@ -39,8 +46,6 @@ export interface AgentFactoryOptions {
39
46
 
40
47
  taskRouter?: TaskRouterConfig
41
48
 
42
- threadId?: string
43
-
44
49
  runId?: string
45
50
 
46
51
  parentRunId?: string
@@ -4,7 +4,7 @@ import type { TokenUsage } from '../common/index.js'
4
4
  import type { RunId, SessionId, TaskId, TenantId } from '../ids/index.js'
5
5
  import type { Message } from '../message/index.js'
6
6
  import type { RunEventListener } from '../run/events.js'
7
- import type { ProjectId } from '../session/ids.js'
7
+ import type { ProjectId, ThreadId } from '../session/ids.js'
8
8
  import type { AgentInput, BaseAgentConfig, BaseAgentResult } from './base.js'
9
9
  import type { Agent } from './core.js'
10
10
  import type { AgentFactoryOptions } from './factory.js'
@@ -23,15 +23,10 @@ export function isTerminalAgentTaskState(state: AgentTaskState): boolean {
23
23
  }
24
24
 
25
25
  /**
26
- * Context carried into {@link AgentManager.sendMessage}. Phase 6 promotes
27
- * `tenantId`, `sessionId`, `projectId`, and `parentActor` to required fields
28
- * the spawn path is the ingress point for the session hierarchy; callers must
29
- * provide the full scoping set (session-hierarchy.md §12.1 required-callsite
30
- * matrix).
31
- *
32
- * `threadId` was removed — `projectId` owns the root scope. The deprecated
33
- * alias `type ThreadId = ProjectId` still compiles for consumers transitioning
34
- * off the name, but the shape no longer exposes a separate slot.
26
+ * Context carried into {@link AgentManager.sendMessage}. `tenantId`,
27
+ * `threadId`, `sessionId`, `projectId`, and `parentActor` are required —
28
+ * the spawn path is the ingress point for the session hierarchy; callers
29
+ * must provide the full scoping set.
35
30
  */
36
31
  export interface AgentTaskContext {
37
32
  parentRunId: RunId
@@ -49,13 +44,26 @@ export interface AgentTaskContext {
49
44
  /** Isolation boundary. Required per session-hierarchy.md §12.1. */
50
45
  tenantId: TenantId
51
46
 
47
+ /**
48
+ * Topic the current task belongs to. Required in 0.3.0 — spawn copies
49
+ * this onto the child session without a second ThreadStore round-trip,
50
+ * and gates creation on {@link ThreadManager.requireOpen}. Children
51
+ * inherit the parent's `threadId` verbatim; cross-thread spawn is
52
+ * forbidden by design (a delegated sub-agent stays on the same topic).
53
+ */
54
+ threadId: ThreadId
55
+
52
56
  /**
53
57
  * Parent session under which any sub-agent spawn is recorded. Required
54
58
  * in 0.2.0; a spawn cannot be attributed without it.
55
59
  */
56
60
  sessionId: SessionId
57
61
 
58
- /** Long-lived goal scope (replaces `threadId`). Required. */
62
+ /**
63
+ * Long-lived goal scope. Required. Denormalized from the owning Thread
64
+ * (see {@link Thread}) — structurally immutable per Phase 2.4 decision
65
+ * (sessions never cross threads, threads never cross projects).
66
+ */
59
67
  projectId: ProjectId
60
68
 
61
69
  /**
@@ -38,29 +38,22 @@ export type MemoryStoreRef = `mms_${string}`
38
38
  export type VaultRef = `vlt_${string}`
39
39
  export type KnowledgeBaseRef = `kbs_${string}`
40
40
 
41
- // Session hierarchy IDs live canonically here (Phase 9 Known Delta #4
42
- // collapse: previously split across `types/ids/` and `types/session/ids.ts`
43
- // with a circular re-export). Convention #2 branded IDs; prefixes mandated
44
- // by session-hierarchy.md §4. The `types/session/ids.ts` barrel re-exports
45
- // these for co-location ergonomics.
41
+ // Session hierarchy IDs. Convention #2 branded IDs; prefixes mandated by the
42
+ // five-layer hierarchy (Project Thread Session → SubSession → Run). The
43
+ // `types/session/ids.ts` barrel re-exports these for co-location ergonomics.
46
44
  export type ProjectId = `prj_${string}`
45
+ export type ThreadId = `thd_${string}`
47
46
  export type SubSessionId = `sub_${string}`
48
47
  export type HandoffId = `hof_${string}`
49
48
  export type WorkspaceId = `wsp_${string}`
50
49
  export type SummaryId = `sum_${string}`
51
50
  export type DeliverableId = `del_${string}`
52
51
 
53
- /**
54
- * @deprecated Use {@link ProjectId}. Alias retained for the 0.2.x migration
55
- * window; will be removed in 0.3.0. See session-hierarchy.md §13.3.1.
56
- */
57
- export type ThreadId = ProjectId
58
-
59
52
  /**
60
53
  * Sentinel {@link TenantId} for legacy pre-0.2.0 runs rehomed by the
61
- * boot-time filesystem migration (session-hierarchy.md §13.4.1). Consumers
62
- * with strict tenant enforcement should either tag these records on first
63
- * access or reject them until a real tenant is assigned — the kernel
64
- * surfaces the sentinel but does not prescribe policy (Convention #17).
54
+ * boot-time filesystem migration. Consumers with strict tenant enforcement
55
+ * should either tag these records on first access or reject them until a
56
+ * real tenant is assigned — the kernel surfaces the sentinel but does not
57
+ * prescribe policy (Convention #17).
65
58
  */
66
59
  export const UNKNOWN_TENANT_ID = 'tnt_unknown_legacy' as TenantId
@@ -1,4 +1,5 @@
1
- import type { KnowledgeBaseId, ThreadId } from '../ids/index.js'
1
+ import type { KnowledgeBaseId } from '../ids/index.js'
2
+ import type { ProjectId } from '../session/ids.js'
2
3
  import type { TenantScope } from './scope.js'
3
4
  import type { VectorSearchResult } from './vector.js'
4
5
 
@@ -13,8 +14,8 @@ export interface RetrievalConfig {
13
14
 
14
15
  export interface RetrievalQuery {
15
16
  text: string
16
- threadId?: ThreadId
17
- threadMessages?: string[]
17
+ projectId?: ProjectId
18
+ recentMessages?: string[]
18
19
  config?: Partial<RetrievalConfig>
19
20
  }
20
21
 
@@ -2,7 +2,7 @@ import type { ModelPricing } from '../../utils/cost.js'
2
2
  import type { Logger } from '../../utils/logger.js'
3
3
  import type { RunId, SessionId, TenantId } from '../ids/index.js'
4
4
  import type { PermissionMode } from '../permission/index.js'
5
- import type { ProjectId } from '../session/ids.js'
5
+ import type { ProjectId, ThreadId } from '../session/ids.js'
6
6
 
7
7
  export interface AgentRunConfig {
8
8
  model: string
@@ -22,10 +22,10 @@ export interface AgentRunConfig {
22
22
  }
23
23
 
24
24
  /**
25
- * Config for {@link RunPersistence}. Phase 6 promotes `sessionId`, `tenantId`,
26
- * and `projectId` to required — every Run must be attributed to a Session
27
- * under a Project within a Tenant (session-hierarchy.md §12.1). The legacy
28
- * `threadId`-only shape is gone.
25
+ * Config for {@link RunPersistence}. `sessionId`, `threadId`, `tenantId`,
26
+ * and `projectId` are required — every Run is attributed across the full
27
+ * five-layer scope (Tenant → Project Thread Session Run,
28
+ * Convention #17).
29
29
  */
30
30
  export interface RunPersistenceConfig {
31
31
  runId: RunId
@@ -38,6 +38,7 @@ export interface RunPersistenceConfig {
38
38
  log: Logger
39
39
 
40
40
  sessionId: SessionId
41
+ threadId: ThreadId
41
42
  tenantId: TenantId
42
43
  projectId: ProjectId
43
44
 
@@ -1,33 +1,20 @@
1
1
  import type { AgentStatus, CostInfo, TokenUsage } from '../common/index.js'
2
- import type { RunId, TaskId, TenantId, ThreadId } from '../ids/index.js'
2
+ import type { RunId, TaskId, TenantId } from '../ids/index.js'
3
3
  import type { ProjectId } from '../session/ids.js'
4
4
  import type { StopReason } from './stop-reason.js'
5
5
 
6
6
  /**
7
7
  * Denormalized metadata for a run.
8
8
  *
9
- * See session-hierarchy.md §4.6, §10.1, and §12.1.
10
- *
11
- * 0.2.0 promotes `projectId` and `tenantId` to required fields. `threadId`
12
- * remains as a deprecated mirror of `projectId` for the 0.2.x migration
13
- * window — consumers should prefer `projectId` and fall back to `threadId`
14
- * only for legacy records. 0.3.x removes `threadId` entirely (§13.1).
9
+ * `projectId` and `tenantId` are required per Convention #17 — every run is
10
+ * attributed to a Project within a Tenant.
15
11
  */
16
12
  export interface RunMetadata {
17
13
  id: RunId
18
- /**
19
- * Long-lived goal scope. Required in 0.2.0. Replaces the root-scope role
20
- * `threadId` played in 0.1.x.
21
- */
14
+ /** Long-lived goal scope. Required. */
22
15
  projectId: ProjectId
23
- /** Isolation boundary (Convention #17). Required in 0.2.0. */
16
+ /** Isolation boundary (Convention #17). Required. */
24
17
  tenantId: TenantId
25
- /**
26
- * @deprecated Use {@link RunMetadata.projectId}. Mirror retained for the
27
- * 0.2.x migration window; scheduled for removal in 0.3.0 per
28
- * session-hierarchy.md §13.1.
29
- */
30
- threadId: ThreadId
31
18
  agentId: string
32
19
  agentName: string
33
20
  status: AgentStatus
@@ -1,16 +1,14 @@
1
1
  /**
2
2
  * Session hierarchy branded ID re-export barrel.
3
3
  *
4
- * Canonical definitions live in `../ids/index.ts` (Phase 9 Known Delta #4
5
- * collapse: previously this file declared ProjectId/SubSessionId/etc. and
6
- * `types/ids/` re-exported them — a circular re-export that TypeScript
7
- * resolved cleanly but smelled). All session IDs now live in one place;
8
- * this barrel exists solely for ergonomic co-location with session-scoped
9
- * callers (they already import from `types/session/`).
4
+ * Canonical definitions live in `../ids/index.ts`. This barrel exists solely
5
+ * for ergonomic co-location with session-scoped callers (they already import
6
+ * from `types/session/`).
10
7
  */
11
8
 
12
9
  export type {
13
10
  ProjectId,
11
+ ThreadId,
14
12
  SubSessionId,
15
13
  HandoffId,
16
14
  WorkspaceId,
@@ -22,13 +20,4 @@ export type {
22
20
  AgentId,
23
21
  UserId,
24
22
  TaskId,
25
- ThreadId,
26
23
  } from '../ids/index.js'
27
-
28
- import type { ProjectId } from '../ids/index.js'
29
-
30
- /**
31
- * @deprecated Use {@link ProjectId}. Alias kept for one version migration
32
- * window; scheduled for removal in 0.3.0 per session-hierarchy.md §13.3.1.
33
- */
34
- export type ThreadIdDeprecated = ProjectId
@@ -4,6 +4,7 @@
4
4
 
5
5
  export type {
6
6
  ProjectId,
7
+ ThreadId,
7
8
  SubSessionId,
8
9
  HandoffId,
9
10
  WorkspaceId,
@@ -15,8 +16,6 @@ export type {
15
16
  AgentId,
16
17
  UserId,
17
18
  TaskId,
18
- ThreadId,
19
- ThreadIdDeprecated,
20
19
  } from './ids.js'
21
20
 
22
21
  export type {
@@ -1,14 +1,9 @@
1
1
  /**
2
2
  * SessionStore — canonical persistence contract for the session hierarchy.
3
3
  *
4
- * Replaces `ConversationStore` (deprecated; `types/conversation/index.ts`).
5
- * Per session-hierarchy.md §4 Entity Model, §10.4 Parent-Child Linkage, §12
6
- * Multi-Tenant and Security every accessor takes explicit {@link TenantId}
7
- * (Convention #17). Cross-tenant access rejects with `TenantIsolationError`.
8
- *
9
- * Minimum surface — covers downstream phases 4 (handoff), 5 (summary), and
10
- * 6 (sub-session spawn) plus the drill primitive (§14.3). Extensions land in
11
- * paired phases alongside their consumers (Convention #0: no speculative API).
4
+ * Every accessor takes explicit {@link TenantId} (Convention #17). Cross-tenant
5
+ * access rejects with `TenantIsolationError`. Convention #0: no speculative
6
+ * APIextensions land alongside their consumers.
12
7
  */
13
8
 
14
9
  import type { ActorRef } from '../../session/hierarchy/actor.js'
@@ -24,13 +19,22 @@ import type { SessionSummaryRef } from '../../session/summary/ref.js'
24
19
  import type { SessionMessage } from '../../store/session/messages.js'
25
20
  import type { MessageId, SessionId, TenantId } from '../ids/index.js'
26
21
  import type { Message } from '../message/index.js'
27
- import type { ProjectId, SubSessionId, SummaryId } from '../session/ids.js'
22
+ import type { ProjectId, SubSessionId, SummaryId, ThreadId } from '../session/ids.js'
28
23
 
29
24
  /**
30
25
  * Params for {@link SessionStore.createSession}. The store owns id generation,
31
- * `ownerVersion` initialization, and timestamps. See session-hierarchy.md §4.3.
26
+ * `ownerVersion` initialization, and timestamps.
27
+ *
28
+ * Both `threadId` and `projectId` are required. `projectId` must equal the
29
+ * `projectId` of the thread identified by `threadId`; the store does NOT
30
+ * perform that cross-store consistency check (it has no ThreadStore handle
31
+ * by design — see the store-boundary rationale in {@link ThreadStore}). The
32
+ * caller is the authority; typically spawn and handoff paths copy both from
33
+ * a freshly-loaded `Thread` record or from their own context which already
34
+ * tracks both.
32
35
  */
33
36
  export interface CreateSessionParams {
37
+ threadId: ThreadId
34
38
  projectId: ProjectId
35
39
  /**
36
40
  * Initial owner of the session. May be `null` for bootstrap scenarios where
@@ -103,6 +107,25 @@ export interface SessionStore {
103
107
 
104
108
  updateSession(session: Session, tenantId: TenantId): Promise<void>
105
109
 
110
+ /**
111
+ * List every Session that belongs to the given Thread for the caller's
112
+ * tenant, ordered by `createdAt` ascending. Returns an empty array when
113
+ * none exist.
114
+ *
115
+ * Thread-scoped queries rely on `session.threadId` (set at creation, never
116
+ * rewritten). Cross-tenant sessions that happen to share the supplied
117
+ * `threadId` are silently skipped — the listing is tenant-scoped, not an
118
+ * isolation violation (the caller did not request a specific record).
119
+ *
120
+ * Exists to back ThreadManager's archival + delete preconditions
121
+ * ({@link import('../../manager/thread/lifecycle.js').ThreadManager.archive}
122
+ * rejects when any session is in a non-terminal state; `delete` rejects
123
+ * while any session still references the thread). Keeping this primitive
124
+ * on {@link SessionStore} preserves the store-ownership boundary —
125
+ * ThreadStore stays unaware of session layout (Convention #0).
126
+ */
127
+ listSessions(threadId: ThreadId, tenantId: TenantId): Promise<readonly Session[]>
128
+
106
129
  /**
107
130
  * Hard-delete a session. Idempotent — absent sessions succeed as a no-op.
108
131
  * Rejects with `TenantIsolationError` on cross-tenant access.
@@ -137,7 +160,7 @@ export interface SessionStore {
137
160
  */
138
161
  deleteSubSession(subSessionId: SubSessionId, tenantId: TenantId): Promise<void>
139
162
 
140
- // Messages (replaces ConversationStore surface) ---------------------------
163
+ // Messages -----------------------------------------------------------------
141
164
 
142
165
  /**
143
166
  * Append a single message to the session's message log. Returns the
@@ -0,0 +1,5 @@
1
+ // Sub-barrel for the Thread type surface (Convention #4).
2
+ // Concrete types live in sibling files; re-export them here so consumers
3
+ // import via `../types/thread/index.js`.
4
+
5
+ export type { ThreadStore, CreateThreadParams } from './store.js'
@@ -0,0 +1,92 @@
1
+ /**
2
+ * ThreadStore — canonical persistence contract for the Thread topic layer
3
+ * (Project → **Thread** → Session → SubSession → Run).
4
+ *
5
+ * Threads are pure containers (Phase 0 decision B.1). They have no own
6
+ * message stream and no fan-in `deriveStatus()` — status is owner-managed
7
+ * (`'open' | 'archived'`). Every accessor takes explicit {@link TenantId};
8
+ * cross-tenant access rejects with `TenantIsolationError` (Convention #17).
9
+ *
10
+ * Read accessors return `null` when the resource does not exist for the
11
+ * supplied tenant (deny-by-default surface). Callers branch on missing
12
+ * explicitly — no fallback substitution.
13
+ *
14
+ * `deleteThread` is intentionally a dumb record-delete at this layer:
15
+ * it does NOT walk session ownership. The "reject when sessions attached"
16
+ * precondition lives in {@link import('../../manager/thread/lifecycle.js').ThreadManager}
17
+ * where both stores are in scope. Keeping ThreadStore free of cross-store
18
+ * awareness preserves the single-boundary ownership boundary that Phase 2
19
+ * has just introduced for this layer (Convention #0).
20
+ */
21
+
22
+ import type { Thread } from '../../session/hierarchy/thread.js'
23
+ import type { TenantId } from '../ids/index.js'
24
+ import type { ProjectId, ThreadId } from '../session/ids.js'
25
+
26
+ /**
27
+ * Params for {@link ThreadStore.createThread}. The store owns id generation,
28
+ * `ownerVersion` initialization (0 at create), and timestamps.
29
+ */
30
+ export interface CreateThreadParams {
31
+ projectId: ProjectId
32
+ /**
33
+ * User-facing display label. Not unique within the project — see
34
+ * {@link Thread} JSDoc. Empty strings are permitted; callers that require
35
+ * a label should validate at the API layer.
36
+ */
37
+ title: string
38
+ }
39
+
40
+ /**
41
+ * Canonical persistence contract for the Thread layer. Every accessor takes
42
+ * explicit `tenantId`; cross-tenant reads/writes reject with
43
+ * `TenantIsolationError` (`session/errors.ts`, Convention #17).
44
+ */
45
+ export interface ThreadStore {
46
+ /**
47
+ * Persist a new Thread under the given project. Returns the minted
48
+ * {@link Thread} with `ownerVersion: 0` and freshly-generated
49
+ * {@link ThreadId}. Callers must ensure the parent project exists and
50
+ * belongs to the same tenant — the store does not validate project
51
+ * ownership (that is a cross-store precondition owned by the manager).
52
+ */
53
+ createThread(params: CreateThreadParams, tenantId: TenantId): Promise<Thread>
54
+
55
+ /**
56
+ * Read a Thread by id. Returns `null` when absent. Cross-tenant reads
57
+ * reject with `TenantIsolationError`.
58
+ */
59
+ getThread(threadId: ThreadId, tenantId: TenantId): Promise<Thread | null>
60
+
61
+ /**
62
+ * Persist a mutation to a Thread record. CAS on `ownerVersion`: if the
63
+ * supplied `thread.ownerVersion` does not match the persisted version,
64
+ * rejects with `StaleThreadError`. On success the write commits with
65
+ * `ownerVersion + 1` and a refreshed `updatedAt`.
66
+ *
67
+ * Archival transition (`status: 'open' → 'archived'`) shares this path;
68
+ * the caller is responsible for verifying that no non-terminal Sessions
69
+ * are attached before flipping (see ThreadManager.archiveThread).
70
+ */
71
+ updateThread(thread: Thread, tenantId: TenantId): Promise<void>
72
+
73
+ /**
74
+ * Hard-delete a Thread record. Idempotent — absent threads succeed as a
75
+ * no-op. Rejects with `TenantIsolationError` on cross-tenant access.
76
+ *
77
+ * **Does NOT cascade to child Sessions** — the caller (typically
78
+ * ThreadManager) enforces the precondition that no Sessions reference
79
+ * this thread. Convention #5: deny-by-default, no implicit cascade.
80
+ */
81
+ deleteThread(threadId: ThreadId, tenantId: TenantId): Promise<void>
82
+
83
+ /**
84
+ * List all Threads under a project for the given tenant, ordered by
85
+ * `createdAt` ascending. Returns an empty array when none exist.
86
+ * Cross-tenant reads reject with `TenantIsolationError`.
87
+ *
88
+ * The return shape is a concrete snapshot — callers that mutate the
89
+ * result array do not affect store state.
90
+ */
91
+ listThreads(projectId: ProjectId, tenantId: TenantId): Promise<readonly Thread[]>
92
+ }
package/src/utils/id.ts CHANGED
@@ -55,17 +55,12 @@ function generateId<T extends string>(prefix: T, length = 12): `${T}${string}` {
55
55
  return `${prefix}${suffix}` as `${T}${string}`
56
56
  }
57
57
 
58
- /**
59
- * @deprecated Prefer {@link generateProjectId}. `ThreadId` is an alias of
60
- * `ProjectId` during the 0.2.x migration window; this helper emits the new
61
- * `prj_` prefix and will be removed in 0.3.0. See session-hierarchy.md §13.
62
- */
63
- export function generateThreadId(): ThreadId {
58
+ export function generateProjectId(): ProjectId {
64
59
  return generateId('prj_')
65
60
  }
66
61
 
67
- export function generateProjectId(): ProjectId {
68
- return generateId('prj_')
62
+ export function generateThreadId(): ThreadId {
63
+ return generateId('thd_')
69
64
  }
70
65
 
71
66
  export function generateRunId(): RunId {
@@ -199,22 +194,6 @@ function parseId<T extends string>(raw: string, prefix: string, typeName: string
199
194
  return raw as T
200
195
  }
201
196
 
202
- /**
203
- * @deprecated Parses either the legacy `thd_*` prefix or the new `prj_*`
204
- * prefix during the 0.2.x migration window. 0.3.x will only accept `prj_*`.
205
- * See session-hierarchy.md §13.3.1.
206
- */
207
- export function parseThreadId(raw: string): ThreadId {
208
- if (raw.startsWith('prj_')) {
209
- return raw as ThreadId
210
- }
211
- if (raw.startsWith('thd_')) {
212
- // Read-accept legacy prefix; a proper coercion pipeline lands in Phase 7.
213
- return raw as unknown as ThreadId
214
- }
215
- throw new Error(`Invalid ThreadId: expected "prj_" or "thd_" prefix, got "${raw}"`)
216
- }
217
-
218
197
  export function parseProjectId(raw: string): ProjectId {
219
198
  return parseId<ProjectId>(raw, 'prj_', 'ProjectId')
220
199
  }