@sema-agent/core 5.20.0 → 5.21.1

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 (313) hide show
  1. package/CHANGELOG.md +19 -0
  2. package/dist/agents/agent-definition.d.ts +7 -0
  3. package/dist/agents/agent-transcript-tool.d.ts +30 -0
  4. package/dist/agents/builtin-agents.d.ts +60 -0
  5. package/dist/agents/cascade.d.ts +107 -0
  6. package/dist/agents/cumulative-stats.d.ts +56 -0
  7. package/dist/agents/observer.d.ts +162 -0
  8. package/dist/agents/peer-admission.d.ts +95 -0
  9. package/dist/agents/repair-loop.d.ts +226 -0
  10. package/dist/agents/retain-ledger.d.ts +141 -0
  11. package/dist/agents/roster-store.d.ts +105 -0
  12. package/dist/agents/send-message-tool.d.ts +92 -0
  13. package/dist/agents/session-util.d.ts +5 -0
  14. package/dist/agents/subagent-steps.d.ts +66 -0
  15. package/dist/agents/subagent.d.ts +600 -0
  16. package/dist/agents/suspend-guard.d.ts +29 -0
  17. package/dist/agents/teacher.d.ts +75 -0
  18. package/dist/agents/team.d.ts +120 -1
  19. package/dist/agents/tool-filter.d.ts +34 -0
  20. package/dist/agents/verify.d.ts +198 -0
  21. package/dist/bench/metrics.d.ts +455 -0
  22. package/dist/brain/anthropic.d.ts +30 -0
  23. package/dist/brain/circuit-breaker.d.ts +33 -0
  24. package/dist/brain/context-overflow.d.ts +60 -3
  25. package/dist/brain/degrading.d.ts +67 -0
  26. package/dist/brain/errors.d.ts +42 -0
  27. package/dist/brain/failover.d.ts +15 -0
  28. package/dist/brain/media-degrade.d.ts +39 -0
  29. package/dist/brain/model-presets.d.ts +31 -0
  30. package/dist/brain/open-responses.d.ts +19 -0
  31. package/dist/brain/openai.d.ts +46 -0
  32. package/dist/brain/reasoning.d.ts +106 -1
  33. package/dist/brain/repetition.d.ts +83 -0
  34. package/dist/brain/request-params.d.ts +56 -0
  35. package/dist/brain/retry.d.ts +46 -0
  36. package/dist/brain/routing.d.ts +12 -0
  37. package/dist/brain/status-sink.d.ts +30 -1
  38. package/dist/brain/stream-engine.d.ts +147 -0
  39. package/dist/brain/stream-shared.d.ts +34 -0
  40. package/dist/brain/terminal-cause.d.ts +31 -0
  41. package/dist/brain/timeout.d.ts +107 -0
  42. package/dist/brain/tool-call-id.d.ts +20 -0
  43. package/dist/brain/tool-call-repair.d.ts +13 -0
  44. package/dist/config/catalog.d.ts +47 -0
  45. package/dist/config/defaults.d.ts +33 -0
  46. package/dist/core/a2a-task-state.d.ts +53 -0
  47. package/dist/core/a2a.d.ts +51 -0
  48. package/dist/core/arg-summary.d.ts +62 -0
  49. package/dist/core/ask-question.d.ts +272 -2
  50. package/dist/core/auto-compaction.d.ts +467 -0
  51. package/dist/core/auto-compaction.js +20 -6
  52. package/dist/core/auto-mode-prompt-assets.d.ts +8 -0
  53. package/dist/core/auto-mode-prompt.d.ts +27 -0
  54. package/dist/core/auto-mode.d.ts +54 -3
  55. package/dist/core/auto-promote.d.ts +100 -0
  56. package/dist/core/background-agent-store.d.ts +292 -0
  57. package/dist/core/background-shell.d.ts +110 -0
  58. package/dist/core/cache-break-detector.d.ts +34 -0
  59. package/dist/core/canonical-json.d.ts +57 -0
  60. package/dist/core/checkpoint-store.d.ts +1574 -16
  61. package/dist/core/compliance.d.ts +30 -0
  62. package/dist/core/consolidate-scope.d.ts +75 -0
  63. package/dist/core/context-edit.d.ts +99 -0
  64. package/dist/core/context-guard.d.ts +46 -0
  65. package/dist/core/exec-gate.d.ts +44 -0
  66. package/dist/core/exec-output-tail.d.ts +61 -0
  67. package/dist/core/file-snapshot-store.d.ts +104 -0
  68. package/dist/core/fs-write-gate-policy.d.ts +36 -0
  69. package/dist/core/git-worktree-env.d.ts +31 -0
  70. package/dist/core/governance-codes.d.ts +19 -0
  71. package/dist/core/hooks.d.ts +608 -1
  72. package/dist/core/human-input-projection.d.ts +37 -0
  73. package/dist/core/human-input-projection.js +13 -0
  74. package/dist/core/image-downsample.d.ts +74 -0
  75. package/dist/core/locked-config.d.ts +37 -0
  76. package/dist/core/lsp-diagnostics.d.ts +77 -0
  77. package/dist/core/lsp-protocol.d.ts +29 -0
  78. package/dist/core/lsp-session.d.ts +60 -1
  79. package/dist/core/lsp.d.ts +150 -1
  80. package/dist/core/mailbox-store.d.ts +57 -0
  81. package/dist/core/mcp.d.ts +381 -0
  82. package/dist/core/media-byte-cap.d.ts +21 -0
  83. package/dist/core/memory-admission.d.ts +71 -0
  84. package/dist/core/memory-engine/content-origin.d.ts +64 -0
  85. package/dist/core/memory-engine/data-plane.d.ts +43 -0
  86. package/dist/core/memory-engine/dual-root.d.ts +24 -0
  87. package/dist/core/memory-engine/engine.d.ts +230 -0
  88. package/dist/core/memory-engine/engine.js +103 -35
  89. package/dist/core/memory-engine/file-backend.d.ts +155 -0
  90. package/dist/core/memory-engine/frontmatter.d.ts +16 -0
  91. package/dist/core/memory-engine/layout.d.ts +217 -0
  92. package/dist/core/memory-engine/memory-backend-contract.d.ts +12 -0
  93. package/dist/core/memory-engine/migrate.d.ts +9 -0
  94. package/dist/core/memory-engine/scan.d.ts +12 -0
  95. package/dist/core/memory-engine/scope-contract.d.ts +61 -1
  96. package/dist/core/memory-engine/sync-client.d.ts +87 -0
  97. package/dist/core/memory-engine/sync.d.ts +60 -0
  98. package/dist/core/memory-engine/tools.d.ts +41 -0
  99. package/dist/core/memory-engine/types.d.ts +188 -0
  100. package/dist/core/memory-recall.d.ts +141 -0
  101. package/dist/core/memory-vector.d.ts +20 -0
  102. package/dist/core/memory.d.ts +458 -0
  103. package/dist/core/message-utils.d.ts +6 -0
  104. package/dist/core/oracle-isolation.d.ts +69 -0
  105. package/dist/core/permission-rule-consent.d.ts +138 -0
  106. package/dist/core/permission-rule-model.d.ts +122 -0
  107. package/dist/core/permission-rule-store.d.ts +119 -3
  108. package/dist/core/permission-rules.d.ts +87 -1
  109. package/dist/core/present-plan-tool.d.ts +20 -0
  110. package/dist/core/pricing.d.ts +26 -0
  111. package/dist/core/property-harness.d.ts +86 -0
  112. package/dist/core/protocol-naming.d.ts +38 -0
  113. package/dist/core/protocol-table.d.ts +61 -0
  114. package/dist/core/push-queue.d.ts +1 -0
  115. package/dist/core/remote-env.d.ts +383 -1
  116. package/dist/core/retention-policy.d.ts +33 -0
  117. package/dist/core/retention.d.ts +51 -0
  118. package/dist/core/roles.d.ts +59 -0
  119. package/dist/core/runner/active-skill-scope.d.ts +34 -0
  120. package/dist/core/runner/assemble-result.d.ts +134 -0
  121. package/dist/core/runner/compaction-call-options.d.ts +97 -1
  122. package/dist/core/runner/grounding-signal.d.ts +10 -0
  123. package/dist/core/runner/image.d.ts +17 -0
  124. package/dist/core/runner/image.js +29 -15
  125. package/dist/core/runner/memory-consolidation.d.ts +60 -0
  126. package/dist/core/runner/prepare-memory.d.ts +59 -0
  127. package/dist/core/runner/prepare-task.d.ts +1011 -2
  128. package/dist/core/runner/prepare-task.js +12 -11
  129. package/dist/core/runner/prompt-suggestions.d.ts +7 -0
  130. package/dist/core/runner/runtask.d.ts +304 -3
  131. package/dist/core/runner/session-file-state-replay.d.ts +49 -0
  132. package/dist/core/runner/session-rule-policy.d.ts +58 -0
  133. package/dist/core/runner/strict-output-schema.d.ts +18 -3
  134. package/dist/core/runner/synthetic-tools.d.ts +113 -0
  135. package/dist/core/runner/teardown-bounded.d.ts +34 -0
  136. package/dist/core/runner/tool-disclosure.d.ts +227 -0
  137. package/dist/core/runner/tool-output-projection.d.ts +6 -0
  138. package/dist/core/runner/turn-attachments.d.ts +634 -0
  139. package/dist/core/runner/usage-accounting.d.ts +32 -0
  140. package/dist/core/runtime.d.ts +9 -0
  141. package/dist/core/safe-notify.d.ts +64 -0
  142. package/dist/core/safety-axis-vocab.d.ts +23 -0
  143. package/dist/core/safety-merge-corpus.d.ts +37 -0
  144. package/dist/core/scheduler.d.ts +121 -0
  145. package/dist/core/secret-env.d.ts +32 -0
  146. package/dist/core/select-model.d.ts +15 -0
  147. package/dist/core/sensitive-path-policy.d.ts +42 -0
  148. package/dist/core/session-policy-store.d.ts +94 -0
  149. package/dist/core/session-reconcile.d.ts +80 -0
  150. package/dist/core/session-store.d.ts +85 -0
  151. package/dist/core/session.d.ts +153 -0
  152. package/dist/core/shared-memory/contract.d.ts +22 -0
  153. package/dist/core/shared-memory/normalize.d.ts +123 -2
  154. package/dist/core/shared-memory/tools.d.ts +14 -0
  155. package/dist/core/shared-memory/types.d.ts +105 -0
  156. package/dist/core/shutdown-debug.d.ts +6 -0
  157. package/dist/core/side-query.d.ts +38 -0
  158. package/dist/core/side-query.js +6 -1
  159. package/dist/core/skill-tool-specifier.d.ts +72 -0
  160. package/dist/core/skills-directory.d.ts +100 -1
  161. package/dist/core/spec-contract.d.ts +89 -0
  162. package/dist/core/store-contracts/background-agent-store-contract.d.ts +31 -0
  163. package/dist/core/store-contracts/checkpoint-store-contract.d.ts +26 -0
  164. package/dist/core/store-contracts/contract-harness.d.ts +20 -0
  165. package/dist/core/store-contracts/contract-kit-version.d.ts +27 -0
  166. package/dist/core/store-contracts/file-snapshot-store-contract.d.ts +8 -0
  167. package/dist/core/store-contracts/mailbox-store-contract.d.ts +42 -0
  168. package/dist/core/store-contracts/tool-result-store-contract.d.ts +13 -0
  169. package/dist/core/strategy-store.d.ts +37 -0
  170. package/dist/core/stub-env.d.ts +7 -0
  171. package/dist/core/surrogate-safe-slice.d.ts +35 -0
  172. package/dist/core/task-notification.d.ts +202 -0
  173. package/dist/core/task-outcome.d.ts +53 -0
  174. package/dist/core/task-registry-agent.d.ts +337 -1
  175. package/dist/core/task-registry-monitor.d.ts +12 -0
  176. package/dist/core/task-registry-shared.d.ts +540 -0
  177. package/dist/core/task-registry.d.ts +343 -0
  178. package/dist/core/task-registry.js +13 -2
  179. package/dist/core/task-tool-shape.d.ts +44 -0
  180. package/dist/core/tighten-task-spec.d.ts +21 -0
  181. package/dist/core/tool-detach.d.ts +21 -0
  182. package/dist/core/tool-errors.d.ts +131 -0
  183. package/dist/core/tool-errors.js +4 -0
  184. package/dist/core/tool-name-aliases.d.ts +27 -0
  185. package/dist/core/tool-policy.d.ts +555 -0
  186. package/dist/core/tool-result-budget.d.ts +32 -0
  187. package/dist/core/tool-result-store.d.ts +174 -1
  188. package/dist/core/tools.d.ts +45 -0
  189. package/dist/core/trace.d.ts +323 -0
  190. package/dist/core/types.d.ts +3859 -2
  191. package/dist/core/untrusted-egress.d.ts +8 -0
  192. package/dist/core/untrusted-text.d.ts +156 -0
  193. package/dist/core/usage-window-store.d.ts +95 -0
  194. package/dist/core/version.d.ts +1 -0
  195. package/dist/core/warm-resume.d.ts +17 -0
  196. package/dist/core/wiring-manifest.d.ts +169 -0
  197. package/dist/core/with-retry.d.ts +24 -0
  198. package/dist/core/workflow-journal-store.d.ts +160 -0
  199. package/dist/core/workflow-run-store-contract.d.ts +25 -0
  200. package/dist/core/workflow-run-store.d.ts +119 -0
  201. package/dist/engine/compaction/compaction.d.ts +256 -1
  202. package/dist/engine/compaction/utils.d.ts +94 -0
  203. package/dist/engine/execution-env/kill-tree.d.ts +29 -0
  204. package/dist/engine/execution-env/node-execution-env.d.ts +94 -0
  205. package/dist/engine/harness/agent-harness.d.ts +116 -0
  206. package/dist/engine/harness/agent-harness.js +3 -14
  207. package/dist/engine/harness/messages.d.ts +15 -0
  208. package/dist/engine/harness/types.d.ts +464 -2
  209. package/dist/engine/llm/diagnostics.d.ts +4 -0
  210. package/dist/engine/llm/event-stream.d.ts +3 -0
  211. package/dist/engine/llm/index.d.ts +7 -0
  212. package/dist/engine/llm/types.d.ts +500 -3
  213. package/dist/engine/llm/validation.d.ts +3 -0
  214. package/dist/engine/loop/agent-loop.d.ts +87 -2
  215. package/dist/engine/loop/runtime-deps.d.ts +7 -0
  216. package/dist/engine/loop/types.d.ts +424 -0
  217. package/dist/engine/lsp/frame-decoder.d.ts +13 -0
  218. package/dist/engine/lsp/node-lsp-manager.d.ts +107 -0
  219. package/dist/engine/lsp/stdio-lsp-transport.d.ts +7 -0
  220. package/dist/engine/session/import-validate.d.ts +27 -0
  221. package/dist/engine/session/log-digest.d.ts +93 -0
  222. package/dist/engine/session/memory-repo.d.ts +6 -0
  223. package/dist/engine/session/memory-storage.d.ts +2 -0
  224. package/dist/engine/session/session.d.ts +75 -0
  225. package/dist/engine/session/storage-base.d.ts +8 -0
  226. package/dist/fixtures/index.d.ts +36 -0
  227. package/dist/index.d.ts +16 -1
  228. package/dist/index.js +0 -1
  229. package/dist/internal/harness-types.d.ts +6 -0
  230. package/dist/internal/harness.d.ts +11 -0
  231. package/dist/internal/llm.d.ts +6 -0
  232. package/dist/orchestration/builtin-workflows.d.ts +53 -0
  233. package/dist/orchestration/dev-vm-script-runner.d.ts +19 -0
  234. package/dist/orchestration/goal.d.ts +57 -0
  235. package/dist/orchestration/goal.js +3 -0
  236. package/dist/orchestration/run-spec.d.ts +42 -0
  237. package/dist/orchestration/run-workflow-tool.d.ts +169 -0
  238. package/dist/orchestration/workflow-governance.d.ts +61 -0
  239. package/dist/orchestration/workflow-meta.d.ts +28 -0
  240. package/dist/orchestration/workflow-observe.d.ts +60 -0
  241. package/dist/orchestration/workflow-primitives.d.ts +23 -1
  242. package/dist/orchestration/workflow-sandbox-conformance.d.ts +38 -0
  243. package/dist/orchestration/workflow-script-runner.d.ts +88 -0
  244. package/dist/orchestration/workflow-script-store.d.ts +98 -0
  245. package/dist/orchestration/workflow-size-guideline.d.ts +67 -0
  246. package/dist/orchestration/workflow-types.d.ts +169 -2
  247. package/dist/orchestration/workflow.d.ts +358 -0
  248. package/dist/prompt-assembly/artifact-store.d.ts +33 -0
  249. package/dist/prompt-assembly/artifact.d.ts +25 -0
  250. package/dist/prompt-assembly/assemble.d.ts +20 -0
  251. package/dist/prompt-assembly/composer.d.ts +29 -0
  252. package/dist/prompt-assembly/epoch.d.ts +55 -1
  253. package/dist/prompt-assembly/event-registry.d.ts +35 -0
  254. package/dist/prompt-assembly/explain.d.ts +12 -0
  255. package/dist/prompt-assembly/tool-catalog.d.ts +38 -0
  256. package/dist/prompt-assembly/turn-snapshot.d.ts +40 -0
  257. package/dist/prompt-assembly/types.d.ts +115 -0
  258. package/dist/prompts/coordinator.d.ts +27 -0
  259. package/dist/prompts/default.d.ts +539 -0
  260. package/dist/prompts/simple-sections.d.ts +45 -0
  261. package/dist/prompts/supervisor.d.ts +66 -0
  262. package/dist/scenarios/env.d.ts +28 -0
  263. package/dist/scenarios/full-body.d.ts +50 -0
  264. package/dist/scenarios/scenario-registry.d.ts +60 -0
  265. package/dist/scenarios/teacher-quickstart.d.ts +27 -0
  266. package/dist/server/http.d.ts +17 -0
  267. package/dist/stores/cc/lockfile.d.ts +6 -0
  268. package/dist/stores/cc/mailbox-store.d.ts +8 -0
  269. package/dist/stores/cc/roster-adapter.d.ts +4 -0
  270. package/dist/stores/cc/sidecar-transcript.d.ts +66 -0
  271. package/dist/stores/file/background-agent-store.d.ts +24 -0
  272. package/dist/stores/file/checkpoint-store.d.ts +38 -0
  273. package/dist/stores/file/file-snapshot-store.d.ts +25 -0
  274. package/dist/stores/file/fs-atomic.d.ts +155 -0
  275. package/dist/stores/file/index.d.ts +89 -0
  276. package/dist/stores/file/mailbox-store.d.ts +36 -0
  277. package/dist/stores/file/memory-store.d.ts +82 -0
  278. package/dist/stores/file/permission-rule-store.d.ts +79 -0
  279. package/dist/stores/file/session-policy-store.d.ts +28 -0
  280. package/dist/stores/file/session-store.d.ts +40 -0
  281. package/dist/stores/file/shared-ledger.d.ts +83 -0
  282. package/dist/stores/file/tool-result-store.d.ts +11 -0
  283. package/dist/stores/file/usage-window-store.d.ts +18 -0
  284. package/dist/stores/file/workflow-journal-store.d.ts +100 -0
  285. package/dist/stores/file/workflow-run-store.d.ts +11 -0
  286. package/dist/tools/fs/bash-readonly-classifier.d.ts +282 -0
  287. package/dist/tools/fs/encoding.d.ts +60 -0
  288. package/dist/tools/fs/fs-bash.d.ts +133 -0
  289. package/dist/tools/fs/fs-pdf.d.ts +28 -0
  290. package/dist/tools/fs/fs-search-tools.d.ts +5 -0
  291. package/dist/tools/fs/fs-search-tools.js +0 -1
  292. package/dist/tools/fs/fs-shared.d.ts +360 -0
  293. package/dist/tools/fs/fs-write.d.ts +16 -0
  294. package/dist/tools/fs/gh-rate-limit.d.ts +22 -0
  295. package/dist/tools/fs/index.d.ts +79 -0
  296. package/dist/tools/fs/notebook.d.ts +56 -0
  297. package/dist/tools/fs/pdf.d.ts +70 -0
  298. package/dist/tools/fs/pdf.js +8 -2
  299. package/dist/tools/fs/repo-map.d.ts +10 -0
  300. package/dist/tools/fs/safety.d.ts +376 -0
  301. package/dist/tools/fs/search.d.ts +131 -0
  302. package/dist/tools/loop-tick.d.ts +24 -0
  303. package/dist/tools/monitor.d.ts +55 -0
  304. package/dist/tools/scheduler-tools.d.ts +51 -0
  305. package/dist/tools/sql-adapters.d.ts +18 -0
  306. package/dist/tools/sql.d.ts +25 -0
  307. package/dist/tools/task-list.d.ts +77 -0
  308. package/dist/tools/todo.d.ts +8 -0
  309. package/dist/tools/web.d.ts +184 -0
  310. package/dist/tools/worktree.d.ts +81 -0
  311. package/package.json +2 -2
  312. package/dist/tools/gitea-issue.d.ts +0 -13
  313. package/dist/tools/gitea-issue.js +0 -75
@@ -2,10 +2,33 @@ import type { AgentTool } from "../internal/harness-types.js";
2
2
  import type { Brain, ToolSpec } from "../core/types.js";
3
3
  import type { Model } from "../internal/llm.js";
4
4
  export interface WebFetchConfig {
5
+ /** If set, ONLY these hostnames may be fetched (exact host match) — and the allowlist is enforced on
6
+ * **every redirect hop**, not just the initial URL (a redirect to a non-allowlisted host is refused
7
+ * before the request is made). Omitted ⇒ no host restriction (the deployment's tool-policy gate is then
8
+ * the only control — wire one for a multi-tenant deployment). */
5
9
  allowHosts?: string[];
10
+ /** Injectable fetch (tests / a proxy). Defaults to the global `fetch`. */
6
11
  fetchImpl?: typeof fetch;
12
+ /** Max response bytes to read (default 2 MB). */
7
13
  maxBytes?: number;
14
+ /** Wall-clock budget for the whole fetch (connect + redirects + body read), in ms. Default 30 000.
15
+ * Without a local timeout, an unreachable host in a no-egress environment hangs until the OS-level
16
+ * TCP timeout (60-120 s+) — an agent that retries then burns wall-clock on nothing. On expiry the
17
+ * tool returns a routable error string, so the model can move on. */
8
18
  timeoutMs?: number;
19
+ /** Optional sub-model extraction: given the (markdown) content + the caller's prompt, return a focused
20
+ * answer. Its output is still derived from untrusted content, so it too is returned fenced.
21
+ *
22
+ * Pre-2.13 review F1 (additive): the object return form lets a summarizer report that its own OUTPUT
23
+ * was cut (`truncated: true` — e.g. the sub-model hit max_tokens) as structured fact. The tool then
24
+ * renders the disclosure OUTSIDE the untrusted fence (a page must not be able to forge it) and stamps
25
+ * `details.truncated`. A plain-string return still works and claims a complete summary.
26
+ *
27
+ * ruled 2026-08-05 (grounding contract): the object form additionally carries `inputTruncated` — the
28
+ * summarizer did not SEE the whole page, because the content exceeded what it could feed its model.
29
+ * That is a different fact from `truncated` (the answer was cut) and used to be invisible: a summarizer
30
+ * silently clipping its input returned a plain string, and the tool then presented an answer derived
31
+ * from a prefix as an answer about the page. `inputChars`/`usedChars` size the gap for the disclosure. */
9
32
  summarize?: (content: string, prompt: string, signal?: AbortSignal) => Promise<string | {
10
33
  text: string;
11
34
  truncated?: boolean;
@@ -13,27 +36,139 @@ export interface WebFetchConfig {
13
36
  inputChars?: number;
14
37
  usedChars?: number;
15
38
  }>;
39
+ /** User-Agent header sent with every hop (批② P2-3). Default {@link DEFAULT_WEBFETCH_USER_AGENT};
40
+ * a deployment can brand it (CC sends `Claude-User (<cc ua>; +https://support.anthropic.com/)`). */
16
41
  userAgent?: string;
17
42
  }
43
+ /**
44
+ * Grounding floor for a fetched page (ruled 2026-08-05, WebFetch grounding contract).
45
+ *
46
+ * A page that returns almost no EXTRACTABLE TEXT — the client-rendered shell whose whole body is a
47
+ * script tag plus an empty mount div is the canonical shape — still produces a perfectly well-formed
48
+ * summary when it is handed to an extraction sub-model, because "there is nothing here" is not an answer
49
+ * the model is asked for. The summary then travels inside the untrusted fence with no marker separating
50
+ * "derived from the page" from "invented to fill the shape of the question", and the caller has no way
51
+ * to tell the two apart. The bytes are the discriminator: below this floor the tool stops presenting the
52
+ * summary as a source and says what it actually got.
53
+ *
54
+ * 200 characters is deliberately low — high enough that a JS shell (typically under 100 chars of text,
55
+ * often zero) is always caught, low enough that a real but terse page (a short API response, a plain-text
56
+ * status endpoint) is the only false positive. A terse page is NOT accused of being unsupportable: the
57
+ * disclosure states the measurement and reproduces the source, which is true and useful either way. The
58
+ * tool genuinely cannot distinguish "this URL serves fourteen characters and they are the answer" from
59
+ * "this URL serves a shell", so it says what it measured instead of ruling on which one happened.
60
+ */
18
61
  export declare const WEBFETCH_GROUNDING_MIN_TEXT_CHARS = 200;
62
+ /** Structured grounding verdict for one fetch — rides `details.grounding` (additive) so a deployment can
63
+ * gate on the same fact the model-facing disclosure is built from, instead of parsing prose. */
19
64
  export interface WebFetchGrounding {
65
+ /** `"low"` ⇒ the extracted text is below {@link WEBFETCH_GROUNDING_MIN_TEXT_CHARS}. */
20
66
  level: "ok" | "low";
67
+ /** Extracted text length after markup removal, whitespace-collapsed. */
21
68
  textChars: number;
69
+ /** Size of the body this verdict was measured against — the same value the details card reports as
70
+ * `bytes`, i.e. wire bytes when the response was read as bytes, characters on a `text()`-only injected
71
+ * fetch, and the KEPT prefix (not the original object) whenever the byte cap or a cut applied. The
72
+ * denominator of {@link textRatio}. */
22
73
  bytes: number;
74
+ /** `textChars / bytes`, rounded to 3 decimals; 0 when nothing was retrieved. A ratio near 0 with a
75
+ * large `bytes` is the markup/script-dominated shape; near 1 is plain text. */
23
76
  textRatio: number;
24
77
  }
25
78
  export declare function htmlToText(html: string): string;
26
79
  export declare function webFetchToolSpec(config?: WebFetchConfig): ToolSpec;
80
+ /** Defined (harness) form of web_fetch — back-compat for direct execution / tests. For `spec.tools`, use the raw
81
+ * {@link webFetchToolSpec} (prepare-task defineTool-wraps spec.tools entries). */
27
82
  export declare function createWebFetchTool(config?: WebFetchConfig): AgentTool;
83
+ /** {@link createWebFetchSummarizer}'s truncation bound — CC's `MAX_MARKDOWN_LENGTH`
84
+ * (WebFetchTool/utils.ts:128). Exported so a deployment wiring the reference summarizer doesn't need
85
+ * its own copy of this number to reason about (黑板 [1900]/[1902] — server asked for this explicitly,
86
+ * to avoid a value-copy of the truncation threshold drifting from this one). */
28
87
  export declare const WEBFETCH_SUMMARY_MAX_CONTENT = 100000;
88
+ /** {@link createWebFetchSummarizer}'s fixed guidelines block — CC's `makeSecondaryModelPrompt`
89
+ * (WebFetchTool/prompt.ts, non-preapproved-domain arm, guidelines verbatim). Exported alongside
90
+ * {@link WEBFETCH_SUMMARY_MAX_CONTENT} for the same reason (黑板 [1900]/[1902]): a deployment composing
91
+ * its OWN summarizer (not this reference one) that still wants CC-parity guidance text doesn't need its
92
+ * own copy of this string. Not runtime-parameterized — the page content and the caller's `prompt` are
93
+ * interpolated AROUND this block, never inside it. */
29
94
  export declare const WEBFETCH_SUMMARY_GUIDELINES: string;
95
+ /**
96
+ * sema's own grounding clause for the reference summarizer (ruled 2026-08-05), kept OUT of
97
+ * {@link WEBFETCH_SUMMARY_GUIDELINES} so that block stays the byte-verbatim CC anchor it is documented to
98
+ * be. Interpolated BEFORE it, so the CC block remains the prompt's fixed tail.
99
+ *
100
+ * Two failure modes observed in the field, both of which produce a confident, well-formed, wrong answer:
101
+ * · a page with no substantive content still gets a specific answer written for it (the code-side
102
+ * grounding floor catches the extreme case, but the model is the only one that can decline mid-band);
103
+ * · a listing of resources is judged relevant or irrelevant from the NAMES in it — "none of these files
104
+ * mention X, so this source has nothing on X" — which reports a property of a naming convention as a
105
+ * property of the data, and sends the caller away from a source that did hold the answer.
106
+ * Both are instructions to report the absence rather than to resolve it, which is why they belong in the
107
+ * prompt rather than in a post-hoc check.
108
+ */
30
109
  export declare const WEBFETCH_SUMMARY_GROUNDING_CLAUSE: string;
110
+ /**
111
+ * Characters of page content the reference summarizer will feed its model, derived from that model's own
112
+ * declared window (ruled 2026-08-05). Previously the only bound was the flat CC-parity
113
+ * {@link WEBFETCH_SUMMARY_MAX_CONTENT}, which is a property of the PAGE side and says nothing about the
114
+ * model on the other end: a small-window extraction model — the usual choice, since this is the "small
115
+ * fast model" leg — was handed ~100 000 characters and the whole call failed, so the caller got the
116
+ * "summarization failed" fallback (a raw dump that is then truncated anyway) instead of an answer.
117
+ *
118
+ * `headroom` exists because the character→token estimate is a floor, not a bound: {@link Model.charsPerToken}
119
+ * defaults to 4, and dense content (CJK, JSON, code, long URLs) tokenizes well below that, so a budget
120
+ * computed at face value overshoots exactly on the pages large enough to matter. The result is still
121
+ * clamped by the CC constant, so no deployment's input grows because of this.
122
+ */
31
123
  export declare const WEBFETCH_SUMMARY_INPUT_HEADROOM = 0.8;
124
+ /**
125
+ * Floor for the derived budget. A model whose declared dimensions leave no room after the output
126
+ * reservation still gets a small excerpt rather than a computation that lands at or below zero and feeds
127
+ * the summarizer an empty page — a call that cannot possibly answer is strictly worse than one that might.
128
+ *
129
+ * Honest scope (adversarial review round 1): this is a FLOOR, not a proof of fit. With the output
130
+ * reservation bounded at window/4 (see `resolveSummaryInputChars`), the floor now fires only on genuinely
131
+ * tiny windows (roughly under 3k tokens at the default chars-per-token) — a model whose declared
132
+ * dimensions leave no room gets a small excerpt whose attempt often succeeds anyway, and a failure is
133
+ * already disclosed by the tool's "summarization failed" head-note rather than swallowed.
134
+ * Refusing at construction instead was considered and declined: `maxTokens` is commonly declared equal to
135
+ * the window by providers of small models, so refusing would reject deployments that work today.
136
+ */
32
137
  export declare const WEBFETCH_SUMMARY_MIN_CONTENT = 4000;
138
+ /**
139
+ * Resolve the page-content budget for {@link createWebFetchSummarizer} against `model`'s window.
140
+ * An explicit `override` wins outright (a deployment that measured its own model beats an estimate).
141
+ *
142
+ * Fail-loud on every non-finite input, same posture as {@link resolveWebMaxBytes} (adversarial review
143
+ * round 1): a `NaN` anywhere in the model's declared dimensions propagates through the arithmetic and out
144
+ * through `Math.min`/`Math.max` unchanged, and a `NaN` budget makes `content.length > budget` false — so
145
+ * the clip silently stops happening and the whole oversize page is fed to the model, which is the failure
146
+ * this function exists to prevent, restored by a different door. An `override` below 1 is refused for the
147
+ * same reason in reverse: it floors to 0 and feeds the model an empty page.
148
+ */
33
149
  export declare function resolveSummaryInputChars(model: Model, override?: number): number;
150
+ /** Options for {@link createWebFetchSummarizer}. */
34
151
  export interface WebFetchSummarizerOptions {
152
+ /** Override the derived page-content budget (see {@link resolveSummaryInputChars}). */
35
153
  maxContentChars?: number;
36
154
  }
155
+ /**
156
+ * 黑板 [1870] L1 / [1900] — a reference {@link WebFetchConfig.summarize} implementation: reuses a
157
+ * caller-supplied `brain` (rather than requiring a dedicated second model) to extract a focused answer
158
+ * from fetched content per the caller's `prompt`, instead of the tool dumping the whole (fenced, still
159
+ * untrusted) page. CC ALWAYS routes fetched content through a secondary model this way
160
+ * (WebFetchTool/utils.ts:484-530); a deployment that omits `summarize` entirely gets `webFetchToolSpec`'s
161
+ * own honest "summarization unavailable in this deployment" head-note + raw dump instead — never a
162
+ * silent one. Prompt shape matches CC's non-preapproved-domain secondary-model prompt (WebFetchTool/
163
+ * prompt.ts `makeSecondaryModelPrompt`, guidelines block verbatim).
164
+ *
165
+ * Not the only valid implementation — a deployment with a genuinely separate summarization model/service
166
+ * can supply its own function of the same shape to `WebFetchConfig.summarize` instead. This one exists so
167
+ * "just reuse whatever brain/model I already have" doesn't have to be reinvented per deployment; it was
168
+ * previously a private copy inside this package's own `sema-tb` CLI entry point, promoted here so other
169
+ * deployments (a server assembling `WebFetchConfig` for its own scenarios, for one) can reuse it directly
170
+ * rather than re-deriving it from source.
171
+ */
37
172
  export declare function createWebFetchSummarizer(brain: Brain, model: Model, options?: WebFetchSummarizerOptions): (content: string, prompt: string, signal?: AbortSignal) => Promise<string | {
38
173
  text: string;
39
174
  truncated?: boolean;
@@ -41,7 +176,23 @@ export declare function createWebFetchSummarizer(brain: Brain, model: Model, opt
41
176
  inputChars?: number;
42
177
  usedChars?: number;
43
178
  }>;
179
+ /**
180
+ * design/102 (K-8 CC full-body) — WebSearch (BRAIN / model-service leg). The search BACKEND is deployment-injected
181
+ * (provider-native search / a search API / an MCP-backed service); core ships NONE — the same boundary as
182
+ * {@link WebFetchConfig.summarize} and the model gateway. Absent backend ⇒ the tool is not assembled
183
+ * ({@link assembleCodeTools} only pushes it when `search` is wired). Results are UNTRUSTED external data —
184
+ * {@link delimitUntrusted}-fenced like web_fetch. 🔴 `effect:"read"`, NO `egress` field: a search is
185
+ * idempotent/retryable; declaring `egress:true` would throw at prep (`config.egress_requires_write_effect`) AND
186
+ * break resume-safety (a read reconciles as safe-to-retry, a write/egress one does not).
187
+ */
44
188
  export interface WebSearchConfig {
189
+ /**
190
+ * Deployment-injected search backend. core ships none. The optional `opts` carries the model's per-call
191
+ * `allowed_domains`/`blocked_domains` HINTS so a backend that supports native domain filtering (e.g. a
192
+ * `site:` query) can apply them up front. A backend MAY ignore `opts` — core re-enforces the domain
193
+ * constraint on the returned results as a floor (see `createWebSearchTool`), so honoring it is an
194
+ * optimization, not a correctness requirement. Back-compat: existing 2-arg backends keep working.
195
+ */
45
196
  search: (query: string, signal?: AbortSignal, opts?: {
46
197
  allowedDomains?: string[];
47
198
  blockedDomains?: string[];
@@ -50,17 +201,50 @@ export interface WebSearchConfig {
50
201
  url: string;
51
202
  snippet: string;
52
203
  }>>;
204
+ /** Max results returned to the model (default 10). */
53
205
  maxResults?: number;
206
+ /** Wall-clock budget for one `search` call, in ms. Default 30 000 (RB-231, 黑板 [1937]). The backend is
207
+ * deployment-injected and may ignore the AbortSignal entirely, so this is enforced with BOTH an abort
208
+ * and a race — a hung backend must not hang the turn, and without this the deployment had no interface
209
+ * to bound it. */
54
210
  timeoutMs?: number;
55
211
  }
212
+ /** Clip by CODE POINT (RB-122/RB-142/RB-147 family: a UTF-16 `.slice` can split a surrogate pair). Clips
213
+ * RAW field text; `delimitUntrusted` owns the neutralization afterwards — clipping with `inlineUntrusted`
214
+ * here would fold newlines and double-neutralize. Exported for the RB-142 D-1 enumerative clipper guard
215
+ * (defectscan-truncation-invariant-surface) — not on the npm face (src/index.ts does not re-export it). */
56
216
  export declare function clipCodePoints(s: string, max: number): string;
57
217
  export declare function createWebSearchTool(config: WebSearchConfig): ToolSpec;
218
+ /** Options for {@link createSearxngSearchBackend}. */
58
219
  export interface SearxngBackendOptions {
220
+ /** Injected fetch (tests / exotic runtimes). Defaults to `globalThis.fetch`. */
59
221
  fetchImpl?: typeof fetch;
222
+ /** Per-request wall clock in ms before the request is aborted. Defaults to 10 000 — well inside
223
+ * WebSearchConfig's own 30 s budget so the tool-level race never fires first on a healthy instance. */
60
224
  timeoutMs?: number;
225
+ /** Extra query parameters appended to every /search call (e.g. `{ language: "zh-CN" }`). */
61
226
  extraParams?: Record<string, string>;
62
227
  }
228
+ /**
229
+ * design/162 (core half) — a {@link WebSearchConfig.search} backend speaking SearXNG's JSON API
230
+ * (`GET <baseUrl>/search?q=…&format=json`). The zero-key rung of the search fallback chain: the shell
231
+ * installs and health-checks a local SearXNG instance; a deployment then assembles this backend from
232
+ * nothing but the base URL. core owns NO process management — a dead instance surfaces as the thrown
233
+ * fetch/HTTP error, which `createWebSearchTool` already fences and bounds (SEARCH_ERROR_EXCERPT_CHARS).
234
+ *
235
+ * The model's `allowed_domains` hint maps to a `site:` query prefix (SearXNG forwards it to engines
236
+ * that understand it) — an OPTIMIZATION only: the tool re-enforces the domain constraint on returned
237
+ * results either way, so a backend ignoring the hint is correct, just wasteful. `blocked_domains` has
238
+ * no reliable engine-side spelling and is left entirely to the tool's own floor.
239
+ *
240
+ * Result mapping keeps the strict {title, url, snippet} shape: SearXNG's `content` field is the
241
+ * snippet; rows missing a url are dropped (an engine-side info box, not a citable result).
242
+ */
63
243
  export declare function createSearxngSearchBackend(baseUrl: string, options?: SearxngBackendOptions): WebSearchConfig["search"];
244
+ /**
245
+ * One live probe of a search backend (design/162 onboarding convenience): calls it with a fixed
246
+ * cheap query and classifies the outcome. Never throws — the classification IS the answer.
247
+ */
64
248
  export declare function probeSearchBackend(search: WebSearchConfig["search"], options?: {
65
249
  timeoutMs?: number;
66
250
  }): Promise<{
@@ -1,14 +1,95 @@
1
+ /**
2
+ * 审计[485]③ / 深挖 G4 — the `EnterWorktree` / `ExitWorktree` tool pair: SESSION-level git-worktree
3
+ * isolation (CC 2.1.198 parity). EnterWorktree creates a managed worktree under `.sema-worktrees/`
4
+ * (the same {@link WORKTREE_PARENT} the subagent `isolation:"worktree"` lane uses) and REALLY switches
5
+ * the task's working directory into it; ExitWorktree returns to the original directory and cleans up.
6
+ *
7
+ * CC-parity semantics (198 bundle, verbatim-checked):
8
+ * ① worktrees live in a managed parent dir inside the repo (CC: `.claude/worktrees/`; sema:
9
+ * `.sema-worktrees/`) — never scattered;
10
+ * ② baseRef is two-state: `"head"` = the current local HEAD (unpushed commits present), `"fresh"` =
11
+ * the default branch tip (CC: `origin/<default-branch>` for a clean tree);
12
+ * ③ a second CREATING EnterWorktree (`name`) while one is active is REFUSED ("Already in a worktree
13
+ * session" — CC errorCode 2); switching into an EXISTING worktree via `path` is allowed (深对比残差
14
+ * M22 RESOLVED, live-CC anchor 2026-07-09: the previous worktree is left on disk untouched, only the
15
+ * new one is tracked for exit-time cleanup, and a path-entered tree is NEVER removed by ExitWorktree);
16
+ * ④ ExitWorktree outside a session is an honest NO-OP (CC errorCode 1), and a worktree with
17
+ * uncommitted files or commits is NOT deleted by default (CC refuses `remove` without
18
+ * `discard_changes`; sema keeps it and reports the path — inspect/merge in userland);
19
+ * ⑤ outside a git repository CC delegates to WorktreeCreate/WorktreeRemove hooks — sema has no such
20
+ * shell extension point, so the tool says so honestly and refuses (no silent degrade).
21
+ *
22
+ * cwd architecture (the load-bearing conclusion): the task's working directory IS mutable state — the
23
+ * hands band shares one {@link CwdRef} (`handsCwdRef` in prepare-task): Bash runs every command in
24
+ * `cwdRef.current` (and `cd` moves it), Read/Edit/Write resolve relative paths against it, Monitor
25
+ * spawns there. EnterWorktree therefore performs a REAL switch by assigning `cwdRef.current`; the
26
+ * Runner's per-tool cwd read reports it as `workspace_changed`, same as an observed `cd`. Path
27
+ * containment is untouched: the worktree lives UNDER the task root, so resolveKey's canonical-within
28
+ * check still holds for every subsequent fs op.
29
+ *
30
+ * ⚠️ Containment ruling (codex 终审 1.255 F4, deliberate): entering a worktree is a **cwd switch, NOT a
31
+ * sandbox**. resolveKey's containment anchor stays the ORIGINAL task root — it is deliberately NOT
32
+ * re-anchored/tightened to the worktree dir, so `../../` from inside the worktree can still reach the
33
+ * rest of the repository (which is WITHIN the task root and was reachable before Enter too), while
34
+ * anything outside the task root stays fenced exactly as before. This matches CC 2.1.198 semantics
35
+ * (CC worktrees live beside the repo with no containment tightening either); tightening here would buy
36
+ * no security (Bash/`cd` already roam the root) and would break legitimate repo-relative access. The
37
+ * tool description + Enter reply state this honestly so the model never assumes isolation.
38
+ *
39
+ * Security posture: both tools only ever run `git` against the task root / managed worktree (no
40
+ * arbitrary command surface), but they create/delete on-disk state ⇒ effect:"write" (plan mode gates
41
+ * them like every other write tool; read-only hands never mount them — see prepare-task).
42
+ *
43
+ * Durability (codex 终审 1.255 F2): the active session lives in a SHARED, ALL-SERIALIZABLE
44
+ * {@link WorktreeSessionRef} owned by prepare-task (never a closure-only var, and no captured destroy
45
+ * closure — Exit re-derives removal as a plain `git worktree remove`). A durable suspend stamps it into
46
+ * `CheckpointState.activeWorktree` (+ the cwd into `handsCwd`); resume re-seeds both, so
47
+ * Enter→suspend→resume→Exit behaves exactly like an unsuspended session.
48
+ */
1
49
  import type { ActiveWorktreeSession, AgentTool, ExecutionEnv } from "../internal/harness-types.js";
2
50
  import type { CwdRef } from "./fs/index.js";
51
+ /** codex 终审 1.255 F2 — the ACTIVE worktree session, ALL-SERIALIZABLE (plain strings, no closures):
52
+ * prepare-task owns the ref, stamps `current` into `CheckpointState.activeWorktree` at a durable
53
+ * suspend, and re-seeds it on resume, so ExitWorktree works across the suspend/resume boundary (the
54
+ * tree survives on disk; removal is re-derived as a plain `git worktree remove`).
55
+ *
56
+ * REF-D3/D4: canonical definition moved to `engine/harness/types.ts` (the harness layer must never
57
+ * import FROM `tools/`, so it cannot point back at a definition declared here); this re-export keeps
58
+ * the existing `ActiveWorktreeSession` import path (including the public one via `src/index.ts`)
59
+ * unchanged for every consumer. */
3
60
  export type { ActiveWorktreeSession };
61
+ /** The shared mutable holder for {@link ActiveWorktreeSession} — the worktree twin of {@link CwdRef}. */
4
62
  export interface WorktreeSessionRef {
5
63
  current?: ActiveWorktreeSession;
64
+ /** HRD-PTL-8 — an ExitWorktree call is in flight on `current`. RUNTIME-ONLY (deliberately not part of
65
+ * the durable `CheckpointState.activeWorktree` projection: a suspend cannot happen inside the exit's
66
+ * own await chain, and a resumed process has no in-flight exit by definition). A concurrent or
67
+ * re-entrant Exit reads this and is refused honestly instead of being told no session is active. */
6
68
  exiting?: boolean;
69
+ /** HRD-PTL-13 — an EnterWorktree call is in flight on this ref (either form). RUNTIME-ONLY, same
70
+ * rationale as {@link exiting}. The single-session rule cannot be enforced by reading `current` alone:
71
+ * the create path assigns it only after several awaits, so two overlapping calls would both pass that
72
+ * check and both create a worktree, leaving the earlier one untracked (see the guard in EnterWorktree
73
+ * for the CAS-reject-vs-serialize trade-off). */
7
74
  entering?: boolean;
8
75
  }
9
76
  export interface WorktreeToolsOptions {
77
+ /** The task root (the repo root the managed worktrees nest under; `git` runs `-C` here). */
10
78
  repoRoot: string;
79
+ /** The task's shared mutable working directory (the hands band's `handsCwdRef`) — EnterWorktree
80
+ * assigns it to the worktree path (a REAL cwd switch: Bash/Read/Edit/Write/Monitor all follow),
81
+ * ExitWorktree restores it. */
11
82
  cwdRef: CwdRef;
83
+ /** codex 终审 1.255 F2: the shared session-state ref (checkpointable — prepare-task serializes it into
84
+ * the durable checkpoint and re-seeds it on resume). Omitted ⇒ a private per-mount ref (same live
85
+ * behavior, minus durable-suspend survival — prepare-task always passes one). */
12
86
  session?: WorktreeSessionRef;
13
87
  }
88
+ /**
89
+ * Build the EnterWorktree/ExitWorktree pair. One session-state closure per mount (= per task): the
90
+ * active worktree handle lives here, never in a model argument. Mounted by prepare-task only when the
91
+ * task has real write hands over a tracked cwd (`handsCwdRef` exists — same premise family as the
92
+ * Monitor mount); git-ness is probed honestly at Enter time (same posture as the subagent
93
+ * worktree-isolation helper — no per-task prepare-time git exec).
94
+ */
14
95
  export declare function createWorktreeTools(env: ExecutionEnv, opts: WorktreeToolsOptions): AgentTool[];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sema-agent/core",
3
- "version": "5.20.0",
3
+ "version": "5.21.1",
4
4
  "description": "Stateless, task-oriented AI agent core",
5
5
  "type": "module",
6
6
  "license": "BUSL-1.1",
@@ -45,7 +45,7 @@
45
45
  "node": ">=20.3.0"
46
46
  },
47
47
  "scripts": {
48
- "build": "rm -rf dist && tsc -p tsconfig.build.json",
48
+ "build": "rm -rf dist && tsc -p tsconfig.build.json && tsc -p tsconfig.build.json --emitDeclarationOnly --removeComments false",
49
49
  "typecheck": "tsc --noEmit",
50
50
  "test": "vitest run --exclude \"**/*.local.test.ts\"",
51
51
  "test:watch": "vitest",
@@ -1,13 +0,0 @@
1
- import type { ToolSpec } from "../core/types.js";
2
- export interface GiteaIssueToolOptions {
3
- baseUrl: string;
4
- owner: string;
5
- repo: string;
6
- token: string;
7
- defaultLabels?: number[];
8
- allowModelLabels?: boolean;
9
- name?: string;
10
- description?: string;
11
- fetchImpl?: typeof fetch;
12
- }
13
- export declare function createGiteaIssueTool(opts: GiteaIssueToolOptions): ToolSpec;
@@ -1,75 +0,0 @@
1
- import { Type } from "typebox";
2
- export function createGiteaIssueTool(opts) {
3
- const doFetch = opts.fetchImpl ?? fetch;
4
- const root = opts.baseUrl.replace(/\/+$/, "");
5
- const url = `${root}/api/v1/repos/${encodeURIComponent(opts.owner)}/${encodeURIComponent(opts.repo)}/issues`;
6
- const properties = {
7
- title: Type.String({ description: "A concise, specific issue title." }),
8
- body: Type.Optional(Type.String({ description: "Markdown body: what's wrong / what's wanted, steps, context, and any evidence." })),
9
- };
10
- if (opts.allowModelLabels) {
11
- properties.labels = Type.Optional(Type.Array(Type.Integer(), { description: "Optional Gitea label IDs (numeric) to tag this issue." }));
12
- }
13
- return {
14
- name: opts.name ?? "open_gitea_issue",
15
- effect: "write",
16
- egress: true,
17
- description: opts.description ??
18
- `Open an issue in the ${opts.owner}/${opts.repo} repository to report a bug or file a request ` +
19
- `to the maintainer. Use it when something is broken or missing and you cannot fix it yourself. ` +
20
- `Provide a clear title and a body with the problem, steps, and any evidence.`,
21
- parameters: Type.Object(properties),
22
- execute: async (args, ctx) => {
23
- const a = args;
24
- const title = String(a.title ?? "").trim();
25
- if (!title) {
26
- return { content: "Issue not created: a non-empty title is required.", details: { error: "empty title" }, isError: true };
27
- }
28
- const modelLabels = opts.allowModelLabels && Array.isArray(a.labels) ? a.labels : [];
29
- const labels = [...new Set([...(opts.defaultLabels ?? []), ...modelLabels])];
30
- const payload = { title };
31
- if (a.body !== undefined && a.body !== null)
32
- payload.body = String(a.body);
33
- if (labels.length > 0)
34
- payload.labels = labels;
35
- let res;
36
- try {
37
- res = await doFetch(url, {
38
- method: "POST",
39
- headers: { "content-type": "application/json", authorization: `token ${opts.token}` },
40
- body: JSON.stringify(payload),
41
- signal: ctx.signal,
42
- });
43
- }
44
- catch (e) {
45
- const msg = e instanceof Error ? e.message : String(e);
46
- return { content: `Issue not created: request failed (${msg}).`, details: { error: msg }, isError: true };
47
- }
48
- if (!res.ok) {
49
- const detail = await res.text().catch(() => "");
50
- return {
51
- content: `Issue not created: Gitea returned HTTP ${res.status}. ${detail.slice(0, 300)}`,
52
- details: { status: res.status },
53
- isError: true,
54
- };
55
- }
56
- const PARSE_FAILED = Symbol("json-parse-failed");
57
- const parsed = (await res.json().catch(() => PARSE_FAILED));
58
- const number = parsed !== PARSE_FAILED && typeof parsed.number === "number" ? parsed.number : undefined;
59
- if (number === undefined) {
60
- return {
61
- content: `Issue request returned HTTP ${res.status} but the response body was not a valid issue ` +
62
- `(no number) — the issue may NOT have been created; verify before retrying.`,
63
- details: { status: res.status, parsed: parsed === PARSE_FAILED ? "unparseable" : "no-number" },
64
- isError: true,
65
- };
66
- }
67
- const issue = parsed;
68
- const link = issue.html_url ? ` — ${issue.html_url}` : "";
69
- return {
70
- content: `Opened issue #${number} in ${opts.owner}/${opts.repo}${link}`,
71
- details: { number, url: issue.html_url },
72
- };
73
- },
74
- };
75
- }