@namzu/sdk 12.2.0 → 13.1.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 (77) hide show
  1. package/CHANGELOG.md +199 -0
  2. package/dist/bridge/a2a/__tests__/project-is-the-a2a-context.test.d.ts +2 -0
  3. package/dist/bridge/a2a/__tests__/project-is-the-a2a-context.test.d.ts.map +1 -0
  4. package/dist/bridge/a2a/__tests__/project-is-the-a2a-context.test.js +55 -0
  5. package/dist/bridge/a2a/__tests__/project-is-the-a2a-context.test.js.map +1 -0
  6. package/dist/manager/agent/__tests__/an-env-reaches-the-child-it-was-set-for.test.d.ts +2 -0
  7. package/dist/manager/agent/__tests__/an-env-reaches-the-child-it-was-set-for.test.d.ts.map +1 -0
  8. package/dist/manager/agent/__tests__/an-env-reaches-the-child-it-was-set-for.test.js +159 -0
  9. package/dist/manager/agent/__tests__/an-env-reaches-the-child-it-was-set-for.test.js.map +1 -0
  10. package/dist/manager/agent/lifecycle.d.ts +15 -0
  11. package/dist/manager/agent/lifecycle.d.ts.map +1 -1
  12. package/dist/manager/agent/lifecycle.js +103 -26
  13. package/dist/manager/agent/lifecycle.js.map +1 -1
  14. package/dist/public-runtime.d.ts +1 -1
  15. package/dist/public-runtime.d.ts.map +1 -1
  16. package/dist/public-runtime.js +7 -1
  17. package/dist/public-runtime.js.map +1 -1
  18. package/dist/session/__tests__/integration/a-successful-delegation-disposes-its-workspace.test.d.ts +21 -0
  19. package/dist/session/__tests__/integration/a-successful-delegation-disposes-its-workspace.test.d.ts.map +1 -0
  20. package/dist/session/__tests__/integration/a-successful-delegation-disposes-its-workspace.test.js +205 -0
  21. package/dist/session/__tests__/integration/a-successful-delegation-disposes-its-workspace.test.js.map +1 -0
  22. package/dist/session/__tests__/integration/handoff-single-e2e.test.js +14 -5
  23. package/dist/session/__tests__/integration/handoff-single-e2e.test.js.map +1 -1
  24. package/dist/session/errors.d.ts +25 -0
  25. package/dist/session/errors.d.ts.map +1 -1
  26. package/dist/session/errors.js +21 -0
  27. package/dist/session/errors.js.map +1 -1
  28. package/dist/session/handoff/broadcast.d.ts.map +1 -1
  29. package/dist/session/handoff/broadcast.js +10 -5
  30. package/dist/session/handoff/broadcast.js.map +1 -1
  31. package/dist/session/handoff/single.d.ts.map +1 -1
  32. package/dist/session/handoff/single.js +27 -4
  33. package/dist/session/handoff/single.js.map +1 -1
  34. package/dist/store/session/__tests__/a-session-has-one-writer.test.d.ts +2 -0
  35. package/dist/store/session/__tests__/a-session-has-one-writer.test.d.ts.map +1 -0
  36. package/dist/store/session/__tests__/a-session-has-one-writer.test.js +79 -0
  37. package/dist/store/session/__tests__/a-session-has-one-writer.test.js.map +1 -0
  38. package/dist/store/session/__tests__/a-workspace-can-be-configured.test.d.ts +2 -0
  39. package/dist/store/session/__tests__/a-workspace-can-be-configured.test.d.ts.map +1 -0
  40. package/dist/store/session/__tests__/a-workspace-can-be-configured.test.js +149 -0
  41. package/dist/store/session/__tests__/a-workspace-can-be-configured.test.js.map +1 -0
  42. package/dist/store/session/disk.d.ts +4 -2
  43. package/dist/store/session/disk.d.ts.map +1 -1
  44. package/dist/store/session/disk.js +71 -4
  45. package/dist/store/session/disk.js.map +1 -1
  46. package/dist/store/session/memory.d.ts +4 -2
  47. package/dist/store/session/memory.d.ts.map +1 -1
  48. package/dist/store/session/memory.js +53 -4
  49. package/dist/store/session/memory.js.map +1 -1
  50. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  51. package/dist/tools/coordinator/agent.js +7 -0
  52. package/dist/tools/coordinator/agent.js.map +1 -1
  53. package/dist/tools/coordinator/index.d.ts.map +1 -1
  54. package/dist/tools/coordinator/index.js +6 -0
  55. package/dist/tools/coordinator/index.js.map +1 -1
  56. package/dist/types/agent/base.d.ts +22 -0
  57. package/dist/types/agent/base.d.ts.map +1 -1
  58. package/dist/types/session/store.d.ts +80 -1
  59. package/dist/types/session/store.d.ts.map +1 -1
  60. package/package.json +1 -1
  61. package/src/bridge/a2a/__tests__/project-is-the-a2a-context.test.ts +66 -0
  62. package/src/manager/agent/__tests__/an-env-reaches-the-child-it-was-set-for.test.ts +196 -0
  63. package/src/manager/agent/lifecycle.ts +107 -26
  64. package/src/public-runtime.ts +6 -0
  65. package/src/session/__tests__/integration/a-successful-delegation-disposes-its-workspace.test.ts +270 -0
  66. package/src/session/__tests__/integration/handoff-single-e2e.test.ts +14 -5
  67. package/src/session/errors.ts +29 -0
  68. package/src/session/handoff/broadcast.ts +10 -5
  69. package/src/session/handoff/single.ts +27 -4
  70. package/src/store/session/__tests__/a-session-has-one-writer.test.ts +116 -0
  71. package/src/store/session/__tests__/a-workspace-can-be-configured.test.ts +210 -0
  72. package/src/store/session/disk.ts +84 -4
  73. package/src/store/session/memory.ts +66 -4
  74. package/src/tools/coordinator/agent.ts +7 -0
  75. package/src/tools/coordinator/index.ts +6 -0
  76. package/src/types/agent/base.ts +23 -0
  77. package/src/types/session/store.ts +88 -1
@@ -146,6 +146,13 @@ export function buildAgentTool(opts: AgentToolOptions): ToolDefinition {
146
146
  // surface, and the one it exports as the canonical shape —
147
147
  // did not.
148
148
  ...(context.parentSpan ? { parentSpan: context.parentSpan } : {}),
149
+ // The parent's environment, which is the whole point of setting
150
+ // one: a delegate that cannot see it runs against different
151
+ // services than the run that launched it, silently.
152
+ // `ToolContext.env` is the parent's own resolved map, per run.
153
+ ...(Object.keys(context.env ?? {}).length > 0
154
+ ? { configOverrides: { env: context.env } }
155
+ : {}),
149
156
  })
150
157
 
151
158
  onTaskLaunched?.(handle.taskId, {
@@ -484,6 +484,12 @@ export function buildCoordinatorTools(opts: CoordinatorToolsOptions): ToolDefini
484
484
  // Hang the child run off THIS tool's span, so the delegation
485
485
  // shows up inside the turn that asked for it.
486
486
  ...(_context.parentSpan ? { parentSpan: _context.parentSpan } : {}),
487
+ // Same as the `Agent` tool: a delegate inherits the environment
488
+ // its parent was given, or it runs against different services
489
+ // than the run that asked for the work.
490
+ ...(Object.keys(_context.env ?? {}).length > 0
491
+ ? { configOverrides: { env: _context.env } }
492
+ : {}),
487
493
  })
488
494
 
489
495
  // Whose task this is. The inbox ignores completions for anything it
@@ -22,6 +22,29 @@ export interface BaseAgentConfig {
22
22
  maxResponseTokens?: number
23
23
  costLimitUsd?: number
24
24
  permissionMode?: PermissionMode
25
+
26
+ /**
27
+ * Extra environment variables for this agent's tools and sandboxed
28
+ * commands, merged over whatever ambient environment the execution path
29
+ * supplies. Inherited by every delegated descendant.
30
+ *
31
+ * **Configuration, not credentials** — and that is a property of the
32
+ * CHANNEL rather than a judgement about any particular value. This map is
33
+ * copied into every child, is readable by any tool that can run a command,
34
+ * and enters a model's context and the run transcript the moment something
35
+ * echoes it. Nothing here is scoped, redacted, or revocable.
36
+ *
37
+ * A value that authenticates to a host belongs on the brokered credential
38
+ * path instead, where the process holds a placeholder and the real value is
39
+ * attached per-host on egress — so it is never in the environment, never in
40
+ * a transcript, and never inherited by a child that had no business with it.
41
+ *
42
+ * Inheritance was broken until it was not: a child built through a
43
+ * `configBuilder` never received this at all, because the builder is
44
+ * written by whoever registered the agent and cannot forward a field it was
45
+ * never told about. It is stamped after the builder returns now, for the
46
+ * same reason `parentSpan` and `resumeHandler` are.
47
+ */
25
48
  env?: Record<string, string>
26
49
 
27
50
  /**
@@ -65,9 +65,42 @@ export interface CreateSubSessionParams {
65
65
  * is out of scope for this phase (session-hierarchy.md §11 defers the project
66
66
  * store to a later phase).
67
67
  */
68
+ /**
69
+ * The part of a Project's configuration a caller may actually set.
70
+ *
71
+ * **Exactly the fields something reads.** `ProjectConfig` declares eight; five
72
+ * enforcement sites read two of them, and the other six have zero readers in
73
+ * production — `maxInterventionDepth` included, whose three apparent hits are
74
+ * all comments claiming a wiring that does not exist. Exposing those here
75
+ * would make a dead field *easier to set*, which is worse than leaving it
76
+ * unreachable: a host would configure a retention policy, get no error, and
77
+ * believe retention was on.
78
+ *
79
+ * The rule is the repo's own: name the code that reads a declaration before
80
+ * shipping it. When a field gains a reader it gains a line here in the same
81
+ * change, and not before.
82
+ */
83
+ export interface ProjectConfigInput {
84
+ /** Read by the spawn path and both handoff paths. Default 4. */
85
+ maxDelegationDepth?: number
86
+ /** Read by the spawn path and broadcast handoff. Default 8. */
87
+ maxDelegationWidth?: number
88
+ }
89
+
68
90
  export interface CreateProjectParams {
69
91
  tenantId: TenantId
70
92
  name: string
93
+
94
+ /**
95
+ * Per-workspace limits. Omitted fields keep the defaults.
96
+ *
97
+ * Until this existed every project in existence ran at depth 4 / width 8,
98
+ * because the config was hardcoded identically in both stores and there was
99
+ * no way to write one afterwards. A tenant with several workspaces could
100
+ * not give them different limits, which is most of what having several
101
+ * workspaces is for.
102
+ */
103
+ config?: ProjectConfigInput
71
104
  }
72
105
 
73
106
  /**
@@ -99,13 +132,67 @@ export interface SessionStore {
99
132
 
100
133
  getProject(projectId: ProjectId, tenantId: TenantId): Promise<Project | null>
101
134
 
135
+ /**
136
+ * Change a Project's limits after it exists. OPTIONAL.
137
+ *
138
+ * Optional because widening a store interface is invisible to callers and
139
+ * fatal to implementors: a host with its own `SessionStore` should not stop
140
+ * compiling because the SDK grew a method. Callers check for it; the two
141
+ * stores here implement it.
142
+ *
143
+ * Only the fields in {@link ProjectConfigInput} can move, and an omitted
144
+ * field is left alone rather than reset — a caller raising the width is not
145
+ * saying anything about the depth. Returns the updated Project, or `null`
146
+ * if it does not exist.
147
+ */
148
+ updateProject?(
149
+ projectId: ProjectId,
150
+ config: ProjectConfigInput,
151
+ tenantId: TenantId,
152
+ ): Promise<Project | null>
153
+
154
+ /**
155
+ * Every Project this tenant owns, oldest first. OPTIONAL, same reasoning.
156
+ *
157
+ * The tenant is the isolation boundary, so this is scoped to it and to
158
+ * nothing else — there is no level above Project to filter by.
159
+ */
160
+ listProjects?(tenantId: TenantId): Promise<readonly Project[]>
161
+
102
162
  // Session CRUD ------------------------------------------------------------
103
163
 
104
164
  createSession(params: CreateSessionParams, tenantId: TenantId): Promise<Session>
105
165
 
106
166
  getSession(sessionId: SessionId, tenantId: TenantId): Promise<Session | null>
107
167
 
108
- updateSession(session: Session, tenantId: TenantId): Promise<void>
168
+ /**
169
+ * Write a Session back, optionally only if nobody else wrote it first.
170
+ *
171
+ * **`expectedOwnerVersion` is the single-writer lock this level is supposed
172
+ * to own, and it did not exist.** `Session.ownerVersion` is documented as
173
+ * the CAS counter for handoff, but nothing enforced it: both stores
174
+ * overwrote unconditionally, and the handoff's own check compared a
175
+ * snapshot it had read several awaits earlier against itself. Two
176
+ * concurrent handoffs on one idle session both passed, both provisioned a
177
+ * worktree, and one silently erased the other.
178
+ *
179
+ * Supply it and the store compares against the version it HAS STORED —
180
+ * not against the payload, which is the caller's stale copy — and throws
181
+ * {@link StaleSessionError} rather than writing. Omit it and the behaviour
182
+ * is exactly what it always was, which is the compatibility promise: this
183
+ * parameter is optional so that widening the interface stays invisible to
184
+ * callers and harmless to hosts implementing their own store. A required
185
+ * parameter would break every implementor for a guarantee they can opt
186
+ * into.
187
+ *
188
+ * **In-process only, stated rather than implied.** `DiskSessionStore`
189
+ * writes atomically, but its read-compare-write is not a critical section,
190
+ * so two PROCESSES can still both pass the check. Closing that needs a
191
+ * lease with an expiry — not a PID registry, because a Session is durable
192
+ * and written from hosts where a PID is not a checkable fact. The same
193
+ * honesty the spawn lock already carries.
194
+ */
195
+ updateSession(session: Session, tenantId: TenantId, expectedOwnerVersion?: number): Promise<void>
109
196
 
110
197
  /**
111
198
  * List every Session that belongs to the given Thread for the caller's