@thirdfy/agent-cli 0.2.68 → 0.2.70
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 +16 -0
- package/README.md +3 -3
- package/package.json +1 -1
- package/src/core/executionContext.mjs +4 -0
- package/src/core/hostedRuntimeIdempotency.mjs +44 -0
- package/src/runtime/actions/selection.mjs +53 -1
- package/src/runtime/execution/earnclawRuntimeWriteGate.mjs +7 -63
- package/src/runtime/execution/hostedRuntimeWriteGate.mjs +56 -0
- package/src/runtime/execution/managedReadExecuteRail.mjs +22 -0
- package/src/runtime/execution/payloads.mjs +19 -3
- package/src/runtime/execution/runners.mjs +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,22 @@ All notable changes to `@thirdfy/agent-cli` are documented here. The format is b
|
|
|
4
4
|
|
|
5
5
|
## [Unreleased]
|
|
6
6
|
|
|
7
|
+
## [0.2.70] - 2026-09-16
|
|
8
|
+
|
|
9
|
+
### Fixed
|
|
10
|
+
|
|
11
|
+
- `--action get_aave_markets` (and other snake/kebab pairs) resolves to the first-class catalog key before colliding earn aliases. Matches `thirdfy-mcp` **0.0.120**. Pin: `test/catalog-canonical-action-resolution.test.cjs`.
|
|
12
|
+
|
|
13
|
+
### Changed
|
|
14
|
+
|
|
15
|
+
- Hosted runtime write idempotency is generic (`hostedRuntimeIdempotency`) instead of EarnOrg-only helpers. Keys still use the `earnclaw:{runtimeId}:` wire prefix so Thirdfy action-event join stays the same. Pairs with `thirdfy-mcp` **0.0.120** and Thirdfy API **3.14.48**.
|
|
16
|
+
|
|
17
|
+
## [0.2.69] - 2026-09-16
|
|
18
|
+
|
|
19
|
+
### Fixed
|
|
20
|
+
|
|
21
|
+
- Managed `agent_wallet` reads do not fall back to `/execute-intent` on `PARAMS_SCHEMA_INVALID` / unknown-key. Fallback stays limited to `does not support execute rail`. Matches `thirdfy-mcp` **0.0.119**. Pin: `test/agent-wallet-readonly-fallback.test.cjs`.
|
|
22
|
+
|
|
7
23
|
## [0.2.68] - 2026-09-16
|
|
8
24
|
|
|
9
25
|
### Fixed
|
package/README.md
CHANGED
|
@@ -40,10 +40,10 @@ Run without global install:
|
|
|
40
40
|
npx @thirdfy/agent-cli --help
|
|
41
41
|
```
|
|
42
42
|
|
|
43
|
-
## What's new in v0.2.
|
|
43
|
+
## What's new in v0.2.70
|
|
44
44
|
|
|
45
|
-
-
|
|
46
|
-
-
|
|
45
|
+
- `--action get_aave_markets` resolves to the first-class catalog key before colliding earn aliases.
|
|
46
|
+
- Hosted runtime write keys stay scoped by runtime UUID so Thirdfy action events can join.
|
|
47
47
|
- See [CHANGELOG.md](./CHANGELOG.md) and GitHub Releases for older versions.
|
|
48
48
|
|
|
49
49
|
## Quick start
|
package/package.json
CHANGED
|
@@ -50,3 +50,7 @@ export function mergeExecutionContext(body) {
|
|
|
50
50
|
if (!executionContext.source) executionContext.source = 'hosted_runtime';
|
|
51
51
|
return { ...body, executionContext };
|
|
52
52
|
}
|
|
53
|
+
|
|
54
|
+
export {
|
|
55
|
+
wrapWriteIdempotencyKeyForHostedRuntime,
|
|
56
|
+
} from './hostedRuntimeIdempotency.mjs';
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
/** Stable Thirdfy execute namespace for hosted runtimes (any control plane). Legacy wire token. */
|
|
4
|
+
export const HOSTED_RUNTIME_IDEMPOTENCY_NAMESPACE = 'earnclaw';
|
|
5
|
+
|
|
6
|
+
const UUID_RE =
|
|
7
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
|
|
8
|
+
|
|
9
|
+
export const HOSTED_RUNTIME_SCOPED_KEY_RE = new RegExp(
|
|
10
|
+
`^${HOSTED_RUNTIME_IDEMPOTENCY_NAMESPACE}:[0-9a-f-]{36}:`,
|
|
11
|
+
'i',
|
|
12
|
+
);
|
|
13
|
+
|
|
14
|
+
export function readHostedRuntimeUuid(value) {
|
|
15
|
+
const trimmed = String(value || '').trim();
|
|
16
|
+
return UUID_RE.test(trimmed) ? trimmed.toLowerCase() : undefined;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isHostedRuntimeScopedIdempotencyKey(key) {
|
|
20
|
+
return HOSTED_RUNTIME_SCOPED_KEY_RE.test(String(key || '').trim());
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export function formatHostedRuntimeScopedIdempotencyKey({ runtimeId, channel, suffix }) {
|
|
24
|
+
const rid = readHostedRuntimeUuid(runtimeId);
|
|
25
|
+
if (!rid) return String(suffix || '').trim();
|
|
26
|
+
const ch = String(channel || 'thirdfy')
|
|
27
|
+
.trim()
|
|
28
|
+
.toLowerCase()
|
|
29
|
+
.replace(/[^a-z0-9_-]+/g, '-')
|
|
30
|
+
.slice(0, 32);
|
|
31
|
+
const tail = String(suffix || '').trim() || `write-${Date.now()}:${randomUUID()}`;
|
|
32
|
+
return `${HOSTED_RUNTIME_IDEMPOTENCY_NAMESPACE}:${rid}:${ch}:${tail}`;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function wrapWriteIdempotencyKeyForHostedRuntime(existingKey, runtimeId, _action, channel = 'thirdfy') {
|
|
36
|
+
const existing = String(existingKey || '').trim();
|
|
37
|
+
const rid = readHostedRuntimeUuid(runtimeId);
|
|
38
|
+
if (existing && isHostedRuntimeScopedIdempotencyKey(existing)) return existing;
|
|
39
|
+
if (rid) {
|
|
40
|
+
const suffix = existing || `cli:${Date.now()}:${randomUUID()}`;
|
|
41
|
+
return formatHostedRuntimeScopedIdempotencyKey({ runtimeId: rid, channel, suffix });
|
|
42
|
+
}
|
|
43
|
+
return existing;
|
|
44
|
+
}
|
|
@@ -35,6 +35,13 @@ function canonicalActionKey(action) {
|
|
|
35
35
|
.toLowerCase();
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
function canonicalizeCatalogActionKey(value) {
|
|
39
|
+
return String(value || '')
|
|
40
|
+
.trim()
|
|
41
|
+
.toLowerCase()
|
|
42
|
+
.replace(/_/g, '-');
|
|
43
|
+
}
|
|
44
|
+
|
|
38
45
|
function inferActionProvider(action) {
|
|
39
46
|
// API catalog metadata (`providerId`, `domain`, `category`) is the source of truth.
|
|
40
47
|
// This fallback only keeps older catalog rows / older API deployments discoverable.
|
|
@@ -337,8 +344,12 @@ function getActionProvider(action) {
|
|
|
337
344
|
|
|
338
345
|
async function resolveActionSelection(ctx, flags) {
|
|
339
346
|
const requestedAction = requireFlag(flags, 'action', 'Missing --action');
|
|
340
|
-
const requestedLower = requestedAction.toLowerCase();
|
|
341
347
|
const actions = applyActionFilters(await getCachedActionsCatalog(ctx, flags), flags);
|
|
348
|
+
return resolveActionFromRows(requestedAction, actions, flags);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
function resolveActionFromRows(requestedAction, actions, flags = {}) {
|
|
352
|
+
const requestedLower = String(requestedAction || '').toLowerCase();
|
|
342
353
|
const keyed = actions
|
|
343
354
|
.map((action) => ({
|
|
344
355
|
key: getActionKey(action),
|
|
@@ -381,11 +392,50 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
381
392
|
);
|
|
382
393
|
}
|
|
383
394
|
|
|
395
|
+
const requestedCanonical = canonicalizeCatalogActionKey(requestedAction);
|
|
396
|
+
const canonicalKey = keyed.filter(
|
|
397
|
+
(entry) => canonicalizeCatalogActionKey(entry.key) === requestedCanonical
|
|
398
|
+
);
|
|
399
|
+
if (canonicalKey.length === 1) {
|
|
400
|
+
return {
|
|
401
|
+
requestedAction,
|
|
402
|
+
resolvedAction: canonicalKey[0].key,
|
|
403
|
+
resolvedActionMeta: canonicalKey[0].action || null,
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
if (canonicalKey.length > 1) {
|
|
407
|
+
const identities = new Set(canonicalKey.map((entry) => canonicalizeCatalogActionKey(entry.key)));
|
|
408
|
+
if (identities.size === 1) {
|
|
409
|
+
const kebab = canonicalKey.find((entry) => entry.key.toLowerCase() === requestedCanonical);
|
|
410
|
+
const picked = kebab || canonicalKey[0];
|
|
411
|
+
return {
|
|
412
|
+
requestedAction,
|
|
413
|
+
resolvedAction: picked.key,
|
|
414
|
+
resolvedActionMeta: picked.action || null,
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
throw new Error(
|
|
418
|
+
`Ambiguous --action "${requestedAction}". Multiple exact matches found: ${formatActionList(
|
|
419
|
+
canonicalKey.map((v) => v.key)
|
|
420
|
+
)}.`
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
384
424
|
const exactAlias = keyed.filter((entry) => entry.aliases.some((a) => a.toLowerCase() === requestedLower));
|
|
385
425
|
if (exactAlias.length === 1) {
|
|
386
426
|
return { requestedAction, resolvedAction: exactAlias[0].key, resolvedActionMeta: exactAlias[0].action || null };
|
|
387
427
|
}
|
|
388
428
|
if (exactAlias.length > 1) {
|
|
429
|
+
const preferred = exactAlias.filter(
|
|
430
|
+
(entry) => canonicalizeCatalogActionKey(entry.key) === requestedCanonical
|
|
431
|
+
);
|
|
432
|
+
if (preferred.length === 1) {
|
|
433
|
+
return {
|
|
434
|
+
requestedAction,
|
|
435
|
+
resolvedAction: preferred[0].key,
|
|
436
|
+
resolvedActionMeta: preferred[0].action || null,
|
|
437
|
+
};
|
|
438
|
+
}
|
|
389
439
|
const providerHint = flags.provider ? getTradingProviderHint(flags.provider) : null;
|
|
390
440
|
throw new Error(
|
|
391
441
|
`Ambiguous --action "${requestedAction}". Alias matches multiple actions: ${formatActionList(
|
|
@@ -420,6 +470,8 @@ async function resolveActionSelection(ctx, flags) {
|
|
|
420
470
|
normalizeProviderId,
|
|
421
471
|
applyActionFilters,
|
|
422
472
|
getActionProvider,
|
|
473
|
+
canonicalizeCatalogActionKey,
|
|
474
|
+
resolveActionFromRows,
|
|
423
475
|
resolveActionSelection,
|
|
424
476
|
};
|
|
425
477
|
}
|
|
@@ -1,63 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const POLYMARKET_PLACE_ACTIONS = new Set([
|
|
11
|
-
'place_polymarket_order',
|
|
12
|
-
'place-polymarket-order',
|
|
13
|
-
'place_prediction_order',
|
|
14
|
-
'place-prediction-order',
|
|
15
|
-
]);
|
|
16
|
-
|
|
17
|
-
export function resolveEarnclawRuntimeId(env = process.env) {
|
|
18
|
-
const runtimeId = readUuid(env.THIRDFY_EXECUTION_RUNTIME_ID)
|
|
19
|
-
|| readUuid(env.EARNCLAW_RUNTIME_ID);
|
|
20
|
-
return runtimeId ? runtimeId.toLowerCase() : '';
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
export function normalizePolymarketPlaceAction(action) {
|
|
24
|
-
return String(action || '')
|
|
25
|
-
.trim()
|
|
26
|
-
.toLowerCase()
|
|
27
|
-
.replace(/_/g, '-');
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
export function isPolymarketPlaceAction(action) {
|
|
31
|
-
const key = String(action || '').trim().toLowerCase();
|
|
32
|
-
if (POLYMARKET_PLACE_ACTIONS.has(key)) return true;
|
|
33
|
-
return normalizePolymarketPlaceAction(key) === 'place-polymarket-order'
|
|
34
|
-
|| normalizePolymarketPlaceAction(key) === 'place-prediction-order';
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* On EarnClaw-managed Hermes machines, ad-hoc CLI/MCP/dashboard tool calls can
|
|
39
|
-
* place Polymarket orders without pack execute-gate. Require an earnclaw-scoped
|
|
40
|
-
* idempotency key so only adapter/operator keys pass.
|
|
41
|
-
*/
|
|
42
|
-
export function assertEarnclawPolymarketWriteIdempotency({
|
|
43
|
-
action,
|
|
44
|
-
idempotencyKey,
|
|
45
|
-
paramsIdempotencyKey,
|
|
46
|
-
env = process.env,
|
|
47
|
-
} = {}) {
|
|
48
|
-
if (!isPolymarketPlaceAction(action)) return null;
|
|
49
|
-
const runtimeId = resolveEarnclawRuntimeId(env);
|
|
50
|
-
if (!runtimeId) return null;
|
|
51
|
-
|
|
52
|
-
const prefix = `earnclaw:${runtimeId}`;
|
|
53
|
-
const keys = [idempotencyKey, paramsIdempotencyKey]
|
|
54
|
-
.map((key) => String(key || '').trim())
|
|
55
|
-
.filter(Boolean);
|
|
56
|
-
if (keys.some((key) => key.toLowerCase().startsWith(prefix))) return null;
|
|
57
|
-
|
|
58
|
-
throw createCliError(
|
|
59
|
-
'EARNCLAW_PM_IDEMPOTENCY_REQUIRED',
|
|
60
|
-
`EarnClaw runtime ${runtimeId} requires Polymarket place orders to use idempotencyKey starting with "${prefix}". ` +
|
|
61
|
-
'Pack execute-gate and operator exits set this automatically. Bare CLI/dashboard tool writes are blocked.',
|
|
62
|
-
);
|
|
63
|
-
}
|
|
1
|
+
/** @deprecated Import from ./hostedRuntimeWriteGate.ts */
|
|
2
|
+
export {
|
|
3
|
+
assertHostedRuntimePolymarketWriteIdempotency as assertEarnclawPolymarketWriteIdempotency,
|
|
4
|
+
resolveHostedRuntimeIdFromEnv as resolveEarnclawRuntimeId,
|
|
5
|
+
isPolymarketPlaceAction,
|
|
6
|
+
normalizePolymarketPlaceAction,
|
|
7
|
+
} from './hostedRuntimeWriteGate.mjs';
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { createCliError } from '../../core/envelope.mjs';
|
|
2
|
+
import {
|
|
3
|
+
HOSTED_RUNTIME_IDEMPOTENCY_NAMESPACE,
|
|
4
|
+
readHostedRuntimeUuid,
|
|
5
|
+
} from '../../core/hostedRuntimeIdempotency.mjs';
|
|
6
|
+
|
|
7
|
+
const POLYMARKET_PLACE_ACTIONS = new Set([
|
|
8
|
+
'place_polymarket_order',
|
|
9
|
+
'place-polymarket-order',
|
|
10
|
+
'place_prediction_order',
|
|
11
|
+
'place-prediction-order',
|
|
12
|
+
]);
|
|
13
|
+
|
|
14
|
+
export function resolveHostedRuntimeIdFromEnv(env = process.env) {
|
|
15
|
+
return (
|
|
16
|
+
readHostedRuntimeUuid(env.THIRDFY_EXECUTION_RUNTIME_ID)
|
|
17
|
+
|| readHostedRuntimeUuid(env.EARNCLAW_RUNTIME_ID)
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function normalizePolymarketPlaceAction(action) {
|
|
22
|
+
return String(action || '')
|
|
23
|
+
.trim()
|
|
24
|
+
.toLowerCase()
|
|
25
|
+
.replace(/_/g, '-');
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
export function isPolymarketPlaceAction(action) {
|
|
29
|
+
const key = String(action || '').trim().toLowerCase();
|
|
30
|
+
if (POLYMARKET_PLACE_ACTIONS.has(key)) return true;
|
|
31
|
+
return normalizePolymarketPlaceAction(key) === 'place-polymarket-order'
|
|
32
|
+
|| normalizePolymarketPlaceAction(key) === 'place-prediction-order';
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export function assertHostedRuntimePolymarketWriteIdempotency({
|
|
36
|
+
action,
|
|
37
|
+
idempotencyKey,
|
|
38
|
+
paramsIdempotencyKey,
|
|
39
|
+
env = process.env,
|
|
40
|
+
} = {}) {
|
|
41
|
+
if (!isPolymarketPlaceAction(action)) return null;
|
|
42
|
+
const runtimeId = resolveHostedRuntimeIdFromEnv(env);
|
|
43
|
+
if (!runtimeId) return null;
|
|
44
|
+
|
|
45
|
+
const prefix = `${HOSTED_RUNTIME_IDEMPOTENCY_NAMESPACE}:${runtimeId}`;
|
|
46
|
+
const keys = [idempotencyKey, paramsIdempotencyKey]
|
|
47
|
+
.map((key) => String(key || '').trim())
|
|
48
|
+
.filter(Boolean);
|
|
49
|
+
if (keys.some((key) => key.toLowerCase().startsWith(prefix))) return null;
|
|
50
|
+
|
|
51
|
+
throw createCliError(
|
|
52
|
+
'HOSTED_RUNTIME_PM_IDEMPOTENCY_REQUIRED',
|
|
53
|
+
`Hosted runtime ${runtimeId} requires Polymarket place orders to use idempotencyKey starting with "${prefix}". ` +
|
|
54
|
+
'Pack execute-gate and operator exits set this automatically. Bare CLI/dashboard tool writes are blocked.',
|
|
55
|
+
);
|
|
56
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Managed `agent_wallet` reads prefer `/execute`. Execute-intent is only a fallback when that
|
|
3
|
+
* rail rejects the action (`does not support execute rail`). Schema failures must not fall back
|
|
4
|
+
* to an empty queued execute-intent envelope.
|
|
5
|
+
*
|
|
6
|
+
* Keep in sync with `thirdfy-mcp` `src/lib/managedReadExecuteRail.ts`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
export const EXECUTE_RAIL_UNSUPPORTED_FRAGMENT = 'does not support execute rail';
|
|
10
|
+
|
|
11
|
+
export function managedReadExecuteErrorText(data) {
|
|
12
|
+
return String(data?.error || data?.message || data?.code || data?.blockedReason || '').toLowerCase();
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function shouldFallbackManagedReadToExecuteIntent({ isReadOnly, errorText } = {}) {
|
|
16
|
+
if (!isReadOnly) return false;
|
|
17
|
+
const err = String(errorText || '').toLowerCase();
|
|
18
|
+
if (err.includes('params_schema_invalid') || err.includes('invalid paramsschema') || err.includes('unknown key')) {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
return err.includes(EXECUTE_RAIL_UNSUPPORTED_FRAGMENT);
|
|
22
|
+
}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { randomUUID } from 'crypto';
|
|
2
|
+
import { wrapWriteIdempotencyKeyForHostedRuntime } from '../../core/hostedRuntimeIdempotency.mjs';
|
|
3
|
+
import { resolveExecutionContextFromEnv } from '../../core/executionContext.mjs';
|
|
2
4
|
import { requireFlag, parseJsonFlag } from '../../core/args.mjs';
|
|
3
5
|
import { loadProfileConfig } from '../../core/context.mjs';
|
|
4
6
|
import { createCliError } from '../../core/envelope.mjs';
|
|
5
7
|
import { normalizeRunMode, normalizeManagedRunMode, normalizeHybridWalletMode } from '../../core/runMode.mjs';
|
|
6
|
-
import {
|
|
8
|
+
import { assertHostedRuntimePolymarketWriteIdempotency } from './hostedRuntimeWriteGate.mjs';
|
|
7
9
|
import { resolveTokenInForFunding } from '../../core/fundingTokenIn.mjs';
|
|
8
10
|
|
|
9
11
|
function isTruthyFlag(value) {
|
|
@@ -157,7 +159,14 @@ function buildManagedExecutePayload(flags, options) {
|
|
|
157
159
|
} else if (flags.idempotencyKey) {
|
|
158
160
|
payload.executionIdempotencyKey = String(flags.idempotencyKey);
|
|
159
161
|
}
|
|
160
|
-
|
|
162
|
+
if (payload.executionIdempotencyKey) {
|
|
163
|
+
payload.executionIdempotencyKey = wrapWriteIdempotencyKeyForHostedRuntime(
|
|
164
|
+
payload.executionIdempotencyKey,
|
|
165
|
+
resolveExecutionContextFromEnv().runtimeId,
|
|
166
|
+
payload.action,
|
|
167
|
+
);
|
|
168
|
+
}
|
|
169
|
+
assertHostedRuntimePolymarketWriteIdempotency({
|
|
161
170
|
action: payload.action,
|
|
162
171
|
idempotencyKey: payload.executionIdempotencyKey,
|
|
163
172
|
paramsIdempotencyKey: managedParams?.idempotencyKey,
|
|
@@ -203,8 +212,15 @@ function buildIntentPayload(flags, options) {
|
|
|
203
212
|
} else if (flags.idempotencyKey) {
|
|
204
213
|
payload.idempotencyKey = String(flags.idempotencyKey);
|
|
205
214
|
}
|
|
215
|
+
if (payload.idempotencyKey) {
|
|
216
|
+
payload.idempotencyKey = wrapWriteIdempotencyKeyForHostedRuntime(
|
|
217
|
+
payload.idempotencyKey,
|
|
218
|
+
resolveExecutionContextFromEnv().runtimeId,
|
|
219
|
+
payload.action,
|
|
220
|
+
);
|
|
221
|
+
}
|
|
206
222
|
if (!options.validationOnly) {
|
|
207
|
-
|
|
223
|
+
assertHostedRuntimePolymarketWriteIdempotency({
|
|
208
224
|
action: payload.action,
|
|
209
225
|
idempotencyKey: payload.idempotencyKey,
|
|
210
226
|
paramsIdempotencyKey: payload.params?.idempotencyKey,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
import { apiGet, apiPost } from '../../core/http.mjs';
|
|
13
13
|
import { withActionTimeout } from '../../core/actionTimeouts.mjs';
|
|
14
14
|
import { isReadOnlyResolvedAction } from '../../core/readOnlyActions.mjs';
|
|
15
|
+
import { shouldFallbackManagedReadToExecuteIntent } from './managedReadExecuteRail.mjs';
|
|
15
16
|
import { createRequire } from 'module';
|
|
16
17
|
|
|
17
18
|
const require = createRequire(import.meta.url);
|
|
@@ -85,9 +86,10 @@ function isReadOnlyAction(resolved) {
|
|
|
85
86
|
}
|
|
86
87
|
|
|
87
88
|
function shouldFallbackAgentWalletToExecuteIntent(resolved, response) {
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
return shouldFallbackManagedReadToExecuteIntent({
|
|
90
|
+
isReadOnly: isReadOnlyAction(resolved),
|
|
91
|
+
errorText: String(response?.error || response?.message || response?.code || response?.blockedReason || ''),
|
|
92
|
+
});
|
|
91
93
|
}
|
|
92
94
|
|
|
93
95
|
// Managed /execute often returns provider payloads as JSON strings under data.result. Pack parsers
|