agentex-creator-sdk 1.0.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.
- package/CHANGELOG.md +36 -0
- package/LICENSE +21 -0
- package/README.md +195 -0
- package/dist/packages/contracts/src/deployer-investigation.d.ts +1015 -0
- package/dist/packages/contracts/src/deployer-investigation.js +101 -0
- package/dist/packages/contracts/src/index.d.ts +1701 -0
- package/dist/packages/contracts/src/index.js +380 -0
- package/dist/packages/contracts/src/indexed-activity.d.ts +684 -0
- package/dist/packages/contracts/src/indexed-activity.js +71 -0
- package/dist/packages/contracts/src/indexed-agents.d.ts +299 -0
- package/dist/packages/contracts/src/indexed-agents.js +131 -0
- package/dist/packages/contracts/src/inspection.d.ts +906 -0
- package/dist/packages/contracts/src/inspection.js +114 -0
- package/dist/packages/contracts/src/kinds.d.ts +5398 -0
- package/dist/packages/contracts/src/kinds.js +156 -0
- package/dist/packages/contracts/src/report-presentation.d.ts +346 -0
- package/dist/packages/contracts/src/report-presentation.js +120 -0
- package/dist/packages/contracts/src/solana-inspection.d.ts +451 -0
- package/dist/packages/contracts/src/solana-inspection.js +94 -0
- package/dist/packages/contracts/src/token-market.d.ts +193 -0
- package/dist/packages/contracts/src/token-market.js +335 -0
- package/dist/packages/contracts/src/wallet-analysis.d.ts +866 -0
- package/dist/packages/contracts/src/wallet-analysis.js +89 -0
- package/dist/packages/contracts/src/watchtower.d.ts +1141 -0
- package/dist/packages/contracts/src/watchtower.js +196 -0
- package/dist/packages/contracts/src/workflow.d.ts +1568 -0
- package/dist/packages/contracts/src/workflow.js +651 -0
- package/dist/packages/inspector/src/decode.d.ts +23 -0
- package/dist/packages/inspector/src/decode.js +150 -0
- package/dist/packages/inspector/src/scope.d.ts +87 -0
- package/dist/packages/inspector/src/scope.js +64 -0
- package/dist/packages/model/src/analysis.d.ts +149 -0
- package/dist/packages/model/src/analysis.js +387 -0
- package/dist/packages/model/src/pricing.d.ts +38 -0
- package/dist/packages/model/src/pricing.js +49 -0
- package/dist/packages/model/src/retry.d.ts +20 -0
- package/dist/packages/model/src/retry.js +31 -0
- package/dist/packages/model/src/schema.d.ts +10 -0
- package/dist/packages/model/src/schema.js +51 -0
- package/dist/packages/model/src/summary.d.ts +91 -0
- package/dist/packages/model/src/summary.js +177 -0
- package/dist/packages/model/src/types.d.ts +81 -0
- package/dist/packages/model/src/types.js +19 -0
- package/dist/packages/monitoring/src/delivery.d.ts +32 -0
- package/dist/packages/monitoring/src/delivery.js +53 -0
- package/dist/packages/providers/src/chain-transport.d.ts +42 -0
- package/dist/packages/providers/src/chain-transport.js +57 -0
- package/dist/packages/providers/src/coverage.d.ts +105 -0
- package/dist/packages/providers/src/coverage.js +260 -0
- package/dist/packages/providers/src/health.d.ts +273 -0
- package/dist/packages/providers/src/health.js +505 -0
- package/dist/packages/providers/src/keyed.d.ts +96 -0
- package/dist/packages/providers/src/keyed.js +240 -0
- package/dist/packages/providers/src/snapshot.d.ts +61 -0
- package/dist/packages/providers/src/snapshot.js +77 -0
- package/dist/packages/publication/src/fixtures.d.ts +45 -0
- package/dist/packages/publication/src/fixtures.js +350 -0
- package/dist/packages/research/src/index.d.ts +188 -0
- package/dist/packages/research/src/index.js +829 -0
- package/dist/packages/runtime/src/checkpoints.d.ts +65 -0
- package/dist/packages/runtime/src/checkpoints.js +214 -0
- package/dist/packages/runtime/src/policy.d.ts +57 -0
- package/dist/packages/runtime/src/policy.js +296 -0
- package/dist/packages/sdk/src/bin/agentex-buyer.d.ts +2 -0
- package/dist/packages/sdk/src/bin/agentex-buyer.js +4 -0
- package/dist/packages/sdk/src/bin/agentex.d.ts +2 -0
- package/dist/packages/sdk/src/bin/agentex.js +3 -0
- package/dist/packages/sdk/src/buyer-cli.d.ts +10 -0
- package/dist/packages/sdk/src/buyer-cli.js +210 -0
- package/dist/packages/sdk/src/buyer.d.ts +534 -0
- package/dist/packages/sdk/src/buyer.js +441 -0
- package/dist/packages/sdk/src/cli.d.ts +14 -0
- package/dist/packages/sdk/src/cli.js +149 -0
- package/dist/packages/sdk/src/errors.d.ts +31 -0
- package/dist/packages/sdk/src/errors.js +24 -0
- package/dist/packages/sdk/src/index.d.ts +236 -0
- package/dist/packages/sdk/src/index.js +150 -0
- package/dist/packages/sdk/src/local.d.ts +11 -0
- package/dist/packages/sdk/src/local.js +110 -0
- package/dist/packages/sdk/src/rails.d.ts +59 -0
- package/dist/packages/sdk/src/rails.js +96 -0
- package/dist/packages/sdk/src/report.d.ts +121 -0
- package/dist/packages/sdk/src/report.js +114 -0
- package/dist/packages/sdk/src/version.d.ts +2 -0
- package/dist/packages/sdk/src/version.js +2 -0
- package/dist/packages/watchtower/src/index.d.ts +150 -0
- package/dist/packages/watchtower/src/index.js +786 -0
- package/dist/packages/workflow/src/registry.d.ts +61 -0
- package/dist/packages/workflow/src/registry.js +76 -0
- package/examples/README.md +34 -0
- package/examples/cli-usage.sh +30 -0
- package/examples/fixtures/base-weth-input.json +4 -0
- package/examples/focused-researcher.json +127 -0
- package/examples/pay-with-eth-robinhood.mts +37 -0
- package/examples/pay-with-usdc.mts +41 -0
- package/examples/quickstart.mts +73 -0
- package/package.json +50 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export class AgentexApiError extends Error {
|
|
2
|
+
kind;
|
|
3
|
+
status;
|
|
4
|
+
code;
|
|
5
|
+
retryable;
|
|
6
|
+
retryAfterMs;
|
|
7
|
+
name = 'AgentexApiError';
|
|
8
|
+
constructor(kind, status, code, message,
|
|
9
|
+
/** True when repeating the same call can succeed (network failures, 5xx other than 503, rate limits, timeouts). */
|
|
10
|
+
retryable,
|
|
11
|
+
/** Server-suggested wait before retrying (from `Retry-After`), when one was sent. */
|
|
12
|
+
retryAfterMs = null) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.kind = kind;
|
|
15
|
+
this.status = status;
|
|
16
|
+
this.code = code;
|
|
17
|
+
this.retryable = retryable;
|
|
18
|
+
this.retryAfterMs = retryAfterMs;
|
|
19
|
+
}
|
|
20
|
+
/** Set when the failure happened after a run was accepted (`research()` waiting), so the caller can resume with `waitForRun(runId)`. */
|
|
21
|
+
runId;
|
|
22
|
+
}
|
|
23
|
+
/** Type guard for `catch (error)` blocks. */
|
|
24
|
+
export function isAgentexApiError(error) { return error instanceof AgentexApiError; }
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgentManifestSchema, type AgentManifest } from '../../contracts/src/index.js';
|
|
3
|
+
export { SDK_VERSION } from './version.js';
|
|
4
|
+
export declare const MAX_CREATOR_JSON_BYTES = 65536;
|
|
5
|
+
export declare const ScaffoldOptionsSchema: z.ZodObject<{
|
|
6
|
+
id: z.ZodString;
|
|
7
|
+
name: z.ZodString;
|
|
8
|
+
description: z.ZodOptional<z.ZodString>;
|
|
9
|
+
chains: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
10
|
+
ethereum: "ethereum";
|
|
11
|
+
base: "base";
|
|
12
|
+
}>>>;
|
|
13
|
+
researchPolicy: z.ZodOptional<z.ZodObject<{
|
|
14
|
+
readOwner: z.ZodBoolean;
|
|
15
|
+
readProxySlots: z.ZodBoolean;
|
|
16
|
+
}, z.core.$strict>>;
|
|
17
|
+
limits: z.ZodOptional<z.ZodObject<{
|
|
18
|
+
maximumRpcCalls: z.ZodOptional<z.ZodNumber>;
|
|
19
|
+
maximumDurationMs: z.ZodOptional<z.ZodNumber>;
|
|
20
|
+
maximumOutputBytes: z.ZodOptional<z.ZodNumber>;
|
|
21
|
+
}, z.core.$strict>>;
|
|
22
|
+
author: z.ZodOptional<z.ZodObject<{
|
|
23
|
+
id: z.ZodString;
|
|
24
|
+
name: z.ZodString;
|
|
25
|
+
}, z.core.$strict>>;
|
|
26
|
+
}, z.core.$strict>;
|
|
27
|
+
export type ScaffoldOptions = z.infer<typeof ScaffoldOptionsSchema>;
|
|
28
|
+
/** Reject executable/accessor/class values before schema parsing or JSON serialization can invoke them. */
|
|
29
|
+
export declare function assertJsonData(raw: unknown): void;
|
|
30
|
+
export declare function parseCreatorJson(text: string): unknown;
|
|
31
|
+
/** Validation checks the actually executable subset, not just a structurally valid graph. */
|
|
32
|
+
export declare function validateManifest(raw: unknown): AgentManifest;
|
|
33
|
+
export declare function scaffoldTokenResearcher(raw: ScaffoldOptions): AgentManifest;
|
|
34
|
+
export declare function estimateManifest(raw: unknown): {
|
|
35
|
+
kind: "bounded_rpc_plan";
|
|
36
|
+
manifestHash: string;
|
|
37
|
+
policy: Readonly<{
|
|
38
|
+
readOwner: boolean;
|
|
39
|
+
readProxySlots: boolean;
|
|
40
|
+
}>;
|
|
41
|
+
rpc: {
|
|
42
|
+
freshFinalized: {
|
|
43
|
+
nominalCalls: number;
|
|
44
|
+
fitsBudget: boolean;
|
|
45
|
+
};
|
|
46
|
+
explicitSnapshot: {
|
|
47
|
+
nominalCalls: number;
|
|
48
|
+
fitsBudget: boolean;
|
|
49
|
+
};
|
|
50
|
+
attemptRange: {
|
|
51
|
+
minimum: number;
|
|
52
|
+
maximum: number;
|
|
53
|
+
};
|
|
54
|
+
totalRunMaximum: number;
|
|
55
|
+
};
|
|
56
|
+
deadlineMs: number;
|
|
57
|
+
maximumOutputBytes: number;
|
|
58
|
+
modelTokens: number;
|
|
59
|
+
providerCost: {
|
|
60
|
+
status: "unpriced";
|
|
61
|
+
atomic: null;
|
|
62
|
+
currency: null;
|
|
63
|
+
};
|
|
64
|
+
limitations: string[];
|
|
65
|
+
};
|
|
66
|
+
/** Fixed platform fixtures run in process. No creator code, credentials, RPC URL or network transport is accepted. */
|
|
67
|
+
export declare function testManifest(raw: unknown): Promise<import("../../publication/src/fixtures.js").EvaluationSnapshot>;
|
|
68
|
+
export declare const CreatorPackageSchema: z.ZodObject<{
|
|
69
|
+
schemaVersion: z.ZodLiteral<"agentex.creator-package.v1">;
|
|
70
|
+
manifest: z.ZodObject<{
|
|
71
|
+
schemaVersion: z.ZodLiteral<"1.0">;
|
|
72
|
+
id: z.ZodString;
|
|
73
|
+
version: z.ZodString;
|
|
74
|
+
name: z.ZodString;
|
|
75
|
+
description: z.ZodString;
|
|
76
|
+
author: z.ZodObject<{
|
|
77
|
+
id: z.ZodString;
|
|
78
|
+
name: z.ZodString;
|
|
79
|
+
ownership: z.ZodEnum<{
|
|
80
|
+
"first-party": "first-party";
|
|
81
|
+
independent: "independent";
|
|
82
|
+
}>;
|
|
83
|
+
}, z.core.$strict>;
|
|
84
|
+
license: z.ZodString;
|
|
85
|
+
visibility: z.ZodEnum<{
|
|
86
|
+
private: "private";
|
|
87
|
+
"source-visible": "source-visible";
|
|
88
|
+
"source-private": "source-private";
|
|
89
|
+
}>;
|
|
90
|
+
chains: z.ZodArray<z.ZodEnum<{
|
|
91
|
+
ethereum: "ethereum";
|
|
92
|
+
base: "base";
|
|
93
|
+
robinhood: "robinhood";
|
|
94
|
+
}>>;
|
|
95
|
+
inputSchema: z.ZodObject<{
|
|
96
|
+
type: z.ZodLiteral<"object">;
|
|
97
|
+
properties: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
98
|
+
type: z.ZodEnum<{
|
|
99
|
+
string: "string";
|
|
100
|
+
number: "number";
|
|
101
|
+
boolean: "boolean";
|
|
102
|
+
array: "array";
|
|
103
|
+
integer: "integer";
|
|
104
|
+
}>;
|
|
105
|
+
description: z.ZodString;
|
|
106
|
+
enum: z.ZodOptional<z.ZodArray<z.ZodUnion<readonly [z.ZodString, z.ZodNumber, z.ZodBoolean]>>>;
|
|
107
|
+
}, z.core.$strict>>;
|
|
108
|
+
required: z.ZodArray<z.ZodString>;
|
|
109
|
+
additionalProperties: z.ZodLiteral<false>;
|
|
110
|
+
}, z.core.$strict>;
|
|
111
|
+
outputSchemaId: z.ZodEnum<{
|
|
112
|
+
"agentex.token-research.v1": "agentex.token-research.v1";
|
|
113
|
+
"agentex.transaction-inspection.v1": "agentex.transaction-inspection.v1";
|
|
114
|
+
"agentex.watchtower-window.v1": "agentex.watchtower-window.v1";
|
|
115
|
+
}>;
|
|
116
|
+
tools: z.ZodArray<z.ZodObject<{
|
|
117
|
+
id: z.ZodString;
|
|
118
|
+
version: z.ZodString;
|
|
119
|
+
capability: z.ZodLiteral<"evm.read">;
|
|
120
|
+
chains: z.ZodArray<z.ZodEnum<{
|
|
121
|
+
ethereum: "ethereum";
|
|
122
|
+
base: "base";
|
|
123
|
+
robinhood: "robinhood";
|
|
124
|
+
}>>;
|
|
125
|
+
addressScope: z.ZodEnum<{
|
|
126
|
+
"input-address": "input-address";
|
|
127
|
+
"input-transaction": "input-transaction";
|
|
128
|
+
"input-watch-scope": "input-watch-scope";
|
|
129
|
+
}>;
|
|
130
|
+
maximumCalls: z.ZodNumber;
|
|
131
|
+
}, z.core.$strict>>;
|
|
132
|
+
modelPolicy: z.ZodObject<{
|
|
133
|
+
mode: z.ZodLiteral<"deterministic">;
|
|
134
|
+
maximumModelTokens: z.ZodLiteral<0>;
|
|
135
|
+
}, z.core.$strict>;
|
|
136
|
+
researchPolicy: z.ZodOptional<z.ZodObject<{
|
|
137
|
+
readOwner: z.ZodBoolean;
|
|
138
|
+
readProxySlots: z.ZodBoolean;
|
|
139
|
+
}, z.core.$strict>>;
|
|
140
|
+
policy: z.ZodOptional<z.ZodObject<{
|
|
141
|
+
analysis: z.ZodObject<{
|
|
142
|
+
mode: z.ZodLiteral<"summary">;
|
|
143
|
+
maximumOutputTokens: z.ZodNumber;
|
|
144
|
+
maximumCostMicrousd: z.ZodNumber;
|
|
145
|
+
}, z.core.$strict>;
|
|
146
|
+
}, z.core.$strict>>;
|
|
147
|
+
marketPolicy: z.ZodOptional<z.ZodObject<{
|
|
148
|
+
discoverPools: z.ZodBoolean;
|
|
149
|
+
recentHolderActivity: z.ZodBoolean;
|
|
150
|
+
}, z.core.$strict>>;
|
|
151
|
+
limits: z.ZodObject<{
|
|
152
|
+
maximumRpcCalls: z.ZodNumber;
|
|
153
|
+
maximumDurationMs: z.ZodNumber;
|
|
154
|
+
maximumOutputBytes: z.ZodNumber;
|
|
155
|
+
maximumGraphDepth: z.ZodNumber;
|
|
156
|
+
maximumPages: z.ZodLiteral<0>;
|
|
157
|
+
maximumExecutionAtomic: z.ZodString;
|
|
158
|
+
}, z.core.$strict>;
|
|
159
|
+
workflow: z.ZodArray<z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
160
|
+
type: z.ZodLiteral<"input">;
|
|
161
|
+
id: z.ZodString;
|
|
162
|
+
dependsOn: z.ZodArray<z.ZodString>;
|
|
163
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
164
|
+
type: z.ZodLiteral<"tool">;
|
|
165
|
+
tool: z.ZodString;
|
|
166
|
+
arguments: z.ZodRecord<z.ZodString, z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
167
|
+
source: z.ZodLiteral<"input">;
|
|
168
|
+
path: z.ZodString;
|
|
169
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
170
|
+
source: z.ZodLiteral<"node">;
|
|
171
|
+
nodeId: z.ZodString;
|
|
172
|
+
path: z.ZodString;
|
|
173
|
+
}, z.core.$strict>], "source">>;
|
|
174
|
+
id: z.ZodString;
|
|
175
|
+
dependsOn: z.ZodArray<z.ZodString>;
|
|
176
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
177
|
+
type: z.ZodLiteral<"condition">;
|
|
178
|
+
field: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
179
|
+
source: z.ZodLiteral<"input">;
|
|
180
|
+
path: z.ZodString;
|
|
181
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
182
|
+
source: z.ZodLiteral<"node">;
|
|
183
|
+
nodeId: z.ZodString;
|
|
184
|
+
path: z.ZodString;
|
|
185
|
+
}, z.core.$strict>], "source">;
|
|
186
|
+
operator: z.ZodEnum<{
|
|
187
|
+
equals: "equals";
|
|
188
|
+
exists: "exists";
|
|
189
|
+
}>;
|
|
190
|
+
value: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodBoolean, z.ZodNumber]>>;
|
|
191
|
+
whenTrue: z.ZodString;
|
|
192
|
+
whenFalse: z.ZodString;
|
|
193
|
+
id: z.ZodString;
|
|
194
|
+
dependsOn: z.ZodArray<z.ZodString>;
|
|
195
|
+
}, z.core.$strict>, z.ZodObject<{
|
|
196
|
+
type: z.ZodLiteral<"output">;
|
|
197
|
+
from: z.ZodString;
|
|
198
|
+
id: z.ZodString;
|
|
199
|
+
dependsOn: z.ZodArray<z.ZodString>;
|
|
200
|
+
}, z.core.$strict>], "type">>;
|
|
201
|
+
testCases: z.ZodArray<z.ZodString>;
|
|
202
|
+
}, z.core.$strict>;
|
|
203
|
+
manifestHash: z.ZodString;
|
|
204
|
+
}, z.core.$strict>;
|
|
205
|
+
export type CreatorPackage = z.infer<typeof CreatorPackageSchema>;
|
|
206
|
+
export declare function parseCreatorPackage(raw: unknown): CreatorPackage;
|
|
207
|
+
export declare function prepareCreatorPackage(raw: unknown): CreatorPackage;
|
|
208
|
+
export declare const ImportKeySchema: z.ZodString;
|
|
209
|
+
export interface CreatorImportRequest {
|
|
210
|
+
method: 'POST';
|
|
211
|
+
path: '/v1/packages/import';
|
|
212
|
+
body: {
|
|
213
|
+
package: CreatorPackage;
|
|
214
|
+
idempotencyKey: string;
|
|
215
|
+
};
|
|
216
|
+
}
|
|
217
|
+
/** Applications supply their authenticated transport; package JSON never supplies credentials or destinations. */
|
|
218
|
+
export type CreatorImportTransport = (request: CreatorImportRequest) => Promise<unknown>;
|
|
219
|
+
export declare function submitCreatorPackage(raw: unknown, options: {
|
|
220
|
+
idempotencyKey: string;
|
|
221
|
+
transport: CreatorImportTransport;
|
|
222
|
+
}): Promise<{
|
|
223
|
+
status: "imported_for_testing";
|
|
224
|
+
notice: string;
|
|
225
|
+
draft: {
|
|
226
|
+
id: string;
|
|
227
|
+
};
|
|
228
|
+
version: {
|
|
229
|
+
id: string;
|
|
230
|
+
manifestHash: string;
|
|
231
|
+
};
|
|
232
|
+
sourceManifestHash: string;
|
|
233
|
+
recovered: boolean;
|
|
234
|
+
}>;
|
|
235
|
+
export { AgentManifestSchema };
|
|
236
|
+
export type { AgentManifest };
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { AgentManifestSchema, ResearchPolicySchema, SupportedTokenResearcherManifestSchema, TOKEN_RESEARCHER_MANIFEST_V2, contentHash, getTokenResearcherRpcPlan, publishManifest } from '../../contracts/src/index.js';
|
|
3
|
+
import { evaluateManifest } from '../../publication/src/fixtures.js';
|
|
4
|
+
export { SDK_VERSION } from './version.js';
|
|
5
|
+
export const MAX_CREATOR_JSON_BYTES = 65_536;
|
|
6
|
+
const Identifier = z.string().regex(/^[a-z][a-z0-9._-]{0,63}$/);
|
|
7
|
+
const Hash = z.string().regex(/^[a-f0-9]{64}$/);
|
|
8
|
+
function invalidData(message) { throw new z.ZodError([{ code: 'custom', path: [], message }]); }
|
|
9
|
+
export const ScaffoldOptionsSchema = z.strictObject({
|
|
10
|
+
id: Identifier, name: z.string().trim().min(1).max(100), description: z.string().trim().min(1).max(2000).optional(),
|
|
11
|
+
chains: z.array(z.enum(['ethereum', 'base'])).min(1).max(2).refine(chains => new Set(chains).size === chains.length, 'Duplicate analysis chain').optional(),
|
|
12
|
+
researchPolicy: ResearchPolicySchema.optional(),
|
|
13
|
+
limits: z.strictObject({ maximumRpcCalls: z.number().int().min(1).max(16).optional(), maximumDurationMs: z.number().int().min(1000).max(60_000).optional(),
|
|
14
|
+
maximumOutputBytes: z.number().int().min(1024).max(131_072).optional() }).optional(),
|
|
15
|
+
author: z.strictObject({ id: Identifier, name: z.string().trim().min(1).max(100) }).optional(),
|
|
16
|
+
});
|
|
17
|
+
/** Reject executable/accessor/class values before schema parsing or JSON serialization can invoke them. */
|
|
18
|
+
export function assertJsonData(raw) {
|
|
19
|
+
const ancestors = new Set();
|
|
20
|
+
let nodes = 0;
|
|
21
|
+
let stringBytes = 0;
|
|
22
|
+
function visit(value, depth) {
|
|
23
|
+
if (++nodes > 20_000 || depth > 32)
|
|
24
|
+
invalidData('Creator JSON exceeds the structural limit.');
|
|
25
|
+
if (typeof value === 'string') {
|
|
26
|
+
stringBytes += Buffer.byteLength(value);
|
|
27
|
+
if (stringBytes > MAX_CREATOR_JSON_BYTES)
|
|
28
|
+
invalidData('Creator JSON exceeds the byte limit.');
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
if (value === null || typeof value === 'boolean' || (typeof value === 'number' && Number.isFinite(value)))
|
|
32
|
+
return;
|
|
33
|
+
if (typeof value !== 'object')
|
|
34
|
+
invalidData('Only finite JSON data is accepted; executable values are unsupported.');
|
|
35
|
+
if (ancestors.has(value))
|
|
36
|
+
invalidData('Cyclic creator data is unsupported.');
|
|
37
|
+
if (Object.getOwnPropertySymbols(value).length)
|
|
38
|
+
invalidData('Symbol properties are unsupported.');
|
|
39
|
+
const array = Array.isArray(value);
|
|
40
|
+
if (!array && Object.getPrototypeOf(value) !== Object.prototype)
|
|
41
|
+
invalidData('Only plain JSON objects are supported.');
|
|
42
|
+
const descriptors = Object.getOwnPropertyDescriptors(value);
|
|
43
|
+
if (array && Object.keys(descriptors).length !== value.length + 1)
|
|
44
|
+
invalidData('Sparse arrays or custom array properties are unsupported.');
|
|
45
|
+
ancestors.add(value);
|
|
46
|
+
for (const [key, descriptor] of Object.entries(descriptors)) {
|
|
47
|
+
if (array && key === 'length')
|
|
48
|
+
continue;
|
|
49
|
+
if (!descriptor.enumerable || !Object.hasOwn(descriptor, 'value'))
|
|
50
|
+
invalidData('Accessors and hidden properties are unsupported.');
|
|
51
|
+
if (array && (!/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= value.length))
|
|
52
|
+
invalidData('Custom array properties are unsupported.');
|
|
53
|
+
stringBytes += Buffer.byteLength(key);
|
|
54
|
+
if (stringBytes > MAX_CREATOR_JSON_BYTES)
|
|
55
|
+
invalidData('Creator JSON exceeds the byte limit.');
|
|
56
|
+
visit(descriptor.value, depth + 1);
|
|
57
|
+
}
|
|
58
|
+
ancestors.delete(value);
|
|
59
|
+
}
|
|
60
|
+
visit(raw, 0);
|
|
61
|
+
if (Buffer.byteLength(JSON.stringify(raw)) > MAX_CREATOR_JSON_BYTES)
|
|
62
|
+
invalidData('Creator JSON exceeds the byte limit.');
|
|
63
|
+
}
|
|
64
|
+
export function parseCreatorJson(text) {
|
|
65
|
+
if (Buffer.byteLength(text) > MAX_CREATOR_JSON_BYTES)
|
|
66
|
+
invalidData('Creator JSON exceeds the byte limit.');
|
|
67
|
+
let raw;
|
|
68
|
+
try {
|
|
69
|
+
raw = JSON.parse(text);
|
|
70
|
+
}
|
|
71
|
+
catch {
|
|
72
|
+
invalidData('Input must contain one valid JSON value. JavaScript and module files are unsupported.');
|
|
73
|
+
}
|
|
74
|
+
assertJsonData(raw);
|
|
75
|
+
return raw;
|
|
76
|
+
}
|
|
77
|
+
/** Validation checks the actually executable subset, not just a structurally valid graph. */
|
|
78
|
+
export function validateManifest(raw) {
|
|
79
|
+
assertJsonData(raw);
|
|
80
|
+
return publishManifest(SupportedTokenResearcherManifestSchema.parse(raw)).manifest;
|
|
81
|
+
}
|
|
82
|
+
export function scaffoldTokenResearcher(raw) {
|
|
83
|
+
assertJsonData(raw);
|
|
84
|
+
const options = ScaffoldOptionsSchema.parse(raw);
|
|
85
|
+
// New packages start from the current 0.2.0 template (instant-read wording); 0.1.0 packages still validate unchanged.
|
|
86
|
+
const manifest = structuredClone(TOKEN_RESEARCHER_MANIFEST_V2);
|
|
87
|
+
manifest.id = options.id;
|
|
88
|
+
manifest.name = options.name;
|
|
89
|
+
manifest.description = options.description ?? 'Inspect required ERC-20 metadata and selected owner/proxy controls at the latest block (sequencer-confirmed), rechecked at completion. Selected omissions are explicit; exhaustive authority, holder and market coverage is unavailable.';
|
|
90
|
+
manifest.author = { ...(options.author ?? { id: 'local-creator', name: 'Local creator' }), ownership: 'independent' };
|
|
91
|
+
manifest.visibility = 'private';
|
|
92
|
+
if (options.chains) {
|
|
93
|
+
manifest.chains = options.chains;
|
|
94
|
+
manifest.tools[0].chains = options.chains;
|
|
95
|
+
manifest.inputSchema.properties.chain.enum = options.chains;
|
|
96
|
+
}
|
|
97
|
+
if (options.researchPolicy)
|
|
98
|
+
manifest.researchPolicy = options.researchPolicy;
|
|
99
|
+
if (options.limits) {
|
|
100
|
+
Object.assign(manifest.limits, options.limits);
|
|
101
|
+
manifest.tools[0].maximumCalls = manifest.limits.maximumRpcCalls;
|
|
102
|
+
}
|
|
103
|
+
return validateManifest(manifest);
|
|
104
|
+
}
|
|
105
|
+
export function estimateManifest(raw) {
|
|
106
|
+
const manifest = validateManifest(raw);
|
|
107
|
+
const plan = getTokenResearcherRpcPlan(manifest);
|
|
108
|
+
return {
|
|
109
|
+
kind: 'bounded_rpc_plan', manifestHash: contentHash(manifest), policy: plan.policy,
|
|
110
|
+
rpc: { freshFinalized: { nominalCalls: plan.latestSnapshotCalls, fitsBudget: plan.latestSnapshotCalls <= plan.maximumRpcCalls },
|
|
111
|
+
explicitSnapshot: { nominalCalls: plan.explicitSnapshotCalls, fitsBudget: plan.explicitSnapshotCalls <= plan.maximumRpcCalls },
|
|
112
|
+
attemptRange: { minimum: 0, maximum: plan.maximumRpcCalls }, totalRunMaximum: plan.maximumRpcCalls },
|
|
113
|
+
deadlineMs: Math.min(60_000, manifest.limits.maximumDurationMs), maximumOutputBytes: Math.min(131_072, manifest.limits.maximumOutputBytes),
|
|
114
|
+
modelTokens: 0, providerCost: { status: 'unpriced', atomic: null, currency: null },
|
|
115
|
+
limitations: ['Nominal calls assume deployed code and all selected reads completing. Failure or cancellation can stop earlier.',
|
|
116
|
+
'Recovery adds fresh identity/header reads and must share the original persisted run budget; retries do not receive a new allowance.',
|
|
117
|
+
'This is an operation estimate, not a marketplace quote or a provider invoice. Actual price and payment authorization come from the server quote flow.',
|
|
118
|
+
'Omitting owner/proxy checks reduces observed coverage and does not establish absence of privileged controls.'],
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
/** Fixed platform fixtures run in process. No creator code, credentials, RPC URL or network transport is accepted. */
|
|
122
|
+
export async function testManifest(raw) { return evaluateManifest(validateManifest(raw)); }
|
|
123
|
+
export const CreatorPackageSchema = z.strictObject({ schemaVersion: z.literal('agentex.creator-package.v1'),
|
|
124
|
+
manifest: SupportedTokenResearcherManifestSchema, manifestHash: Hash,
|
|
125
|
+
}).superRefine((envelope, ctx) => {
|
|
126
|
+
if (contentHash(envelope.manifest) !== envelope.manifestHash)
|
|
127
|
+
ctx.addIssue({ code: 'custom', path: ['manifestHash'], message: 'Package manifest hash does not match its JSON data.' });
|
|
128
|
+
});
|
|
129
|
+
export function parseCreatorPackage(raw) {
|
|
130
|
+
assertJsonData(raw);
|
|
131
|
+
const envelope = CreatorPackageSchema.parse(raw);
|
|
132
|
+
return Object.freeze({ ...envelope, manifest: validateManifest(envelope.manifest) });
|
|
133
|
+
}
|
|
134
|
+
export function prepareCreatorPackage(raw) {
|
|
135
|
+
const manifest = validateManifest(raw);
|
|
136
|
+
return parseCreatorPackage({ schemaVersion: 'agentex.creator-package.v1', manifest, manifestHash: contentHash(manifest) });
|
|
137
|
+
}
|
|
138
|
+
export const ImportKeySchema = z.string().min(8).max(128).regex(/^[A-Za-z0-9_-]+$/);
|
|
139
|
+
const ImportResponseSchema = z.object({ draft: z.object({ id: z.uuid() }), version: z.object({ id: z.uuid(), manifestHash: Hash }), sourceManifestHash: Hash, recovered: z.boolean() });
|
|
140
|
+
export async function submitCreatorPackage(raw, options) {
|
|
141
|
+
const envelope = parseCreatorPackage(raw);
|
|
142
|
+
const idempotencyKey = ImportKeySchema.parse(options.idempotencyKey);
|
|
143
|
+
const response = ImportResponseSchema.parse(await options.transport({ method: 'POST', path: '/v1/packages/import', body: { package: envelope, idempotencyKey } }));
|
|
144
|
+
if (response.sourceManifestHash !== envelope.manifestHash)
|
|
145
|
+
throw new Error('The import response does not match the submitted package hash.');
|
|
146
|
+
return { ...response, status: 'imported_for_testing',
|
|
147
|
+
notice: 'The server bound author identity and private visibility to the authenticated creator. Import is not evaluation, review approval, publication or a buyer purchase.' };
|
|
148
|
+
}
|
|
149
|
+
// Export the generic contract type for SDK users; unsupported manifests still fail validateManifest.
|
|
150
|
+
export { AgentManifestSchema };
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type CreatorImportTransport } from './index.js';
|
|
2
|
+
export declare function readCreatorFile(file: string, workspace?: string): Promise<unknown>;
|
|
3
|
+
/** Parents must already exist. wx rejects existing files, including a final-component symlink. */
|
|
4
|
+
export declare function writeCreatorFile(file: string, value: unknown, workspace?: string): Promise<void>;
|
|
5
|
+
export declare function loopbackOrigin(raw: string): string;
|
|
6
|
+
/** Development SIWE session transport. Endpoint selection is never taken from package data. */
|
|
7
|
+
export declare function createLocalImportTransport(options: {
|
|
8
|
+
api: string;
|
|
9
|
+
origin: string;
|
|
10
|
+
sessionToken: string;
|
|
11
|
+
}): CreatorImportTransport;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { constants } from 'node:fs';
|
|
2
|
+
import { lstat, open, realpath, writeFile } from 'node:fs/promises';
|
|
3
|
+
import { dirname, extname, isAbsolute, relative, resolve } from 'node:path';
|
|
4
|
+
import { MAX_CREATOR_JSON_BYTES, parseCreatorJson } from './index.js';
|
|
5
|
+
function inside(root, target) { const path = relative(root, target); return path !== '' && path !== '..' && !path.startsWith(`..${process.platform === 'win32' ? '\\' : '/'}`) && !isAbsolute(path); }
|
|
6
|
+
async function jsonPath(file, workspace, existing) {
|
|
7
|
+
if (extname(file).toLowerCase() !== '.json' || file.includes('\0'))
|
|
8
|
+
throw new Error('A local .json file is required.');
|
|
9
|
+
const root = await realpath(workspace);
|
|
10
|
+
const target = resolve(workspace, file);
|
|
11
|
+
if (!inside(root, target))
|
|
12
|
+
throw new Error('The JSON file must remain inside the selected working directory.');
|
|
13
|
+
if (process.platform === 'win32' && relative(root, target).split(/[\\/]/).some(part => part.includes(':') || /[. ]$/.test(part) || /^(con|prn|aux|nul|com[1-9]|lpt[1-9])(?:\.|$)/i.test(part)))
|
|
14
|
+
throw new Error('Windows device paths, alternate data streams and ambiguous path components are unsupported.');
|
|
15
|
+
const parent = await realpath(dirname(target));
|
|
16
|
+
if (parent !== root && !inside(root, parent))
|
|
17
|
+
throw new Error('The JSON parent directory escapes the working directory.');
|
|
18
|
+
if (existing) {
|
|
19
|
+
const stat = await lstat(target);
|
|
20
|
+
if (!stat.isFile() || stat.isSymbolicLink() || !inside(root, await realpath(target)))
|
|
21
|
+
throw new Error('Only regular JSON files inside the working directory are accepted.');
|
|
22
|
+
}
|
|
23
|
+
return target;
|
|
24
|
+
}
|
|
25
|
+
export async function readCreatorFile(file, workspace = process.cwd()) {
|
|
26
|
+
const target = await jsonPath(file, workspace, true);
|
|
27
|
+
const handle = await open(target, constants.O_RDONLY | (constants.O_NOFOLLOW ?? 0));
|
|
28
|
+
try {
|
|
29
|
+
const stat = await handle.stat();
|
|
30
|
+
if (!stat.isFile() || stat.size > MAX_CREATOR_JSON_BYTES)
|
|
31
|
+
throw new Error('Creator JSON exceeds the regular-file or size limit.');
|
|
32
|
+
const buffer = Buffer.alloc(MAX_CREATOR_JSON_BYTES + 1);
|
|
33
|
+
let length = 0;
|
|
34
|
+
while (length < buffer.length) {
|
|
35
|
+
const read = await handle.read(buffer, length, buffer.length - length, null);
|
|
36
|
+
if (!read.bytesRead)
|
|
37
|
+
break;
|
|
38
|
+
length += read.bytesRead;
|
|
39
|
+
}
|
|
40
|
+
if (length > MAX_CREATOR_JSON_BYTES)
|
|
41
|
+
throw new Error('Creator JSON exceeds the byte limit.');
|
|
42
|
+
const text = new TextDecoder('utf-8', { fatal: true }).decode(buffer.subarray(0, length));
|
|
43
|
+
return parseCreatorJson(text);
|
|
44
|
+
}
|
|
45
|
+
finally {
|
|
46
|
+
await handle.close();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Parents must already exist. wx rejects existing files, including a final-component symlink. */
|
|
50
|
+
export async function writeCreatorFile(file, value, workspace = process.cwd()) {
|
|
51
|
+
const target = await jsonPath(file, workspace, false);
|
|
52
|
+
const data = `${JSON.stringify(value, null, 2)}\n`;
|
|
53
|
+
if (Buffer.byteLength(data) > 2_097_152)
|
|
54
|
+
throw new Error('CLI output exceeds its file-size limit.');
|
|
55
|
+
await writeFile(target, data, { flag: 'wx', mode: 0o600 });
|
|
56
|
+
}
|
|
57
|
+
export function loopbackOrigin(raw) {
|
|
58
|
+
const url = new URL(raw);
|
|
59
|
+
if (raw !== raw.trim() || !['http:', 'https:'].includes(url.protocol) || !['127.0.0.1', 'localhost', '[::1]'].includes(url.hostname)
|
|
60
|
+
|| url.username || url.password || url.pathname !== '/' || url.search || url.hash)
|
|
61
|
+
throw new Error('An exact loopback HTTP(S) origin is required.');
|
|
62
|
+
return url.origin;
|
|
63
|
+
}
|
|
64
|
+
/** Development SIWE session transport. Endpoint selection is never taken from package data. */
|
|
65
|
+
export function createLocalImportTransport(options) {
|
|
66
|
+
const api = loopbackOrigin(options.api);
|
|
67
|
+
const origin = loopbackOrigin(options.origin);
|
|
68
|
+
if (!/^[a-f0-9]{64}$/.test(options.sessionToken))
|
|
69
|
+
throw new Error('A valid development session token is required.');
|
|
70
|
+
return async (request) => {
|
|
71
|
+
if (request.path !== '/v1/packages/import' || request.method !== 'POST')
|
|
72
|
+
throw new Error('Only the creator import endpoint is supported.');
|
|
73
|
+
const response = await fetch(`${api}${request.path}`, { method: 'POST', headers: { 'content-type': 'application/json', origin,
|
|
74
|
+
cookie: `agentex_session=${options.sessionToken}` }, body: JSON.stringify(request.body), redirect: 'error', signal: AbortSignal.timeout(10_000) });
|
|
75
|
+
if (!response.ok) {
|
|
76
|
+
await response.body?.cancel();
|
|
77
|
+
throw new Error(`Creator import rejected with HTTP ${response.status}.`);
|
|
78
|
+
}
|
|
79
|
+
if (!/^application\/json(?:;|$)/i.test(response.headers.get('content-type') ?? '') || Number(response.headers.get('content-length') ?? 0) > 131_072) {
|
|
80
|
+
await response.body?.cancel();
|
|
81
|
+
throw new Error('Creator import response has an unsupported type or size.');
|
|
82
|
+
}
|
|
83
|
+
const reader = response.body?.getReader();
|
|
84
|
+
if (!reader)
|
|
85
|
+
throw new Error('Creator import response is empty.');
|
|
86
|
+
const chunks = [];
|
|
87
|
+
let size = 0;
|
|
88
|
+
try {
|
|
89
|
+
while (true) {
|
|
90
|
+
const { done, value } = await reader.read();
|
|
91
|
+
if (done)
|
|
92
|
+
break;
|
|
93
|
+
size += value.byteLength;
|
|
94
|
+
if (size > 131_072)
|
|
95
|
+
throw new Error('Creator import response exceeds its byte limit.');
|
|
96
|
+
chunks.push(value);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
finally {
|
|
100
|
+
await reader.cancel().catch(() => undefined);
|
|
101
|
+
reader.releaseLock();
|
|
102
|
+
}
|
|
103
|
+
try {
|
|
104
|
+
return JSON.parse(new TextDecoder('utf-8', { fatal: true }).decode(Buffer.concat(chunks)));
|
|
105
|
+
}
|
|
106
|
+
catch {
|
|
107
|
+
throw new Error('Creator import response is not valid JSON.');
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Payment rails and asset ids. AGENTEX names every payment asset with a ledger asset id:
|
|
3
|
+
*
|
|
4
|
+
* - `solana:mainnet-beta/native`: SOL on Solana (9 decimals). The default rail.
|
|
5
|
+
* - `solana:mainnet-beta/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v`: USDC on Solana (6 decimals).
|
|
6
|
+
* - `eip155:4663/native`: ETH on Robinhood Chain (18 decimals).
|
|
7
|
+
*
|
|
8
|
+
* One listing can accept several rails. An API key is bound to one payment profile, and so to one asset: a SOL or USDC key belongs to a
|
|
9
|
+
* Solana account, an ETH key to an EVM account. These helpers are pure data; they never contact the network.
|
|
10
|
+
*/
|
|
11
|
+
export type BuyerProfile = 'sim' | 'local_custody' | 'solana_sol' | 'solana_usdc';
|
|
12
|
+
export type PaymentRail = 'solana' | 'evm' | 'sim';
|
|
13
|
+
export declare const USDC_MINT = "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
14
|
+
export declare const SOL_ASSET_ID = "solana:mainnet-beta/native";
|
|
15
|
+
export declare const USDC_ASSET_ID = "solana:mainnet-beta/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
16
|
+
export declare const ETH_ROBINHOOD_ASSET_ID = "eip155:4663/native";
|
|
17
|
+
/** The production payment assets, SOL first. */
|
|
18
|
+
export declare const ASSETS: Readonly<{
|
|
19
|
+
readonly SOL: "solana:mainnet-beta/native";
|
|
20
|
+
readonly USDC: "solana:mainnet-beta/spl:EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v";
|
|
21
|
+
readonly ETH_ROBINHOOD: "eip155:4663/native";
|
|
22
|
+
}>;
|
|
23
|
+
/** SOL on Solana. */
|
|
24
|
+
export declare const DEFAULT_ASSET_ID = "solana:mainnet-beta/native";
|
|
25
|
+
/** Short names accepted wherever an asset id is (`sol`, `usdc`, `eth`). */
|
|
26
|
+
export declare const ASSET_ALIASES: Readonly<Record<'sol' | 'usdc' | 'eth', string>>;
|
|
27
|
+
export interface PaymentAsset {
|
|
28
|
+
assetId: string;
|
|
29
|
+
rail: PaymentRail;
|
|
30
|
+
/** The API key profile that pays in this asset. */
|
|
31
|
+
profile: BuyerProfile;
|
|
32
|
+
/** Solana cluster (`mainnet-beta`, `devnet`, `localnet`), the EVM chain id as text, or `local-sim`. */
|
|
33
|
+
network: string;
|
|
34
|
+
networkLabel: string;
|
|
35
|
+
/** `SOL`, `USDC`, `ETH` or `SIM`. An unrecognised SPL mint or ERC-20 reads as `SPL` or `ERC-20` with unknown decimals. */
|
|
36
|
+
currency: string;
|
|
37
|
+
decimals: number | null;
|
|
38
|
+
mint: string | null;
|
|
39
|
+
chainId: number | null;
|
|
40
|
+
contract: string | null;
|
|
41
|
+
/** For example "SOL on Solana" or "ETH on Robinhood Chain". */
|
|
42
|
+
label: string;
|
|
43
|
+
}
|
|
44
|
+
/** Accepts an asset id or an alias (`sol`, `usdc`, `eth`) and returns the validated asset id. */
|
|
45
|
+
export declare function resolveAssetId(value: string): string;
|
|
46
|
+
/** Parses an asset id (or an alias) into its rail, network, currency and decimals. Throws `invalid_input` for anything else. */
|
|
47
|
+
export declare function describeAsset(value: string): PaymentAsset;
|
|
48
|
+
/** The API key profile that pays in an asset: SOL → `solana_sol`, USDC → `solana_usdc`, ETH → `local_custody`. */
|
|
49
|
+
export declare function profileForAsset(assetId: string): BuyerProfile;
|
|
50
|
+
/** The quote, acceptance, catalog and billing route prefix for a profile. The Solana rail serves SOL and USDC keys. */
|
|
51
|
+
export declare function railPath(profile: BuyerProfile): '/v1/rehearsal' | '/v1/custody' | '/v1/solana-custody';
|
|
52
|
+
/** The asset id of a ledger asset object, such as a quote's `asset` (`{ namespace: 'solana', cluster, kind, mint?, decimals }`). */
|
|
53
|
+
export declare function assetIdOf(asset: unknown): string | null;
|
|
54
|
+
/** Exact decimal text for an atomic amount: `formatAtomic('2200000', 9)` is `"0.0022"`. No floats, no rounding. */
|
|
55
|
+
export declare function formatAtomic(amount: string | bigint, decimals: number): string;
|
|
56
|
+
/** Exact atomic amount for a decimal text: `parseAmount('0.05', 9)` is `"50000000"`. Throws when the text has more precision than the asset. */
|
|
57
|
+
export declare function parseAmount(value: string, decimals: number): string;
|
|
58
|
+
/** "0.0022 SOL". Falls back to the atomic amount and asset id when the asset's decimals are unknown. */
|
|
59
|
+
export declare function formatAmount(amount: string | bigint, asset: string | PaymentAsset): string;
|