@dtlabs/ai-toolkit 0.24.2 → 0.24.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,4 +1,12 @@
1
1
  ## 0.1.4 (2026-07-21)
2
+ ## [0.24.3](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.2...v0.24.3) (2026-10-27)
3
+
4
+
5
+ ### Bug Fixes
6
+
7
+ * don't fail a worker call over a read-only permission denial ([1b4c521](https://github.com/dtlab-tech/ai-toolkit/commit/1b4c5217b42e9c9dcb74c9bbe60f209522644f9c))
8
+ * **workflow-control:** don't fail a worker call over a read-only permission denial ([fb283c6](https://github.com/dtlab-tech/ai-toolkit/commit/fb283c6a0f44f56d0ca152bcf84bf81c1ca10125))
9
+
2
10
  ## [0.24.2](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.1...v0.24.2) (2026-10-26)
3
11
 
4
12
 
@@ -230,10 +230,27 @@ function createControl(options) {
230
230
  tokenLedger.push({ agent: identity.nativeName, model: definition.model,
231
231
  phase_delta_tokens: measuredTokens, usage: result.result?.usage || null, evidence_path: evidence.file });
232
232
  evidence.save({ response: result, attempts });
233
+ // A denial on a read-only tool (Read/Glob/Grep) means the agent couldn't fetch some EXTRA
234
+ // context — a real, recurring pattern where a path the model constructs itself (e.g. a
235
+ // single leading backslash with no drive letter) resolves outside the project directory
236
+ // and is correctly denied. Confirmed via production evidence twice, on two different
237
+ // paths: the agent recovers and still produces a complete, structurally valid result, which
238
+ // this unconditional check threw away anyway, wasting the entire call and forcing a resume.
239
+ // Any OTHER tool (Write/Edit/Bash/...) stays an immediate, unconditional failure — a denial
240
+ // there is a near-miss on a real side effect, not a missed read, and must never be silently
241
+ // tolerated regardless of what the rest of the response looks like.
242
+ const READ_ONLY_DENIAL_TOOLS = new Set(['Read', 'Glob', 'Grep'])
233
243
  const denials = result.result?.permission_denials;
234
244
  if (Array.isArray(denials) && denials.length) {
235
- const tools = [...new Set(denials.map(d => d.tool_name || 'unknown'))].join(', ');
236
- throw new Error('Worker permission denied: ' + id + '; tools: ' + tools);
245
+ const nonReadOnly = denials.filter(d => !READ_ONLY_DENIAL_TOOLS.has(d.tool_name));
246
+ if (nonReadOnly.length) {
247
+ const tools = [...new Set(nonReadOnly.map(d => d.tool_name || 'unknown'))].join(', ');
248
+ throw new Error('Worker permission denied: ' + id + '; tools: ' + tools);
249
+ }
250
+ // Read-only denial(s) only: fall through to the normal result-validity checks below —
251
+ // an agent that actually proceeded with missing context will still fail there (a bad
252
+ // exitCode/is_error, or the caller's own downstream structural validation), the same way
253
+ // it would if no denial had ever happened.
237
254
  }
238
255
  if (result.exitCode !== 0 || result.parseError || result.timedOut ||
239
256
  !result.result || result.result.is_error !== false) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dtlabs/ai-toolkit",
3
- "version": "0.24.2",
3
+ "version": "0.24.3",
4
4
  "description": "AI Toolkit — reusable agents and procedures for developers to build AI-powered applications.",
5
5
  "files": [
6
6
  "docs/",