@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.
- package/CHANGELOG.md +53 -2
- package/dist/agents/ReactiveAgent.d.ts.map +1 -1
- package/dist/agents/ReactiveAgent.js +3 -2
- package/dist/agents/ReactiveAgent.js.map +1 -1
- package/dist/agents/SupervisorAgent.d.ts.map +1 -1
- package/dist/agents/SupervisorAgent.js +5 -2
- package/dist/agents/SupervisorAgent.js.map +1 -1
- package/dist/bridge/a2a/index.d.ts +1 -1
- package/dist/bridge/a2a/index.d.ts.map +1 -1
- package/dist/bridge/a2a/index.js +1 -1
- package/dist/bridge/a2a/index.js.map +1 -1
- package/dist/bridge/a2a/message.d.ts +0 -2
- package/dist/bridge/a2a/message.d.ts.map +1 -1
- package/dist/bridge/a2a/message.js +0 -26
- package/dist/bridge/a2a/message.js.map +1 -1
- package/dist/bridge/a2a/task.d.ts +4 -3
- package/dist/bridge/a2a/task.d.ts.map +1 -1
- package/dist/bridge/a2a/task.js +4 -4
- package/dist/bridge/a2a/task.js.map +1 -1
- package/dist/contracts/api.d.ts +6 -38
- package/dist/contracts/api.d.ts.map +1 -1
- package/dist/contracts/ids.d.ts +1 -1
- package/dist/contracts/ids.d.ts.map +1 -1
- package/dist/contracts/index.d.ts +3 -5
- package/dist/contracts/index.d.ts.map +1 -1
- package/dist/contracts/index.js +1 -1
- package/dist/contracts/index.js.map +1 -1
- package/dist/contracts/schemas.d.ts +1 -31
- package/dist/contracts/schemas.d.ts.map +1 -1
- package/dist/contracts/schemas.js +1 -7
- package/dist/contracts/schemas.js.map +1 -1
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -3
- package/dist/index.js.map +1 -1
- package/dist/manager/agent/__tests__/lifecycle.test.js +27 -13
- package/dist/manager/agent/__tests__/lifecycle.test.js.map +1 -1
- package/dist/manager/agent/lifecycle.d.ts +9 -0
- package/dist/manager/agent/lifecycle.d.ts.map +1 -1
- package/dist/manager/agent/lifecycle.js +93 -31
- package/dist/manager/agent/lifecycle.js.map +1 -1
- package/dist/manager/index.d.ts +2 -0
- package/dist/manager/index.d.ts.map +1 -1
- package/dist/manager/index.js +1 -0
- package/dist/manager/index.js.map +1 -1
- package/dist/manager/run/persistence.d.ts +3 -1
- package/dist/manager/run/persistence.d.ts.map +1 -1
- package/dist/manager/run/persistence.js +5 -0
- package/dist/manager/run/persistence.js.map +1 -1
- package/dist/manager/thread/__tests__/lifecycle.test.d.ts +2 -0
- package/dist/manager/thread/__tests__/lifecycle.test.d.ts.map +1 -0
- package/dist/manager/thread/__tests__/lifecycle.test.js +216 -0
- package/dist/manager/thread/__tests__/lifecycle.test.js.map +1 -0
- package/dist/manager/thread/lifecycle.d.ts +105 -0
- package/dist/manager/thread/lifecycle.d.ts.map +1 -0
- package/dist/manager/thread/lifecycle.js +186 -0
- package/dist/manager/thread/lifecycle.js.map +1 -0
- package/dist/rag/retriever.js +2 -2
- package/dist/runtime/query/__tests__/context.test.js +8 -7
- package/dist/runtime/query/__tests__/context.test.js.map +1 -1
- package/dist/runtime/query/context-cache.d.ts +3 -3
- package/dist/runtime/query/context-cache.d.ts.map +1 -1
- package/dist/runtime/query/context-cache.js +2 -2
- package/dist/runtime/query/context-cache.js.map +1 -1
- package/dist/runtime/query/context.d.ts +12 -21
- package/dist/runtime/query/context.d.ts.map +1 -1
- package/dist/runtime/query/context.js +3 -1
- package/dist/runtime/query/context.js.map +1 -1
- package/dist/runtime/query/index.d.ts +13 -15
- package/dist/runtime/query/index.d.ts.map +1 -1
- package/dist/runtime/query/index.js +1 -0
- package/dist/runtime/query/index.js.map +1 -1
- package/dist/session/__tests__/integration/_fixtures.d.ts +11 -4
- package/dist/session/__tests__/integration/_fixtures.d.ts.map +1 -1
- package/dist/session/__tests__/integration/_fixtures.js +23 -6
- package/dist/session/__tests__/integration/_fixtures.js.map +1 -1
- package/dist/session/__tests__/integration/archive-gate.test.d.ts +15 -0
- package/dist/session/__tests__/integration/archive-gate.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/archive-gate.test.js +214 -0
- package/dist/session/__tests__/integration/archive-gate.test.js.map +1 -0
- package/dist/session/__tests__/integration/capacity-caps.test.js +13 -6
- package/dist/session/__tests__/integration/capacity-caps.test.js.map +1 -1
- package/dist/session/__tests__/integration/e2e-spawn.test.js +14 -2
- package/dist/session/__tests__/integration/e2e-spawn.test.js.map +1 -1
- package/dist/session/__tests__/integration/event-stream-ordering.test.js +14 -7
- package/dist/session/__tests__/integration/event-stream-ordering.test.js.map +1 -1
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js +26 -14
- package/dist/session/__tests__/integration/handoff-broadcast-e2e.test.js.map +1 -1
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.js +30 -20
- package/dist/session/__tests__/integration/handoff-illegal-transition.test.js.map +1 -1
- package/dist/session/__tests__/integration/handoff-single-e2e.test.js +25 -9
- package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -1
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js +11 -10
- package/dist/session/__tests__/integration/hierarchy-lifecycle.test.js.map +1 -1
- package/dist/session/__tests__/integration/prev-artifact-dag.test.js +5 -4
- package/dist/session/__tests__/integration/prev-artifact-dag.test.js.map +1 -1
- package/dist/session/__tests__/integration/retention-archive.test.js +3 -2
- package/dist/session/__tests__/integration/retention-archive.test.js.map +1 -1
- package/dist/session/__tests__/integration/spawn-rollback.test.d.ts +26 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.d.ts.map +1 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.js +236 -0
- package/dist/session/__tests__/integration/spawn-rollback.test.js.map +1 -0
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.js +2 -1
- package/dist/session/__tests__/integration/summary-materialization-e2e.test.js.map +1 -1
- package/dist/session/__tests__/integration/tenant-isolation.test.js +14 -5
- package/dist/session/__tests__/integration/tenant-isolation.test.js.map +1 -1
- package/dist/session/errors.d.ts +79 -0
- package/dist/session/errors.d.ts.map +1 -1
- package/dist/session/errors.js +57 -0
- package/dist/session/errors.js.map +1 -1
- package/dist/session/handoff/__tests__/broadcast.test.js +49 -31
- package/dist/session/handoff/__tests__/broadcast.test.js.map +1 -1
- package/dist/session/handoff/__tests__/capacity.test.js +21 -18
- package/dist/session/handoff/__tests__/capacity.test.js.map +1 -1
- package/dist/session/handoff/__tests__/single.test.js +39 -30
- package/dist/session/handoff/__tests__/single.test.js.map +1 -1
- package/dist/session/handoff/assignment.d.ts +13 -1
- package/dist/session/handoff/assignment.d.ts.map +1 -1
- package/dist/session/handoff/broadcast.d.ts +7 -0
- package/dist/session/handoff/broadcast.d.ts.map +1 -1
- package/dist/session/handoff/broadcast.js +16 -1
- package/dist/session/handoff/broadcast.js.map +1 -1
- package/dist/session/handoff/single.d.ts +7 -0
- package/dist/session/handoff/single.d.ts.map +1 -1
- package/dist/session/handoff/single.js +13 -1
- package/dist/session/handoff/single.js.map +1 -1
- package/dist/session/hierarchy/__tests__/session.test.js +2 -0
- package/dist/session/hierarchy/__tests__/session.test.js.map +1 -1
- package/dist/session/hierarchy/index.d.ts +1 -0
- package/dist/session/hierarchy/index.d.ts.map +1 -1
- package/dist/session/hierarchy/index.js.map +1 -1
- package/dist/session/hierarchy/session.d.ts +15 -3
- package/dist/session/hierarchy/session.d.ts.map +1 -1
- package/dist/session/hierarchy/session.js.map +1 -1
- package/dist/session/hierarchy/thread.d.ts +54 -0
- package/dist/session/hierarchy/thread.d.ts.map +1 -0
- package/dist/session/hierarchy/thread.js +2 -0
- package/dist/session/hierarchy/thread.js.map +1 -0
- package/dist/session/migration/id-prefix.d.ts +8 -13
- package/dist/session/migration/id-prefix.d.ts.map +1 -1
- package/dist/session/migration/id-prefix.js +8 -13
- package/dist/session/migration/id-prefix.js.map +1 -1
- package/dist/session/retention/__tests__/archive.test.js +3 -2
- package/dist/session/retention/__tests__/archive.test.js.map +1 -1
- package/dist/session/summary/__tests__/materialize.test.js +4 -3
- package/dist/session/summary/__tests__/materialize.test.js.map +1 -1
- package/dist/store/index.d.ts +0 -2
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +0 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store/session/__tests__/disk.test.js +32 -5
- package/dist/store/session/__tests__/disk.test.js.map +1 -1
- package/dist/store/session/__tests__/memory.test.js +50 -9
- package/dist/store/session/__tests__/memory.test.js.map +1 -1
- package/dist/store/session/disk.d.ts +2 -1
- package/dist/store/session/disk.d.ts.map +1 -1
- package/dist/store/session/disk.js +61 -0
- package/dist/store/session/disk.js.map +1 -1
- package/dist/store/session/index.d.ts.map +1 -1
- package/dist/store/session/index.js +3 -4
- package/dist/store/session/index.js.map +1 -1
- package/dist/store/session/memory.d.ts +2 -1
- package/dist/store/session/memory.d.ts.map +1 -1
- package/dist/store/session/memory.js +13 -0
- package/dist/store/session/memory.js.map +1 -1
- package/dist/store/thread/disk.d.ts +41 -0
- package/dist/store/thread/disk.d.ts.map +1 -0
- package/dist/store/thread/disk.js +229 -0
- package/dist/store/thread/disk.js.map +1 -0
- package/dist/store/thread/index.d.ts +4 -0
- package/dist/store/thread/index.d.ts.map +1 -0
- package/dist/store/thread/index.js +6 -0
- package/dist/store/thread/index.js.map +1 -0
- package/dist/store/thread/memory.d.ts +23 -0
- package/dist/store/thread/memory.d.ts.map +1 -0
- package/dist/store/thread/memory.js +90 -0
- package/dist/store/thread/memory.js.map +1 -0
- package/dist/types/agent/base.d.ts +17 -21
- package/dist/types/agent/base.d.ts.map +1 -1
- package/dist/types/agent/factory.d.ts +8 -2
- package/dist/types/agent/factory.d.ts.map +1 -1
- package/dist/types/agent/task.d.ts +18 -11
- package/dist/types/agent/task.d.ts.map +1 -1
- package/dist/types/ids/index.d.ts +5 -9
- package/dist/types/ids/index.d.ts.map +1 -1
- package/dist/types/ids/index.js +4 -4
- package/dist/types/ids/index.js.map +1 -1
- package/dist/types/rag/retrieval.d.ts +4 -3
- package/dist/types/rag/retrieval.d.ts.map +1 -1
- package/dist/types/run/config.d.ts +6 -5
- package/dist/types/run/config.d.ts.map +1 -1
- package/dist/types/run/metadata.d.ts +5 -18
- package/dist/types/run/metadata.d.ts.map +1 -1
- package/dist/types/session/ids.d.ts +4 -13
- package/dist/types/session/ids.d.ts.map +1 -1
- package/dist/types/session/ids.js +3 -6
- package/dist/types/session/ids.js.map +1 -1
- package/dist/types/session/index.d.ts +1 -1
- package/dist/types/session/index.d.ts.map +1 -1
- package/dist/types/session/store.d.ts +32 -10
- package/dist/types/session/store.d.ts.map +1 -1
- package/dist/types/session/store.js +3 -8
- package/dist/types/session/store.js.map +1 -1
- package/dist/types/thread/index.d.ts +2 -0
- package/dist/types/thread/index.d.ts.map +1 -0
- package/dist/types/thread/index.js +5 -0
- package/dist/types/thread/index.js.map +1 -0
- package/dist/types/thread/store.d.ts +86 -0
- package/dist/types/thread/store.d.ts.map +1 -0
- package/dist/types/thread/store.js +22 -0
- package/dist/types/thread/store.js.map +1 -0
- package/dist/utils/id.d.ts +1 -12
- package/dist/utils/id.d.ts.map +1 -1
- package/dist/utils/id.js +3 -23
- package/dist/utils/id.js.map +1 -1
- package/package.json +6 -11
- package/src/agents/ReactiveAgent.ts +3 -2
- package/src/agents/SupervisorAgent.ts +5 -2
- package/src/bridge/a2a/index.ts +0 -1
- package/src/bridge/a2a/message.ts +0 -32
- package/src/bridge/a2a/task.ts +8 -7
- package/src/contracts/api.ts +6 -42
- package/src/contracts/ids.ts +1 -1
- package/src/contracts/index.ts +2 -8
- package/src/contracts/schemas.ts +1 -8
- package/src/index.ts +0 -4
- package/src/manager/agent/__tests__/lifecycle.test.ts +34 -13
- package/src/manager/agent/lifecycle.ts +114 -35
- package/src/manager/index.ts +3 -0
- package/src/manager/run/persistence.ts +7 -1
- package/src/manager/thread/__tests__/lifecycle.test.ts +286 -0
- package/src/manager/thread/lifecycle.ts +217 -0
- package/src/rag/retriever.ts +2 -2
- package/src/runtime/query/__tests__/context.test.ts +9 -8
- package/src/runtime/query/context-cache.ts +4 -4
- package/src/runtime/query/context.ts +15 -22
- package/src/runtime/query/index.ts +15 -16
- package/src/session/__tests__/integration/_fixtures.ts +36 -8
- package/src/session/__tests__/integration/archive-gate.test.ts +288 -0
- package/src/session/__tests__/integration/capacity-caps.test.ts +13 -6
- package/src/session/__tests__/integration/e2e-spawn.test.ts +20 -2
- package/src/session/__tests__/integration/event-stream-ordering.test.ts +14 -7
- package/src/session/__tests__/integration/handoff-broadcast-e2e.test.ts +39 -13
- package/src/session/__tests__/integration/handoff-illegal-transition.test.ts +54 -19
- package/src/session/__tests__/integration/handoff-single-e2e.test.ts +40 -9
- package/src/session/__tests__/integration/hierarchy-lifecycle.test.ts +13 -10
- package/src/session/__tests__/integration/prev-artifact-dag.test.ts +12 -5
- package/src/session/__tests__/integration/retention-archive.test.ts +5 -3
- package/src/session/__tests__/integration/spawn-rollback.test.ts +313 -0
- package/src/session/__tests__/integration/summary-materialization-e2e.test.ts +4 -2
- package/src/session/__tests__/integration/tenant-isolation.test.ts +16 -6
- package/src/session/errors.ts +89 -0
- package/src/session/handoff/__tests__/broadcast.test.ts +56 -28
- package/src/session/handoff/__tests__/capacity.test.ts +26 -20
- package/src/session/handoff/__tests__/single.test.ts +45 -28
- package/src/session/handoff/assignment.ts +13 -1
- package/src/session/handoff/broadcast.ts +26 -1
- package/src/session/handoff/single.ts +23 -1
- package/src/session/hierarchy/__tests__/session.test.ts +9 -1
- package/src/session/hierarchy/index.ts +1 -0
- package/src/session/hierarchy/session.ts +15 -3
- package/src/session/hierarchy/thread.ts +55 -0
- package/src/session/migration/id-prefix.ts +8 -13
- package/src/session/retention/__tests__/archive.test.ts +5 -3
- package/src/session/summary/__tests__/materialize.test.ts +6 -4
- package/src/store/index.ts +0 -3
- package/src/store/session/__tests__/disk.test.ts +57 -6
- package/src/store/session/__tests__/memory.test.ts +84 -9
- package/src/store/session/disk.ts +57 -1
- package/src/store/session/index.ts +3 -4
- package/src/store/session/memory.ts +13 -1
- package/src/store/thread/disk.ts +261 -0
- package/src/store/thread/index.ts +7 -0
- package/src/store/thread/memory.ts +104 -0
- package/src/types/agent/base.ts +17 -21
- package/src/types/agent/factory.ts +8 -3
- package/src/types/agent/task.ts +19 -11
- package/src/types/ids/index.ts +8 -15
- package/src/types/rag/retrieval.ts +4 -3
- package/src/types/run/config.ts +6 -5
- package/src/types/run/metadata.ts +5 -18
- package/src/types/session/ids.ts +4 -15
- package/src/types/session/index.ts +1 -2
- package/src/types/session/store.ts +34 -11
- package/src/types/thread/index.ts +5 -0
- package/src/types/thread/store.ts +92 -0
- package/src/utils/id.ts +3 -24
- package/dist/store/conversation/memory.d.ts +0 -43
- package/dist/store/conversation/memory.d.ts.map +0 -1
- package/dist/store/conversation/memory.js +0 -108
- package/dist/store/conversation/memory.js.map +0 -1
- package/dist/types/conversation/index.d.ts +0 -14
- package/dist/types/conversation/index.d.ts.map +0 -1
- package/dist/types/conversation/index.js +0 -2
- package/dist/types/conversation/index.js.map +0 -1
- package/src/store/conversation/memory.ts +0 -144
- 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
|
+
}
|
package/src/types/agent/base.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { AgentStatus, CostInfo, TokenUsage } from '../common/index.js'
|
|
2
|
-
import type { RunId, SessionId, TenantId
|
|
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
|
-
*
|
|
28
|
-
*
|
|
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
|
-
|
|
36
|
+
projectId?: ProjectId
|
|
31
37
|
|
|
32
38
|
/**
|
|
33
|
-
*
|
|
34
|
-
*
|
|
35
|
-
*
|
|
36
|
-
*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
package/src/types/agent/task.ts
CHANGED
|
@@ -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}.
|
|
27
|
-
* `
|
|
28
|
-
* the spawn path is the ingress point for the session hierarchy; callers
|
|
29
|
-
* provide the full scoping set
|
|
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
|
-
/**
|
|
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
|
/**
|
package/src/types/ids/index.ts
CHANGED
|
@@ -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
|
|
42
|
-
//
|
|
43
|
-
//
|
|
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
|
|
62
|
-
*
|
|
63
|
-
*
|
|
64
|
-
*
|
|
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
|
|
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
|
-
|
|
17
|
-
|
|
17
|
+
projectId?: ProjectId
|
|
18
|
+
recentMessages?: string[]
|
|
18
19
|
config?: Partial<RetrievalConfig>
|
|
19
20
|
}
|
|
20
21
|
|
package/src/types/run/config.ts
CHANGED
|
@@ -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}.
|
|
26
|
-
* and `projectId`
|
|
27
|
-
*
|
|
28
|
-
*
|
|
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
|
|
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
|
-
*
|
|
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
|
|
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
|
package/src/types/session/ids.ts
CHANGED
|
@@ -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
|
|
5
|
-
*
|
|
6
|
-
* `types/
|
|
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
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* SessionStore — canonical persistence contract for the session hierarchy.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
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
|
+
* API — extensions 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.
|
|
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
|
|
163
|
+
// Messages -----------------------------------------------------------------
|
|
141
164
|
|
|
142
165
|
/**
|
|
143
166
|
* Append a single message to the session's message log. Returns the
|
|
@@ -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
|
|
68
|
-
return generateId('
|
|
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
|
}
|