@namzu/sdk 32.0.0 → 33.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 (305) hide show
  1. package/CHANGELOG.md +157 -0
  2. package/dist/authorization/gate.d.ts +1 -1
  3. package/dist/authorization/gate.js +1 -1
  4. package/dist/bridge/a2a/mapper.d.ts.map +1 -1
  5. package/dist/bridge/a2a/mapper.js +13 -0
  6. package/dist/bridge/a2a/mapper.js.map +1 -1
  7. package/dist/bridge/sse/mapper.d.ts.map +1 -1
  8. package/dist/bridge/sse/mapper.js +3 -0
  9. package/dist/bridge/sse/mapper.js.map +1 -1
  10. package/dist/connector/index.d.ts +1 -1
  11. package/dist/connector/index.d.ts.map +1 -1
  12. package/dist/connector/index.js +1 -1
  13. package/dist/connector/index.js.map +1 -1
  14. package/dist/connector/mcp/adapter.d.ts.map +1 -1
  15. package/dist/connector/mcp/adapter.js +71 -16
  16. package/dist/connector/mcp/adapter.js.map +1 -1
  17. package/dist/connector/mcp/client.d.ts.map +1 -1
  18. package/dist/connector/mcp/client.js +3 -2
  19. package/dist/connector/mcp/client.js.map +1 -1
  20. package/dist/connector/mcp/http-redirect.d.ts +17 -0
  21. package/dist/connector/mcp/http-redirect.d.ts.map +1 -0
  22. package/dist/connector/mcp/http-redirect.js +31 -0
  23. package/dist/connector/mcp/http-redirect.js.map +1 -0
  24. package/dist/connector/mcp/http-sse.d.ts.map +1 -1
  25. package/dist/connector/mcp/http-sse.js +5 -0
  26. package/dist/connector/mcp/http-sse.js.map +1 -1
  27. package/dist/connector/mcp/image-admission.d.ts +16 -0
  28. package/dist/connector/mcp/image-admission.d.ts.map +1 -0
  29. package/dist/connector/mcp/image-admission.js +288 -0
  30. package/dist/connector/mcp/image-admission.js.map +1 -0
  31. package/dist/connector/mcp/stdio.d.ts +13 -0
  32. package/dist/connector/mcp/stdio.d.ts.map +1 -1
  33. package/dist/connector/mcp/stdio.js +66 -23
  34. package/dist/connector/mcp/stdio.js.map +1 -1
  35. package/dist/connector/mcp/streamable-http.d.ts.map +1 -1
  36. package/dist/connector/mcp/streamable-http.js +3 -0
  37. package/dist/connector/mcp/streamable-http.js.map +1 -1
  38. package/dist/constants/tools/index.js +1 -1
  39. package/dist/constants/tools/index.js.map +1 -1
  40. package/dist/execution/base.d.ts +13 -0
  41. package/dist/execution/base.d.ts.map +1 -1
  42. package/dist/execution/base.js +103 -8
  43. package/dist/execution/base.js.map +1 -1
  44. package/dist/execution/errors.d.ts +12 -0
  45. package/dist/execution/errors.d.ts.map +1 -0
  46. package/dist/execution/errors.js +21 -0
  47. package/dist/execution/errors.js.map +1 -0
  48. package/dist/execution/factory.d.ts.map +1 -1
  49. package/dist/execution/factory.js +1 -0
  50. package/dist/execution/factory.js.map +1 -1
  51. package/dist/execution/hybrid.d.ts +5 -0
  52. package/dist/execution/hybrid.d.ts.map +1 -1
  53. package/dist/execution/hybrid.js +36 -16
  54. package/dist/execution/hybrid.js.map +1 -1
  55. package/dist/execution/index.d.ts +1 -0
  56. package/dist/execution/index.d.ts.map +1 -1
  57. package/dist/execution/index.js +1 -0
  58. package/dist/execution/index.js.map +1 -1
  59. package/dist/execution/local.d.ts +13 -0
  60. package/dist/execution/local.d.ts.map +1 -1
  61. package/dist/execution/local.js +145 -19
  62. package/dist/execution/local.js.map +1 -1
  63. package/dist/execution/output.d.ts +27 -0
  64. package/dist/execution/output.d.ts.map +1 -0
  65. package/dist/execution/output.js +105 -0
  66. package/dist/execution/output.js.map +1 -0
  67. package/dist/execution/remote.d.ts +26 -2
  68. package/dist/execution/remote.d.ts.map +1 -1
  69. package/dist/execution/remote.js +86 -15
  70. package/dist/execution/remote.js.map +1 -1
  71. package/dist/plugin/lifecycle.d.ts.map +1 -1
  72. package/dist/plugin/lifecycle.js +9 -3
  73. package/dist/plugin/lifecycle.js.map +1 -1
  74. package/dist/process/kill-tree.d.ts +11 -13
  75. package/dist/process/kill-tree.d.ts.map +1 -1
  76. package/dist/process/kill-tree.js +11 -13
  77. package/dist/process/kill-tree.js.map +1 -1
  78. package/dist/provider/capabilities.d.ts +2 -0
  79. package/dist/provider/capabilities.d.ts.map +1 -1
  80. package/dist/provider/capabilities.js +6 -0
  81. package/dist/provider/capabilities.js.map +1 -1
  82. package/dist/provider/fallback.d.ts.map +1 -1
  83. package/dist/provider/fallback.js +31 -0
  84. package/dist/provider/fallback.js.map +1 -1
  85. package/dist/provider/idle-timeout.d.ts.map +1 -1
  86. package/dist/provider/idle-timeout.js +5 -0
  87. package/dist/provider/idle-timeout.js.map +1 -1
  88. package/dist/provider/retry.d.ts.map +1 -1
  89. package/dist/provider/retry.js +5 -0
  90. package/dist/provider/retry.js.map +1 -1
  91. package/dist/public-runtime.d.ts +2 -2
  92. package/dist/public-runtime.d.ts.map +1 -1
  93. package/dist/public-runtime.js +2 -2
  94. package/dist/public-runtime.js.map +1 -1
  95. package/dist/registry/tool/execute.d.ts +7 -1
  96. package/dist/registry/tool/execute.d.ts.map +1 -1
  97. package/dist/registry/tool/execute.js +201 -54
  98. package/dist/registry/tool/execute.js.map +1 -1
  99. package/dist/run/command-gate.d.ts.map +1 -1
  100. package/dist/run/command-gate.js +11 -0
  101. package/dist/run/command-gate.js.map +1 -1
  102. package/dist/run/workspace-fingerprint.d.ts +4 -4
  103. package/dist/run/workspace-fingerprint.d.ts.map +1 -1
  104. package/dist/run/workspace-fingerprint.js +6 -4
  105. package/dist/run/workspace-fingerprint.js.map +1 -1
  106. package/dist/runtime/bidi/index.d.ts +1 -1
  107. package/dist/runtime/bidi/index.d.ts.map +1 -1
  108. package/dist/runtime/bidi/index.js +1 -1
  109. package/dist/runtime/bidi/index.js.map +1 -1
  110. package/dist/runtime/bidi/session.d.ts +19 -0
  111. package/dist/runtime/bidi/session.d.ts.map +1 -1
  112. package/dist/runtime/bidi/session.js +150 -26
  113. package/dist/runtime/bidi/session.js.map +1 -1
  114. package/dist/runtime/query/executor.d.ts +43 -1
  115. package/dist/runtime/query/executor.d.ts.map +1 -1
  116. package/dist/runtime/query/executor.js +626 -161
  117. package/dist/runtime/query/executor.js.map +1 -1
  118. package/dist/runtime/query/index.d.ts +3 -1
  119. package/dist/runtime/query/index.d.ts.map +1 -1
  120. package/dist/runtime/query/index.js +48 -4
  121. package/dist/runtime/query/index.js.map +1 -1
  122. package/dist/runtime/query/iteration/index.d.ts +10 -0
  123. package/dist/runtime/query/iteration/index.d.ts.map +1 -1
  124. package/dist/runtime/query/iteration/index.js +67 -0
  125. package/dist/runtime/query/iteration/index.js.map +1 -1
  126. package/dist/runtime/query/iteration/phases/context.d.ts +5 -0
  127. package/dist/runtime/query/iteration/phases/context.d.ts.map +1 -1
  128. package/dist/runtime/query/iteration/phases/context.js.map +1 -1
  129. package/dist/runtime/query/iteration/phases/tool-review.d.ts.map +1 -1
  130. package/dist/runtime/query/iteration/phases/tool-review.js +84 -22
  131. package/dist/runtime/query/iteration/phases/tool-review.js.map +1 -1
  132. package/dist/runtime/query/request-rich-content.d.ts.map +1 -1
  133. package/dist/runtime/query/request-rich-content.js +33 -13
  134. package/dist/runtime/query/request-rich-content.js.map +1 -1
  135. package/dist/runtime/query/result.d.ts.map +1 -1
  136. package/dist/runtime/query/result.js +25 -22
  137. package/dist/runtime/query/result.js.map +1 -1
  138. package/dist/runtime/query/resume-pending.d.ts +5 -1
  139. package/dist/runtime/query/resume-pending.d.ts.map +1 -1
  140. package/dist/runtime/query/resume-pending.js +66 -1
  141. package/dist/runtime/query/resume-pending.js.map +1 -1
  142. package/dist/runtime/query/tool-output-budget.d.ts.map +1 -1
  143. package/dist/runtime/query/tool-output-budget.js +45 -16
  144. package/dist/runtime/query/tool-output-budget.js.map +1 -1
  145. package/dist/runtime/query/tooling.d.ts +6 -0
  146. package/dist/runtime/query/tooling.d.ts.map +1 -1
  147. package/dist/runtime/query/tooling.js +4 -0
  148. package/dist/runtime/query/tooling.js.map +1 -1
  149. package/dist/sandbox/provider/local.d.ts.map +1 -1
  150. package/dist/sandbox/provider/local.js +193 -41
  151. package/dist/sandbox/provider/local.js.map +1 -1
  152. package/dist/scheduler/delegating.d.ts +2 -1
  153. package/dist/scheduler/delegating.d.ts.map +1 -1
  154. package/dist/scheduler/delegating.js +6 -5
  155. package/dist/scheduler/delegating.js.map +1 -1
  156. package/dist/scheduler/local.d.ts +2 -1
  157. package/dist/scheduler/local.d.ts.map +1 -1
  158. package/dist/scheduler/local.js +2 -2
  159. package/dist/scheduler/local.js.map +1 -1
  160. package/dist/session/workspace/driver.d.ts +12 -4
  161. package/dist/session/workspace/driver.d.ts.map +1 -1
  162. package/dist/session/workspace/git-worktree.d.ts +17 -3
  163. package/dist/session/workspace/git-worktree.d.ts.map +1 -1
  164. package/dist/session/workspace/git-worktree.js +153 -34
  165. package/dist/session/workspace/git-worktree.js.map +1 -1
  166. package/dist/skills/registry.d.ts +15 -0
  167. package/dist/skills/registry.d.ts.map +1 -1
  168. package/dist/skills/registry.js +33 -0
  169. package/dist/skills/registry.js.map +1 -1
  170. package/dist/tools/builtins/computer-use.d.ts.map +1 -1
  171. package/dist/tools/builtins/computer-use.js +76 -2
  172. package/dist/tools/builtins/computer-use.js.map +1 -1
  173. package/dist/tools/builtins/run-code.d.ts.map +1 -1
  174. package/dist/tools/builtins/run-code.js +9 -11
  175. package/dist/tools/builtins/run-code.js.map +1 -1
  176. package/dist/tools/builtins/skill.d.ts +2 -1
  177. package/dist/tools/builtins/skill.d.ts.map +1 -1
  178. package/dist/tools/builtins/skill.js +250 -6
  179. package/dist/tools/builtins/skill.js.map +1 -1
  180. package/dist/tools/coordinator/agent.d.ts.map +1 -1
  181. package/dist/tools/coordinator/agent.js +100 -30
  182. package/dist/tools/coordinator/agent.js.map +1 -1
  183. package/dist/types/agent/manager.d.ts +1 -1
  184. package/dist/types/agent/manager.d.ts.map +1 -1
  185. package/dist/types/agent/scheduler.d.ts +10 -1
  186. package/dist/types/agent/scheduler.d.ts.map +1 -1
  187. package/dist/types/authorization/index.d.ts +12 -12
  188. package/dist/types/bidi/index.d.ts +19 -2
  189. package/dist/types/bidi/index.d.ts.map +1 -1
  190. package/dist/types/computer-use/index.d.ts +18 -0
  191. package/dist/types/computer-use/index.d.ts.map +1 -1
  192. package/dist/types/connector/execution-context.d.ts +3 -1
  193. package/dist/types/connector/execution-context.d.ts.map +1 -1
  194. package/dist/types/errors/catalog.d.ts.map +1 -1
  195. package/dist/types/errors/catalog.js +13 -6
  196. package/dist/types/errors/catalog.js.map +1 -1
  197. package/dist/types/errors/index.d.ts.map +1 -1
  198. package/dist/types/errors/index.js +21 -8
  199. package/dist/types/errors/index.js.map +1 -1
  200. package/dist/types/execution/index.d.ts +43 -1
  201. package/dist/types/execution/index.d.ts.map +1 -1
  202. package/dist/types/hitl/index.d.ts +11 -0
  203. package/dist/types/hitl/index.d.ts.map +1 -1
  204. package/dist/types/hitl/index.js.map +1 -1
  205. package/dist/types/message/index.d.ts +1 -1
  206. package/dist/types/message/index.d.ts.map +1 -1
  207. package/dist/types/message/index.js +2 -1
  208. package/dist/types/message/index.js.map +1 -1
  209. package/dist/types/plugin/index.d.ts +14 -1
  210. package/dist/types/plugin/index.d.ts.map +1 -1
  211. package/dist/types/plugin/index.js +1 -0
  212. package/dist/types/plugin/index.js.map +1 -1
  213. package/dist/types/provider/config.d.ts +9 -0
  214. package/dist/types/provider/config.d.ts.map +1 -1
  215. package/dist/types/provider/interface.d.ts +14 -0
  216. package/dist/types/provider/interface.d.ts.map +1 -1
  217. package/dist/types/run/events.d.ts +17 -0
  218. package/dist/types/run/events.d.ts.map +1 -1
  219. package/dist/types/run/events.js.map +1 -1
  220. package/dist/types/sandbox/index.d.ts +15 -10
  221. package/dist/types/sandbox/index.d.ts.map +1 -1
  222. package/dist/types/sandbox/index.js.map +1 -1
  223. package/dist/types/tool/index.d.ts +77 -6
  224. package/dist/types/tool/index.d.ts.map +1 -1
  225. package/dist/types/tool/index.js.map +1 -1
  226. package/dist/types/tool/presentation.d.ts +6 -2
  227. package/dist/types/tool/presentation.d.ts.map +1 -1
  228. package/dist/types/workspace/ref.d.ts +5 -0
  229. package/dist/types/workspace/ref.d.ts.map +1 -1
  230. package/dist/utils/abort.d.ts +8 -0
  231. package/dist/utils/abort.d.ts.map +1 -1
  232. package/dist/utils/abort.js +16 -0
  233. package/dist/utils/abort.js.map +1 -1
  234. package/package.json +4 -4
  235. package/src/authorization/gate.ts +1 -1
  236. package/src/bridge/a2a/mapper.ts +23 -4
  237. package/src/bridge/sse/mapper.ts +3 -0
  238. package/src/connector/index.ts +2 -0
  239. package/src/connector/mcp/adapter.ts +82 -21
  240. package/src/connector/mcp/client.ts +2 -1
  241. package/src/connector/mcp/http-redirect.ts +32 -0
  242. package/src/connector/mcp/http-sse.ts +5 -0
  243. package/src/connector/mcp/image-admission.ts +272 -0
  244. package/src/connector/mcp/stdio.ts +63 -21
  245. package/src/connector/mcp/streamable-http.ts +3 -0
  246. package/src/constants/tools/index.ts +1 -1
  247. package/src/execution/base.ts +124 -7
  248. package/src/execution/errors.ts +24 -0
  249. package/src/execution/factory.ts +1 -0
  250. package/src/execution/hybrid.ts +47 -16
  251. package/src/execution/index.ts +1 -0
  252. package/src/execution/local.ts +164 -19
  253. package/src/execution/output.ts +104 -0
  254. package/src/execution/remote.ts +122 -17
  255. package/src/plugin/lifecycle.ts +9 -3
  256. package/src/process/kill-tree.ts +11 -13
  257. package/src/provider/capabilities.ts +10 -0
  258. package/src/provider/fallback.ts +39 -0
  259. package/src/provider/idle-timeout.ts +8 -0
  260. package/src/provider/retry.ts +8 -0
  261. package/src/public-runtime.ts +7 -1
  262. package/src/registry/tool/execute.ts +230 -64
  263. package/src/run/command-gate.ts +12 -0
  264. package/src/run/workspace-fingerprint.ts +5 -4
  265. package/src/runtime/bidi/index.ts +1 -1
  266. package/src/runtime/bidi/session.ts +177 -28
  267. package/src/runtime/query/executor.ts +769 -163
  268. package/src/runtime/query/index.ts +58 -7
  269. package/src/runtime/query/iteration/index.ts +72 -0
  270. package/src/runtime/query/iteration/phases/context.ts +5 -0
  271. package/src/runtime/query/iteration/phases/tool-review.ts +87 -23
  272. package/src/runtime/query/request-rich-content.ts +39 -14
  273. package/src/runtime/query/result.ts +25 -23
  274. package/src/runtime/query/resume-pending.ts +83 -1
  275. package/src/runtime/query/tool-output-budget.ts +52 -17
  276. package/src/runtime/query/tooling.ts +10 -0
  277. package/src/sandbox/provider/local.ts +213 -45
  278. package/src/scheduler/delegating.ts +6 -5
  279. package/src/scheduler/local.ts +3 -2
  280. package/src/session/workspace/driver.ts +12 -4
  281. package/src/session/workspace/git-worktree.ts +173 -34
  282. package/src/skills/registry.ts +47 -0
  283. package/src/tools/builtins/computer-use.ts +86 -2
  284. package/src/tools/builtins/run-code.ts +9 -11
  285. package/src/tools/builtins/skill.ts +325 -7
  286. package/src/tools/coordinator/agent.ts +108 -33
  287. package/src/types/agent/manager.ts +1 -1
  288. package/src/types/agent/scheduler.ts +10 -1
  289. package/src/types/bidi/index.ts +19 -2
  290. package/src/types/computer-use/index.ts +19 -0
  291. package/src/types/connector/execution-context.ts +3 -0
  292. package/src/types/errors/catalog.ts +14 -6
  293. package/src/types/errors/index.ts +22 -8
  294. package/src/types/execution/index.ts +46 -1
  295. package/src/types/hitl/index.ts +11 -0
  296. package/src/types/message/index.ts +3 -2
  297. package/src/types/plugin/index.ts +15 -0
  298. package/src/types/provider/config.ts +9 -0
  299. package/src/types/provider/interface.ts +18 -0
  300. package/src/types/run/events.ts +17 -3
  301. package/src/types/sandbox/index.ts +15 -10
  302. package/src/types/tool/index.ts +85 -6
  303. package/src/types/tool/presentation.ts +10 -3
  304. package/src/types/workspace/ref.ts +5 -0
  305. package/src/utils/abort.ts +18 -0
@@ -1,3 +1,4 @@
1
+ import { createHash } from 'node:crypto'
1
2
  import { z } from 'zod'
2
3
 
3
4
  import { isInvocableBy, skillInvocation } from '../../types/skills/index.js'
@@ -23,11 +24,213 @@ const inputSchema = z.object({
23
24
  name: z
24
25
  .string()
25
26
  .min(1)
26
- .describe('The skill to load, exactly as listed in the available-skills manifest.'),
27
+ .optional()
28
+ .describe(
29
+ 'The skill to load, exactly as listed in the available-skills manifest. Omit it to list model-invocable skills.',
30
+ ),
31
+ cursor: z
32
+ .string()
33
+ .max(160)
34
+ .optional()
35
+ .describe('Opaque continuation cursor returned by an earlier call in the same mode.'),
27
36
  })
28
37
 
29
38
  type SkillInput = z.infer<typeof inputSchema>
30
39
 
40
+ const CURSOR_PATTERN = /^v1\.([1-9][0-9]*)\.([A-Za-z0-9_-]{43})$/
41
+ const LIST_CURSOR_PATTERN = /^v1\.list\.(0|[1-9][0-9]*)\.([01])\.([A-Za-z0-9_-]{43})$/
42
+ const MAX_SKILLS_PER_PAGE = 20
43
+ const OVERSIZED_CATALOG_WARNING =
44
+ 'Some skills were omitted because their metadata is too large for this response budget.'
45
+
46
+ interface SkillSnapshot {
47
+ readonly name: string
48
+ readonly body: string
49
+ readonly allowedTools: readonly string[] | undefined
50
+ readonly invocation: ReturnType<typeof skillInvocation>
51
+ }
52
+
53
+ interface SkillPage {
54
+ readonly output: string
55
+ readonly nextCursor?: string
56
+ }
57
+
58
+ interface ListedSkill {
59
+ readonly name: string
60
+ readonly description: string
61
+ readonly location: string
62
+ readonly allowedTools?: string
63
+ }
64
+
65
+ interface SkillListPage {
66
+ readonly skills: readonly ListedSkill[]
67
+ readonly warnings: readonly string[]
68
+ readonly nextCursor: string | null
69
+ }
70
+
71
+ function snapshotDigest(snapshot: SkillSnapshot): string {
72
+ return createHash('sha256')
73
+ .update(
74
+ JSON.stringify({
75
+ version: 1,
76
+ name: snapshot.name,
77
+ body: snapshot.body,
78
+ allowedTools: snapshot.allowedTools ?? null,
79
+ invocation: snapshot.invocation,
80
+ }),
81
+ )
82
+ .digest('base64url')
83
+ }
84
+
85
+ function cursorFor(offset: number, digest: string): string {
86
+ return `v1.${offset}.${digest}`
87
+ }
88
+
89
+ function parseCursor(cursor: string): { offset: number; digest: string } | undefined {
90
+ const match = CURSOR_PATTERN.exec(cursor)
91
+ if (!match) return undefined
92
+ const offset = Number(match[1])
93
+ if (!Number.isSafeInteger(offset)) return undefined
94
+ return { offset, digest: match[2] ?? '' }
95
+ }
96
+
97
+ function listCursorFor(offset: number, warned: boolean, digest: string): string {
98
+ return `v1.list.${offset}.${warned ? 1 : 0}.${digest}`
99
+ }
100
+
101
+ function parseListCursor(
102
+ cursor: string,
103
+ ): { offset: number; warned: boolean; digest: string } | undefined {
104
+ const match = LIST_CURSOR_PATTERN.exec(cursor)
105
+ if (!match) return undefined
106
+ const offset = Number(match[1])
107
+ if (!Number.isSafeInteger(offset)) return undefined
108
+ return { offset, warned: match[2] === '1', digest: match[3] ?? '' }
109
+ }
110
+
111
+ function activeOutputCap(maxChars: number | undefined): number | undefined {
112
+ return maxChars !== undefined && maxChars > 0 ? maxChars : undefined
113
+ }
114
+
115
+ function listDigest(skills: readonly ListedSkill[], maxChars: number | undefined): string {
116
+ return createHash('sha256')
117
+ .update(JSON.stringify({ version: 1, kind: 'list', maxChars: maxChars ?? null, skills }))
118
+ .digest('base64url')
119
+ }
120
+
121
+ function serializeListPage(page: SkillListPage): string {
122
+ return JSON.stringify(page)
123
+ }
124
+
125
+ function fitsListBudget(page: SkillListPage, maxChars: number | undefined): boolean {
126
+ return maxChars === undefined || serializeListPage(page).length <= maxChars
127
+ }
128
+
129
+ function pageSkillCatalog(input: {
130
+ readonly skills: readonly ListedSkill[]
131
+ readonly digest: string
132
+ readonly start: number
133
+ readonly warningAlreadyShown: boolean
134
+ readonly maxChars: number | undefined
135
+ }): SkillListPage | undefined {
136
+ const { skills, digest, start, warningAlreadyShown, maxChars } = input
137
+ const retained: Array<{ index: number; skill: ListedSkill }> = []
138
+ let omitted = false
139
+ let hasRetainedLater = false
140
+
141
+ // Work backwards so the final retained entry is tested without a cursor.
142
+ // A last entry that fits by itself must not be dropped merely because an
143
+ // earlier page will need a continuation token to reach it.
144
+ for (let index = skills.length - 1; index >= start; index -= 1) {
145
+ const skill = skills[index]
146
+ if (!skill) continue
147
+ const nextCursor = hasRetainedLater ? listCursorFor(index + 1, true, digest) : null
148
+ if (fitsListBudget({ skills: [skill], warnings: [], nextCursor }, maxChars)) {
149
+ retained.push({ index, skill })
150
+ hasRetainedLater = true
151
+ } else {
152
+ omitted = true
153
+ }
154
+ }
155
+ retained.reverse()
156
+
157
+ const warning = omitted && !warningAlreadyShown ? [OVERSIZED_CATALOG_WARNING] : []
158
+ let count = Math.min(MAX_SKILLS_PER_PAGE, retained.length)
159
+ while (count > 0) {
160
+ const selected = retained.slice(0, count)
161
+ const last = selected.at(-1)
162
+ const hasMore = count < retained.length
163
+ const page: SkillListPage = {
164
+ skills: selected.map((entry) => entry.skill),
165
+ warnings: warning,
166
+ nextCursor:
167
+ hasMore && last
168
+ ? listCursorFor(last.index + 1, warningAlreadyShown || warning.length > 0, digest)
169
+ : null,
170
+ }
171
+ if (fitsListBudget(page, maxChars)) return page
172
+ count -= 1
173
+ }
174
+
175
+ if (warning.length > 0) {
176
+ const page: SkillListPage = {
177
+ skills: [],
178
+ warnings: warning,
179
+ nextCursor: retained.length > 0 ? listCursorFor(start, true, digest) : null,
180
+ }
181
+ if (fitsListBudget(page, maxChars)) return page
182
+ }
183
+
184
+ const empty: SkillListPage = { skills: [], warnings: [], nextCursor: null }
185
+ return retained.length === 0 && fitsListBudget(empty, maxChars) ? empty : undefined
186
+ }
187
+
188
+ function isCodePointBoundary(text: string, index: number): boolean {
189
+ if (index <= 0 || index >= text.length) return true
190
+ const before = text.charCodeAt(index - 1)
191
+ const after = text.charCodeAt(index)
192
+ return !(before >= 0xd800 && before <= 0xdbff && after >= 0xdc00 && after <= 0xdfff)
193
+ }
194
+
195
+ function boundaryAtOrBefore(text: string, index: number): number {
196
+ const bounded = Math.max(0, Math.min(text.length, index))
197
+ return isCodePointBoundary(text, bounded) ? bounded : bounded - 1
198
+ }
199
+
200
+ function continuationNotice(name: string, cursor: string): string {
201
+ return `\n\n[More skill instructions remain. Call skill again with name "${name}" and cursor "${cursor}" before acting.]`
202
+ }
203
+
204
+ function pageSkillBody(input: {
205
+ readonly snapshot: SkillSnapshot
206
+ readonly digest: string
207
+ readonly start: number
208
+ readonly notice: string
209
+ readonly maxChars: number | undefined
210
+ }): SkillPage | undefined {
211
+ const { snapshot, digest, start, notice, maxChars } = input
212
+ const remaining = `${snapshot.body.slice(start)}${notice}`
213
+ if (maxChars === undefined || maxChars <= 0 || remaining.length <= maxChars) {
214
+ return { output: remaining }
215
+ }
216
+
217
+ // Estimate once, then remove exactly the overflow until the page fits.
218
+ // The cursor grows only at powers of ten, so this converges in a handful
219
+ // of steps without allocating an index for every character in a large file.
220
+ let end = boundaryAtOrBefore(snapshot.body, Math.min(snapshot.body.length - 1, start + maxChars))
221
+ while (end > start) {
222
+ const nextCursor = cursorFor(end, digest)
223
+ const output = `${snapshot.body.slice(start, end)}${continuationNotice(
224
+ snapshot.name,
225
+ nextCursor,
226
+ )}${notice}`
227
+ if (output.length <= maxChars) return { output, nextCursor }
228
+ end = boundaryAtOrBefore(snapshot.body, end - Math.max(1, output.length - maxChars))
229
+ }
230
+
231
+ return undefined
232
+ }
233
+
31
234
  /**
32
235
  * `allowed-tools` as a list.
33
236
  *
@@ -54,7 +257,7 @@ export const SKILL_TOOL_NAME = 'skill'
54
257
  export const SkillTool = defineTool({
55
258
  name: SKILL_TOOL_NAME,
56
259
  description:
57
- 'Loads the full instructions for a skill listed in the available-skills manifest. Call this before doing work the skill describes; the manifest carries only names and descriptions.',
260
+ 'Lists model-invocable skills when called without a name, or loads one skill by its exact listed name. Long lists and bodies return an opaque continuation cursor; keep calling in the same mode with that cursor until no continuation remains. The manifest carries only names and descriptions.',
58
261
  inputSchema,
59
262
  category: 'analysis',
60
263
  permissions: [],
@@ -75,6 +278,75 @@ export const SkillTool = defineTool({
75
278
  }
76
279
  }
77
280
 
281
+ if (input.name === undefined) {
282
+ if (!context.skills.catalog) {
283
+ return {
284
+ success: false,
285
+ output: '',
286
+ error:
287
+ 'This skills registry cannot enumerate model-safe metadata. Use a skill name from the available-skills manifest.',
288
+ }
289
+ }
290
+ const skills = (await context.skills.catalog())
291
+ .filter(
292
+ (entry) =>
293
+ entry.invocation === undefined ||
294
+ entry.invocation === 'model' ||
295
+ entry.invocation === 'both',
296
+ )
297
+ .map(
298
+ (entry): ListedSkill => ({
299
+ name: entry.registeredName,
300
+ description: entry.description,
301
+ location: entry.location,
302
+ ...(entry.allowedTools === undefined ? {} : { allowedTools: entry.allowedTools }),
303
+ }),
304
+ )
305
+ const maxChars = activeOutputCap(context.maxToolOutputChars)
306
+ const digest = listDigest(skills, maxChars)
307
+ let start = 0
308
+ let warningAlreadyShown = false
309
+ if (input.cursor !== undefined) {
310
+ const parsed = parseListCursor(input.cursor)
311
+ if (!parsed || parsed.digest !== digest || parsed.offset >= skills.length) {
312
+ return {
313
+ success: false,
314
+ output: '',
315
+ error:
316
+ 'The skill-list continuation cursor is stale or invalid. Call skill again without a cursor to read the current catalog.',
317
+ }
318
+ }
319
+ start = parsed.offset
320
+ warningAlreadyShown = parsed.warned
321
+ }
322
+
323
+ const page = pageSkillCatalog({
324
+ skills,
325
+ digest,
326
+ start,
327
+ warningAlreadyShown,
328
+ maxChars,
329
+ })
330
+ if (!page) {
331
+ return {
332
+ success: false,
333
+ output: '',
334
+ error:
335
+ 'The model-visible tool-output budget is too small to list skill metadata safely. Increase maxToolOutputChars and retry.',
336
+ }
337
+ }
338
+
339
+ return {
340
+ success: true,
341
+ output: serializeListPage(page),
342
+ data: {
343
+ kind: 'list',
344
+ count: page.skills.length,
345
+ ...(page.nextCursor === null ? {} : { nextCursor: page.nextCursor }),
346
+ },
347
+ }
348
+ }
349
+
78
350
  // The registry answers with a load RESULT, not a skill — the shape
79
351
  // mirrors the implementation rather than an adapter, so there is
80
352
  // nothing between them to drift.
@@ -92,6 +364,7 @@ export const SkillTool = defineTool({
92
364
  }
93
365
 
94
366
  const skill = loaded.skill
367
+ const invocation = skillInvocation(skill)
95
368
  if (!isInvocableBy(skill, 'model')) {
96
369
  // Reachable even though the manifest omits it: the model can name
97
370
  // anything, and a check that only filtered the listing would be a
@@ -105,6 +378,54 @@ export const SkillTool = defineTool({
105
378
  }
106
379
 
107
380
  const allowed = parseAllowedTools(skill.metadata.allowedTools)
381
+ const snapshot: SkillSnapshot = {
382
+ name: input.name,
383
+ body: skill.body ?? '(this skill has no body)',
384
+ allowedTools: allowed,
385
+ invocation,
386
+ }
387
+ const digest = snapshotDigest(snapshot)
388
+ let start = 0
389
+ if (input.cursor !== undefined) {
390
+ const parsed = parseCursor(input.cursor)
391
+ if (
392
+ !parsed ||
393
+ parsed.digest !== digest ||
394
+ parsed.offset >= snapshot.body.length ||
395
+ !isCodePointBoundary(snapshot.body, parsed.offset)
396
+ ) {
397
+ return {
398
+ success: false,
399
+ output: '',
400
+ error: `The continuation cursor for "${input.name}" is stale or invalid. Call skill again without a cursor to read the current instructions.`,
401
+ }
402
+ }
403
+ start = parsed.offset
404
+ }
405
+
406
+ const notice =
407
+ allowed === undefined
408
+ ? ''
409
+ : `\n\n[While following this skill, restrict yourself to: ${allowed.length > 0 ? allowed.join(', ') : '(no tools)'}. This takes effect from your next turn.]`
410
+ const page = pageSkillBody({
411
+ snapshot,
412
+ digest,
413
+ start,
414
+ notice,
415
+ maxChars: context.maxToolOutputChars,
416
+ })
417
+ if (!page) {
418
+ return {
419
+ success: false,
420
+ output: '',
421
+ error: `The model-visible tool-output budget is too small to read "${input.name}" safely. Increase maxToolOutputChars and retry.`,
422
+ }
423
+ }
424
+
425
+ // Cursor and policy validation must finish before this mutation. A
426
+ // continuation is bound to the body AND its effective authorization
427
+ // metadata, so an edit to allowed-tools or invocation cannot widen the
428
+ // next batch under an old cursor.
108
429
  if (allowed !== undefined) {
109
430
  // Adopted, not merely announced. The notice below tells the model
110
431
  // what happened; this is what makes it true whether or not the
@@ -117,17 +438,14 @@ export const SkillTool = defineTool({
117
438
  // advice.
118
439
  context.adoptSkillScope?.({ skill: skill.metadata.name, allowedTools: allowed })
119
440
  }
120
- const notice =
121
- allowed === undefined
122
- ? ''
123
- : `\n\n[While following this skill, restrict yourself to: ${allowed.length > 0 ? allowed.join(', ') : '(no tools)'}. This takes effect from your next turn.]`
124
441
 
125
442
  return {
126
443
  success: true,
127
- output: `${skill.body ?? '(this skill has no body)'}${notice}`,
444
+ output: page.output,
128
445
  data: {
129
446
  skill: skill.metadata.name,
130
447
  ...(allowed === undefined ? {} : { allowedTools: allowed }),
448
+ ...(page.nextCursor === undefined ? {} : { nextCursor: page.nextCursor }),
131
449
  },
132
450
  }
133
451
  },
@@ -1,7 +1,7 @@
1
1
  import { z } from 'zod'
2
2
 
3
3
  import type { AgentRuntimeContext } from '../../types/agent/base.js'
4
- import type { TaskScheduler } from '../../types/agent/scheduler.js'
4
+ import type { CreateTaskOptions, TaskHandle, TaskScheduler } from '../../types/agent/scheduler.js'
5
5
  import type { ToolDefinition } from '../../types/tool/index.js'
6
6
  import { defineTool } from '../defineTool.js'
7
7
  import { wrapUntrusted } from '../untrusted-envelope.js'
@@ -146,40 +146,42 @@ export function buildAgentTool(opts: AgentToolOptions): ToolDefinition {
146
146
  error: `Unknown subagent_type "${agentId}" — choose one of: ${agentIds.join(', ')}`,
147
147
  }
148
148
  }
149
- const handle = await gateway.createTask({
150
- agentId,
151
- prompt,
152
- workingDirectory: cwd,
153
- runtimeContext: opts.runtimeContext,
154
- // Hang the child off the executing tool's span, so the
155
- // delegation appears inside the turn that asked for it rather
156
- // than as a disconnected root trace. `create_task` has done
157
- // this all along; this tool the kernel's other delegation
158
- // surface, and the one it exports as the canonical shape —
159
- // did not.
160
- ...(context.parentSpan ? { parentSpan: context.parentSpan } : {}),
161
- // The parent's environment, which is the whole point of setting
162
- // one: a delegate that cannot see it runs against different
163
- // services than the run that launched it, silently.
164
- // `ToolContext.env` is the parent's own resolved map, per run.
165
- ...(Object.keys(context.env ?? {}).length > 0
166
- ? { configOverrides: { env: context.env } }
167
- : {}),
168
- })
169
-
170
- onTaskLaunched?.(handle.taskId, {
171
- agentId,
172
- description,
173
- // Same canonical-envelope plumbing as coordinator/index.ts
174
- // (ses_009-task-notification-envelope). For Agent-tool path
175
- // the subagent run is awaited synchronously below, so this
176
- // id is only used if a probe / hook unexpectedly forks the
177
- // completion to the background notification channel.
178
- originalToolUseId: context.toolUseId,
149
+ const { handle, completed } = await runBlockingAgentTask({
150
+ gateway,
151
+ signal: context.abortSignal,
152
+ create: {
153
+ agentId,
154
+ prompt,
155
+ workingDirectory: cwd,
156
+ runtimeContext: opts.runtimeContext,
157
+ // Hang the child off the executing tool's span, so the
158
+ // delegation appears inside the turn that asked for it rather
159
+ // than as a disconnected root trace. `create_task` has done
160
+ // this all along; this tool the kernel's other delegation
161
+ // surface, and the one it exports as the canonical shape
162
+ // did not.
163
+ ...(context.parentSpan ? { parentSpan: context.parentSpan } : {}),
164
+ // The parent's environment, which is the whole point of setting
165
+ // one: a delegate that cannot see it runs against different
166
+ // services than the run that launched it, silently.
167
+ // `ToolContext.env` is the parent's own resolved map, per run.
168
+ ...(Object.keys(context.env ?? {}).length > 0
169
+ ? { configOverrides: { env: context.env } }
170
+ : {}),
171
+ },
172
+ onCreated: (handle) =>
173
+ onTaskLaunched?.(handle.taskId, {
174
+ agentId,
175
+ description,
176
+ // Same canonical-envelope plumbing as coordinator/index.ts
177
+ // (ses_009-task-notification-envelope). For Agent-tool path
178
+ // the subagent run is awaited synchronously below, so this
179
+ // id is only used if a probe / hook unexpectedly forks the
180
+ // completion to the background notification channel.
181
+ originalToolUseId: context.toolUseId,
182
+ }),
179
183
  })
180
184
 
181
- const completed = await gateway.waitForTask(handle.taskId)
182
-
183
185
  // Both authorities must agree — see `taskSucceeded` for which two
184
186
  // and why either alone is wrong. The reasoning used to live here
185
187
  // alone, which is exactly how `create_task` came to ship without
@@ -253,3 +255,76 @@ export function buildAgentTool(opts: AgentToolOptions): ToolDefinition {
253
255
  },
254
256
  })
255
257
  }
258
+
259
+ interface BlockingAgentTaskInput {
260
+ readonly gateway: TaskScheduler
261
+ readonly signal: AbortSignal
262
+ readonly create: CreateTaskOptions
263
+ readonly onCreated?: (handle: TaskHandle) => void
264
+ }
265
+
266
+ /**
267
+ * Own a blocking child from before creation until its terminal handle.
268
+ *
269
+ * The late-create branch is load-bearing. `createTask()` can be inside an
270
+ * asynchronous workspace/config build when its parent is cancelled. Racing
271
+ * that await lets the parent settle promptly, but the eventual handle still
272
+ * has to be cancelled or the task is born after its authority disappeared.
273
+ */
274
+ async function runBlockingAgentTask(
275
+ input: BlockingAgentTaskInput,
276
+ ): Promise<{ handle: TaskHandle; completed: TaskHandle }> {
277
+ const { gateway, signal } = input
278
+ signal.throwIfAborted()
279
+
280
+ let handle: TaskHandle | undefined
281
+ let cancellationRequested = false
282
+ let taskCancellationAttempted = false
283
+ let rejectAbort: (reason: unknown) => void = () => {}
284
+ const aborted = new Promise<never>((_resolve, reject) => {
285
+ rejectAbort = reject
286
+ })
287
+ const cancel = (task: TaskHandle): void => {
288
+ if (taskCancellationAttempted) return
289
+ taskCancellationAttempted = true
290
+ try {
291
+ gateway.cancelTask(task.taskId, 'parent')
292
+ } catch {
293
+ // Parent cancellation is authoritative even when a host scheduler
294
+ // cannot honour cancellation for its delegate. Do not replace the
295
+ // parent's exact abort reason with a secondary capability error.
296
+ }
297
+ }
298
+ const onAbort = (): void => {
299
+ cancellationRequested = true
300
+ if (handle) cancel(handle)
301
+ rejectAbort(signal.reason)
302
+ }
303
+
304
+ signal.addEventListener('abort', onAbort, { once: true })
305
+ if (signal.aborted) onAbort()
306
+ const creation = gateway.createTask(input.create)
307
+ // The abort race can win first. Observe the losing creation promise and
308
+ // cancel its eventual task in `finally` rather than leaving a rejection or
309
+ // late child detached.
310
+ creation.catch(() => {})
311
+
312
+ try {
313
+ handle = await Promise.race([creation, aborted])
314
+ if (cancellationRequested || signal.aborted) {
315
+ cancel(handle)
316
+ signal.throwIfAborted()
317
+ }
318
+ input.onCreated?.(handle)
319
+ const completed = await Promise.race([gateway.waitForTask(handle.taskId), aborted])
320
+ return { handle, completed }
321
+ } catch (error) {
322
+ if (handle) cancel(handle)
323
+ throw error
324
+ } finally {
325
+ if (!handle && cancellationRequested) {
326
+ void creation.then(cancel, () => {})
327
+ }
328
+ signal.removeEventListener('abort', onAbort)
329
+ }
330
+ }
@@ -16,7 +16,7 @@ export interface AgentManagerContract {
16
16
  listener?: RunEventListener,
17
17
  ): Promise<AgentTask>
18
18
 
19
- cancel(taskId: TaskId): void
19
+ cancel(taskId: TaskId, cause?: CancelCause): void
20
20
  /**
21
21
  * Defaults to `'parent'` when a caller names nothing, because this call
22
22
  * site IS a parent abandoning its children — unlike `AbstractAgent.cancel`,
@@ -1,5 +1,6 @@
1
1
  import type { TaskId } from '../ids/index.js'
2
2
  import type { AgentPersona } from '../persona/index.js'
3
+ import type { CancelCause } from '../run/cancel-cause.js'
3
4
  import type { AgentRuntimeContext, BaseAgentConfig, BaseAgentResult } from './base.js'
4
5
  import type { AgentTaskState } from './task.js'
5
6
 
@@ -93,7 +94,15 @@ export interface TaskScheduler {
93
94
 
94
95
  continueTask(taskId: TaskId, message: string): Promise<void>
95
96
 
96
- cancelTask(taskId: TaskId): void
97
+ /**
98
+ * Stop one task. A cause is relative to the child: a blocking delegation
99
+ * abandoned by the run that launched it is cancelled by its `parent`.
100
+ *
101
+ * Optional so existing host schedulers remain structurally compatible. A
102
+ * scheduler that can preserve the cause should carry it to the task's abort
103
+ * signal; built-in local and foreign-delegate schedulers do.
104
+ */
105
+ cancelTask(taskId: TaskId, cause?: CancelCause): void
97
106
 
98
107
  /**
99
108
  * The task's current state, or `undefined` if this gateway does not know
@@ -44,6 +44,7 @@ export type BidiEvent =
44
44
  | { readonly type: 'audio'; readonly data: string; readonly mediaType: string }
45
45
  | {
46
46
  readonly type: 'tool_call'
47
+ /** Unique for the complete session; a duplicate is a protocol failure. */
47
48
  readonly id: string
48
49
  readonly name: string
49
50
  /** JSON, as the model produced it. */
@@ -51,7 +52,11 @@ export type BidiEvent =
51
52
  }
52
53
  /** The model finished a stretch of output and is waiting. */
53
54
  | { readonly type: 'turn_complete' }
54
- /** The human spoke over the model; anything in flight is now stale. */
55
+ /**
56
+ * The human spoke over the model; work that has not started publishing a
57
+ * result is now stale. This is not run cancellation: tool code keeps its
58
+ * live signal so an irreversible side effect is not stopped halfway.
59
+ */
55
60
  | { readonly type: 'interrupted' }
56
61
  | { readonly type: 'error'; readonly message: string }
57
62
  | { readonly type: 'closed'; readonly reason?: string }
@@ -60,6 +65,10 @@ export interface BidiConnectParams {
60
65
  readonly model: string
61
66
  readonly system?: string
62
67
  readonly tools?: readonly LLMToolSchema[]
68
+ /**
69
+ * Lifetime of the host-owned run. A provider uses it for connection and
70
+ * ongoing transport work; the host also invokes `close()` when it aborts.
71
+ */
63
72
  readonly signal?: AbortSignal
64
73
  }
65
74
 
@@ -72,9 +81,14 @@ export interface BidiSession {
72
81
  * Separate from {@link send} because it is not input from the human:
73
82
  * a driver has to attach it to the call it answers, and a session that
74
83
  * received it as ordinary input would have to guess.
84
+ *
85
+ * Atomically publish one result. Entering this call is the commit point:
86
+ * a later conversational interruption cannot recall it. Resolve only after
87
+ * the provider accepted the result; reject when it did not.
75
88
  */
76
89
  sendToolResult(id: string, output: string, isError?: boolean): Promise<void>
77
90
  events(): AsyncIterable<BidiEvent>
91
+ /** Stop the event stream and release provider resources. Called at most once. */
78
92
  close(): Promise<void>
79
93
  }
80
94
 
@@ -106,7 +120,10 @@ export type BidiRunEvent =
106
120
  readonly output: string
107
121
  readonly isError: boolean
108
122
  }
109
- /** A tool's answer was thrown away because the human interrupted. */
123
+ /**
124
+ * A tool's answer was thrown away because the human interrupted before
125
+ * publication began. The operation itself may have run to completion.
126
+ */
110
127
  | {
111
128
  readonly type: 'tool_abandoned'
112
129
  readonly runId: RunId
@@ -109,6 +109,25 @@ export type ComputerUseResult =
109
109
  | { readonly type: 'cursor_position'; readonly point: Point }
110
110
  | { readonly type: 'ok' }
111
111
 
112
+ /**
113
+ * A state-changing desktop action started, but its subprocess did not report
114
+ * a clean completion. The desktop may already have changed, so treating this
115
+ * as an ordinary failure and automatically replaying the action is unsafe.
116
+ *
117
+ * Host packages throw an error carrying this shape. The SDK recognises it
118
+ * structurally so separately installed host and SDK versions do not need to
119
+ * share an error constructor identity.
120
+ */
121
+ export interface ComputerUseOutcomeUnknown {
122
+ readonly code: 'computer_use_outcome_unknown'
123
+ readonly action: ComputerUseAction['type']
124
+ readonly outcome: 'unknown'
125
+ readonly retrySafety: 'unsafe'
126
+ readonly timedOut: boolean
127
+ readonly exitCode: number
128
+ readonly message: string
129
+ }
130
+
112
131
  // ---------------------------------------------------------------------------
113
132
  // Host interface — the core abstraction. Mirrors Sandbox/SandboxProvider shape.
114
133
  // Implementations live outside @namzu/sdk (e.g. @namzu/computer-use).
@@ -13,6 +13,7 @@ export type {
13
13
  export type {
14
14
  CommandOptions,
15
15
  CommandResult,
16
+ CommandTermination,
16
17
  CommandExecutor,
17
18
  RemoteCommandHandler,
18
19
  } from '../execution/index.js'
@@ -33,6 +34,8 @@ export interface LocalExecutionContextConfig extends ExecutionContextBase {
33
34
  fsAccess: boolean
34
35
  envVars?: Record<string, string>
35
36
  shell?: string
37
+ /** Retained bytes per stdout/stderr stream. Defaults to 4 MiB; maximum 64 MiB. */
38
+ maxOutputBytes?: number
36
39
  }
37
40
 
38
41
  export interface RemoteExecutionContextConfig extends ExecutionContextBase {