@notis_ai/cli 0.2.0-beta.120.1 → 0.2.0-beta.121.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@notis_ai/cli",
3
- "version": "0.2.0-beta.120.1",
3
+ "version": "0.2.0-beta.121.1",
4
4
  "description": "Agent-first Notis CLI for apps and generic tool execution",
5
5
  "type": "module",
6
6
  "bin": {
@@ -1,4 +1,4 @@
1
- import { createHash } from 'node:crypto';
1
+ import { createHash, randomUUID } from 'node:crypto';
2
2
  import { existsSync, readFileSync } from 'node:fs';
3
3
  import { usageError } from '../runtime/errors.js';
4
4
  import {
@@ -178,6 +178,11 @@ async function executeReadOnlySql(ctx, query, phase) {
178
178
  tools: [{ tool_slug: toolName, arguments: { query } }],
179
179
  },
180
180
  mutating: false,
181
+ // Always a fresh key, never the operator's --idempotency-key: a diagnostic
182
+ // must observe current state rather than replay a cached response, and two
183
+ // different queries under one reused key would collide on the request hash.
184
+ idempotencyKey: randomUUID(),
185
+ sendIdempotencyKeyWhenReading: true,
181
186
  });
182
187
  if (result.payload?.successful === false || result.payload?.error) {
183
188
  throw usageError(
@@ -56,12 +56,18 @@ export async function runToolCommand({
56
56
  mutating = false,
57
57
  idempotencyKey,
58
58
  fileBindings = [],
59
+ sendIdempotencyKeyWhenReading = false,
59
60
  }) {
61
+ // The server owns effect classification and requires a key whenever *its*
62
+ // metadata says write or unknown — a client-side `mutating: false` hint does
63
+ // not exempt the call. Callers that knowingly dispatch through an
64
+ // unknown-classified wrapper (e.g. COMPOSIO_MULTI_EXECUTE_TOOL) opt in so the
65
+ // request carries a key instead of being rejected as idempotency_key_required.
60
66
  const result = await callTool({
61
67
  runtime: { ...runtime, mutating },
62
68
  toolName,
63
69
  arguments_,
64
- idempotencyKey: mutating ? idempotencyKey : null,
70
+ idempotencyKey: mutating || sendIdempotencyKeyWhenReading ? idempotencyKey : null,
65
71
  fileBindings,
66
72
  });
67
73
  return result;