@pulseai/sdk 0.1.0 → 0.1.2
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 +475 -4
- package/dist/index.js +1262 -44
- package/dist/index.js.map +1 -1
- package/package.json +20 -12
package/dist/index.js
CHANGED
|
@@ -34,16 +34,17 @@ var TESTNET_ADDRESSES = {
|
|
|
34
34
|
reputationRegistry: "0x8004B663056A597Dffe9eCcC1965A193B7388713",
|
|
35
35
|
usdm: "0x939Ff43f7c4A2E94069af7DBbc4497377DdcCE3f"
|
|
36
36
|
};
|
|
37
|
-
var PLACEHOLDER_ADDRESS = "0x0";
|
|
38
37
|
var MAINNET_ADDRESSES = {
|
|
39
|
-
pulseExtension:
|
|
40
|
-
serviceMarketplace:
|
|
41
|
-
jobEngine:
|
|
42
|
-
feeDistributor:
|
|
38
|
+
pulseExtension: "0xf1616D2008c4Ff5Ed7BDBd448DAE68615b7A71f0",
|
|
39
|
+
serviceMarketplace: "0xfC180058FCB69531818B832C12473302811dfFF6",
|
|
40
|
+
jobEngine: "0xb5E56262b55aE453E8B16470228F0a5Ef617FF67",
|
|
41
|
+
feeDistributor: "0x51EdD8E4C4B423b952821fc9e2a7dad15a858B56",
|
|
43
42
|
identityRegistry: "0x8004A169FB4a3325136EB29fA0ceB6D2e539a432",
|
|
44
43
|
reputationRegistry: "0x8004BAa17C55a88189AE136b182e5fdA19dE9b63",
|
|
45
|
-
usdm: "0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7"
|
|
44
|
+
usdm: "0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7",
|
|
45
|
+
buyerRelay: "0x633054593db34c5aAe36F784faeAe51b9604e037"
|
|
46
46
|
};
|
|
47
|
+
var PLATFORM_BUYER_AGENT_ID = 8154n;
|
|
47
48
|
var DEFAULT_INDEXER_URLS = {
|
|
48
49
|
testnet: "https://pulse-indexer.up.railway.app",
|
|
49
50
|
mainnet: "https://pulse-indexer.up.railway.app"
|
|
@@ -2387,13 +2388,29 @@ async function acceptJob(client, jobId, warrenTermsHash) {
|
|
|
2387
2388
|
args: [jobId, signature]
|
|
2388
2389
|
});
|
|
2389
2390
|
}
|
|
2390
|
-
async function submitDeliverable(client, jobId, deliverableHash) {
|
|
2391
|
-
|
|
2391
|
+
async function submitDeliverable(client, jobId, deliverableHash, options) {
|
|
2392
|
+
const txHash = await write(client, {
|
|
2392
2393
|
address: client.addresses.jobEngine,
|
|
2393
2394
|
abi: jobEngineAbi,
|
|
2394
2395
|
functionName: "submitDeliverable",
|
|
2395
2396
|
args: [jobId, deliverableHash]
|
|
2396
2397
|
});
|
|
2398
|
+
if (options?.content && options?.indexerUrl) {
|
|
2399
|
+
try {
|
|
2400
|
+
await fetch(`${options.indexerUrl.replace(/\/$/, "")}/deliverables`, {
|
|
2401
|
+
method: "POST",
|
|
2402
|
+
headers: { "Content-Type": "application/json" },
|
|
2403
|
+
body: JSON.stringify({
|
|
2404
|
+
jobId: Number(jobId),
|
|
2405
|
+
content: options.content,
|
|
2406
|
+
contentHash: deliverableHash,
|
|
2407
|
+
storageType: "indexer"
|
|
2408
|
+
})
|
|
2409
|
+
});
|
|
2410
|
+
} catch {
|
|
2411
|
+
}
|
|
2412
|
+
}
|
|
2413
|
+
return txHash;
|
|
2397
2414
|
}
|
|
2398
2415
|
async function evaluate(client, jobId, approved, feedback) {
|
|
2399
2416
|
return write(client, {
|
|
@@ -2435,6 +2452,17 @@ async function getJobCount(client) {
|
|
|
2435
2452
|
functionName: "getJobCount"
|
|
2436
2453
|
});
|
|
2437
2454
|
}
|
|
2455
|
+
async function rejectJob(client, jobId, feedback) {
|
|
2456
|
+
return evaluate(client, jobId, false, feedback);
|
|
2457
|
+
}
|
|
2458
|
+
async function resolveDispute(client, jobId, favorBuyer) {
|
|
2459
|
+
return write(client, {
|
|
2460
|
+
address: client.addresses.jobEngine,
|
|
2461
|
+
abi: jobEngineAbi,
|
|
2462
|
+
functionName: "resolveDispute",
|
|
2463
|
+
args: [jobId, favorBuyer]
|
|
2464
|
+
});
|
|
2465
|
+
}
|
|
2438
2466
|
|
|
2439
2467
|
// src/warren/index.ts
|
|
2440
2468
|
import { keccak256, toHex as toHex2 } from "viem";
|
|
@@ -2638,10 +2666,17 @@ async function deployJobTerms(client, agentId, params) {
|
|
|
2638
2666
|
const { masterAddress } = await deployWarrenMaster(client, agentId, pageAddress, contentBytes.length, 0);
|
|
2639
2667
|
return { masterAddress, pageAddress, hash, txHash };
|
|
2640
2668
|
}
|
|
2669
|
+
function stripCodeFence(content) {
|
|
2670
|
+
let result = content.trim();
|
|
2671
|
+
result = result.replace(/^```\w*\n?/, "");
|
|
2672
|
+
result = result.replace(/\n?```\s*$/, "");
|
|
2673
|
+
return result;
|
|
2674
|
+
}
|
|
2641
2675
|
async function deployDeliverable(client, agentId, jobId, params, indexerUrl) {
|
|
2642
2676
|
const { json, hash } = createDeliverable(params);
|
|
2643
|
-
const
|
|
2644
|
-
const
|
|
2677
|
+
const warrenContent = params.type === "inline" && params.content ? stripCodeFence(params.content) : json;
|
|
2678
|
+
const contentBytes = new TextEncoder().encode(warrenContent);
|
|
2679
|
+
const { pageAddress, txHash } = await deployWarrenPage(client, warrenContent);
|
|
2645
2680
|
const { masterAddress } = await deployWarrenMaster(client, agentId, pageAddress, contentBytes.length, 1);
|
|
2646
2681
|
await write(client, {
|
|
2647
2682
|
address: client.addresses.jobEngine,
|
|
@@ -2664,6 +2699,21 @@ async function deployDeliverable(client, agentId, jobId, params, indexerUrl) {
|
|
|
2664
2699
|
} catch {
|
|
2665
2700
|
}
|
|
2666
2701
|
}
|
|
2702
|
+
if (indexerUrl) {
|
|
2703
|
+
try {
|
|
2704
|
+
await fetch(`${indexerUrl.replace(/\/$/, "")}/deliverables`, {
|
|
2705
|
+
method: "POST",
|
|
2706
|
+
headers: { "Content-Type": "application/json" },
|
|
2707
|
+
body: JSON.stringify({
|
|
2708
|
+
jobId: Number(jobId),
|
|
2709
|
+
content: json,
|
|
2710
|
+
contentHash: hash,
|
|
2711
|
+
storageType: "warren"
|
|
2712
|
+
})
|
|
2713
|
+
});
|
|
2714
|
+
} catch {
|
|
2715
|
+
}
|
|
2716
|
+
}
|
|
2667
2717
|
return { masterAddress, pageAddress, hash, txHash };
|
|
2668
2718
|
}
|
|
2669
2719
|
async function readDeliverable(client, jobId, indexerUrl) {
|
|
@@ -2787,6 +2837,520 @@ function createRequirements(params) {
|
|
|
2787
2837
|
return { json, hash };
|
|
2788
2838
|
}
|
|
2789
2839
|
|
|
2840
|
+
// src/ai/provider.ts
|
|
2841
|
+
function parseErrorMessage(payload) {
|
|
2842
|
+
if (typeof payload !== "object" || payload === null) return null;
|
|
2843
|
+
const record = payload;
|
|
2844
|
+
const error = record.error;
|
|
2845
|
+
if (typeof error === "string") return error;
|
|
2846
|
+
if (typeof error === "object" && error !== null) {
|
|
2847
|
+
const message2 = error.message;
|
|
2848
|
+
if (typeof message2 === "string" && message2.length > 0) return message2;
|
|
2849
|
+
}
|
|
2850
|
+
const message = record.message;
|
|
2851
|
+
if (typeof message === "string" && message.length > 0) return message;
|
|
2852
|
+
return null;
|
|
2853
|
+
}
|
|
2854
|
+
function extractTextContent(content) {
|
|
2855
|
+
if (typeof content === "string") return content.trim();
|
|
2856
|
+
if (!Array.isArray(content)) return "";
|
|
2857
|
+
return content.map((entry) => {
|
|
2858
|
+
if (typeof entry === "string") return entry;
|
|
2859
|
+
if (typeof entry !== "object" || entry === null) return "";
|
|
2860
|
+
const text = entry.text;
|
|
2861
|
+
return typeof text === "string" ? text : "";
|
|
2862
|
+
}).join("\n").trim();
|
|
2863
|
+
}
|
|
2864
|
+
async function parseJsonResponse(response) {
|
|
2865
|
+
try {
|
|
2866
|
+
return await response.json();
|
|
2867
|
+
} catch {
|
|
2868
|
+
return null;
|
|
2869
|
+
}
|
|
2870
|
+
}
|
|
2871
|
+
async function callOpenAI(params) {
|
|
2872
|
+
const response = await fetch("https://api.openai.com/v1/chat/completions", {
|
|
2873
|
+
method: "POST",
|
|
2874
|
+
headers: {
|
|
2875
|
+
"Content-Type": "application/json",
|
|
2876
|
+
Authorization: `Bearer ${params.apiKey}`
|
|
2877
|
+
},
|
|
2878
|
+
body: JSON.stringify({
|
|
2879
|
+
model: params.model,
|
|
2880
|
+
messages: params.messages.map((message) => ({
|
|
2881
|
+
role: message.role,
|
|
2882
|
+
content: message.content
|
|
2883
|
+
})),
|
|
2884
|
+
max_tokens: params.maxTokens
|
|
2885
|
+
}),
|
|
2886
|
+
signal: params.signal
|
|
2887
|
+
});
|
|
2888
|
+
const payload = await parseJsonResponse(response);
|
|
2889
|
+
if (!response.ok) {
|
|
2890
|
+
throw new Error(
|
|
2891
|
+
`OpenAI request failed (${response.status}): ${parseErrorMessage(payload) ?? response.statusText}`
|
|
2892
|
+
);
|
|
2893
|
+
}
|
|
2894
|
+
const content = extractTextContent(payload?.choices?.[0]?.message?.content);
|
|
2895
|
+
if (!content) {
|
|
2896
|
+
throw new Error("OpenAI returned an empty response");
|
|
2897
|
+
}
|
|
2898
|
+
const truncated = payload?.choices?.[0]?.finish_reason === "length";
|
|
2899
|
+
return { content, truncated, raw: payload };
|
|
2900
|
+
}
|
|
2901
|
+
async function callAnthropic(params) {
|
|
2902
|
+
const systemPrompt = params.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n").trim();
|
|
2903
|
+
const messages = params.messages.filter((message) => message.role !== "system").map((message) => ({
|
|
2904
|
+
role: message.role === "assistant" ? "assistant" : "user",
|
|
2905
|
+
content: message.content
|
|
2906
|
+
}));
|
|
2907
|
+
const response = await fetch("https://api.anthropic.com/v1/messages", {
|
|
2908
|
+
method: "POST",
|
|
2909
|
+
headers: {
|
|
2910
|
+
"Content-Type": "application/json",
|
|
2911
|
+
"x-api-key": params.apiKey,
|
|
2912
|
+
"anthropic-version": "2023-06-01"
|
|
2913
|
+
},
|
|
2914
|
+
body: JSON.stringify({
|
|
2915
|
+
model: params.model,
|
|
2916
|
+
max_tokens: params.maxTokens ?? 1024,
|
|
2917
|
+
system: systemPrompt.length > 0 ? systemPrompt : void 0,
|
|
2918
|
+
messages
|
|
2919
|
+
}),
|
|
2920
|
+
signal: params.signal
|
|
2921
|
+
});
|
|
2922
|
+
const payload = await parseJsonResponse(response);
|
|
2923
|
+
if (!response.ok) {
|
|
2924
|
+
throw new Error(
|
|
2925
|
+
`Anthropic request failed (${response.status}): ${parseErrorMessage(payload) ?? response.statusText}`
|
|
2926
|
+
);
|
|
2927
|
+
}
|
|
2928
|
+
const content = extractTextContent(payload?.content);
|
|
2929
|
+
if (!content) {
|
|
2930
|
+
throw new Error("Anthropic returned an empty response");
|
|
2931
|
+
}
|
|
2932
|
+
const truncated = payload?.stop_reason === "max_tokens";
|
|
2933
|
+
return { content, truncated, raw: payload };
|
|
2934
|
+
}
|
|
2935
|
+
async function callGoogle(params) {
|
|
2936
|
+
const systemPrompt = params.messages.filter((message) => message.role === "system").map((message) => message.content).join("\n\n").trim();
|
|
2937
|
+
const contents = params.messages.filter((message) => message.role !== "system").map((message) => ({
|
|
2938
|
+
role: message.role === "assistant" ? "model" : "user",
|
|
2939
|
+
parts: [{ text: message.content }]
|
|
2940
|
+
}));
|
|
2941
|
+
const url = new URL(
|
|
2942
|
+
`https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(params.model)}:generateContent`
|
|
2943
|
+
);
|
|
2944
|
+
url.searchParams.set("key", params.apiKey);
|
|
2945
|
+
const response = await fetch(url, {
|
|
2946
|
+
method: "POST",
|
|
2947
|
+
headers: {
|
|
2948
|
+
"Content-Type": "application/json"
|
|
2949
|
+
},
|
|
2950
|
+
body: JSON.stringify({
|
|
2951
|
+
contents,
|
|
2952
|
+
systemInstruction: systemPrompt.length > 0 ? { parts: [{ text: systemPrompt }] } : void 0,
|
|
2953
|
+
generationConfig: params.maxTokens !== void 0 ? { maxOutputTokens: params.maxTokens } : void 0
|
|
2954
|
+
}),
|
|
2955
|
+
signal: params.signal
|
|
2956
|
+
});
|
|
2957
|
+
const payload = await parseJsonResponse(response);
|
|
2958
|
+
if (!response.ok) {
|
|
2959
|
+
throw new Error(
|
|
2960
|
+
`Google request failed (${response.status}): ${parseErrorMessage(payload) ?? response.statusText}`
|
|
2961
|
+
);
|
|
2962
|
+
}
|
|
2963
|
+
const content = extractTextContent(payload?.candidates?.[0]?.content?.parts);
|
|
2964
|
+
if (!content) {
|
|
2965
|
+
throw new Error("Google returned an empty response");
|
|
2966
|
+
}
|
|
2967
|
+
const truncated = payload?.candidates?.[0]?.finishReason === "MAX_TOKENS";
|
|
2968
|
+
return { content, truncated, raw: payload };
|
|
2969
|
+
}
|
|
2970
|
+
async function callAI(params) {
|
|
2971
|
+
if (params.provider === "openai") {
|
|
2972
|
+
return callOpenAI(params);
|
|
2973
|
+
}
|
|
2974
|
+
if (params.provider === "anthropic") {
|
|
2975
|
+
return callAnthropic(params);
|
|
2976
|
+
}
|
|
2977
|
+
if (params.provider === "google") {
|
|
2978
|
+
return callGoogle(params);
|
|
2979
|
+
}
|
|
2980
|
+
throw new Error(`Unsupported AI provider: ${String(params.provider)}`);
|
|
2981
|
+
}
|
|
2982
|
+
|
|
2983
|
+
// src/handler/site-modifier.ts
|
|
2984
|
+
var FETCH_TIMEOUT_MS = 3e4;
|
|
2985
|
+
var MAX_HTML_BYTES = 500 * 1024;
|
|
2986
|
+
var DEFAULT_MAX_TOKENS = 16384;
|
|
2987
|
+
var AI_MAX_RETRIES = 3;
|
|
2988
|
+
var RETRY_DELAY_MS = 2e3;
|
|
2989
|
+
var GOOGLE_FALLBACK_MODEL = "gemini-2.5-pro";
|
|
2990
|
+
var SUPPORTED_PROVIDERS = ["anthropic", "google", "openai"];
|
|
2991
|
+
var DEFAULT_MODELS = {
|
|
2992
|
+
openai: "gpt-4o-mini",
|
|
2993
|
+
anthropic: "claude-3-5-sonnet-latest",
|
|
2994
|
+
google: "gemini-3.1-pro-preview"
|
|
2995
|
+
};
|
|
2996
|
+
var DEFAULT_SYSTEM_PROMPT = [
|
|
2997
|
+
"You are an expert frontend engineer modifying an existing HTML document.",
|
|
2998
|
+
"Return a complete, self-contained HTML file.",
|
|
2999
|
+
"Inline all CSS in <style> tags and do not use external stylesheets.",
|
|
3000
|
+
"Do not add any external dependencies (no CDNs, external scripts, fonts, or assets).",
|
|
3001
|
+
"Preserve all existing functionality unless explicitly requested to change it.",
|
|
3002
|
+
"Keep the output valid HTML and include all required tags.",
|
|
3003
|
+
"Wrap the final HTML output in a ```html code block."
|
|
3004
|
+
].join("\n");
|
|
3005
|
+
function isRecord(value) {
|
|
3006
|
+
return typeof value === "object" && value !== null;
|
|
3007
|
+
}
|
|
3008
|
+
function isNonEmptyString(value) {
|
|
3009
|
+
return typeof value === "string" && value.trim().length > 0;
|
|
3010
|
+
}
|
|
3011
|
+
function isSupportedProvider(value) {
|
|
3012
|
+
return typeof value === "string" && SUPPORTED_PROVIDERS.includes(value);
|
|
3013
|
+
}
|
|
3014
|
+
function normalizeDomain(domain) {
|
|
3015
|
+
return domain.trim().toLowerCase().replace(/^\*\./, "").replace(/\.$/, "");
|
|
3016
|
+
}
|
|
3017
|
+
function isAllowedDomain(hostname, allowedDomains) {
|
|
3018
|
+
const host = normalizeDomain(hostname);
|
|
3019
|
+
return allowedDomains.some((domain) => {
|
|
3020
|
+
const normalized = normalizeDomain(domain);
|
|
3021
|
+
if (!normalized) return false;
|
|
3022
|
+
return host === normalized || host.endsWith(`.${normalized}`);
|
|
3023
|
+
});
|
|
3024
|
+
}
|
|
3025
|
+
function parseAndValidateUrl(urlString) {
|
|
3026
|
+
let url;
|
|
3027
|
+
try {
|
|
3028
|
+
url = new URL(urlString);
|
|
3029
|
+
} catch {
|
|
3030
|
+
throw new Error("siteUrl must be a valid URL");
|
|
3031
|
+
}
|
|
3032
|
+
if (url.protocol !== "http:" && url.protocol !== "https:") {
|
|
3033
|
+
throw new Error("siteUrl must use http or https");
|
|
3034
|
+
}
|
|
3035
|
+
return url;
|
|
3036
|
+
}
|
|
3037
|
+
function ensureAllowedUrl(url, allowedDomains) {
|
|
3038
|
+
if (!allowedDomains || allowedDomains.length === 0) return;
|
|
3039
|
+
if (!isAllowedDomain(url.hostname, allowedDomains)) {
|
|
3040
|
+
throw new Error(`siteUrl domain "${url.hostname}" is not allowed`);
|
|
3041
|
+
}
|
|
3042
|
+
}
|
|
3043
|
+
function isHtmlContentType(contentType) {
|
|
3044
|
+
const lower = contentType.toLowerCase();
|
|
3045
|
+
return lower.includes("text/html") || lower.includes("application/xhtml+xml");
|
|
3046
|
+
}
|
|
3047
|
+
function isJsonContentType(contentType) {
|
|
3048
|
+
const lower = contentType.toLowerCase();
|
|
3049
|
+
return lower.includes("application/json") || lower.includes("text/json");
|
|
3050
|
+
}
|
|
3051
|
+
function extractHtmlFromText(text) {
|
|
3052
|
+
const htmlFence = text.match(/```html\s*([\s\S]*?)```/i);
|
|
3053
|
+
if (htmlFence?.[1]) {
|
|
3054
|
+
const fencedHtml = htmlFence[1].trim();
|
|
3055
|
+
if (fencedHtml) return fencedHtml;
|
|
3056
|
+
}
|
|
3057
|
+
const anyFence = text.match(/```\s*([\s\S]*?)```/);
|
|
3058
|
+
if (anyFence?.[1]) {
|
|
3059
|
+
const fencedContent = anyFence[1].trim();
|
|
3060
|
+
if (/<html[\s>]|<!doctype html/i.test(fencedContent)) {
|
|
3061
|
+
return fencedContent;
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
const openFence = text.match(/```html?\s*\n?([\s\S]+)/i);
|
|
3065
|
+
if (openFence?.[1]) {
|
|
3066
|
+
const content = openFence[1].trim();
|
|
3067
|
+
if (/<html[\s>]|<!doctype html/i.test(content)) {
|
|
3068
|
+
return content;
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
const trimmed = text.trim();
|
|
3072
|
+
if (/<html[\s>]|<!doctype html/i.test(trimmed)) {
|
|
3073
|
+
return trimmed;
|
|
3074
|
+
}
|
|
3075
|
+
return null;
|
|
3076
|
+
}
|
|
3077
|
+
function extractHtmlFromJson(jsonText) {
|
|
3078
|
+
try {
|
|
3079
|
+
const parsed = JSON.parse(jsonText);
|
|
3080
|
+
if (typeof parsed === "string") {
|
|
3081
|
+
if (/<html[\s>]|<!doctype html/i.test(parsed)) return parsed;
|
|
3082
|
+
return null;
|
|
3083
|
+
}
|
|
3084
|
+
if (typeof parsed !== "object" || parsed === null) return null;
|
|
3085
|
+
const obj = parsed;
|
|
3086
|
+
const nested = obj.data && typeof obj.data === "object" ? obj.data : null;
|
|
3087
|
+
const candidates = [
|
|
3088
|
+
obj.html,
|
|
3089
|
+
obj.content,
|
|
3090
|
+
obj.body,
|
|
3091
|
+
nested?.content,
|
|
3092
|
+
nested?.html,
|
|
3093
|
+
nested?.body
|
|
3094
|
+
];
|
|
3095
|
+
for (const candidate of candidates) {
|
|
3096
|
+
if (typeof candidate === "string" && candidate.trim().length > 0) {
|
|
3097
|
+
if (/<html[\s>]|<!doctype html|<head[\s>]|<body[\s>]|<div[\s>]/i.test(candidate)) {
|
|
3098
|
+
return candidate.trim();
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
}
|
|
3102
|
+
return null;
|
|
3103
|
+
} catch {
|
|
3104
|
+
return null;
|
|
3105
|
+
}
|
|
3106
|
+
}
|
|
3107
|
+
function getByteLength(content) {
|
|
3108
|
+
return new TextEncoder().encode(content).byteLength;
|
|
3109
|
+
}
|
|
3110
|
+
var SiteModifierHandler = class {
|
|
3111
|
+
offeringId;
|
|
3112
|
+
autoAccept;
|
|
3113
|
+
config;
|
|
3114
|
+
constructor(offeringId, config, options) {
|
|
3115
|
+
this.offeringId = offeringId;
|
|
3116
|
+
this.config = config;
|
|
3117
|
+
this.autoAccept = options?.autoAccept;
|
|
3118
|
+
}
|
|
3119
|
+
async validateRequirements(context) {
|
|
3120
|
+
try {
|
|
3121
|
+
this.parseRequirements(context.requirements);
|
|
3122
|
+
return { valid: true };
|
|
3123
|
+
} catch (error) {
|
|
3124
|
+
return {
|
|
3125
|
+
valid: false,
|
|
3126
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
3127
|
+
};
|
|
3128
|
+
}
|
|
3129
|
+
}
|
|
3130
|
+
async executeJob(context) {
|
|
3131
|
+
const requirements = this.parseRequirements(context.requirements);
|
|
3132
|
+
const targetUrl = parseAndValidateUrl(requirements.siteUrl);
|
|
3133
|
+
ensureAllowedUrl(targetUrl, this.config.allowedDomains);
|
|
3134
|
+
const provider = requirements.provider ?? this.config.defaultProvider ?? "openai";
|
|
3135
|
+
const model = requirements.model?.trim() || this.config.defaultModel?.trim() || DEFAULT_MODELS[provider];
|
|
3136
|
+
const maxTokens = this.config.maxTokens && this.config.maxTokens > 0 ? this.config.maxTokens : DEFAULT_MAX_TOKENS;
|
|
3137
|
+
if (!model) {
|
|
3138
|
+
throw new Error(
|
|
3139
|
+
`No model configured for provider "${provider}". Set defaultModel or provide requirements.model`
|
|
3140
|
+
);
|
|
3141
|
+
}
|
|
3142
|
+
const originalHtml = await this.fetchHtmlWithTimeout(
|
|
3143
|
+
targetUrl.toString(),
|
|
3144
|
+
context.abortSignal
|
|
3145
|
+
);
|
|
3146
|
+
const apiKey = await this.config.getApiKey(provider);
|
|
3147
|
+
if (!isNonEmptyString(apiKey)) {
|
|
3148
|
+
throw new Error(
|
|
3149
|
+
`Missing API key for provider "${provider}". Check BYOK setup for indexer ${this.config.indexerUrl}`
|
|
3150
|
+
);
|
|
3151
|
+
}
|
|
3152
|
+
const systemPrompt = this.config.systemPrompt?.trim() || DEFAULT_SYSTEM_PROMPT;
|
|
3153
|
+
const userPrompt = [
|
|
3154
|
+
`Modification request: ${requirements.modificationRequest}`,
|
|
3155
|
+
"",
|
|
3156
|
+
"Current HTML:",
|
|
3157
|
+
"```html",
|
|
3158
|
+
originalHtml,
|
|
3159
|
+
"```"
|
|
3160
|
+
].join("\n");
|
|
3161
|
+
let aiResponse = null;
|
|
3162
|
+
let lastError = null;
|
|
3163
|
+
const aiMessages = [
|
|
3164
|
+
{ role: "system", content: systemPrompt },
|
|
3165
|
+
{ role: "user", content: userPrompt }
|
|
3166
|
+
];
|
|
3167
|
+
for (let attempt = 1; attempt <= AI_MAX_RETRIES; attempt++) {
|
|
3168
|
+
try {
|
|
3169
|
+
aiResponse = await callAI({
|
|
3170
|
+
provider,
|
|
3171
|
+
model,
|
|
3172
|
+
maxTokens,
|
|
3173
|
+
apiKey,
|
|
3174
|
+
signal: context.abortSignal,
|
|
3175
|
+
messages: aiMessages
|
|
3176
|
+
});
|
|
3177
|
+
if (aiResponse.truncated) {
|
|
3178
|
+
throw new Error(
|
|
3179
|
+
"AI output was truncated (hit token limit). The generated HTML is incomplete."
|
|
3180
|
+
);
|
|
3181
|
+
}
|
|
3182
|
+
break;
|
|
3183
|
+
} catch (err) {
|
|
3184
|
+
lastError = err instanceof Error ? err : new Error(String(err));
|
|
3185
|
+
console.error(
|
|
3186
|
+
`[site-modifier] ${model} failed (attempt ${attempt}/${AI_MAX_RETRIES}): ${lastError.message}`
|
|
3187
|
+
);
|
|
3188
|
+
if (provider === "google" && model !== GOOGLE_FALLBACK_MODEL) {
|
|
3189
|
+
try {
|
|
3190
|
+
console.log(
|
|
3191
|
+
`[site-modifier] falling back to ${GOOGLE_FALLBACK_MODEL} (attempt ${attempt}/${AI_MAX_RETRIES})`
|
|
3192
|
+
);
|
|
3193
|
+
aiResponse = await callAI({
|
|
3194
|
+
provider,
|
|
3195
|
+
model: GOOGLE_FALLBACK_MODEL,
|
|
3196
|
+
maxTokens,
|
|
3197
|
+
apiKey,
|
|
3198
|
+
signal: context.abortSignal,
|
|
3199
|
+
messages: aiMessages
|
|
3200
|
+
});
|
|
3201
|
+
if (aiResponse.truncated) {
|
|
3202
|
+
throw new Error(
|
|
3203
|
+
"AI output was truncated (hit token limit). The generated HTML is incomplete."
|
|
3204
|
+
);
|
|
3205
|
+
}
|
|
3206
|
+
break;
|
|
3207
|
+
} catch (fallbackErr) {
|
|
3208
|
+
lastError = fallbackErr instanceof Error ? fallbackErr : new Error(String(fallbackErr));
|
|
3209
|
+
console.error(
|
|
3210
|
+
`[site-modifier] ${GOOGLE_FALLBACK_MODEL} also failed (attempt ${attempt}/${AI_MAX_RETRIES}): ${lastError.message}`
|
|
3211
|
+
);
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
}
|
|
3215
|
+
if (attempt < AI_MAX_RETRIES) {
|
|
3216
|
+
const delay = RETRY_DELAY_MS * attempt;
|
|
3217
|
+
console.log(`[site-modifier] retrying in ${delay}ms...`);
|
|
3218
|
+
await new Promise((r) => setTimeout(r, delay));
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
if (!aiResponse) {
|
|
3222
|
+
throw new Error(
|
|
3223
|
+
`AI generation failed after ${AI_MAX_RETRIES} attempts. Please try again later. Last error: ${lastError?.message ?? "unknown"}`
|
|
3224
|
+
);
|
|
3225
|
+
}
|
|
3226
|
+
const modifiedHtml = extractHtmlFromText(aiResponse.content);
|
|
3227
|
+
if (!modifiedHtml) {
|
|
3228
|
+
throw new Error("AI response did not contain valid HTML output");
|
|
3229
|
+
}
|
|
3230
|
+
if (getByteLength(modifiedHtml) > MAX_HTML_BYTES) {
|
|
3231
|
+
throw new Error(
|
|
3232
|
+
`Modified HTML exceeds size limit (${MAX_HTML_BYTES} bytes)`
|
|
3233
|
+
);
|
|
3234
|
+
}
|
|
3235
|
+
return {
|
|
3236
|
+
type: "inline",
|
|
3237
|
+
content: modifiedHtml,
|
|
3238
|
+
mimeType: "text/html"
|
|
3239
|
+
};
|
|
3240
|
+
}
|
|
3241
|
+
parseRequirements(requirements) {
|
|
3242
|
+
if (!isRecord(requirements)) {
|
|
3243
|
+
throw new Error("Missing requirements object");
|
|
3244
|
+
}
|
|
3245
|
+
const siteUrl = requirements.siteUrl;
|
|
3246
|
+
if (!isNonEmptyString(siteUrl)) {
|
|
3247
|
+
throw new Error("requirements.siteUrl must be a non-empty string");
|
|
3248
|
+
}
|
|
3249
|
+
const parsedUrl = parseAndValidateUrl(siteUrl);
|
|
3250
|
+
ensureAllowedUrl(parsedUrl, this.config.allowedDomains);
|
|
3251
|
+
const modificationRequest = requirements.modificationRequest;
|
|
3252
|
+
if (!isNonEmptyString(modificationRequest)) {
|
|
3253
|
+
throw new Error(
|
|
3254
|
+
"requirements.modificationRequest must be a non-empty string"
|
|
3255
|
+
);
|
|
3256
|
+
}
|
|
3257
|
+
const provider = requirements.provider;
|
|
3258
|
+
if (provider !== void 0 && !isSupportedProvider(provider)) {
|
|
3259
|
+
throw new Error(
|
|
3260
|
+
`requirements.provider must be one of: ${SUPPORTED_PROVIDERS.join(", ")}`
|
|
3261
|
+
);
|
|
3262
|
+
}
|
|
3263
|
+
const model = requirements.model;
|
|
3264
|
+
if (model !== void 0 && !isNonEmptyString(model)) {
|
|
3265
|
+
throw new Error("requirements.model must be a non-empty string");
|
|
3266
|
+
}
|
|
3267
|
+
return {
|
|
3268
|
+
siteUrl: siteUrl.trim(),
|
|
3269
|
+
modificationRequest: modificationRequest.trim(),
|
|
3270
|
+
provider,
|
|
3271
|
+
model: typeof model === "string" ? model.trim() : void 0
|
|
3272
|
+
};
|
|
3273
|
+
}
|
|
3274
|
+
async fetchHtmlWithTimeout(siteUrl, parentSignal) {
|
|
3275
|
+
const controller = new AbortController();
|
|
3276
|
+
const timeoutId = setTimeout(() => {
|
|
3277
|
+
controller.abort(
|
|
3278
|
+
new Error(`Site fetch timed out after ${FETCH_TIMEOUT_MS}ms for ${siteUrl}`)
|
|
3279
|
+
);
|
|
3280
|
+
}, FETCH_TIMEOUT_MS);
|
|
3281
|
+
const parentAbort = () => controller.abort(parentSignal?.reason);
|
|
3282
|
+
if (parentSignal) {
|
|
3283
|
+
if (parentSignal.aborted) {
|
|
3284
|
+
controller.abort(parentSignal.reason);
|
|
3285
|
+
} else {
|
|
3286
|
+
parentSignal.addEventListener("abort", parentAbort, { once: true });
|
|
3287
|
+
}
|
|
3288
|
+
}
|
|
3289
|
+
try {
|
|
3290
|
+
const response = await fetch(siteUrl, {
|
|
3291
|
+
method: "GET",
|
|
3292
|
+
headers: { Accept: "text/html,application/xhtml+xml" },
|
|
3293
|
+
signal: controller.signal
|
|
3294
|
+
});
|
|
3295
|
+
if (!response.ok) {
|
|
3296
|
+
throw new Error(
|
|
3297
|
+
`Failed to fetch site HTML: ${response.status} ${response.statusText}`
|
|
3298
|
+
);
|
|
3299
|
+
}
|
|
3300
|
+
const contentType = response.headers.get("content-type") ?? "";
|
|
3301
|
+
const isHtml = !contentType || isHtmlContentType(contentType);
|
|
3302
|
+
const isJson = isJsonContentType(contentType);
|
|
3303
|
+
if (!isHtml && !isJson) {
|
|
3304
|
+
throw new Error(
|
|
3305
|
+
`Fetched content is not HTML or JSON (content-type: ${contentType}, url: ${siteUrl})`
|
|
3306
|
+
);
|
|
3307
|
+
}
|
|
3308
|
+
const contentLengthHeader = response.headers.get("content-length");
|
|
3309
|
+
if (contentLengthHeader) {
|
|
3310
|
+
const contentLength = Number.parseInt(contentLengthHeader, 10);
|
|
3311
|
+
if (Number.isFinite(contentLength) && contentLength > MAX_HTML_BYTES) {
|
|
3312
|
+
throw new Error(
|
|
3313
|
+
`HTML too large (${contentLength} bytes). Limit is ${MAX_HTML_BYTES} bytes`
|
|
3314
|
+
);
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
const htmlBuffer = await response.arrayBuffer();
|
|
3318
|
+
if (htmlBuffer.byteLength > MAX_HTML_BYTES) {
|
|
3319
|
+
throw new Error(
|
|
3320
|
+
`HTML too large (${htmlBuffer.byteLength} bytes). Limit is ${MAX_HTML_BYTES} bytes`
|
|
3321
|
+
);
|
|
3322
|
+
}
|
|
3323
|
+
let html = new TextDecoder().decode(htmlBuffer).trim();
|
|
3324
|
+
if (!html) {
|
|
3325
|
+
throw new Error("Fetched content is empty");
|
|
3326
|
+
}
|
|
3327
|
+
if (isJson) {
|
|
3328
|
+
const extracted = extractHtmlFromJson(html);
|
|
3329
|
+
if (!extracted) {
|
|
3330
|
+
throw new Error(
|
|
3331
|
+
`JSON response from ${siteUrl} does not contain extractable HTML content`
|
|
3332
|
+
);
|
|
3333
|
+
}
|
|
3334
|
+
html = extracted;
|
|
3335
|
+
}
|
|
3336
|
+
return html;
|
|
3337
|
+
} catch (error) {
|
|
3338
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
3339
|
+
if (parentSignal?.aborted) {
|
|
3340
|
+
throw new Error("Site fetch aborted");
|
|
3341
|
+
}
|
|
3342
|
+
throw new Error(`Site fetch timed out after ${FETCH_TIMEOUT_MS}ms for ${siteUrl}`);
|
|
3343
|
+
}
|
|
3344
|
+
throw error;
|
|
3345
|
+
} finally {
|
|
3346
|
+
clearTimeout(timeoutId);
|
|
3347
|
+
if (parentSignal) {
|
|
3348
|
+
parentSignal.removeEventListener("abort", parentAbort);
|
|
3349
|
+
}
|
|
3350
|
+
}
|
|
3351
|
+
}
|
|
3352
|
+
};
|
|
3353
|
+
|
|
2790
3354
|
// src/utils.ts
|
|
2791
3355
|
var USDM_DECIMALS = 18;
|
|
2792
3356
|
var USDM_SCALE = 10n ** BigInt(USDM_DECIMALS);
|
|
@@ -2858,7 +3422,7 @@ var IndexerClientError = class extends Error {
|
|
|
2858
3422
|
this.body = options.body;
|
|
2859
3423
|
}
|
|
2860
3424
|
};
|
|
2861
|
-
function
|
|
3425
|
+
function isRecord2(value) {
|
|
2862
3426
|
return typeof value === "object" && value !== null;
|
|
2863
3427
|
}
|
|
2864
3428
|
function toIndexerAgent(raw) {
|
|
@@ -2986,6 +3550,31 @@ var IndexerClient = class {
|
|
|
2986
3550
|
);
|
|
2987
3551
|
return toIndexerWarrenLinks(payload.data);
|
|
2988
3552
|
}
|
|
3553
|
+
async postDeliverable(jobId, content, contentHash, storageType) {
|
|
3554
|
+
await this.requestJson("/deliverables", {
|
|
3555
|
+
method: "POST",
|
|
3556
|
+
headers: { "Content-Type": "application/json" },
|
|
3557
|
+
body: JSON.stringify({
|
|
3558
|
+
jobId,
|
|
3559
|
+
content,
|
|
3560
|
+
contentHash,
|
|
3561
|
+
storageType: storageType ?? "indexer"
|
|
3562
|
+
})
|
|
3563
|
+
});
|
|
3564
|
+
}
|
|
3565
|
+
async getDeliverable(jobId) {
|
|
3566
|
+
try {
|
|
3567
|
+
const response = await this.request(`/deliverables/${jobId}`);
|
|
3568
|
+
if (response.status === 404) return null;
|
|
3569
|
+
const payload = await this.parseResponse(
|
|
3570
|
+
response,
|
|
3571
|
+
`/deliverables/${jobId}`
|
|
3572
|
+
);
|
|
3573
|
+
return { content: payload.data.content, storageType: payload.data.storage_type };
|
|
3574
|
+
} catch {
|
|
3575
|
+
return null;
|
|
3576
|
+
}
|
|
3577
|
+
}
|
|
2989
3578
|
async request(path, init) {
|
|
2990
3579
|
const url = `${this.baseUrl}${path}`;
|
|
2991
3580
|
const controller = new AbortController();
|
|
@@ -3021,7 +3610,7 @@ var IndexerClient = class {
|
|
|
3021
3610
|
});
|
|
3022
3611
|
}
|
|
3023
3612
|
if (!response.ok) {
|
|
3024
|
-
const apiError =
|
|
3613
|
+
const apiError = isRecord2(payload) ? payload : void 0;
|
|
3025
3614
|
const message = response.status === 404 && notFoundMessage ? notFoundMessage : apiError?.error ?? apiError?.message ?? `Indexer request failed (${response.status})`;
|
|
3026
3615
|
throw new IndexerClientError(message, {
|
|
3027
3616
|
url,
|
|
@@ -3075,10 +3664,11 @@ var ProviderRuntime = class {
|
|
|
3075
3664
|
});
|
|
3076
3665
|
const jobs = await this.indexer.getJobs({ status: 0 });
|
|
3077
3666
|
for (const job of jobs) {
|
|
3078
|
-
|
|
3667
|
+
const newKey = `new:${job.jobId}`;
|
|
3668
|
+
if (this.processedJobs.has(newKey)) continue;
|
|
3079
3669
|
const matchesOffering = offerings.some((o) => o.offeringId === job.offeringId);
|
|
3080
3670
|
if (!matchesOffering) continue;
|
|
3081
|
-
this.processedJobs.add(
|
|
3671
|
+
this.processedJobs.add(newKey);
|
|
3082
3672
|
if (this.callbacks.onJobReceived) {
|
|
3083
3673
|
try {
|
|
3084
3674
|
const accept = await this.callbacks.onJobReceived(job);
|
|
@@ -3103,7 +3693,7 @@ var ProviderRuntime = class {
|
|
|
3103
3693
|
agentId: Number(this.agentId)
|
|
3104
3694
|
});
|
|
3105
3695
|
for (const job of inProgressJobs) {
|
|
3106
|
-
const deliverKey = job.jobId
|
|
3696
|
+
const deliverKey = `deliver:${job.jobId}`;
|
|
3107
3697
|
if (this.processedJobs.has(deliverKey)) continue;
|
|
3108
3698
|
if (this.callbacks.onDeliverableRequested) {
|
|
3109
3699
|
try {
|
|
@@ -3130,7 +3720,7 @@ var ProviderRuntime = class {
|
|
|
3130
3720
|
agentId: Number(this.agentId)
|
|
3131
3721
|
});
|
|
3132
3722
|
for (const job of completedJobs) {
|
|
3133
|
-
const completeKey = job.jobId
|
|
3723
|
+
const completeKey = `complete:${job.jobId}`;
|
|
3134
3724
|
if (this.processedJobs.has(completeKey)) continue;
|
|
3135
3725
|
this.processedJobs.add(completeKey);
|
|
3136
3726
|
this.callbacks.onJobCompleted?.(job);
|
|
@@ -3241,8 +3831,9 @@ var BuyerRuntime = class {
|
|
|
3241
3831
|
agentId: Number(this.agentId)
|
|
3242
3832
|
});
|
|
3243
3833
|
for (const job of deliveredJobs) {
|
|
3244
|
-
|
|
3245
|
-
this.processedJobs.
|
|
3834
|
+
const deliveredKey = `delivered:${job.jobId}`;
|
|
3835
|
+
if (this.processedJobs.has(deliveredKey)) continue;
|
|
3836
|
+
this.processedJobs.add(deliveredKey);
|
|
3246
3837
|
try {
|
|
3247
3838
|
const deliverable = await readDeliverable(
|
|
3248
3839
|
this.client,
|
|
@@ -3267,7 +3858,7 @@ var BuyerRuntime = class {
|
|
|
3267
3858
|
agentId: Number(this.agentId)
|
|
3268
3859
|
});
|
|
3269
3860
|
for (const job of completedJobs) {
|
|
3270
|
-
const completeKey = job.jobId
|
|
3861
|
+
const completeKey = `complete:${job.jobId}`;
|
|
3271
3862
|
if (this.processedJobs.has(completeKey)) continue;
|
|
3272
3863
|
this.processedJobs.add(completeKey);
|
|
3273
3864
|
this.callbacks.onJobCompleted?.(job);
|
|
@@ -3283,8 +3874,11 @@ var HandlerProviderRuntime = class {
|
|
|
3283
3874
|
indexer;
|
|
3284
3875
|
indexerUrl;
|
|
3285
3876
|
pollInterval;
|
|
3877
|
+
executionTimeoutMs;
|
|
3286
3878
|
running = false;
|
|
3287
3879
|
processedJobs = /* @__PURE__ */ new Set();
|
|
3880
|
+
failedJobs = /* @__PURE__ */ new Map();
|
|
3881
|
+
maxRetries = 3;
|
|
3288
3882
|
onError;
|
|
3289
3883
|
constructor(client, agentId, options) {
|
|
3290
3884
|
this.client = client;
|
|
@@ -3292,6 +3886,7 @@ var HandlerProviderRuntime = class {
|
|
|
3292
3886
|
this.indexer = new IndexerClient({ baseUrl: options.indexerUrl });
|
|
3293
3887
|
this.indexerUrl = options.indexerUrl.replace(/\/$/, "");
|
|
3294
3888
|
this.pollInterval = options.pollInterval ?? 5e3;
|
|
3889
|
+
this.executionTimeoutMs = options.executionTimeoutMs ?? 5 * 60 * 1e3;
|
|
3295
3890
|
}
|
|
3296
3891
|
registerHandler(handler) {
|
|
3297
3892
|
this.handlers.set(handler.offeringId, handler);
|
|
@@ -3311,6 +3906,7 @@ var HandlerProviderRuntime = class {
|
|
|
3311
3906
|
try {
|
|
3312
3907
|
await this.checkNewJobs();
|
|
3313
3908
|
await this.checkInProgressJobs();
|
|
3909
|
+
await this.checkEvaluatedJobs();
|
|
3314
3910
|
} catch (e) {
|
|
3315
3911
|
this.onError?.(e instanceof Error ? e : new Error(String(e)));
|
|
3316
3912
|
}
|
|
@@ -3324,13 +3920,38 @@ var HandlerProviderRuntime = class {
|
|
|
3324
3920
|
});
|
|
3325
3921
|
const jobs = await this.indexer.getJobs({ status: 0 });
|
|
3326
3922
|
for (const job of jobs) {
|
|
3327
|
-
|
|
3923
|
+
const newKey = `new:${job.jobId}`;
|
|
3924
|
+
if (!this.canProcess(newKey)) continue;
|
|
3328
3925
|
const matchesOffering = offerings.some((o) => o.offeringId === job.offeringId);
|
|
3329
3926
|
if (!matchesOffering) continue;
|
|
3330
3927
|
const handler = this.handlers.get(job.offeringId);
|
|
3331
3928
|
if (!handler) continue;
|
|
3332
|
-
this.processedJobs.add(job.jobId);
|
|
3333
3929
|
try {
|
|
3930
|
+
if (job.slaMinutes === null) {
|
|
3931
|
+
throw new Error(`Job ${job.jobId} is missing slaMinutes`);
|
|
3932
|
+
}
|
|
3933
|
+
const context = {
|
|
3934
|
+
jobId: BigInt(job.jobId),
|
|
3935
|
+
offeringId: BigInt(job.offeringId),
|
|
3936
|
+
buyerAgentId: BigInt(job.buyerAgentId),
|
|
3937
|
+
providerAgentId: BigInt(job.providerAgentId),
|
|
3938
|
+
priceUsdm: job.priceUsdm,
|
|
3939
|
+
slaMinutes: job.slaMinutes
|
|
3940
|
+
};
|
|
3941
|
+
const reqData = await readRequirements(
|
|
3942
|
+
this.client,
|
|
3943
|
+
BigInt(job.jobId),
|
|
3944
|
+
this.indexerUrl
|
|
3945
|
+
);
|
|
3946
|
+
if (reqData) {
|
|
3947
|
+
context.requirements = reqData.requirements;
|
|
3948
|
+
}
|
|
3949
|
+
if (handler.validateRequirements) {
|
|
3950
|
+
const validation = await handler.validateRequirements(context);
|
|
3951
|
+
if (!validation.valid) {
|
|
3952
|
+
throw new Error(`Validation failed for job ${job.jobId}: ${validation.reason}`);
|
|
3953
|
+
}
|
|
3954
|
+
}
|
|
3334
3955
|
if (handler.autoAccept !== false) {
|
|
3335
3956
|
await acceptJob(
|
|
3336
3957
|
this.client,
|
|
@@ -3338,8 +3959,9 @@ var HandlerProviderRuntime = class {
|
|
|
3338
3959
|
job.warrenTermsHash
|
|
3339
3960
|
);
|
|
3340
3961
|
}
|
|
3962
|
+
this.markProcessed(newKey);
|
|
3341
3963
|
} catch (e) {
|
|
3342
|
-
this.
|
|
3964
|
+
this.markFailed(newKey, e);
|
|
3343
3965
|
}
|
|
3344
3966
|
}
|
|
3345
3967
|
}
|
|
@@ -3349,15 +3971,13 @@ var HandlerProviderRuntime = class {
|
|
|
3349
3971
|
agentId: Number(this.agentId)
|
|
3350
3972
|
});
|
|
3351
3973
|
for (const job of inProgressJobs) {
|
|
3352
|
-
const deliverKey = job.jobId
|
|
3353
|
-
if (this.
|
|
3974
|
+
const deliverKey = `deliver:${job.jobId}`;
|
|
3975
|
+
if (!this.canProcess(deliverKey)) continue;
|
|
3354
3976
|
const handler = this.handlers.get(job.offeringId);
|
|
3355
3977
|
if (!handler) continue;
|
|
3356
|
-
this.processedJobs.add(deliverKey);
|
|
3357
3978
|
try {
|
|
3358
3979
|
if (job.slaMinutes === null) {
|
|
3359
|
-
|
|
3360
|
-
continue;
|
|
3980
|
+
throw new Error(`Job ${job.jobId} is missing slaMinutes`);
|
|
3361
3981
|
}
|
|
3362
3982
|
const context = {
|
|
3363
3983
|
jobId: BigInt(job.jobId),
|
|
@@ -3378,32 +3998,102 @@ var HandlerProviderRuntime = class {
|
|
|
3378
3998
|
if (handler.validateRequirements) {
|
|
3379
3999
|
const validation = await handler.validateRequirements(context);
|
|
3380
4000
|
if (!validation.valid) {
|
|
3381
|
-
this.
|
|
4001
|
+
this.markFailed(
|
|
4002
|
+
deliverKey,
|
|
3382
4003
|
new Error(`Validation failed for job ${job.jobId}: ${validation.reason}`)
|
|
3383
4004
|
);
|
|
3384
4005
|
continue;
|
|
3385
4006
|
}
|
|
3386
4007
|
}
|
|
3387
|
-
const
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
}
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
4008
|
+
const remainingSlaMs = this.getRemainingSlaMs(job.createdAt, job.acceptedAt, job.slaMinutes);
|
|
4009
|
+
if (remainingSlaMs !== null && remainingSlaMs < 10 * 60 * 1e3) {
|
|
4010
|
+
console.warn(
|
|
4011
|
+
`Skipping job ${job.jobId}: SLA remaining ${Math.max(0, Math.floor(remainingSlaMs / 1e3))}s is below 10 minutes`
|
|
4012
|
+
);
|
|
4013
|
+
this.markProcessed(deliverKey);
|
|
4014
|
+
continue;
|
|
4015
|
+
}
|
|
4016
|
+
const controller = new AbortController();
|
|
4017
|
+
const executionContext = { ...context, abortSignal: controller.signal };
|
|
4018
|
+
let timeoutId;
|
|
4019
|
+
try {
|
|
4020
|
+
const timeoutPromise = new Promise((_, reject) => {
|
|
4021
|
+
timeoutId = setTimeout(() => {
|
|
4022
|
+
controller.abort();
|
|
4023
|
+
reject(
|
|
4024
|
+
new Error(
|
|
4025
|
+
`Execution timed out for job ${job.jobId} after ${this.executionTimeoutMs}ms`
|
|
4026
|
+
)
|
|
4027
|
+
);
|
|
4028
|
+
}, this.executionTimeoutMs);
|
|
4029
|
+
});
|
|
4030
|
+
const result = await Promise.race([
|
|
4031
|
+
handler.executeJob(executionContext),
|
|
4032
|
+
timeoutPromise
|
|
4033
|
+
]);
|
|
4034
|
+
const deliverableParams = {
|
|
4035
|
+
type: result.type,
|
|
4036
|
+
content: result.content,
|
|
4037
|
+
url: result.url,
|
|
4038
|
+
mimeType: result.mimeType,
|
|
4039
|
+
jobId: BigInt(job.jobId)
|
|
4040
|
+
};
|
|
4041
|
+
await deployDeliverable(
|
|
4042
|
+
this.client,
|
|
4043
|
+
this.agentId,
|
|
4044
|
+
BigInt(job.jobId),
|
|
4045
|
+
deliverableParams,
|
|
4046
|
+
this.indexerUrl
|
|
4047
|
+
);
|
|
4048
|
+
} finally {
|
|
4049
|
+
if (timeoutId) clearTimeout(timeoutId);
|
|
4050
|
+
}
|
|
4051
|
+
this.markProcessed(deliverKey);
|
|
3402
4052
|
} catch (e) {
|
|
3403
|
-
this.
|
|
4053
|
+
this.markFailed(deliverKey, e);
|
|
4054
|
+
}
|
|
4055
|
+
}
|
|
4056
|
+
}
|
|
4057
|
+
async checkEvaluatedJobs() {
|
|
4058
|
+
const evaluatedJobs = await this.indexer.getJobs({
|
|
4059
|
+
status: 4,
|
|
4060
|
+
agentId: Number(this.agentId)
|
|
4061
|
+
});
|
|
4062
|
+
for (const job of evaluatedJobs) {
|
|
4063
|
+
const settleKey = `settle:${job.jobId}`;
|
|
4064
|
+
if (!this.canProcess(settleKey)) continue;
|
|
4065
|
+
try {
|
|
4066
|
+
await settle(this.client, BigInt(job.jobId));
|
|
4067
|
+
console.log(`[handler-provider] auto-settled job ${job.jobId}`);
|
|
4068
|
+
this.markProcessed(settleKey);
|
|
4069
|
+
} catch (e) {
|
|
4070
|
+
this.markFailed(settleKey, e);
|
|
3404
4071
|
}
|
|
3405
4072
|
}
|
|
3406
4073
|
}
|
|
4074
|
+
canProcess(key) {
|
|
4075
|
+
if (this.processedJobs.has(key)) return false;
|
|
4076
|
+
return (this.failedJobs.get(key) ?? 0) < this.maxRetries;
|
|
4077
|
+
}
|
|
4078
|
+
markProcessed(key) {
|
|
4079
|
+
this.failedJobs.delete(key);
|
|
4080
|
+
this.processedJobs.add(key);
|
|
4081
|
+
}
|
|
4082
|
+
markFailed(key, error) {
|
|
4083
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
4084
|
+
this.onError?.(err);
|
|
4085
|
+
const retries = (this.failedJobs.get(key) ?? 0) + 1;
|
|
4086
|
+
this.failedJobs.set(key, retries);
|
|
4087
|
+
if (retries >= this.maxRetries) {
|
|
4088
|
+
this.onError?.(new Error(`Giving up on ${key} after ${retries} failed attempts`));
|
|
4089
|
+
}
|
|
4090
|
+
}
|
|
4091
|
+
getRemainingSlaMs(createdAt, acceptedAt, slaMinutes) {
|
|
4092
|
+
const start = acceptedAt ?? createdAt;
|
|
4093
|
+
if (start === null) return null;
|
|
4094
|
+
const startMs = start > 1e12 ? start : start * 1e3;
|
|
4095
|
+
return startMs + slaMinutes * 60 * 1e3 - Date.now();
|
|
4096
|
+
}
|
|
3407
4097
|
};
|
|
3408
4098
|
|
|
3409
4099
|
// src/abis/FeeDistributor.ts
|
|
@@ -4253,6 +4943,528 @@ var erc8004ReputationAbi = [
|
|
|
4253
4943
|
"anonymous": false
|
|
4254
4944
|
}
|
|
4255
4945
|
];
|
|
4946
|
+
|
|
4947
|
+
// src/abis/BuyerRelay.ts
|
|
4948
|
+
var buyerRelayAbi = [
|
|
4949
|
+
{
|
|
4950
|
+
"type": "constructor",
|
|
4951
|
+
"inputs": [
|
|
4952
|
+
{
|
|
4953
|
+
"name": "owner_",
|
|
4954
|
+
"type": "address",
|
|
4955
|
+
"internalType": "address"
|
|
4956
|
+
},
|
|
4957
|
+
{
|
|
4958
|
+
"name": "identityRegistry_",
|
|
4959
|
+
"type": "address",
|
|
4960
|
+
"internalType": "address"
|
|
4961
|
+
},
|
|
4962
|
+
{
|
|
4963
|
+
"name": "pulseExtension_",
|
|
4964
|
+
"type": "address",
|
|
4965
|
+
"internalType": "address"
|
|
4966
|
+
},
|
|
4967
|
+
{
|
|
4968
|
+
"name": "jobEngine_",
|
|
4969
|
+
"type": "address",
|
|
4970
|
+
"internalType": "address"
|
|
4971
|
+
},
|
|
4972
|
+
{
|
|
4973
|
+
"name": "serviceMarketplace_",
|
|
4974
|
+
"type": "address",
|
|
4975
|
+
"internalType": "address"
|
|
4976
|
+
},
|
|
4977
|
+
{
|
|
4978
|
+
"name": "usdm_",
|
|
4979
|
+
"type": "address",
|
|
4980
|
+
"internalType": "address"
|
|
4981
|
+
}
|
|
4982
|
+
],
|
|
4983
|
+
"stateMutability": "nonpayable"
|
|
4984
|
+
},
|
|
4985
|
+
{
|
|
4986
|
+
"type": "function",
|
|
4987
|
+
"name": "buyerAgentId",
|
|
4988
|
+
"inputs": [],
|
|
4989
|
+
"outputs": [
|
|
4990
|
+
{
|
|
4991
|
+
"name": "",
|
|
4992
|
+
"type": "uint256",
|
|
4993
|
+
"internalType": "uint256"
|
|
4994
|
+
}
|
|
4995
|
+
],
|
|
4996
|
+
"stateMutability": "view"
|
|
4997
|
+
},
|
|
4998
|
+
{
|
|
4999
|
+
"type": "function",
|
|
5000
|
+
"name": "cancelFor",
|
|
5001
|
+
"inputs": [
|
|
5002
|
+
{
|
|
5003
|
+
"name": "jobId",
|
|
5004
|
+
"type": "uint256",
|
|
5005
|
+
"internalType": "uint256"
|
|
5006
|
+
}
|
|
5007
|
+
],
|
|
5008
|
+
"outputs": [],
|
|
5009
|
+
"stateMutability": "nonpayable"
|
|
5010
|
+
},
|
|
5011
|
+
{
|
|
5012
|
+
"type": "function",
|
|
5013
|
+
"name": "claimRefund",
|
|
5014
|
+
"inputs": [
|
|
5015
|
+
{
|
|
5016
|
+
"name": "jobId",
|
|
5017
|
+
"type": "uint256",
|
|
5018
|
+
"internalType": "uint256"
|
|
5019
|
+
}
|
|
5020
|
+
],
|
|
5021
|
+
"outputs": [],
|
|
5022
|
+
"stateMutability": "nonpayable"
|
|
5023
|
+
},
|
|
5024
|
+
{
|
|
5025
|
+
"type": "function",
|
|
5026
|
+
"name": "createJobFor",
|
|
5027
|
+
"inputs": [
|
|
5028
|
+
{
|
|
5029
|
+
"name": "offeringId",
|
|
5030
|
+
"type": "uint256",
|
|
5031
|
+
"internalType": "uint256"
|
|
5032
|
+
},
|
|
5033
|
+
{
|
|
5034
|
+
"name": "termsHash",
|
|
5035
|
+
"type": "bytes32",
|
|
5036
|
+
"internalType": "bytes32"
|
|
5037
|
+
},
|
|
5038
|
+
{
|
|
5039
|
+
"name": "maxPrice",
|
|
5040
|
+
"type": "uint256",
|
|
5041
|
+
"internalType": "uint256"
|
|
5042
|
+
}
|
|
5043
|
+
],
|
|
5044
|
+
"outputs": [
|
|
5045
|
+
{
|
|
5046
|
+
"name": "jobId",
|
|
5047
|
+
"type": "uint256",
|
|
5048
|
+
"internalType": "uint256"
|
|
5049
|
+
}
|
|
5050
|
+
],
|
|
5051
|
+
"stateMutability": "nonpayable"
|
|
5052
|
+
},
|
|
5053
|
+
{
|
|
5054
|
+
"type": "function",
|
|
5055
|
+
"name": "evaluateFor",
|
|
5056
|
+
"inputs": [
|
|
5057
|
+
{
|
|
5058
|
+
"name": "jobId",
|
|
5059
|
+
"type": "uint256",
|
|
5060
|
+
"internalType": "uint256"
|
|
5061
|
+
},
|
|
5062
|
+
{
|
|
5063
|
+
"name": "approved",
|
|
5064
|
+
"type": "bool",
|
|
5065
|
+
"internalType": "bool"
|
|
5066
|
+
},
|
|
5067
|
+
{
|
|
5068
|
+
"name": "feedback",
|
|
5069
|
+
"type": "string",
|
|
5070
|
+
"internalType": "string"
|
|
5071
|
+
}
|
|
5072
|
+
],
|
|
5073
|
+
"outputs": [],
|
|
5074
|
+
"stateMutability": "nonpayable"
|
|
5075
|
+
},
|
|
5076
|
+
{
|
|
5077
|
+
"type": "function",
|
|
5078
|
+
"name": "identityRegistry",
|
|
5079
|
+
"inputs": [],
|
|
5080
|
+
"outputs": [
|
|
5081
|
+
{
|
|
5082
|
+
"name": "",
|
|
5083
|
+
"type": "address",
|
|
5084
|
+
"internalType": "contract IERC8004Identity"
|
|
5085
|
+
}
|
|
5086
|
+
],
|
|
5087
|
+
"stateMutability": "view"
|
|
5088
|
+
},
|
|
5089
|
+
{
|
|
5090
|
+
"type": "function",
|
|
5091
|
+
"name": "jobDeposit",
|
|
5092
|
+
"inputs": [
|
|
5093
|
+
{
|
|
5094
|
+
"name": "",
|
|
5095
|
+
"type": "uint256",
|
|
5096
|
+
"internalType": "uint256"
|
|
5097
|
+
}
|
|
5098
|
+
],
|
|
5099
|
+
"outputs": [
|
|
5100
|
+
{
|
|
5101
|
+
"name": "",
|
|
5102
|
+
"type": "uint256",
|
|
5103
|
+
"internalType": "uint256"
|
|
5104
|
+
}
|
|
5105
|
+
],
|
|
5106
|
+
"stateMutability": "view"
|
|
5107
|
+
},
|
|
5108
|
+
{
|
|
5109
|
+
"type": "function",
|
|
5110
|
+
"name": "jobEngine",
|
|
5111
|
+
"inputs": [],
|
|
5112
|
+
"outputs": [
|
|
5113
|
+
{
|
|
5114
|
+
"name": "",
|
|
5115
|
+
"type": "address",
|
|
5116
|
+
"internalType": "contract IJobEngine"
|
|
5117
|
+
}
|
|
5118
|
+
],
|
|
5119
|
+
"stateMutability": "view"
|
|
5120
|
+
},
|
|
5121
|
+
{
|
|
5122
|
+
"type": "function",
|
|
5123
|
+
"name": "jobPayer",
|
|
5124
|
+
"inputs": [
|
|
5125
|
+
{
|
|
5126
|
+
"name": "",
|
|
5127
|
+
"type": "uint256",
|
|
5128
|
+
"internalType": "uint256"
|
|
5129
|
+
}
|
|
5130
|
+
],
|
|
5131
|
+
"outputs": [
|
|
5132
|
+
{
|
|
5133
|
+
"name": "",
|
|
5134
|
+
"type": "address",
|
|
5135
|
+
"internalType": "address"
|
|
5136
|
+
}
|
|
5137
|
+
],
|
|
5138
|
+
"stateMutability": "view"
|
|
5139
|
+
},
|
|
5140
|
+
{
|
|
5141
|
+
"type": "function",
|
|
5142
|
+
"name": "jobRefundState",
|
|
5143
|
+
"inputs": [
|
|
5144
|
+
{
|
|
5145
|
+
"name": "",
|
|
5146
|
+
"type": "uint256",
|
|
5147
|
+
"internalType": "uint256"
|
|
5148
|
+
}
|
|
5149
|
+
],
|
|
5150
|
+
"outputs": [
|
|
5151
|
+
{
|
|
5152
|
+
"name": "",
|
|
5153
|
+
"type": "uint8",
|
|
5154
|
+
"internalType": "enum IBuyerRelay.RefundState"
|
|
5155
|
+
}
|
|
5156
|
+
],
|
|
5157
|
+
"stateMutability": "view"
|
|
5158
|
+
},
|
|
5159
|
+
{
|
|
5160
|
+
"type": "function",
|
|
5161
|
+
"name": "onERC721Received",
|
|
5162
|
+
"inputs": [
|
|
5163
|
+
{
|
|
5164
|
+
"name": "",
|
|
5165
|
+
"type": "address",
|
|
5166
|
+
"internalType": "address"
|
|
5167
|
+
},
|
|
5168
|
+
{
|
|
5169
|
+
"name": "",
|
|
5170
|
+
"type": "address",
|
|
5171
|
+
"internalType": "address"
|
|
5172
|
+
},
|
|
5173
|
+
{
|
|
5174
|
+
"name": "",
|
|
5175
|
+
"type": "uint256",
|
|
5176
|
+
"internalType": "uint256"
|
|
5177
|
+
},
|
|
5178
|
+
{
|
|
5179
|
+
"name": "",
|
|
5180
|
+
"type": "bytes",
|
|
5181
|
+
"internalType": "bytes"
|
|
5182
|
+
}
|
|
5183
|
+
],
|
|
5184
|
+
"outputs": [
|
|
5185
|
+
{
|
|
5186
|
+
"name": "",
|
|
5187
|
+
"type": "bytes4",
|
|
5188
|
+
"internalType": "bytes4"
|
|
5189
|
+
}
|
|
5190
|
+
],
|
|
5191
|
+
"stateMutability": "pure"
|
|
5192
|
+
},
|
|
5193
|
+
{
|
|
5194
|
+
"type": "function",
|
|
5195
|
+
"name": "owner",
|
|
5196
|
+
"inputs": [],
|
|
5197
|
+
"outputs": [
|
|
5198
|
+
{
|
|
5199
|
+
"name": "",
|
|
5200
|
+
"type": "address",
|
|
5201
|
+
"internalType": "address"
|
|
5202
|
+
}
|
|
5203
|
+
],
|
|
5204
|
+
"stateMutability": "view"
|
|
5205
|
+
},
|
|
5206
|
+
{
|
|
5207
|
+
"type": "function",
|
|
5208
|
+
"name": "pulseExtension",
|
|
5209
|
+
"inputs": [],
|
|
5210
|
+
"outputs": [
|
|
5211
|
+
{
|
|
5212
|
+
"name": "",
|
|
5213
|
+
"type": "address",
|
|
5214
|
+
"internalType": "contract IPulseExtension"
|
|
5215
|
+
}
|
|
5216
|
+
],
|
|
5217
|
+
"stateMutability": "view"
|
|
5218
|
+
},
|
|
5219
|
+
{
|
|
5220
|
+
"type": "function",
|
|
5221
|
+
"name": "renounceOwnership",
|
|
5222
|
+
"inputs": [],
|
|
5223
|
+
"outputs": [],
|
|
5224
|
+
"stateMutability": "nonpayable"
|
|
5225
|
+
},
|
|
5226
|
+
{
|
|
5227
|
+
"type": "function",
|
|
5228
|
+
"name": "serviceMarketplace",
|
|
5229
|
+
"inputs": [],
|
|
5230
|
+
"outputs": [
|
|
5231
|
+
{
|
|
5232
|
+
"name": "",
|
|
5233
|
+
"type": "address",
|
|
5234
|
+
"internalType": "contract IServiceMarketplace"
|
|
5235
|
+
}
|
|
5236
|
+
],
|
|
5237
|
+
"stateMutability": "view"
|
|
5238
|
+
},
|
|
5239
|
+
{
|
|
5240
|
+
"type": "function",
|
|
5241
|
+
"name": "setup",
|
|
5242
|
+
"inputs": [
|
|
5243
|
+
{
|
|
5244
|
+
"name": "agentURI",
|
|
5245
|
+
"type": "string",
|
|
5246
|
+
"internalType": "string"
|
|
5247
|
+
}
|
|
5248
|
+
],
|
|
5249
|
+
"outputs": [],
|
|
5250
|
+
"stateMutability": "nonpayable"
|
|
5251
|
+
},
|
|
5252
|
+
{
|
|
5253
|
+
"type": "function",
|
|
5254
|
+
"name": "transferOwnership",
|
|
5255
|
+
"inputs": [
|
|
5256
|
+
{
|
|
5257
|
+
"name": "newOwner",
|
|
5258
|
+
"type": "address",
|
|
5259
|
+
"internalType": "address"
|
|
5260
|
+
}
|
|
5261
|
+
],
|
|
5262
|
+
"outputs": [],
|
|
5263
|
+
"stateMutability": "nonpayable"
|
|
5264
|
+
},
|
|
5265
|
+
{
|
|
5266
|
+
"type": "function",
|
|
5267
|
+
"name": "usdm",
|
|
5268
|
+
"inputs": [],
|
|
5269
|
+
"outputs": [
|
|
5270
|
+
{
|
|
5271
|
+
"name": "",
|
|
5272
|
+
"type": "address",
|
|
5273
|
+
"internalType": "address"
|
|
5274
|
+
}
|
|
5275
|
+
],
|
|
5276
|
+
"stateMutability": "view"
|
|
5277
|
+
},
|
|
5278
|
+
{
|
|
5279
|
+
"type": "event",
|
|
5280
|
+
"name": "EvaluatedFor",
|
|
5281
|
+
"inputs": [
|
|
5282
|
+
{
|
|
5283
|
+
"name": "jobId",
|
|
5284
|
+
"type": "uint256",
|
|
5285
|
+
"indexed": true,
|
|
5286
|
+
"internalType": "uint256"
|
|
5287
|
+
},
|
|
5288
|
+
{
|
|
5289
|
+
"name": "payer",
|
|
5290
|
+
"type": "address",
|
|
5291
|
+
"indexed": true,
|
|
5292
|
+
"internalType": "address"
|
|
5293
|
+
},
|
|
5294
|
+
{
|
|
5295
|
+
"name": "approved",
|
|
5296
|
+
"type": "bool",
|
|
5297
|
+
"indexed": false,
|
|
5298
|
+
"internalType": "bool"
|
|
5299
|
+
}
|
|
5300
|
+
],
|
|
5301
|
+
"anonymous": false
|
|
5302
|
+
},
|
|
5303
|
+
{
|
|
5304
|
+
"type": "event",
|
|
5305
|
+
"name": "JobCreatedFor",
|
|
5306
|
+
"inputs": [
|
|
5307
|
+
{
|
|
5308
|
+
"name": "jobId",
|
|
5309
|
+
"type": "uint256",
|
|
5310
|
+
"indexed": true,
|
|
5311
|
+
"internalType": "uint256"
|
|
5312
|
+
},
|
|
5313
|
+
{
|
|
5314
|
+
"name": "payer",
|
|
5315
|
+
"type": "address",
|
|
5316
|
+
"indexed": true,
|
|
5317
|
+
"internalType": "address"
|
|
5318
|
+
},
|
|
5319
|
+
{
|
|
5320
|
+
"name": "price",
|
|
5321
|
+
"type": "uint256",
|
|
5322
|
+
"indexed": false,
|
|
5323
|
+
"internalType": "uint256"
|
|
5324
|
+
}
|
|
5325
|
+
],
|
|
5326
|
+
"anonymous": false
|
|
5327
|
+
},
|
|
5328
|
+
{
|
|
5329
|
+
"type": "event",
|
|
5330
|
+
"name": "OwnershipTransferred",
|
|
5331
|
+
"inputs": [
|
|
5332
|
+
{
|
|
5333
|
+
"name": "previousOwner",
|
|
5334
|
+
"type": "address",
|
|
5335
|
+
"indexed": true,
|
|
5336
|
+
"internalType": "address"
|
|
5337
|
+
},
|
|
5338
|
+
{
|
|
5339
|
+
"name": "newOwner",
|
|
5340
|
+
"type": "address",
|
|
5341
|
+
"indexed": true,
|
|
5342
|
+
"internalType": "address"
|
|
5343
|
+
}
|
|
5344
|
+
],
|
|
5345
|
+
"anonymous": false
|
|
5346
|
+
},
|
|
5347
|
+
{
|
|
5348
|
+
"type": "event",
|
|
5349
|
+
"name": "RefundClaimed",
|
|
5350
|
+
"inputs": [
|
|
5351
|
+
{
|
|
5352
|
+
"name": "jobId",
|
|
5353
|
+
"type": "uint256",
|
|
5354
|
+
"indexed": true,
|
|
5355
|
+
"internalType": "uint256"
|
|
5356
|
+
},
|
|
5357
|
+
{
|
|
5358
|
+
"name": "payer",
|
|
5359
|
+
"type": "address",
|
|
5360
|
+
"indexed": true,
|
|
5361
|
+
"internalType": "address"
|
|
5362
|
+
},
|
|
5363
|
+
{
|
|
5364
|
+
"name": "amount",
|
|
5365
|
+
"type": "uint256",
|
|
5366
|
+
"indexed": false,
|
|
5367
|
+
"internalType": "uint256"
|
|
5368
|
+
}
|
|
5369
|
+
],
|
|
5370
|
+
"anonymous": false
|
|
5371
|
+
},
|
|
5372
|
+
{
|
|
5373
|
+
"type": "error",
|
|
5374
|
+
"name": "AgentAlreadyInitialized",
|
|
5375
|
+
"inputs": []
|
|
5376
|
+
},
|
|
5377
|
+
{
|
|
5378
|
+
"type": "error",
|
|
5379
|
+
"name": "AgentNotActive",
|
|
5380
|
+
"inputs": []
|
|
5381
|
+
},
|
|
5382
|
+
{
|
|
5383
|
+
"type": "error",
|
|
5384
|
+
"name": "InsufficientPayment",
|
|
5385
|
+
"inputs": [
|
|
5386
|
+
{
|
|
5387
|
+
"name": "required",
|
|
5388
|
+
"type": "uint256",
|
|
5389
|
+
"internalType": "uint256"
|
|
5390
|
+
},
|
|
5391
|
+
{
|
|
5392
|
+
"name": "provided",
|
|
5393
|
+
"type": "uint256",
|
|
5394
|
+
"internalType": "uint256"
|
|
5395
|
+
}
|
|
5396
|
+
]
|
|
5397
|
+
},
|
|
5398
|
+
{
|
|
5399
|
+
"type": "error",
|
|
5400
|
+
"name": "InvalidJobStatus",
|
|
5401
|
+
"inputs": [
|
|
5402
|
+
{
|
|
5403
|
+
"name": "current",
|
|
5404
|
+
"type": "uint8",
|
|
5405
|
+
"internalType": "enum DataTypes.JobStatus"
|
|
5406
|
+
},
|
|
5407
|
+
{
|
|
5408
|
+
"name": "expected",
|
|
5409
|
+
"type": "uint8",
|
|
5410
|
+
"internalType": "enum DataTypes.JobStatus"
|
|
5411
|
+
}
|
|
5412
|
+
]
|
|
5413
|
+
},
|
|
5414
|
+
{
|
|
5415
|
+
"type": "error",
|
|
5416
|
+
"name": "InvalidRefundState",
|
|
5417
|
+
"inputs": [
|
|
5418
|
+
{
|
|
5419
|
+
"name": "current",
|
|
5420
|
+
"type": "uint8",
|
|
5421
|
+
"internalType": "enum IBuyerRelay.RefundState"
|
|
5422
|
+
},
|
|
5423
|
+
{
|
|
5424
|
+
"name": "expected",
|
|
5425
|
+
"type": "uint8",
|
|
5426
|
+
"internalType": "enum IBuyerRelay.RefundState"
|
|
5427
|
+
}
|
|
5428
|
+
]
|
|
5429
|
+
},
|
|
5430
|
+
{
|
|
5431
|
+
"type": "error",
|
|
5432
|
+
"name": "OnlyBuyer",
|
|
5433
|
+
"inputs": []
|
|
5434
|
+
},
|
|
5435
|
+
{
|
|
5436
|
+
"type": "error",
|
|
5437
|
+
"name": "OwnableInvalidOwner",
|
|
5438
|
+
"inputs": [
|
|
5439
|
+
{
|
|
5440
|
+
"name": "owner",
|
|
5441
|
+
"type": "address",
|
|
5442
|
+
"internalType": "address"
|
|
5443
|
+
}
|
|
5444
|
+
]
|
|
5445
|
+
},
|
|
5446
|
+
{
|
|
5447
|
+
"type": "error",
|
|
5448
|
+
"name": "OwnableUnauthorizedAccount",
|
|
5449
|
+
"inputs": [
|
|
5450
|
+
{
|
|
5451
|
+
"name": "account",
|
|
5452
|
+
"type": "address",
|
|
5453
|
+
"internalType": "address"
|
|
5454
|
+
}
|
|
5455
|
+
]
|
|
5456
|
+
},
|
|
5457
|
+
{
|
|
5458
|
+
"type": "error",
|
|
5459
|
+
"name": "Reentrancy",
|
|
5460
|
+
"inputs": []
|
|
5461
|
+
},
|
|
5462
|
+
{
|
|
5463
|
+
"type": "error",
|
|
5464
|
+
"name": "ZeroAddress",
|
|
5465
|
+
"inputs": []
|
|
5466
|
+
}
|
|
5467
|
+
];
|
|
4256
5468
|
export {
|
|
4257
5469
|
ACCEPT_TIMEOUT,
|
|
4258
5470
|
BPS_DENOMINATOR,
|
|
@@ -4266,15 +5478,19 @@ export {
|
|
|
4266
5478
|
JobStatus,
|
|
4267
5479
|
MAINNET_ADDRESSES,
|
|
4268
5480
|
MEMO_TYPES,
|
|
5481
|
+
PLATFORM_BUYER_AGENT_ID,
|
|
4269
5482
|
PULSE_DOMAIN,
|
|
4270
5483
|
ProviderRuntime,
|
|
4271
5484
|
RISK_POOL_BPS,
|
|
4272
5485
|
ServiceType,
|
|
5486
|
+
SiteModifierHandler,
|
|
4273
5487
|
TESTNET_ADDRESSES,
|
|
4274
5488
|
TREASURY_BPS,
|
|
4275
5489
|
USDM_MAINNET,
|
|
4276
5490
|
acceptJob,
|
|
4277
5491
|
activateOffering,
|
|
5492
|
+
buyerRelayAbi,
|
|
5493
|
+
callAI,
|
|
4278
5494
|
cancelJob,
|
|
4279
5495
|
createAgentCard,
|
|
4280
5496
|
createDeliverable,
|
|
@@ -4317,6 +5533,8 @@ export {
|
|
|
4317
5533
|
readWarrenMaster,
|
|
4318
5534
|
readWarrenPage,
|
|
4319
5535
|
registerAgent,
|
|
5536
|
+
rejectJob,
|
|
5537
|
+
resolveDispute,
|
|
4320
5538
|
serviceMarketplaceAbi,
|
|
4321
5539
|
setOperator,
|
|
4322
5540
|
setWarrenContract,
|