@pulseai/sdk 0.1.2 → 0.1.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/dist/index.d.ts +46 -1
- package/dist/index.js +333 -31
- package/dist/index.js.map +1 -1
- package/package.json +10 -9
package/dist/index.d.ts
CHANGED
|
@@ -321,6 +321,32 @@ declare function createRequirements(params: RequirementsParams): {
|
|
|
321
321
|
hash: Hex;
|
|
322
322
|
};
|
|
323
323
|
|
|
324
|
+
type JsonSchema = {
|
|
325
|
+
type: 'object';
|
|
326
|
+
properties: Record<string, {
|
|
327
|
+
type: 'string' | 'number' | 'boolean' | 'object' | 'array';
|
|
328
|
+
description?: string;
|
|
329
|
+
enum?: unknown[];
|
|
330
|
+
items?: {
|
|
331
|
+
type: string;
|
|
332
|
+
};
|
|
333
|
+
}>;
|
|
334
|
+
required?: string[];
|
|
335
|
+
};
|
|
336
|
+
/** Pulse offering schema document (JSON Schema-based). */
|
|
337
|
+
type OfferingSchema = {
|
|
338
|
+
version: number;
|
|
339
|
+
serviceRequirements: JsonSchema;
|
|
340
|
+
deliverableRequirements: JsonSchema;
|
|
341
|
+
};
|
|
342
|
+
/** Default schemas by service type (Custom/5 intentionally omitted). */
|
|
343
|
+
declare const DEFAULT_SCHEMAS: Record<number, OfferingSchema>;
|
|
344
|
+
/** Validate runtime data against a compact JSON Schema object definition. */
|
|
345
|
+
declare function validateAgainstSchema(data: Record<string, unknown> | undefined, schema: JsonSchema): {
|
|
346
|
+
valid: boolean;
|
|
347
|
+
reason?: string;
|
|
348
|
+
};
|
|
349
|
+
|
|
324
350
|
type JobContext = {
|
|
325
351
|
jobId: bigint;
|
|
326
352
|
offeringId: bigint;
|
|
@@ -336,6 +362,11 @@ type ExecuteJobResult = {
|
|
|
336
362
|
content?: string;
|
|
337
363
|
url?: string;
|
|
338
364
|
mimeType?: string;
|
|
365
|
+
usage?: {
|
|
366
|
+
provider: string;
|
|
367
|
+
inputTokens: number;
|
|
368
|
+
outputTokens: number;
|
|
369
|
+
};
|
|
339
370
|
};
|
|
340
371
|
type ValidationResult = {
|
|
341
372
|
valid: boolean;
|
|
@@ -344,6 +375,7 @@ type ValidationResult = {
|
|
|
344
375
|
interface OfferingHandler {
|
|
345
376
|
offeringId: number;
|
|
346
377
|
autoAccept?: boolean;
|
|
378
|
+
schema?: OfferingSchema;
|
|
347
379
|
validateRequirements?(context: JobContext): Promise<ValidationResult>;
|
|
348
380
|
executeJob(context: JobContext): Promise<ExecuteJobResult>;
|
|
349
381
|
}
|
|
@@ -360,6 +392,7 @@ type SiteModifierConfig = {
|
|
|
360
392
|
declare class SiteModifierHandler implements OfferingHandler {
|
|
361
393
|
readonly offeringId: number;
|
|
362
394
|
readonly autoAccept?: boolean;
|
|
395
|
+
readonly schema: OfferingSchema;
|
|
363
396
|
private readonly config;
|
|
364
397
|
constructor(offeringId: number, config: SiteModifierConfig, options?: {
|
|
365
398
|
autoAccept?: boolean;
|
|
@@ -542,10 +575,15 @@ type CallAIParams = {
|
|
|
542
575
|
maxTokens?: number;
|
|
543
576
|
signal?: AbortSignal;
|
|
544
577
|
};
|
|
578
|
+
type AIUsage = {
|
|
579
|
+
inputTokens: number;
|
|
580
|
+
outputTokens: number;
|
|
581
|
+
};
|
|
545
582
|
type CallAIResult = {
|
|
546
583
|
content: string;
|
|
547
584
|
truncated: boolean;
|
|
548
585
|
raw: unknown;
|
|
586
|
+
usage?: AIUsage;
|
|
549
587
|
};
|
|
550
588
|
type AICallOptions = CallAIParams;
|
|
551
589
|
type AICallResult = CallAIResult;
|
|
@@ -588,6 +626,7 @@ interface IndexerOffering {
|
|
|
588
626
|
priceUsdm: string;
|
|
589
627
|
slaMinutes: number | null;
|
|
590
628
|
description: string | null;
|
|
629
|
+
requirementsSchemaUri?: string;
|
|
591
630
|
active: boolean;
|
|
592
631
|
blockNumber: number | null;
|
|
593
632
|
txHash: string | null;
|
|
@@ -720,6 +759,7 @@ declare class HandlerProviderRuntime {
|
|
|
720
759
|
private running;
|
|
721
760
|
private processedJobs;
|
|
722
761
|
private failedJobs;
|
|
762
|
+
private schemaCache;
|
|
723
763
|
private readonly maxRetries;
|
|
724
764
|
private onError?;
|
|
725
765
|
constructor(client: PulseClient, agentId: bigint, options: HandlerProviderRuntimeOptions);
|
|
@@ -734,6 +774,11 @@ declare class HandlerProviderRuntime {
|
|
|
734
774
|
private canProcess;
|
|
735
775
|
private markProcessed;
|
|
736
776
|
private markFailed;
|
|
777
|
+
private validateSchemaRequirements;
|
|
778
|
+
private resolveOfferingSchemaFromUri;
|
|
779
|
+
private parseDataUriJson;
|
|
780
|
+
private isOfferingSchema;
|
|
781
|
+
private isJsonSchema;
|
|
737
782
|
private getRemainingSlaMs;
|
|
738
783
|
}
|
|
739
784
|
|
|
@@ -3629,4 +3674,4 @@ declare const masterAbi: readonly [{
|
|
|
3629
3674
|
readonly anonymous: false;
|
|
3630
3675
|
}];
|
|
3631
3676
|
|
|
3632
|
-
export { ACCEPT_TIMEOUT, type AICallOptions, type AICallResult, type AIMessage, type AIProvider, type AgentCardParams, BPS_DENOMINATOR, type BuyerCallbacks, BuyerRuntime, type BuyerRuntimeOptions, type CreateJobParams, type CreatePresetPulseClientOptions, type CreatePulseClientOptions, DEFAULT_INDEXER_URLS, type DeliverableData, type DeliverableParams, EVALUATION_TIMEOUT, type ExecuteJobResult, FEE_BPS, HandlerProviderRuntime, type HandlerProviderRuntimeOptions, type IndexerAgent, IndexerClient, IndexerClientError, type IndexerClientOptions, type IndexerJob, type IndexerJobsFilter, type IndexerOffering, type IndexerOfferingsFilter, type IndexerWarrenLink, type IndexerWarrenLinks, type Job, type JobContext, type JobOffering, JobStatus, type JobTermsParams, type ListOfferingParams, MAINNET_ADDRESSES, MEMO_TYPES, type OfferingHandler, PLATFORM_BUYER_AGENT_ID, PULSE_DOMAIN, type PresetPulseClient, type ProviderCallbacks, ProviderRuntime, type ProviderRuntimeOptions, type PulseAddresses, type PulseAgentData, type PulseClient, RISK_POOL_BPS, type RequirementsData, type RequirementsParams, ServiceType, type SignMemoParams, type SiteModifierConfig, SiteModifierHandler, TESTNET_ADDRESSES, TREASURY_BPS, USDM_MAINNET, type ValidationResult, acceptJob, activateOffering, buyerRelayAbi, callAI, cancelJob, createAgentCard, createDeliverable, createJob, createJobTerms, createMainnetClient, createPulseClient, createRequirements, createTestnetClient, deactivateOffering, deployAgentCard, deployDeliverable, deployJobTerms, deployRequirements, deployWarrenMaster, deployWarrenPage, erc20Abi, erc8004IdentityAbi, erc8004ReputationAbi, evaluate, feeDistributorAbi, formatUsdm, getAgent, getJob, getJobCount, getOffering, getOfferingCount, initAgent, jobEngineAbi, listOffering, mainnetERC8004, masterAbi, megaethMainnet, megaethTestnet, pageAbi, parseUsdm, pulseExtensionAbi, readDeliverable, readRequirements, readWarrenMaster, readWarrenPage, registerAgent, rejectJob, resolveDispute, serviceMarketplaceAbi, setOperator, setWarrenContract, settle, signMemo, submitDeliverable, testnetERC8004, updateOffering, verifyContentHash };
|
|
3677
|
+
export { ACCEPT_TIMEOUT, type AICallOptions, type AICallResult, type AIMessage, type AIProvider, type AIUsage, type AgentCardParams, BPS_DENOMINATOR, type BuyerCallbacks, BuyerRuntime, type BuyerRuntimeOptions, type CreateJobParams, type CreatePresetPulseClientOptions, type CreatePulseClientOptions, DEFAULT_INDEXER_URLS, DEFAULT_SCHEMAS, type DeliverableData, type DeliverableParams, EVALUATION_TIMEOUT, type ExecuteJobResult, FEE_BPS, HandlerProviderRuntime, type HandlerProviderRuntimeOptions, type IndexerAgent, IndexerClient, IndexerClientError, type IndexerClientOptions, type IndexerJob, type IndexerJobsFilter, type IndexerOffering, type IndexerOfferingsFilter, type IndexerWarrenLink, type IndexerWarrenLinks, type Job, type JobContext, type JobOffering, JobStatus, type JobTermsParams, type JsonSchema, type ListOfferingParams, MAINNET_ADDRESSES, MEMO_TYPES, type OfferingHandler, type OfferingSchema, PLATFORM_BUYER_AGENT_ID, PULSE_DOMAIN, type PresetPulseClient, type ProviderCallbacks, ProviderRuntime, type ProviderRuntimeOptions, type PulseAddresses, type PulseAgentData, type PulseClient, RISK_POOL_BPS, type RequirementsData, type RequirementsParams, ServiceType, type SignMemoParams, type SiteModifierConfig, SiteModifierHandler, TESTNET_ADDRESSES, TREASURY_BPS, USDM_MAINNET, type ValidationResult, acceptJob, activateOffering, buyerRelayAbi, callAI, cancelJob, createAgentCard, createDeliverable, createJob, createJobTerms, createMainnetClient, createPulseClient, createRequirements, createTestnetClient, deactivateOffering, deployAgentCard, deployDeliverable, deployJobTerms, deployRequirements, deployWarrenMaster, deployWarrenPage, erc20Abi, erc8004IdentityAbi, erc8004ReputationAbi, evaluate, feeDistributorAbi, formatUsdm, getAgent, getJob, getJobCount, getOffering, getOfferingCount, initAgent, jobEngineAbi, listOffering, mainnetERC8004, masterAbi, megaethMainnet, megaethTestnet, pageAbi, parseUsdm, pulseExtensionAbi, readDeliverable, readRequirements, readWarrenMaster, readWarrenPage, registerAgent, rejectJob, resolveDispute, serviceMarketplaceAbi, setOperator, setWarrenContract, settle, signMemo, submitDeliverable, testnetERC8004, updateOffering, validateAgainstSchema, verifyContentHash };
|
package/dist/index.js
CHANGED
|
@@ -2896,7 +2896,8 @@ async function callOpenAI(params) {
|
|
|
2896
2896
|
throw new Error("OpenAI returned an empty response");
|
|
2897
2897
|
}
|
|
2898
2898
|
const truncated = payload?.choices?.[0]?.finish_reason === "length";
|
|
2899
|
-
|
|
2899
|
+
const usage = payload?.usage ? { inputTokens: payload.usage.prompt_tokens ?? 0, outputTokens: payload.usage.completion_tokens ?? 0 } : void 0;
|
|
2900
|
+
return { content, truncated, raw: payload, usage };
|
|
2900
2901
|
}
|
|
2901
2902
|
async function callAnthropic(params) {
|
|
2902
2903
|
const systemPrompt = params.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n").trim();
|
|
@@ -2930,7 +2931,8 @@ async function callAnthropic(params) {
|
|
|
2930
2931
|
throw new Error("Anthropic returned an empty response");
|
|
2931
2932
|
}
|
|
2932
2933
|
const truncated = payload?.stop_reason === "max_tokens";
|
|
2933
|
-
|
|
2934
|
+
const usage = payload?.usage ? { inputTokens: payload.usage.input_tokens ?? 0, outputTokens: payload.usage.output_tokens ?? 0 } : void 0;
|
|
2935
|
+
return { content, truncated, raw: payload, usage };
|
|
2934
2936
|
}
|
|
2935
2937
|
async function callGoogle(params) {
|
|
2936
2938
|
const systemPrompt = params.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n").trim();
|
|
@@ -2965,7 +2967,8 @@ async function callGoogle(params) {
|
|
|
2965
2967
|
throw new Error("Google returned an empty response");
|
|
2966
2968
|
}
|
|
2967
2969
|
const truncated = payload?.candidates?.[0]?.finishReason === "MAX_TOKENS";
|
|
2968
|
-
|
|
2970
|
+
const usage = payload?.usageMetadata ? { inputTokens: payload.usageMetadata.promptTokenCount ?? 0, outputTokens: payload.usageMetadata.candidatesTokenCount ?? 0 } : void 0;
|
|
2971
|
+
return { content, truncated, raw: payload, usage };
|
|
2969
2972
|
}
|
|
2970
2973
|
async function callAI(params) {
|
|
2971
2974
|
if (params.provider === "openai") {
|
|
@@ -2989,8 +2992,8 @@ var RETRY_DELAY_MS = 2e3;
|
|
|
2989
2992
|
var GOOGLE_FALLBACK_MODEL = "gemini-2.5-pro";
|
|
2990
2993
|
var SUPPORTED_PROVIDERS = ["anthropic", "google", "openai"];
|
|
2991
2994
|
var DEFAULT_MODELS = {
|
|
2992
|
-
openai: "gpt-
|
|
2993
|
-
anthropic: "claude-
|
|
2995
|
+
openai: "gpt-5.2",
|
|
2996
|
+
anthropic: "claude-sonnet-4-6",
|
|
2994
2997
|
google: "gemini-3.1-pro-preview"
|
|
2995
2998
|
};
|
|
2996
2999
|
var DEFAULT_SYSTEM_PROMPT = [
|
|
@@ -3110,6 +3113,52 @@ function getByteLength(content) {
|
|
|
3110
3113
|
var SiteModifierHandler = class {
|
|
3111
3114
|
offeringId;
|
|
3112
3115
|
autoAccept;
|
|
3116
|
+
schema = {
|
|
3117
|
+
version: 1,
|
|
3118
|
+
serviceRequirements: {
|
|
3119
|
+
type: "object",
|
|
3120
|
+
properties: {
|
|
3121
|
+
siteUrl: {
|
|
3122
|
+
type: "string",
|
|
3123
|
+
description: "URL of the site to modify (http/https)"
|
|
3124
|
+
},
|
|
3125
|
+
modificationRequest: {
|
|
3126
|
+
type: "string",
|
|
3127
|
+
description: "What changes to make"
|
|
3128
|
+
},
|
|
3129
|
+
provider: {
|
|
3130
|
+
type: "string",
|
|
3131
|
+
description: "AI provider",
|
|
3132
|
+
enum: ["google", "anthropic", "openai"]
|
|
3133
|
+
},
|
|
3134
|
+
model: {
|
|
3135
|
+
type: "string",
|
|
3136
|
+
description: "Specific model override"
|
|
3137
|
+
}
|
|
3138
|
+
},
|
|
3139
|
+
required: ["siteUrl", "modificationRequest"]
|
|
3140
|
+
},
|
|
3141
|
+
deliverableRequirements: {
|
|
3142
|
+
type: "object",
|
|
3143
|
+
properties: {
|
|
3144
|
+
type: {
|
|
3145
|
+
type: "string",
|
|
3146
|
+
description: 'Delivery type, always "inline"',
|
|
3147
|
+
enum: ["inline"]
|
|
3148
|
+
},
|
|
3149
|
+
content: {
|
|
3150
|
+
type: "string",
|
|
3151
|
+
description: "Modified HTML content"
|
|
3152
|
+
},
|
|
3153
|
+
mimeType: {
|
|
3154
|
+
type: "string",
|
|
3155
|
+
description: 'Content type, always "text/html"',
|
|
3156
|
+
enum: ["text/html"]
|
|
3157
|
+
}
|
|
3158
|
+
},
|
|
3159
|
+
required: ["type", "content", "mimeType"]
|
|
3160
|
+
}
|
|
3161
|
+
};
|
|
3113
3162
|
config;
|
|
3114
3163
|
constructor(offeringId, config, options) {
|
|
3115
3164
|
this.offeringId = offeringId;
|
|
@@ -3132,7 +3181,8 @@ var SiteModifierHandler = class {
|
|
|
3132
3181
|
const targetUrl = parseAndValidateUrl(requirements.siteUrl);
|
|
3133
3182
|
ensureAllowedUrl(targetUrl, this.config.allowedDomains);
|
|
3134
3183
|
const provider = requirements.provider ?? this.config.defaultProvider ?? "openai";
|
|
3135
|
-
const
|
|
3184
|
+
const useConfigModel = provider === (this.config.defaultProvider ?? "openai");
|
|
3185
|
+
const model = requirements.model?.trim() || (useConfigModel ? this.config.defaultModel?.trim() : void 0) || DEFAULT_MODELS[provider];
|
|
3136
3186
|
const maxTokens = this.config.maxTokens && this.config.maxTokens > 0 ? this.config.maxTokens : DEFAULT_MAX_TOKENS;
|
|
3137
3187
|
if (!model) {
|
|
3138
3188
|
throw new Error(
|
|
@@ -3235,7 +3285,8 @@ var SiteModifierHandler = class {
|
|
|
3235
3285
|
return {
|
|
3236
3286
|
type: "inline",
|
|
3237
3287
|
content: modifiedHtml,
|
|
3238
|
-
mimeType: "text/html"
|
|
3288
|
+
mimeType: "text/html",
|
|
3289
|
+
usage: aiResponse.usage ? { provider, inputTokens: aiResponse.usage.inputTokens, outputTokens: aiResponse.usage.outputTokens } : void 0
|
|
3239
3290
|
};
|
|
3240
3291
|
}
|
|
3241
3292
|
parseRequirements(requirements) {
|
|
@@ -3351,6 +3402,189 @@ var SiteModifierHandler = class {
|
|
|
3351
3402
|
}
|
|
3352
3403
|
};
|
|
3353
3404
|
|
|
3405
|
+
// src/types.ts
|
|
3406
|
+
var JobStatus = /* @__PURE__ */ ((JobStatus2) => {
|
|
3407
|
+
JobStatus2[JobStatus2["Created"] = 0] = "Created";
|
|
3408
|
+
JobStatus2[JobStatus2["Accepted"] = 1] = "Accepted";
|
|
3409
|
+
JobStatus2[JobStatus2["InProgress"] = 2] = "InProgress";
|
|
3410
|
+
JobStatus2[JobStatus2["Delivered"] = 3] = "Delivered";
|
|
3411
|
+
JobStatus2[JobStatus2["Evaluated"] = 4] = "Evaluated";
|
|
3412
|
+
JobStatus2[JobStatus2["Completed"] = 5] = "Completed";
|
|
3413
|
+
JobStatus2[JobStatus2["Disputed"] = 6] = "Disputed";
|
|
3414
|
+
JobStatus2[JobStatus2["Cancelled"] = 7] = "Cancelled";
|
|
3415
|
+
return JobStatus2;
|
|
3416
|
+
})(JobStatus || {});
|
|
3417
|
+
var ServiceType = /* @__PURE__ */ ((ServiceType2) => {
|
|
3418
|
+
ServiceType2[ServiceType2["TextGeneration"] = 0] = "TextGeneration";
|
|
3419
|
+
ServiceType2[ServiceType2["ImageGeneration"] = 1] = "ImageGeneration";
|
|
3420
|
+
ServiceType2[ServiceType2["DataAnalysis"] = 2] = "DataAnalysis";
|
|
3421
|
+
ServiceType2[ServiceType2["CodeGeneration"] = 3] = "CodeGeneration";
|
|
3422
|
+
ServiceType2[ServiceType2["Translation"] = 4] = "Translation";
|
|
3423
|
+
ServiceType2[ServiceType2["Custom"] = 5] = "Custom";
|
|
3424
|
+
return ServiceType2;
|
|
3425
|
+
})(ServiceType || {});
|
|
3426
|
+
|
|
3427
|
+
// src/handler/schema.ts
|
|
3428
|
+
var DEFAULT_SCHEMAS = {
|
|
3429
|
+
[0 /* TextGeneration */]: {
|
|
3430
|
+
version: 1,
|
|
3431
|
+
serviceRequirements: {
|
|
3432
|
+
type: "object",
|
|
3433
|
+
properties: {
|
|
3434
|
+
prompt: { type: "string", description: "Text prompt to generate from" },
|
|
3435
|
+
maxTokens: { type: "number", description: "Maximum output token count" }
|
|
3436
|
+
},
|
|
3437
|
+
required: ["prompt"]
|
|
3438
|
+
},
|
|
3439
|
+
deliverableRequirements: {
|
|
3440
|
+
type: "object",
|
|
3441
|
+
properties: {
|
|
3442
|
+
text: { type: "string", description: "Generated text output" },
|
|
3443
|
+
tokenCount: { type: "number", description: "Tokens used to produce output" }
|
|
3444
|
+
},
|
|
3445
|
+
required: ["text"]
|
|
3446
|
+
}
|
|
3447
|
+
},
|
|
3448
|
+
[1 /* ImageGeneration */]: {
|
|
3449
|
+
version: 1,
|
|
3450
|
+
serviceRequirements: {
|
|
3451
|
+
type: "object",
|
|
3452
|
+
properties: {
|
|
3453
|
+
prompt: { type: "string", description: "Image prompt to generate from" },
|
|
3454
|
+
size: { type: "string", description: "Output size (for example: 1024x1024)" },
|
|
3455
|
+
style: { type: "string", description: "Desired visual style" }
|
|
3456
|
+
},
|
|
3457
|
+
required: ["prompt"]
|
|
3458
|
+
},
|
|
3459
|
+
deliverableRequirements: {
|
|
3460
|
+
type: "object",
|
|
3461
|
+
properties: {
|
|
3462
|
+
imageUrl: { type: "string", description: "URL of the generated image" },
|
|
3463
|
+
mimeType: { type: "string", description: "Image MIME type" }
|
|
3464
|
+
},
|
|
3465
|
+
required: ["imageUrl"]
|
|
3466
|
+
}
|
|
3467
|
+
},
|
|
3468
|
+
[2 /* DataAnalysis */]: {
|
|
3469
|
+
version: 1,
|
|
3470
|
+
serviceRequirements: {
|
|
3471
|
+
type: "object",
|
|
3472
|
+
properties: {
|
|
3473
|
+
data: { type: "string", description: "Input data for analysis" },
|
|
3474
|
+
analysisRequest: { type: "string", description: "Question or analysis task" }
|
|
3475
|
+
},
|
|
3476
|
+
required: ["data", "analysisRequest"]
|
|
3477
|
+
},
|
|
3478
|
+
deliverableRequirements: {
|
|
3479
|
+
type: "object",
|
|
3480
|
+
properties: {
|
|
3481
|
+
summary: { type: "string", description: "Analysis summary" },
|
|
3482
|
+
findings: {
|
|
3483
|
+
type: "array",
|
|
3484
|
+
description: "Structured key findings",
|
|
3485
|
+
items: { type: "string" }
|
|
3486
|
+
}
|
|
3487
|
+
},
|
|
3488
|
+
required: ["summary"]
|
|
3489
|
+
}
|
|
3490
|
+
},
|
|
3491
|
+
[3 /* CodeGeneration */]: {
|
|
3492
|
+
version: 1,
|
|
3493
|
+
serviceRequirements: {
|
|
3494
|
+
type: "object",
|
|
3495
|
+
properties: {
|
|
3496
|
+
prompt: { type: "string", description: "Code generation request" },
|
|
3497
|
+
language: { type: "string", description: "Target programming language" }
|
|
3498
|
+
},
|
|
3499
|
+
required: ["prompt"]
|
|
3500
|
+
},
|
|
3501
|
+
deliverableRequirements: {
|
|
3502
|
+
type: "object",
|
|
3503
|
+
properties: {
|
|
3504
|
+
code: { type: "string", description: "Generated source code" },
|
|
3505
|
+
language: { type: "string", description: "Detected or requested language" }
|
|
3506
|
+
},
|
|
3507
|
+
required: ["code"]
|
|
3508
|
+
}
|
|
3509
|
+
},
|
|
3510
|
+
[4 /* Translation */]: {
|
|
3511
|
+
version: 1,
|
|
3512
|
+
serviceRequirements: {
|
|
3513
|
+
type: "object",
|
|
3514
|
+
properties: {
|
|
3515
|
+
text: { type: "string", description: "Text to translate" },
|
|
3516
|
+
targetLanguage: { type: "string", description: "Target language code or name" },
|
|
3517
|
+
sourceLanguage: { type: "string", description: "Optional source language code or name" }
|
|
3518
|
+
},
|
|
3519
|
+
required: ["text", "targetLanguage"]
|
|
3520
|
+
},
|
|
3521
|
+
deliverableRequirements: {
|
|
3522
|
+
type: "object",
|
|
3523
|
+
properties: {
|
|
3524
|
+
translatedText: { type: "string", description: "Translated text output" },
|
|
3525
|
+
sourceLanguage: { type: "string", description: "Detected or provided source language" }
|
|
3526
|
+
},
|
|
3527
|
+
required: ["translatedText"]
|
|
3528
|
+
}
|
|
3529
|
+
}
|
|
3530
|
+
};
|
|
3531
|
+
function isObjectRecord(value) {
|
|
3532
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
3533
|
+
}
|
|
3534
|
+
function isTypeMatch(value, type) {
|
|
3535
|
+
switch (type) {
|
|
3536
|
+
case "string":
|
|
3537
|
+
return typeof value === "string";
|
|
3538
|
+
case "number":
|
|
3539
|
+
return typeof value === "number" && Number.isFinite(value);
|
|
3540
|
+
case "boolean":
|
|
3541
|
+
return typeof value === "boolean";
|
|
3542
|
+
case "object":
|
|
3543
|
+
return isObjectRecord(value);
|
|
3544
|
+
case "array":
|
|
3545
|
+
return Array.isArray(value);
|
|
3546
|
+
default:
|
|
3547
|
+
return false;
|
|
3548
|
+
}
|
|
3549
|
+
}
|
|
3550
|
+
function validateAgainstSchema(data, schema) {
|
|
3551
|
+
if (!data || !isObjectRecord(data)) {
|
|
3552
|
+
return { valid: false, reason: "Requirements must be a JSON object" };
|
|
3553
|
+
}
|
|
3554
|
+
for (const requiredField of schema.required ?? []) {
|
|
3555
|
+
if (!(requiredField in data)) {
|
|
3556
|
+
return { valid: false, reason: `Missing required field: ${requiredField}` };
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
for (const [field, fieldSchema] of Object.entries(schema.properties)) {
|
|
3560
|
+
const value = data[field];
|
|
3561
|
+
if (value === void 0) continue;
|
|
3562
|
+
if (!isTypeMatch(value, fieldSchema.type)) {
|
|
3563
|
+
return {
|
|
3564
|
+
valid: false,
|
|
3565
|
+
reason: `Field "${field}" must be of type ${fieldSchema.type}`
|
|
3566
|
+
};
|
|
3567
|
+
}
|
|
3568
|
+
if (fieldSchema.enum && !fieldSchema.enum.some((enumValue) => Object.is(enumValue, value))) {
|
|
3569
|
+
return {
|
|
3570
|
+
valid: false,
|
|
3571
|
+
reason: `Field "${field}" must be one of: ${fieldSchema.enum.map((v) => JSON.stringify(v)).join(", ")}`
|
|
3572
|
+
};
|
|
3573
|
+
}
|
|
3574
|
+
if (fieldSchema.type === "array" && fieldSchema.items && Array.isArray(value)) {
|
|
3575
|
+
for (let i = 0; i < value.length; i += 1) {
|
|
3576
|
+
if (!isTypeMatch(value[i], fieldSchema.items.type)) {
|
|
3577
|
+
return {
|
|
3578
|
+
valid: false,
|
|
3579
|
+
reason: `Field "${field}[${i}]" must be of type ${fieldSchema.items.type}`
|
|
3580
|
+
};
|
|
3581
|
+
}
|
|
3582
|
+
}
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
return { valid: true };
|
|
3586
|
+
}
|
|
3587
|
+
|
|
3354
3588
|
// src/utils.ts
|
|
3355
3589
|
var USDM_DECIMALS = 18;
|
|
3356
3590
|
var USDM_SCALE = 10n ** BigInt(USDM_DECIMALS);
|
|
@@ -3387,28 +3621,6 @@ function formatUsdm(amount) {
|
|
|
3387
3621
|
return `${whole}.${trimmedFraction.padEnd(2, "0")}`;
|
|
3388
3622
|
}
|
|
3389
3623
|
|
|
3390
|
-
// src/types.ts
|
|
3391
|
-
var JobStatus = /* @__PURE__ */ ((JobStatus2) => {
|
|
3392
|
-
JobStatus2[JobStatus2["Created"] = 0] = "Created";
|
|
3393
|
-
JobStatus2[JobStatus2["Accepted"] = 1] = "Accepted";
|
|
3394
|
-
JobStatus2[JobStatus2["InProgress"] = 2] = "InProgress";
|
|
3395
|
-
JobStatus2[JobStatus2["Delivered"] = 3] = "Delivered";
|
|
3396
|
-
JobStatus2[JobStatus2["Evaluated"] = 4] = "Evaluated";
|
|
3397
|
-
JobStatus2[JobStatus2["Completed"] = 5] = "Completed";
|
|
3398
|
-
JobStatus2[JobStatus2["Disputed"] = 6] = "Disputed";
|
|
3399
|
-
JobStatus2[JobStatus2["Cancelled"] = 7] = "Cancelled";
|
|
3400
|
-
return JobStatus2;
|
|
3401
|
-
})(JobStatus || {});
|
|
3402
|
-
var ServiceType = /* @__PURE__ */ ((ServiceType2) => {
|
|
3403
|
-
ServiceType2[ServiceType2["TextGeneration"] = 0] = "TextGeneration";
|
|
3404
|
-
ServiceType2[ServiceType2["ImageGeneration"] = 1] = "ImageGeneration";
|
|
3405
|
-
ServiceType2[ServiceType2["DataAnalysis"] = 2] = "DataAnalysis";
|
|
3406
|
-
ServiceType2[ServiceType2["CodeGeneration"] = 3] = "CodeGeneration";
|
|
3407
|
-
ServiceType2[ServiceType2["Translation"] = 4] = "Translation";
|
|
3408
|
-
ServiceType2[ServiceType2["Custom"] = 5] = "Custom";
|
|
3409
|
-
return ServiceType2;
|
|
3410
|
-
})(ServiceType || {});
|
|
3411
|
-
|
|
3412
3624
|
// src/indexer/client.ts
|
|
3413
3625
|
var IndexerClientError = class extends Error {
|
|
3414
3626
|
status;
|
|
@@ -3446,6 +3658,7 @@ function toIndexerOffering(raw) {
|
|
|
3446
3658
|
priceUsdm: raw.price_usdm,
|
|
3447
3659
|
slaMinutes: raw.sla_minutes,
|
|
3448
3660
|
description: raw.description,
|
|
3661
|
+
requirementsSchemaUri: raw.requirements_schema_uri ?? void 0,
|
|
3449
3662
|
active: raw.active === 1,
|
|
3450
3663
|
blockNumber: raw.block_number,
|
|
3451
3664
|
txHash: raw.tx_hash
|
|
@@ -3878,6 +4091,7 @@ var HandlerProviderRuntime = class {
|
|
|
3878
4091
|
running = false;
|
|
3879
4092
|
processedJobs = /* @__PURE__ */ new Set();
|
|
3880
4093
|
failedJobs = /* @__PURE__ */ new Map();
|
|
4094
|
+
schemaCache = /* @__PURE__ */ new Map();
|
|
3881
4095
|
maxRetries = 3;
|
|
3882
4096
|
onError;
|
|
3883
4097
|
constructor(client, agentId, options) {
|
|
@@ -3922,8 +4136,8 @@ var HandlerProviderRuntime = class {
|
|
|
3922
4136
|
for (const job of jobs) {
|
|
3923
4137
|
const newKey = `new:${job.jobId}`;
|
|
3924
4138
|
if (!this.canProcess(newKey)) continue;
|
|
3925
|
-
const
|
|
3926
|
-
if (!
|
|
4139
|
+
const offering = offerings.find((o) => o.offeringId === job.offeringId);
|
|
4140
|
+
if (!offering) continue;
|
|
3927
4141
|
const handler = this.handlers.get(job.offeringId);
|
|
3928
4142
|
if (!handler) continue;
|
|
3929
4143
|
try {
|
|
@@ -3946,6 +4160,10 @@ var HandlerProviderRuntime = class {
|
|
|
3946
4160
|
if (reqData) {
|
|
3947
4161
|
context.requirements = reqData.requirements;
|
|
3948
4162
|
}
|
|
4163
|
+
const schemaValidation = await this.validateSchemaRequirements(context, handler, offering);
|
|
4164
|
+
if (!schemaValidation.valid) {
|
|
4165
|
+
throw new Error(`Schema validation failed for job ${job.jobId}: ${schemaValidation.reason}`);
|
|
4166
|
+
}
|
|
3949
4167
|
if (handler.validateRequirements) {
|
|
3950
4168
|
const validation = await handler.validateRequirements(context);
|
|
3951
4169
|
if (!validation.valid) {
|
|
@@ -3966,6 +4184,10 @@ var HandlerProviderRuntime = class {
|
|
|
3966
4184
|
}
|
|
3967
4185
|
}
|
|
3968
4186
|
async checkInProgressJobs() {
|
|
4187
|
+
const offerings = await this.indexer.getOfferings({ agentId: Number(this.agentId) });
|
|
4188
|
+
const offeringsById = new Map(
|
|
4189
|
+
offerings.map((offering) => [offering.offeringId, offering])
|
|
4190
|
+
);
|
|
3969
4191
|
const inProgressJobs = await this.indexer.getJobs({
|
|
3970
4192
|
status: 2,
|
|
3971
4193
|
agentId: Number(this.agentId)
|
|
@@ -3975,6 +4197,7 @@ var HandlerProviderRuntime = class {
|
|
|
3975
4197
|
if (!this.canProcess(deliverKey)) continue;
|
|
3976
4198
|
const handler = this.handlers.get(job.offeringId);
|
|
3977
4199
|
if (!handler) continue;
|
|
4200
|
+
const offering = offeringsById.get(job.offeringId);
|
|
3978
4201
|
try {
|
|
3979
4202
|
if (job.slaMinutes === null) {
|
|
3980
4203
|
throw new Error(`Job ${job.jobId} is missing slaMinutes`);
|
|
@@ -3995,6 +4218,14 @@ var HandlerProviderRuntime = class {
|
|
|
3995
4218
|
if (reqData) {
|
|
3996
4219
|
context.requirements = reqData.requirements;
|
|
3997
4220
|
}
|
|
4221
|
+
const schemaValidation = await this.validateSchemaRequirements(context, handler, offering);
|
|
4222
|
+
if (!schemaValidation.valid) {
|
|
4223
|
+
this.markFailed(
|
|
4224
|
+
deliverKey,
|
|
4225
|
+
new Error(`Schema validation failed for job ${job.jobId}: ${schemaValidation.reason}`)
|
|
4226
|
+
);
|
|
4227
|
+
continue;
|
|
4228
|
+
}
|
|
3998
4229
|
if (handler.validateRequirements) {
|
|
3999
4230
|
const validation = await handler.validateRequirements(context);
|
|
4000
4231
|
if (!validation.valid) {
|
|
@@ -4088,6 +4319,75 @@ var HandlerProviderRuntime = class {
|
|
|
4088
4319
|
this.onError?.(new Error(`Giving up on ${key} after ${retries} failed attempts`));
|
|
4089
4320
|
}
|
|
4090
4321
|
}
|
|
4322
|
+
async validateSchemaRequirements(context, handler, offering) {
|
|
4323
|
+
if (offering?.requirementsSchemaUri) {
|
|
4324
|
+
try {
|
|
4325
|
+
const offeringSchema = await this.resolveOfferingSchemaFromUri(offering.requirementsSchemaUri);
|
|
4326
|
+
if (!offeringSchema) {
|
|
4327
|
+
return {
|
|
4328
|
+
valid: false,
|
|
4329
|
+
reason: `Unsupported requirementsSchemaUri format: ${offering.requirementsSchemaUri}`
|
|
4330
|
+
};
|
|
4331
|
+
}
|
|
4332
|
+
return validateAgainstSchema(context.requirements, offeringSchema.serviceRequirements);
|
|
4333
|
+
} catch (error) {
|
|
4334
|
+
return {
|
|
4335
|
+
valid: false,
|
|
4336
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
4337
|
+
};
|
|
4338
|
+
}
|
|
4339
|
+
}
|
|
4340
|
+
const defaultSchema = offering ? DEFAULT_SCHEMAS[offering.serviceType] : void 0;
|
|
4341
|
+
const schema = handler.schema ?? defaultSchema;
|
|
4342
|
+
if (!schema) return { valid: true };
|
|
4343
|
+
return validateAgainstSchema(context.requirements, schema.serviceRequirements);
|
|
4344
|
+
}
|
|
4345
|
+
async resolveOfferingSchemaFromUri(schemaUri) {
|
|
4346
|
+
const cached = this.schemaCache.get(schemaUri);
|
|
4347
|
+
if (cached !== void 0) {
|
|
4348
|
+
return cached;
|
|
4349
|
+
}
|
|
4350
|
+
let schemaPayload;
|
|
4351
|
+
if (schemaUri.startsWith("data:")) {
|
|
4352
|
+
schemaPayload = this.parseDataUriJson(schemaUri);
|
|
4353
|
+
} else if (schemaUri.startsWith("http://") || schemaUri.startsWith("https://")) {
|
|
4354
|
+
const response = await fetch(schemaUri);
|
|
4355
|
+
if (!response.ok) {
|
|
4356
|
+
throw new Error(`Failed to fetch requirements schema URI (${response.status} ${response.statusText})`);
|
|
4357
|
+
}
|
|
4358
|
+
schemaPayload = await response.json();
|
|
4359
|
+
} else if (schemaUri.trim().startsWith("{")) {
|
|
4360
|
+
schemaPayload = JSON.parse(schemaUri);
|
|
4361
|
+
} else {
|
|
4362
|
+
this.schemaCache.set(schemaUri, null);
|
|
4363
|
+
return null;
|
|
4364
|
+
}
|
|
4365
|
+
if (!this.isOfferingSchema(schemaPayload)) {
|
|
4366
|
+
throw new Error("requirementsSchemaUri did not resolve to a valid OfferingSchema document");
|
|
4367
|
+
}
|
|
4368
|
+
this.schemaCache.set(schemaUri, schemaPayload);
|
|
4369
|
+
return schemaPayload;
|
|
4370
|
+
}
|
|
4371
|
+
parseDataUriJson(dataUri) {
|
|
4372
|
+
const commaIndex = dataUri.indexOf(",");
|
|
4373
|
+
if (commaIndex < 0) {
|
|
4374
|
+
throw new Error("Invalid data URI schema format");
|
|
4375
|
+
}
|
|
4376
|
+
const metadata = dataUri.slice(5, commaIndex);
|
|
4377
|
+
const payload = dataUri.slice(commaIndex + 1);
|
|
4378
|
+
const decoded = metadata.includes(";base64") ? new TextDecoder().decode(Uint8Array.from(atob(payload), (char) => char.charCodeAt(0))) : decodeURIComponent(payload);
|
|
4379
|
+
return JSON.parse(decoded);
|
|
4380
|
+
}
|
|
4381
|
+
isOfferingSchema(value) {
|
|
4382
|
+
if (typeof value !== "object" || value === null) return false;
|
|
4383
|
+
const candidate = value;
|
|
4384
|
+
return typeof candidate.version === "number" && this.isJsonSchema(candidate.serviceRequirements) && this.isJsonSchema(candidate.deliverableRequirements);
|
|
4385
|
+
}
|
|
4386
|
+
isJsonSchema(value) {
|
|
4387
|
+
if (typeof value !== "object" || value === null) return false;
|
|
4388
|
+
const candidate = value;
|
|
4389
|
+
return candidate.type === "object" && typeof candidate.properties === "object" && candidate.properties !== null;
|
|
4390
|
+
}
|
|
4091
4391
|
getRemainingSlaMs(createdAt, acceptedAt, slaMinutes) {
|
|
4092
4392
|
const start = acceptedAt ?? createdAt;
|
|
4093
4393
|
if (start === null) return null;
|
|
@@ -5470,6 +5770,7 @@ export {
|
|
|
5470
5770
|
BPS_DENOMINATOR,
|
|
5471
5771
|
BuyerRuntime,
|
|
5472
5772
|
DEFAULT_INDEXER_URLS,
|
|
5773
|
+
DEFAULT_SCHEMAS,
|
|
5473
5774
|
EVALUATION_TIMEOUT,
|
|
5474
5775
|
FEE_BPS,
|
|
5475
5776
|
HandlerProviderRuntime,
|
|
@@ -5543,6 +5844,7 @@ export {
|
|
|
5543
5844
|
submitDeliverable,
|
|
5544
5845
|
testnetERC8004,
|
|
5545
5846
|
updateOffering,
|
|
5847
|
+
validateAgainstSchema,
|
|
5546
5848
|
verifyContentHash
|
|
5547
5849
|
};
|
|
5548
5850
|
//# sourceMappingURL=index.js.map
|