@agalmic/contextengine 0.1.2 → 0.2.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/README.md +42 -22
- package/dist/contextengine.mjs +413 -267
- package/package.json +1 -1
package/dist/contextengine.mjs
CHANGED
|
@@ -7618,8 +7618,8 @@ var require_bytes32 = __commonJS({
|
|
|
7618
7618
|
var constants_1 = require_lib8();
|
|
7619
7619
|
var bytes_1 = require_lib2();
|
|
7620
7620
|
var utf8_1 = require_utf8();
|
|
7621
|
-
function formatBytes32String(
|
|
7622
|
-
var bytes = (0, utf8_1.toUtf8Bytes)(
|
|
7621
|
+
function formatBytes32String(text5) {
|
|
7622
|
+
var bytes = (0, utf8_1.toUtf8Bytes)(text5);
|
|
7623
7623
|
if (bytes.length > 31) {
|
|
7624
7624
|
throw new Error("bytes32 string must be less than 32 bytes");
|
|
7625
7625
|
}
|
|
@@ -8137,8 +8137,8 @@ var require_id = __commonJS({
|
|
|
8137
8137
|
exports.id = void 0;
|
|
8138
8138
|
var keccak256_1 = require_lib5();
|
|
8139
8139
|
var strings_1 = require_lib9();
|
|
8140
|
-
function id(
|
|
8141
|
-
return (0, keccak256_1.keccak256)((0, strings_1.toUtf8Bytes)(
|
|
8140
|
+
function id(text5) {
|
|
8141
|
+
return (0, keccak256_1.keccak256)((0, strings_1.toUtf8Bytes)(text5));
|
|
8142
8142
|
}
|
|
8143
8143
|
exports.id = id;
|
|
8144
8144
|
}
|
|
@@ -21923,13 +21923,13 @@ var require_aes_js = __commonJS({
|
|
|
21923
21923
|
targetArray.set(sourceArray, targetStart);
|
|
21924
21924
|
}
|
|
21925
21925
|
var convertUtf8 = /* @__PURE__ */ (function() {
|
|
21926
|
-
function toBytes(
|
|
21926
|
+
function toBytes(text5) {
|
|
21927
21927
|
var result = [], i = 0;
|
|
21928
|
-
|
|
21929
|
-
while (i <
|
|
21930
|
-
var c =
|
|
21928
|
+
text5 = encodeURI(text5);
|
|
21929
|
+
while (i < text5.length) {
|
|
21930
|
+
var c = text5.charCodeAt(i++);
|
|
21931
21931
|
if (c === 37) {
|
|
21932
|
-
result.push(parseInt(
|
|
21932
|
+
result.push(parseInt(text5.substr(i, 2), 16));
|
|
21933
21933
|
i += 2;
|
|
21934
21934
|
} else {
|
|
21935
21935
|
result.push(c);
|
|
@@ -21960,10 +21960,10 @@ var require_aes_js = __commonJS({
|
|
|
21960
21960
|
};
|
|
21961
21961
|
})();
|
|
21962
21962
|
var convertHex = /* @__PURE__ */ (function() {
|
|
21963
|
-
function toBytes(
|
|
21963
|
+
function toBytes(text5) {
|
|
21964
21964
|
var result = [];
|
|
21965
|
-
for (var i = 0; i <
|
|
21966
|
-
result.push(parseInt(
|
|
21965
|
+
for (var i = 0; i < text5.length; i += 2) {
|
|
21966
|
+
result.push(parseInt(text5.substr(i, 2), 16));
|
|
21967
21967
|
}
|
|
21968
21968
|
return result;
|
|
21969
21969
|
}
|
|
@@ -32137,7 +32137,7 @@ var require_websocket_server = __commonJS({
|
|
|
32137
32137
|
const ws = new WebSocket(null);
|
|
32138
32138
|
let protocol = req.headers["sec-websocket-protocol"];
|
|
32139
32139
|
if (protocol) {
|
|
32140
|
-
protocol = protocol.split(",").map(
|
|
32140
|
+
protocol = protocol.split(",").map(trim9);
|
|
32141
32141
|
if (this.options.handleProtocols) {
|
|
32142
32142
|
protocol = this.options.handleProtocols(protocol, req);
|
|
32143
32143
|
} else {
|
|
@@ -32206,7 +32206,7 @@ var require_websocket_server = __commonJS({
|
|
|
32206
32206
|
socket.removeListener("error", socketOnError);
|
|
32207
32207
|
socket.destroy();
|
|
32208
32208
|
}
|
|
32209
|
-
function
|
|
32209
|
+
function trim9(str) {
|
|
32210
32210
|
return str.trim();
|
|
32211
32211
|
}
|
|
32212
32212
|
}
|
|
@@ -36406,15 +36406,15 @@ var SETTINGS = Object.freeze({
|
|
|
36406
36406
|
var MAX_LABEL_LENGTH = 80;
|
|
36407
36407
|
var trim = (value) => String(value ?? "").trim();
|
|
36408
36408
|
var normalizeLabel = (value, field) => {
|
|
36409
|
-
const
|
|
36410
|
-
if (
|
|
36411
|
-
return
|
|
36409
|
+
const text5 = trim(value).replace(/\s+/g, " ");
|
|
36410
|
+
if (text5.length > MAX_LABEL_LENGTH) throw new Error(`${field} must be ${MAX_LABEL_LENGTH} characters or fewer.`);
|
|
36411
|
+
return text5;
|
|
36412
36412
|
};
|
|
36413
36413
|
var normalizeHttpOrigin = (value, field) => {
|
|
36414
|
-
const
|
|
36414
|
+
const text5 = trim(value);
|
|
36415
36415
|
let parsed;
|
|
36416
36416
|
try {
|
|
36417
|
-
parsed = new URL(
|
|
36417
|
+
parsed = new URL(text5);
|
|
36418
36418
|
} catch {
|
|
36419
36419
|
throw new Error(`${field} must be an http(s) origin.`);
|
|
36420
36420
|
}
|
|
@@ -36425,11 +36425,11 @@ var normalizeHttpOrigin = (value, field) => {
|
|
|
36425
36425
|
};
|
|
36426
36426
|
var isLocalUrl = (url) => ["localhost", "127.0.0.1", "[::1]"].includes(url.hostname);
|
|
36427
36427
|
var normalizeRpcUrl = (value, allowLocal) => {
|
|
36428
|
-
const
|
|
36429
|
-
if (!
|
|
36428
|
+
const text5 = trim(value);
|
|
36429
|
+
if (!text5) return "";
|
|
36430
36430
|
let parsed;
|
|
36431
36431
|
try {
|
|
36432
|
-
parsed = new URL(
|
|
36432
|
+
parsed = new URL(text5);
|
|
36433
36433
|
} catch {
|
|
36434
36434
|
throw new Error("CE_MCP_RPC_URL must be an https URL.");
|
|
36435
36435
|
}
|
|
@@ -36494,13 +36494,22 @@ var ensureStateDir = async (stateDir) => {
|
|
|
36494
36494
|
var writeOwnerOnlyJson = async (filePath, value, { exclusive = false } = {}) => {
|
|
36495
36495
|
const body = `${JSON.stringify(value, null, 2)}
|
|
36496
36496
|
`;
|
|
36497
|
-
if (exclusive) {
|
|
36498
|
-
await fs.writeFile(filePath, body, { mode: OWNER_ONLY_FILE, flag: "wx" });
|
|
36499
|
-
return;
|
|
36500
|
-
}
|
|
36501
36497
|
const temporary = `${filePath}.${process.pid}.${crypto.randomBytes(6).toString("hex")}.tmp`;
|
|
36502
36498
|
await fs.writeFile(temporary, body, { mode: OWNER_ONLY_FILE, flag: "wx" });
|
|
36503
|
-
|
|
36499
|
+
try {
|
|
36500
|
+
if (exclusive) {
|
|
36501
|
+
try {
|
|
36502
|
+
await fs.link(temporary, filePath);
|
|
36503
|
+
} catch (error) {
|
|
36504
|
+
if (!["EPERM", "ENOTSUP", "EXDEV"].includes(error?.code)) throw error;
|
|
36505
|
+
await fs.writeFile(filePath, body, { mode: OWNER_ONLY_FILE, flag: "wx" });
|
|
36506
|
+
}
|
|
36507
|
+
} else {
|
|
36508
|
+
await fs.rename(temporary, filePath);
|
|
36509
|
+
}
|
|
36510
|
+
} finally {
|
|
36511
|
+
await fs.rm(temporary, { force: true });
|
|
36512
|
+
}
|
|
36504
36513
|
};
|
|
36505
36514
|
var readKeyFile = async (keyPath) => {
|
|
36506
36515
|
const info = await fs.lstat(keyPath);
|
|
@@ -36631,9 +36640,9 @@ var DIAGNOSTICS = /\[ See: |\((?=\w+=)|\b(?:requestBody|body|url|transaction|dat
|
|
|
36631
36640
|
var URLS = /\b[a-z][\w+.-]*:\/\/[^\s"'`]+/gi;
|
|
36632
36641
|
var hostOnly = (url) => /<\w+>/.test(url) ? url : url.replace(/^([^:]+:\/\/)(?:[^/?#]*@)?([^/?#]*)[\s\S]*$/, "$1$2");
|
|
36633
36642
|
var describeError = (error) => {
|
|
36634
|
-
const
|
|
36635
|
-
const cut =
|
|
36636
|
-
return (cut < 0 ?
|
|
36643
|
+
const text5 = String(error?.message || error || "").slice(0, MAX_ERROR_LENGTH);
|
|
36644
|
+
const cut = text5.search(DIAGNOSTICS);
|
|
36645
|
+
return (cut < 0 ? text5 : text5.slice(0, cut)).trimEnd().replace(URLS, hostOnly) || "Unknown error.";
|
|
36637
36646
|
};
|
|
36638
36647
|
var DEFAULT_TOOL_TIMEOUT_MS = 15 * 60 * 1e3;
|
|
36639
36648
|
var createMcpServer = ({
|
|
@@ -36656,8 +36665,8 @@ var createMcpServer = ({
|
|
|
36656
36665
|
...annotations ? { annotations } : {}
|
|
36657
36666
|
}));
|
|
36658
36667
|
const toolResult = (value, isError = false) => {
|
|
36659
|
-
const
|
|
36660
|
-
const result = { content: [{ type: "text", text:
|
|
36668
|
+
const text5 = typeof value === "string" ? value : JSON.stringify(value, null, 2);
|
|
36669
|
+
const result = { content: [{ type: "text", text: text5 }] };
|
|
36661
36670
|
if (!isError && isRecord2(value) && protocolVersion >= STRUCTURED_CONTENT_SINCE) {
|
|
36662
36671
|
result.structuredContent = value;
|
|
36663
36672
|
}
|
|
@@ -36752,11 +36761,11 @@ var createMcpServer = ({
|
|
|
36752
36761
|
}
|
|
36753
36762
|
};
|
|
36754
36763
|
const handleLine = async (line) => {
|
|
36755
|
-
const
|
|
36756
|
-
if (!
|
|
36764
|
+
const text5 = String(line || "").trim();
|
|
36765
|
+
if (!text5) return "";
|
|
36757
36766
|
let decoded;
|
|
36758
36767
|
try {
|
|
36759
|
-
decoded = JSON.parse(
|
|
36768
|
+
decoded = JSON.parse(text5);
|
|
36760
36769
|
} catch {
|
|
36761
36770
|
return JSON.stringify(errorResponse(null, PARSE_ERROR, "Parse error."));
|
|
36762
36771
|
}
|
|
@@ -36905,6 +36914,7 @@ var createTestEthRequester = ({
|
|
|
36905
36914
|
paid = await ctx.client.request("/", {
|
|
36906
36915
|
method: "POST",
|
|
36907
36916
|
auth: true,
|
|
36917
|
+
signal,
|
|
36908
36918
|
headers: { "X-Session-Slug": ctx.info.slug },
|
|
36909
36919
|
body: { action: "request_test_eth", to: wallet.address }
|
|
36910
36920
|
});
|
|
@@ -36961,6 +36971,17 @@ import { createHash, randomUUID as randomUUID2 } from "node:crypto";
|
|
|
36961
36971
|
// mcp/lib/registrySession.mjs
|
|
36962
36972
|
var import_ethers5 = __toESM(require_lib32(), 1);
|
|
36963
36973
|
|
|
36974
|
+
// shared/responseReadWindow.mjs
|
|
36975
|
+
var responsePairKey = (responder, id) => `${String(responder || "").toLowerCase()}|${String(id || "").toLowerCase()}`;
|
|
36976
|
+
var responseReadWindowOptions = (window2, responder, id) => window2 ? {
|
|
36977
|
+
_responseReadWindow: window2,
|
|
36978
|
+
blockTag: window2.laterPairs && !window2.laterPairs.has(responsePairKey(responder, id)) ? window2.unchangedBlockTag : window2.blockTag
|
|
36979
|
+
} : {};
|
|
36980
|
+
var historicalResponseReadError = (error, blockTag) => Object.assign(
|
|
36981
|
+
new Error(`Response state at block ${String(blockTag)} is unavailable: ${error instanceof Error ? error.message : String(error)}`),
|
|
36982
|
+
{ code: "RESPONSE_HISTORY_UNAVAILABLE", retryable: true, blockTag, cause: error }
|
|
36983
|
+
);
|
|
36984
|
+
|
|
36964
36985
|
// client/src/variables/contracts.json
|
|
36965
36986
|
var contracts_default = {
|
|
36966
36987
|
sessionRegistryAddresses: {
|
|
@@ -38202,40 +38223,6 @@ function summarizeQuadraticAllocations(responses, question) {
|
|
|
38202
38223
|
return { options, totalResponders, excludedResponses };
|
|
38203
38224
|
}
|
|
38204
38225
|
|
|
38205
|
-
// shared/questions/questionId.mjs
|
|
38206
|
-
var validOptions = (options) => Array.isArray(options) ? options.filter((o) => o && o.trim() !== "") : [];
|
|
38207
|
-
var legacyPreimage = (type, prompt, options, singleSelect, voiceCredits) => {
|
|
38208
|
-
let preimage = `${type}:${(prompt || "").trim().toLowerCase()}`;
|
|
38209
|
-
const validOpts = validOptions(options);
|
|
38210
|
-
if (type === "multichoice") {
|
|
38211
|
-
if (validOpts.length > 0)
|
|
38212
|
-
preimage += `:${validOpts.map((o) => o.trim()).join(",").toLowerCase()}`;
|
|
38213
|
-
if (singleSelect) preimage += ":single";
|
|
38214
|
-
}
|
|
38215
|
-
if (type === "quadratic") {
|
|
38216
|
-
preimage += `:${JSON.stringify(validOpts.map((option) => option.trim().toLowerCase()))}:${voiceCredits}`;
|
|
38217
|
-
}
|
|
38218
|
-
return preimage;
|
|
38219
|
-
};
|
|
38220
|
-
var legacyIsAmbiguous = (type, options, singleSelect) => {
|
|
38221
|
-
if (type !== "multichoice") return false;
|
|
38222
|
-
const labels = validOptions(options).map((o) => o.trim().toLowerCase());
|
|
38223
|
-
return labels.length === 0 || labels.some((label) => label.includes(":") || label.includes(",")) || !singleSelect && labels.length === 1 && labels[0] === "single";
|
|
38224
|
-
};
|
|
38225
|
-
var v2Text = (text4) => (text4 || "").trim().toLowerCase().normalize("NFC");
|
|
38226
|
-
var v2Preimage = (type, prompt, options, singleSelect) => JSON.stringify(["ce-question-id", 2, type, v2Text(prompt), validOptions(options).map(v2Text), !!singleSelect]);
|
|
38227
|
-
var createQuestionIdDerivation = (ethers7) => {
|
|
38228
|
-
const { id: hash } = ethers7.utils;
|
|
38229
|
-
const generateQuestionId2 = (type, prompt, options = [], singleSelect = false, voiceCredits = 99) => hash(
|
|
38230
|
-
legacyIsAmbiguous(type, options, singleSelect) ? v2Preimage(type, prompt, options, singleSelect) : legacyPreimage(type, prompt, options, singleSelect, voiceCredits)
|
|
38231
|
-
);
|
|
38232
|
-
const questionIdMatchesContent2 = (id, { type, prompt, options = [], singleSelect = false, voiceCredits = 99 } = {}) => {
|
|
38233
|
-
const wanted = String(id).toLowerCase();
|
|
38234
|
-
return hash(legacyPreimage(type, prompt, options, singleSelect, voiceCredits)) === wanted || type === "multichoice" && hash(v2Preimage(type, prompt, options, singleSelect)) === wanted;
|
|
38235
|
-
};
|
|
38236
|
-
return Object.freeze({ generateQuestionId: generateQuestionId2, questionIdMatchesContent: questionIdMatchesContent2 });
|
|
38237
|
-
};
|
|
38238
|
-
|
|
38239
38226
|
// shared/questions/ratingScale.mjs
|
|
38240
38227
|
var trim2 = (value) => String(value == null ? "" : value).trim();
|
|
38241
38228
|
var isObj = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
@@ -38290,39 +38277,41 @@ var normalizeRatingScale = (question = {}) => {
|
|
|
38290
38277
|
)
|
|
38291
38278
|
};
|
|
38292
38279
|
};
|
|
38280
|
+
var DEFAULT_RATING_SCALE = Object.freeze({ min: 0, max: 10, minLabel: "0", maxLabel: "10" });
|
|
38281
|
+
var ratingStepFor = (question = {}) => {
|
|
38282
|
+
const source = [question.scale, question.ratingScale].find((record) => isObj(record) && recordHasRatingScaleMetadata(record)) || question;
|
|
38283
|
+
const step = Number(source.step);
|
|
38284
|
+
return Number.isFinite(step) && step > 0 ? step : 1;
|
|
38285
|
+
};
|
|
38286
|
+
var decimalPlaces = (value) => {
|
|
38287
|
+
const [coefficient, exponent = "0"] = String(value).split("e");
|
|
38288
|
+
return Math.max(0, (coefficient.split(".")[1]?.length || 0) - Number(exponent));
|
|
38289
|
+
};
|
|
38290
|
+
var normalizeRatingAnswer = (value, question = {}) => {
|
|
38291
|
+
if (typeof value !== "number" && typeof value !== "string") return null;
|
|
38292
|
+
if (typeof value === "string" && value.trim() === "") return null;
|
|
38293
|
+
const number = Number(value);
|
|
38294
|
+
const { min, max } = normalizeRatingScale(question) || DEFAULT_RATING_SCALE;
|
|
38295
|
+
const step = ratingStepFor(question);
|
|
38296
|
+
const index = (number - min) / step;
|
|
38297
|
+
if (!Number.isFinite(number) || number < min || number > max || !Number.isFinite(index) || Math.abs(index - Math.round(index)) > 1e-9) return null;
|
|
38298
|
+
const precision = Math.min(100, Math.max(decimalPlaces(step), decimalPlaces(min)));
|
|
38299
|
+
return Number((min + Math.round(index) * step).toFixed(precision));
|
|
38300
|
+
};
|
|
38293
38301
|
|
|
38294
|
-
//
|
|
38302
|
+
// shared/questions/answerValue.mjs
|
|
38295
38303
|
var QUESTION_TYPES = Object.freeze(["binary", "rating", "multichoice", "quadratic", "freeform"]);
|
|
38296
38304
|
var BINARY_ANSWERS = Object.freeze(["Agree", "Unsure", "Disagree"]);
|
|
38297
|
-
var MAX_PROMPT_LENGTH = 1e3;
|
|
38298
|
-
var MAX_OPTION_LENGTH = 200;
|
|
38299
|
-
var MAX_OPTIONS = 12;
|
|
38300
|
-
var MAX_TAGS = 10;
|
|
38301
|
-
var MAX_TAG_LENGTH = 40;
|
|
38302
38305
|
var MAX_FREEFORM_LENGTH = 8e3;
|
|
38303
|
-
var MAX_COMMENT_LENGTH = 4e3;
|
|
38304
38306
|
var trim3 = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
38305
|
-
var isRecord3 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
38306
38307
|
var fail = (error) => ({ ok: false, error });
|
|
38307
|
-
var
|
|
38308
|
-
var ratingScaleFor = (question = {}) => normalizeRatingScale(question) || { min: 0, max: 10, minLabel: "0", maxLabel: "10" };
|
|
38308
|
+
var ratingScaleFor = (question = {}) => ({ ...normalizeRatingScale(question) || DEFAULT_RATING_SCALE, step: ratingStepFor(question) });
|
|
38309
38309
|
var optionsOf = (question) => Array.isArray(question.options) ? question.options.filter((option) => typeof option === "string") : [];
|
|
38310
38310
|
var isSingleSelect = (question) => question.singleSelect === true || question.oneSelectionOnly === true || question.singleChoice === true;
|
|
38311
|
-
var isLockedQuestion = (question) => question?.locked === true || !!question?.promptEncrypted || !!question?.encryption && typeof question.encryption === "object" || typeof question?.prompt === "string" && question.prompt.trim() === "[encrypted]";
|
|
38312
|
-
var normalizeRecruitmentSource = (value) => {
|
|
38313
|
-
const normalized2 = (typeof value === "string" ? value : "").trim().replace(/\s+/g, "-").slice(0, 128);
|
|
38314
|
-
return /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(normalized2) ? normalized2 : "";
|
|
38315
|
-
};
|
|
38316
38311
|
var matchOption = (options, value) => {
|
|
38317
38312
|
const wanted = trim3(value).toLowerCase();
|
|
38318
38313
|
return options.find((option) => option.trim().toLowerCase() === wanted);
|
|
38319
38314
|
};
|
|
38320
|
-
var readScore = (value, field) => {
|
|
38321
|
-
if (value === void 0 || value === null || value === "") return { ok: true, value: null };
|
|
38322
|
-
const number = Number(value);
|
|
38323
|
-
if (!Number.isInteger(number) || number < 0 || number > 10) return fail(`${field} must be a whole number from 0 to 10.`);
|
|
38324
|
-
return { ok: true, value: number };
|
|
38325
|
-
};
|
|
38326
38315
|
var normalizeAnswerValue = (question = {}, value) => {
|
|
38327
38316
|
switch (question.type) {
|
|
38328
38317
|
case "binary": {
|
|
@@ -38331,9 +38320,9 @@ var normalizeAnswerValue = (question = {}, value) => {
|
|
|
38331
38320
|
}
|
|
38332
38321
|
case "rating": {
|
|
38333
38322
|
const scale = ratingScaleFor(question);
|
|
38334
|
-
const number =
|
|
38335
|
-
if (
|
|
38336
|
-
return fail(`Rating answers must be
|
|
38323
|
+
const number = normalizeRatingAnswer(value, question);
|
|
38324
|
+
if (number === null) {
|
|
38325
|
+
return fail(`Rating answers must be from ${scale.min} to ${scale.max} in increments of ${scale.step} from ${scale.min}.`);
|
|
38337
38326
|
}
|
|
38338
38327
|
return { ok: true, value: number };
|
|
38339
38328
|
}
|
|
@@ -38361,15 +38350,72 @@ var normalizeAnswerValue = (question = {}, value) => {
|
|
|
38361
38350
|
return { ok: true, value: votes };
|
|
38362
38351
|
}
|
|
38363
38352
|
case "freeform": {
|
|
38364
|
-
const
|
|
38365
|
-
if (!
|
|
38366
|
-
if (
|
|
38367
|
-
return { ok: true, value:
|
|
38353
|
+
const text5 = trim3(value);
|
|
38354
|
+
if (!text5) return fail("Freeform answers must be non-empty text.");
|
|
38355
|
+
if (text5.length > MAX_FREEFORM_LENGTH) return fail(`Freeform answers must be ${MAX_FREEFORM_LENGTH} characters or fewer.`);
|
|
38356
|
+
return { ok: true, value: text5 };
|
|
38368
38357
|
}
|
|
38369
38358
|
default:
|
|
38370
38359
|
return fail(`Unsupported question type "${trim3(question.type)}".`);
|
|
38371
38360
|
}
|
|
38372
38361
|
};
|
|
38362
|
+
|
|
38363
|
+
// shared/questions/questionId.mjs
|
|
38364
|
+
var validOptions = (options) => Array.isArray(options) ? options.filter((o) => o && o.trim() !== "") : [];
|
|
38365
|
+
var legacyPreimage = (type, prompt, options, singleSelect, voiceCredits) => {
|
|
38366
|
+
let preimage = `${type}:${(prompt || "").trim().toLowerCase()}`;
|
|
38367
|
+
const validOpts = validOptions(options);
|
|
38368
|
+
if (type === "multichoice") {
|
|
38369
|
+
if (validOpts.length > 0)
|
|
38370
|
+
preimage += `:${validOpts.map((o) => o.trim()).join(",").toLowerCase()}`;
|
|
38371
|
+
if (singleSelect) preimage += ":single";
|
|
38372
|
+
}
|
|
38373
|
+
if (type === "quadratic") {
|
|
38374
|
+
preimage += `:${JSON.stringify(validOpts.map((option) => option.trim().toLowerCase()))}:${voiceCredits}`;
|
|
38375
|
+
}
|
|
38376
|
+
return preimage;
|
|
38377
|
+
};
|
|
38378
|
+
var legacyIsAmbiguous = (type, options, singleSelect) => {
|
|
38379
|
+
if (type !== "multichoice") return false;
|
|
38380
|
+
const labels = validOptions(options).map((o) => o.trim().toLowerCase());
|
|
38381
|
+
return labels.length === 0 || labels.some((label) => label.includes(":") || label.includes(",")) || !singleSelect && labels.length === 1 && labels[0] === "single";
|
|
38382
|
+
};
|
|
38383
|
+
var v2Text = (text5) => (text5 || "").trim().toLowerCase().normalize("NFC");
|
|
38384
|
+
var v2Preimage = (type, prompt, options, singleSelect) => JSON.stringify(["ce-question-id", 2, type, v2Text(prompt), validOptions(options).map(v2Text), !!singleSelect]);
|
|
38385
|
+
var createQuestionIdDerivation = (ethers7) => {
|
|
38386
|
+
const { id: hash } = ethers7.utils;
|
|
38387
|
+
const generateQuestionId2 = (type, prompt, options = [], singleSelect = false, voiceCredits = 99) => hash(
|
|
38388
|
+
legacyIsAmbiguous(type, options, singleSelect) ? v2Preimage(type, prompt, options, singleSelect) : legacyPreimage(type, prompt, options, singleSelect, voiceCredits)
|
|
38389
|
+
);
|
|
38390
|
+
const questionIdMatchesContent2 = (id, { type, prompt, options = [], singleSelect = false, voiceCredits = 99 } = {}) => {
|
|
38391
|
+
const wanted = String(id).toLowerCase();
|
|
38392
|
+
return hash(legacyPreimage(type, prompt, options, singleSelect, voiceCredits)) === wanted || type === "multichoice" && hash(v2Preimage(type, prompt, options, singleSelect)) === wanted;
|
|
38393
|
+
};
|
|
38394
|
+
return Object.freeze({ generateQuestionId: generateQuestionId2, questionIdMatchesContent: questionIdMatchesContent2 });
|
|
38395
|
+
};
|
|
38396
|
+
|
|
38397
|
+
// mcp/lib/records.mjs
|
|
38398
|
+
var MAX_PROMPT_LENGTH = 1e3;
|
|
38399
|
+
var MAX_OPTION_LENGTH = 200;
|
|
38400
|
+
var MAX_OPTIONS = 12;
|
|
38401
|
+
var MAX_TAGS = 10;
|
|
38402
|
+
var MAX_TAG_LENGTH = 40;
|
|
38403
|
+
var MAX_COMMENT_LENGTH = 4e3;
|
|
38404
|
+
var trim4 = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
38405
|
+
var isRecord3 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
38406
|
+
var fail2 = (error) => ({ ok: false, error });
|
|
38407
|
+
var { generateQuestionId, questionIdMatchesContent } = createQuestionIdDerivation(import_ethers3.ethers);
|
|
38408
|
+
var isLockedQuestion = (question) => question?.locked === true || !!question?.promptEncrypted || !!question?.encryption && typeof question.encryption === "object" || typeof question?.prompt === "string" && question.prompt.trim() === "[encrypted]";
|
|
38409
|
+
var normalizeRecruitmentSource = (value) => {
|
|
38410
|
+
const normalized2 = (typeof value === "string" ? value : "").trim().replace(/\s+/g, "-").slice(0, 128);
|
|
38411
|
+
return /^[a-zA-Z0-9][a-zA-Z0-9._:-]{0,127}$/.test(normalized2) ? normalized2 : "";
|
|
38412
|
+
};
|
|
38413
|
+
var readScore = (value, field) => {
|
|
38414
|
+
if (value === void 0 || value === null || value === "") return { ok: true, value: null };
|
|
38415
|
+
const number = Number(value);
|
|
38416
|
+
if (!Number.isInteger(number) || number < 0 || number > 10) return fail2(`${field} must be a whole number from 0 to 10.`);
|
|
38417
|
+
return { ok: true, value: number };
|
|
38418
|
+
};
|
|
38373
38419
|
var plaintextField = (value, hash) => ({
|
|
38374
38420
|
value,
|
|
38375
38421
|
encrypted: false,
|
|
@@ -38382,8 +38428,8 @@ var plaintextField = (value, hash) => ({
|
|
|
38382
38428
|
var textHash = (value) => typeof value === "string" && value ? import_ethers3.ethers.utils.id(value) : "";
|
|
38383
38429
|
var buildParticipantMarker = ({ modelId = "", platform = "" } = {}) => ({
|
|
38384
38430
|
kind: "agent",
|
|
38385
|
-
...
|
|
38386
|
-
...
|
|
38431
|
+
...trim4(modelId) ? { modelId: trim4(modelId) } : {},
|
|
38432
|
+
...trim4(platform) ? { platform: trim4(platform) } : {},
|
|
38387
38433
|
verification: "self_reported"
|
|
38388
38434
|
});
|
|
38389
38435
|
var buildResponseRecord = ({
|
|
@@ -38397,21 +38443,21 @@ var buildResponseRecord = ({
|
|
|
38397
38443
|
profile = {},
|
|
38398
38444
|
recruitmentSource = ""
|
|
38399
38445
|
}) => {
|
|
38400
|
-
if (!isRecord3(question) || !
|
|
38401
|
-
if (isLockedQuestion(question)) return
|
|
38446
|
+
if (!isRecord3(question) || !trim4(question.id)) return fail2("Unknown question.");
|
|
38447
|
+
if (isLockedQuestion(question)) return fail2("This question is locked to certain members; agents cannot answer locked questions yet.");
|
|
38402
38448
|
const answer = normalizeAnswerValue(question, value);
|
|
38403
38449
|
if (!answer.ok) return answer;
|
|
38404
|
-
const note =
|
|
38405
|
-
if (note.length > MAX_COMMENT_LENGTH) return
|
|
38450
|
+
const note = trim4(comment);
|
|
38451
|
+
if (note.length > MAX_COMMENT_LENGTH) return fail2(`Comments must be ${MAX_COMMENT_LENGTH} characters or fewer.`);
|
|
38406
38452
|
const convictionScore = readScore(conviction, "Conviction");
|
|
38407
38453
|
if (!convictionScore.ok) return convictionScore;
|
|
38408
38454
|
const importanceScore = readScore(importance, "Importance");
|
|
38409
38455
|
if (!importanceScore.ok) return importanceScore;
|
|
38410
|
-
const displayName =
|
|
38456
|
+
const displayName = trim4(profile.displayName);
|
|
38411
38457
|
return {
|
|
38412
38458
|
ok: true,
|
|
38413
38459
|
record: {
|
|
38414
|
-
questionID:
|
|
38460
|
+
questionID: trim4(question.id).toLowerCase(),
|
|
38415
38461
|
responder: import_ethers3.ethers.utils.getAddress(responder),
|
|
38416
38462
|
type: question.type,
|
|
38417
38463
|
prompt: typeof question.prompt === "string" ? question.prompt : "",
|
|
@@ -38429,19 +38475,19 @@ var buildResponseRecord = ({
|
|
|
38429
38475
|
};
|
|
38430
38476
|
};
|
|
38431
38477
|
var normalizeOptionList = (options) => {
|
|
38432
|
-
const list = (Array.isArray(options) ? options : []).map(
|
|
38433
|
-
if (list.length < 2) return
|
|
38434
|
-
if (list.length > MAX_OPTIONS) return
|
|
38435
|
-
if (list.some((option) => option.length > MAX_OPTION_LENGTH)) return
|
|
38436
|
-
if (new Set(list.map((option) => option.toLowerCase())).size !== list.length) return
|
|
38478
|
+
const list = (Array.isArray(options) ? options : []).map(trim4).filter(Boolean);
|
|
38479
|
+
if (list.length < 2) return fail2("Provide at least two options.");
|
|
38480
|
+
if (list.length > MAX_OPTIONS) return fail2(`Provide at most ${MAX_OPTIONS} options.`);
|
|
38481
|
+
if (list.some((option) => option.length > MAX_OPTION_LENGTH)) return fail2(`Options must be ${MAX_OPTION_LENGTH} characters or fewer.`);
|
|
38482
|
+
if (new Set(list.map((option) => option.toLowerCase())).size !== list.length) return fail2("Options must be unique.");
|
|
38437
38483
|
return { ok: true, value: list };
|
|
38438
38484
|
};
|
|
38439
38485
|
var buildQuestionRecord = ({ type = "binary", prompt, options, singleSelect = false, voiceCredits, tags = [], creator, session, profile = {} }) => {
|
|
38440
|
-
if (!QUESTION_TYPES.includes(type)) return
|
|
38441
|
-
const
|
|
38442
|
-
if (!
|
|
38443
|
-
if (
|
|
38444
|
-
const record = { id: "", type, prompt:
|
|
38486
|
+
if (!QUESTION_TYPES.includes(type)) return fail2(`Question type must be one of: ${QUESTION_TYPES.join(", ")}.`);
|
|
38487
|
+
const text5 = trim4(prompt);
|
|
38488
|
+
if (!text5) return fail2("The statement text is empty.");
|
|
38489
|
+
if (text5.length > MAX_PROMPT_LENGTH) return fail2(`Statements must be ${MAX_PROMPT_LENGTH} characters or fewer.`);
|
|
38490
|
+
const record = { id: "", type, prompt: text5 };
|
|
38445
38491
|
let optionList = [];
|
|
38446
38492
|
if (type === "multichoice" || type === "quadratic") {
|
|
38447
38493
|
const normalized2 = normalizeOptionList(options);
|
|
@@ -38455,20 +38501,20 @@ var buildQuestionRecord = ({ type = "binary", prompt, options, singleSelect = fa
|
|
|
38455
38501
|
credits = voiceCredits === void 0 || voiceCredits === null ? 99 : Number(voiceCredits);
|
|
38456
38502
|
record.voiceCredits = credits;
|
|
38457
38503
|
const error = validateQuadraticQuestion(record);
|
|
38458
|
-
if (error) return
|
|
38504
|
+
if (error) return fail2(error);
|
|
38459
38505
|
}
|
|
38460
|
-
const tagList = (Array.isArray(tags) ? tags : []).map(
|
|
38506
|
+
const tagList = (Array.isArray(tags) ? tags : []).map(trim4).filter(Boolean);
|
|
38461
38507
|
if (tagList.length > MAX_TAGS || tagList.some((tag) => tag.length > MAX_TAG_LENGTH)) {
|
|
38462
|
-
return
|
|
38508
|
+
return fail2(`Use at most ${MAX_TAGS} tags of ${MAX_TAG_LENGTH} characters or fewer.`);
|
|
38463
38509
|
}
|
|
38464
38510
|
record.tags = tagList;
|
|
38465
38511
|
record.creator = import_ethers3.ethers.utils.getAddress(creator);
|
|
38466
38512
|
record.associatedSurveyId = import_ethers3.ethers.constants.HashZero;
|
|
38467
38513
|
record.participant = buildParticipantMarker(profile);
|
|
38468
|
-
record.sessionName =
|
|
38514
|
+
record.sessionName = trim4(session.sessionName) || session.sessionSlug;
|
|
38469
38515
|
record.sessionSlug = session.sessionSlug;
|
|
38470
38516
|
record.sessionId = session.sessionId;
|
|
38471
|
-
record.id = generateQuestionId(type,
|
|
38517
|
+
record.id = generateQuestionId(type, text5, optionList, record.singleSelect === true, credits);
|
|
38472
38518
|
return { ok: true, id: record.id, record };
|
|
38473
38519
|
};
|
|
38474
38520
|
|
|
@@ -38476,9 +38522,9 @@ var buildQuestionRecord = ({ type = "binary", prompt, options, singleSelect = fa
|
|
|
38476
38522
|
var SLUG_RE = /^[a-z0-9_-]{1,128}$/;
|
|
38477
38523
|
var ADDRESS_RE = /^0x[0-9a-fA-F]{40}$/;
|
|
38478
38524
|
var GROUP_ID_RE = /^[A-Za-z0-9._:-]{1,128}$/;
|
|
38479
|
-
var
|
|
38525
|
+
var trim5 = (value) => String(value ?? "").trim();
|
|
38480
38526
|
var normalizeSessionSlug = (value) => {
|
|
38481
|
-
const slug =
|
|
38527
|
+
const slug = trim5(value).toLowerCase();
|
|
38482
38528
|
if (!SLUG_RE.test(slug)) throw new Error("Session slug must be 1-128 lowercase letters, digits, dashes, or underscores.");
|
|
38483
38529
|
return slug;
|
|
38484
38530
|
};
|
|
@@ -38501,9 +38547,9 @@ var readClaimPairs = (params) => {
|
|
|
38501
38547
|
const pairs = [];
|
|
38502
38548
|
const seen = /* @__PURE__ */ new Set();
|
|
38503
38549
|
const add = (sbt, gp, inv, auto) => {
|
|
38504
|
-
const address =
|
|
38550
|
+
const address = trim5(sbt);
|
|
38505
38551
|
if (!ADDRESS_RE.test(address)) return;
|
|
38506
|
-
const pair = { sbt: address, groupPassword:
|
|
38552
|
+
const pair = { sbt: address, groupPassword: trim5(gp), inviteCode: trim5(inv), auto };
|
|
38507
38553
|
const key = `${address.toLowerCase()}|${pair.groupPassword}|${pair.inviteCode}`;
|
|
38508
38554
|
if (seen.has(key)) return;
|
|
38509
38555
|
seen.add(key);
|
|
@@ -38521,7 +38567,7 @@ var readClaimPairs = (params) => {
|
|
|
38521
38567
|
var parseSessionLink = (link, { allowLocalWorkers = false } = {}) => {
|
|
38522
38568
|
let url;
|
|
38523
38569
|
try {
|
|
38524
|
-
url = new URL(
|
|
38570
|
+
url = new URL(trim5(link));
|
|
38525
38571
|
} catch {
|
|
38526
38572
|
throw new Error("Session link must be a full URL, such as https://contextengine.sh/session/<slug>?worker=<origin>.");
|
|
38527
38573
|
}
|
|
@@ -38534,7 +38580,7 @@ var parseSessionLink = (link, { allowLocalWorkers = false } = {}) => {
|
|
|
38534
38580
|
if (workers.length > 1) {
|
|
38535
38581
|
throw new Error("Session link must name exactly one hosted Worker when using ?worker=.");
|
|
38536
38582
|
}
|
|
38537
|
-
const joinGroup =
|
|
38583
|
+
const joinGroup = trim5(params.get("joinGroup"));
|
|
38538
38584
|
if (joinGroup && !GROUP_ID_RE.test(joinGroup)) throw new Error("Session link has an invalid group id.");
|
|
38539
38585
|
return {
|
|
38540
38586
|
appOrigin: normalizeHttpOrigin(url.origin, "Session link"),
|
|
@@ -38710,8 +38756,13 @@ var createWorkerClient = ({ workerOrigin, slug, trustedOrigins, wallet, fetchImp
|
|
|
38710
38756
|
let pendingLogin = null;
|
|
38711
38757
|
let presence = null;
|
|
38712
38758
|
let presenceLoadedAt = -Infinity;
|
|
38713
|
-
const request = async (path3, { method = "GET", headers = {}, body, auth = false, retried = false, maxBytes = MAX_RESPONSE_BYTES } = {}) => {
|
|
38759
|
+
const request = async (path3, { method = "GET", headers = {}, body, auth = false, retried = false, maxBytes = MAX_RESPONSE_BYTES, signal } = {}) => {
|
|
38760
|
+
const checkpoint = () => {
|
|
38761
|
+
if (signal?.aborted) throw new Error("Stopped before the Worker request was sent.");
|
|
38762
|
+
};
|
|
38763
|
+
checkpoint();
|
|
38714
38764
|
if (auth) await ensureToken();
|
|
38765
|
+
checkpoint();
|
|
38715
38766
|
let response;
|
|
38716
38767
|
try {
|
|
38717
38768
|
response = await fetchImpl(`${workerOrigin}${path3}`, {
|
|
@@ -38741,7 +38792,7 @@ var createWorkerClient = ({ workerOrigin, slug, trustedOrigins, wallet, fetchImp
|
|
|
38741
38792
|
const error = isRecord4(data) ? text(data.error) || text(data.message) : "";
|
|
38742
38793
|
if (response.status === 401 && auth && !retried && (!error || TOKEN_ERROR_RE.test(error))) {
|
|
38743
38794
|
token = "";
|
|
38744
|
-
return request(path3, { method, headers, body, auth, retried: true, maxBytes });
|
|
38795
|
+
return request(path3, { method, headers, body, auth, retried: true, maxBytes, signal });
|
|
38745
38796
|
}
|
|
38746
38797
|
if (response.status === 401 && error && !TOKEN_ERROR_RE.test(error)) {
|
|
38747
38798
|
throw new WorkerRequestError(error.slice(0, MAX_ERROR_DETAIL), { status: 401, code: error });
|
|
@@ -38859,15 +38910,16 @@ var createWorkerClient = ({ workerOrigin, slug, trustedOrigins, wallet, fetchImp
|
|
|
38859
38910
|
}
|
|
38860
38911
|
return data;
|
|
38861
38912
|
};
|
|
38862
|
-
const upload = async ({ resource, data, tags = [], requestId = "" }) => {
|
|
38913
|
+
const upload = async ({ resource, data, tags = [], requestId = "", signal }) => {
|
|
38863
38914
|
const result = await request("/storage/upload", {
|
|
38915
|
+
signal,
|
|
38864
38916
|
method: "POST",
|
|
38865
38917
|
auth: true,
|
|
38866
38918
|
body: { backend: "cloudflare", resource, contentType: "application/json", payloadEncrypted: false, tags, data, ...requestId ? { requestId } : {} }
|
|
38867
38919
|
});
|
|
38868
38920
|
return isRecord4(result?.storageRef) ? result.storageRef : { id: text(result?.id) };
|
|
38869
38921
|
};
|
|
38870
|
-
const joinGroup = (groupId) => request("/groups/join", { method: "POST", auth: true, body: { sessionId, groupId } });
|
|
38922
|
+
const joinGroup = (groupId, { signal } = {}) => request("/groups/join", { method: "POST", auth: true, signal, body: { sessionId, groupId } });
|
|
38871
38923
|
const describeTestEth = async () => {
|
|
38872
38924
|
await refreshConfig();
|
|
38873
38925
|
if (now() - presenceLoadedAt >= CONFIG_MAX_AGE_MS) {
|
|
@@ -39101,6 +39153,7 @@ var createRegistryWriter = ({ provider, chainId, wallet, surveys, slug, remember
|
|
|
39101
39153
|
if (offer.offered && offer.tokenHasFaucetScope !== false) {
|
|
39102
39154
|
let funding;
|
|
39103
39155
|
try {
|
|
39156
|
+
stopped(signal);
|
|
39104
39157
|
funding = await fund();
|
|
39105
39158
|
} catch (error) {
|
|
39106
39159
|
throw new Error(`${shortfall} ${String(error?.message || "The faucet request failed.").slice(0, 250)}`);
|
|
@@ -39117,7 +39170,7 @@ var createRegistryWriter = ({ provider, chainId, wallet, surveys, slug, remember
|
|
|
39117
39170
|
};
|
|
39118
39171
|
const upload = async (client, resource, id, record, signal) => {
|
|
39119
39172
|
stopped(signal);
|
|
39120
|
-
const result = await client.request("/arweave/upload", { method: "POST", auth: true, body: {
|
|
39173
|
+
const result = await client.request("/arweave/upload", { method: "POST", auth: true, signal, body: {
|
|
39121
39174
|
data: JSON.stringify(record),
|
|
39122
39175
|
contentType: "application/json",
|
|
39123
39176
|
requestId: randomUUID(),
|
|
@@ -39163,6 +39216,7 @@ var createRegistryWriter = ({ provider, chainId, wallet, surveys, slug, remember
|
|
|
39163
39216
|
for (const record of records) pointers.push(await upload(client, "responses", record.questionID, record, signal));
|
|
39164
39217
|
stopped(signal);
|
|
39165
39218
|
await checkChain();
|
|
39219
|
+
stopped(signal);
|
|
39166
39220
|
const tx = await chainRequest(() => surveys.connect(wallet.connect(provider)).submitResponses(ids, pointers, import_ethers4.ethers.constants.HashZero, import_ethers4.ethers.constants.HashZero, fees), { submission: true });
|
|
39167
39221
|
const receipt = await confirm(tx, "ResponsesSubmitted", ids);
|
|
39168
39222
|
records.forEach((record, index) => remember("responses", record.questionID, record, pointers[index], receipt));
|
|
@@ -39177,6 +39231,7 @@ var createRegistryWriter = ({ provider, chainId, wallet, surveys, slug, remember
|
|
|
39177
39231
|
const pointer = await upload(client, "questions", record.id, record, signal);
|
|
39178
39232
|
stopped(signal);
|
|
39179
39233
|
await checkChain();
|
|
39234
|
+
stopped(signal);
|
|
39180
39235
|
const tx = await chainRequest(() => surveys.connect(wallet.connect(provider)).addQuestions([record.id], [pointer], [import_ethers4.ethers.constants.HashZero], fees), { submission: true });
|
|
39181
39236
|
const receipt = await confirm(tx, "QuestionsAdded", [record.id]);
|
|
39182
39237
|
remember("questions", record.id, record, pointer, receipt);
|
|
@@ -39240,6 +39295,11 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39240
39295
|
let workerOrigin;
|
|
39241
39296
|
let surveys;
|
|
39242
39297
|
let startBlock;
|
|
39298
|
+
const creationBlocks = /* @__PURE__ */ new Map();
|
|
39299
|
+
let endBlock = null;
|
|
39300
|
+
let readEnd;
|
|
39301
|
+
let windowKey;
|
|
39302
|
+
let questionMark = null;
|
|
39243
39303
|
let questionCursor;
|
|
39244
39304
|
const pending = /* @__PURE__ */ new Map();
|
|
39245
39305
|
const questions = /* @__PURE__ */ new Map();
|
|
@@ -39247,9 +39307,23 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39247
39307
|
const localAnswers = /* @__PURE__ */ new Map();
|
|
39248
39308
|
const answerScans = /* @__PURE__ */ new Map();
|
|
39249
39309
|
let loadingQuestions;
|
|
39310
|
+
const containsBlock = (block) => Number.isSafeInteger(block) && block >= startBlock && (endBlock === null || block <= readEnd);
|
|
39311
|
+
const readWindowEnd = async () => {
|
|
39312
|
+
const head = await chainRequest(() => provider.getBlockNumber());
|
|
39313
|
+
readEnd = endBlock === null ? head : Math.min(endBlock, head);
|
|
39314
|
+
return readEnd;
|
|
39315
|
+
};
|
|
39316
|
+
const configuredBlock = (value, name) => {
|
|
39317
|
+
if (value == null) return null;
|
|
39318
|
+
const block = Number(value);
|
|
39319
|
+
if (typeof value !== "number" && typeof value !== "string" || String(value).trim() === "" || !Number.isSafeInteger(block) || block < 0) {
|
|
39320
|
+
throw new Error(`Invalid session block limit: ${name} must be a nonnegative integer.`);
|
|
39321
|
+
}
|
|
39322
|
+
return block;
|
|
39323
|
+
};
|
|
39250
39324
|
const loadConfig = async () => {
|
|
39251
39325
|
await checkRegistryChain(provider, chainId);
|
|
39252
|
-
const slug = info.slug
|
|
39326
|
+
const slug = info.slug || "general";
|
|
39253
39327
|
const row = await chainRequest(() => registry.getSessionBySlug(slug));
|
|
39254
39328
|
if (normalized(row[0]) !== slug) throw new Error("The registry returned a different session.");
|
|
39255
39329
|
if (text(row[3])) throw new Error("Encrypted registry metadata is unsupported; use an unencrypted session.");
|
|
@@ -39277,11 +39351,32 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39277
39351
|
corsWorkerUrl: workerOrigin,
|
|
39278
39352
|
contracts: { ...metadata.contracts, surveys: { address, chainId } }
|
|
39279
39353
|
};
|
|
39280
|
-
|
|
39281
|
-
|
|
39282
|
-
|
|
39283
|
-
|
|
39354
|
+
const head = await chainRequest(() => provider.getBlockNumber());
|
|
39355
|
+
let nextStart = configuredBlock(metadata.blockLimits?.start, "start");
|
|
39356
|
+
if (nextStart === null) {
|
|
39357
|
+
const createdAt = Number(row[5]);
|
|
39358
|
+
if (!creationBlocks.has(createdAt)) {
|
|
39359
|
+
const lookup = findStartBlock(provider, createdAt, head).catch((error) => {
|
|
39360
|
+
creationBlocks.delete(createdAt);
|
|
39361
|
+
throw error;
|
|
39362
|
+
});
|
|
39363
|
+
creationBlocks.set(createdAt, lookup);
|
|
39364
|
+
}
|
|
39365
|
+
nextStart = await creationBlocks.get(createdAt);
|
|
39366
|
+
}
|
|
39367
|
+
const nextEnd = configuredBlock(metadata.blockLimits?.end, "end");
|
|
39368
|
+
if (nextEnd !== null && nextEnd < nextStart) throw new Error("Invalid session block window: end must not precede start.");
|
|
39369
|
+
const nextKey = `${nextStart}:${nextEnd ?? "head"}`;
|
|
39370
|
+
startBlock = nextStart;
|
|
39371
|
+
endBlock = nextEnd;
|
|
39372
|
+
readEnd = endBlock === null ? head : Math.min(endBlock, head);
|
|
39373
|
+
if (windowKey !== nextKey) {
|
|
39374
|
+
windowKey = nextKey;
|
|
39284
39375
|
questionCursor = { block: startBlock, offset: 0 };
|
|
39376
|
+
questionMark = null;
|
|
39377
|
+
pending.clear();
|
|
39378
|
+
for (const [id, entry] of questions) if (!entry.local || !containsBlock(entry.blockNumber)) questions.delete(id);
|
|
39379
|
+
answerScans.clear();
|
|
39285
39380
|
}
|
|
39286
39381
|
return sessionConfig;
|
|
39287
39382
|
};
|
|
@@ -39311,14 +39406,14 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39311
39406
|
return block?.hash ? block.hash !== mark.hash : null;
|
|
39312
39407
|
};
|
|
39313
39408
|
const replacedWrite = (entry, blocks = /* @__PURE__ */ new Map()) => historyReplaced(entry?.blockHash ? { number: entry.blockNumber, hash: entry.blockHash } : null, blocks);
|
|
39314
|
-
let questionMark = null;
|
|
39315
39409
|
const visibleQuestions = () => {
|
|
39316
39410
|
const blocked = new Set((Array.isArray(sessionConfig.BLOCKED_QUESTION_IDS) ? sessionConfig.BLOCKED_QUESTION_IDS : []).map(normalized));
|
|
39317
|
-
return [...questions.values()].filter((entry) => !blocked.has(entry.id));
|
|
39411
|
+
return [...questions.values()].filter((entry) => !blocked.has(entry.id) && containsBlock(entry.blockNumber));
|
|
39318
39412
|
};
|
|
39319
39413
|
const readQuestions = async ({ signal } = {}) => {
|
|
39320
39414
|
const deadline = now() + 9e4;
|
|
39321
39415
|
const blocks = /* @__PURE__ */ new Map();
|
|
39416
|
+
const end = await readWindowEnd();
|
|
39322
39417
|
let complete = true;
|
|
39323
39418
|
const replaced = await historyReplaced(questionMark, blocks);
|
|
39324
39419
|
if (replaced === null) return { items: visibleQuestions(), complete: false };
|
|
@@ -39335,7 +39430,7 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39335
39430
|
if (replaced2) questions.delete(id);
|
|
39336
39431
|
}
|
|
39337
39432
|
if (pending.size < MAX_CACHE && questions.size < MAX_QUESTIONS) {
|
|
39338
|
-
const head = await readHeadMark(
|
|
39433
|
+
const head = await readHeadMark(end, blocks);
|
|
39339
39434
|
if (head) {
|
|
39340
39435
|
const scanned = await scanRegistryLogs({
|
|
39341
39436
|
provider,
|
|
@@ -39389,7 +39484,7 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39389
39484
|
let verified = true;
|
|
39390
39485
|
const responseFilter = filter("ResponsesSubmitted");
|
|
39391
39486
|
if (mine) responseFilter.topics.push(import_ethers5.ethers.utils.hexZeroPad(wallet.address, 32));
|
|
39392
|
-
const head = await
|
|
39487
|
+
const head = await readWindowEnd();
|
|
39393
39488
|
const scope = [...known].sort().join(",");
|
|
39394
39489
|
let state = answerScans.get(mine);
|
|
39395
39490
|
const replaced = !!state && state.scope === scope && head >= state.head && await historyReplaced(state.mark, blocks);
|
|
@@ -39397,7 +39492,7 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39397
39492
|
const held = new Map((state.result?.entries || []).map((entry) => [`${entry.questionId}:${normalized(entry.responder)}`, entry]));
|
|
39398
39493
|
const chainOrders2 = new Map(state.result?.chainOrders || []);
|
|
39399
39494
|
for (const entry of localAnswers.values()) {
|
|
39400
|
-
if (!known.has(entry.questionId)) continue;
|
|
39495
|
+
if (!known.has(entry.questionId) || !containsBlock(entry.blockNumber)) continue;
|
|
39401
39496
|
const key = `${entry.questionId}:${normalized(entry.responder)}`;
|
|
39402
39497
|
if ([state.latest.get(key), held.get(key)].some((previous) => previous && compareChainOrder(entry, previous) < 0)) continue;
|
|
39403
39498
|
chainOrders2.set(entry.questionId, entry);
|
|
@@ -39407,7 +39502,8 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39407
39502
|
return {
|
|
39408
39503
|
entries: [...held.values()].sort((a, b) => compareChainOrder(b, a)).slice(0, maxRecords),
|
|
39409
39504
|
complete: false,
|
|
39410
|
-
chainOrders: chainOrders2
|
|
39505
|
+
chainOrders: chainOrders2,
|
|
39506
|
+
unreadAnswers: state.result?.unreadAnswers || 0
|
|
39411
39507
|
};
|
|
39412
39508
|
}
|
|
39413
39509
|
if (!state || state.scope !== scope || head < state.head || replaced) {
|
|
@@ -39473,7 +39569,7 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39473
39569
|
const scannedAll = !state.ranges.length && !state.capped;
|
|
39474
39570
|
const latest = new Map(state.latest);
|
|
39475
39571
|
for (const [id, entry] of localAnswers) {
|
|
39476
|
-
if (!known.has(entry.questionId)) continue;
|
|
39572
|
+
if (!known.has(entry.questionId) || !containsBlock(entry.blockNumber)) continue;
|
|
39477
39573
|
const replaced2 = await replacedWrite(entry, blocks);
|
|
39478
39574
|
if (replaced2 === null) verified = false;
|
|
39479
39575
|
if (replaced2) {
|
|
@@ -39488,6 +39584,7 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39488
39584
|
const chainOrders = new Map(candidates.filter((entry) => normalized(entry.responder) === normalized(wallet.address)).map((entry) => [entry.questionId, entry]));
|
|
39489
39585
|
const entries = [];
|
|
39490
39586
|
let complete = verified && scannedAll && candidates.length <= maxRecords;
|
|
39587
|
+
let unreadAnswers = 0;
|
|
39491
39588
|
let next = 0;
|
|
39492
39589
|
const selected = candidates.slice(0, maxRecords);
|
|
39493
39590
|
await Promise.all(Array.from({ length: Math.min(6, selected.length) }, async () => {
|
|
@@ -39498,7 +39595,16 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39498
39595
|
}
|
|
39499
39596
|
const entry = selected[next++];
|
|
39500
39597
|
try {
|
|
39501
|
-
const
|
|
39598
|
+
const { blockTag } = responseReadWindowOptions(endBlock === null ? null : { blockTag: head }, entry.responder, entry.questionId);
|
|
39599
|
+
let pointer;
|
|
39600
|
+
if (entry.local) pointer = entry.storageId;
|
|
39601
|
+
else {
|
|
39602
|
+
try {
|
|
39603
|
+
pointer = await chainRequest(() => blockTag == null ? surveys.getResponse(entry.responder, entry.questionId) : surveys.getResponse(entry.responder, entry.questionId, { blockTag }));
|
|
39604
|
+
} catch (error) {
|
|
39605
|
+
throw blockTag == null ? error : historicalResponseReadError(error, blockTag);
|
|
39606
|
+
}
|
|
39607
|
+
}
|
|
39502
39608
|
const payload = await readPayload(pointer);
|
|
39503
39609
|
if (!registryResponseMatchesSession(payload, sessionConfig) || payload.answer?.encrypted === true) continue;
|
|
39504
39610
|
if (normalized(payload.questionID || payload.questionId) !== entry.questionId) continue;
|
|
@@ -39508,10 +39614,12 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39508
39614
|
entries.push({ ...entry, storageId: pointer, createdAt, payload });
|
|
39509
39615
|
} catch {
|
|
39510
39616
|
complete = false;
|
|
39617
|
+
unreadAnswers++;
|
|
39511
39618
|
}
|
|
39512
39619
|
}
|
|
39513
39620
|
}));
|
|
39514
|
-
|
|
39621
|
+
unreadAnswers += selected.length - next;
|
|
39622
|
+
state.result = { entries, complete, chainOrders, unreadAnswers };
|
|
39515
39623
|
return state.result;
|
|
39516
39624
|
};
|
|
39517
39625
|
const writer = createRegistryWriter({ provider, chainId, wallet, surveys, slug: info.slug, remember: (resource, id, payload, pointer, receipt) => {
|
|
@@ -39531,15 +39639,17 @@ var createRegistrySession = async ({ info, config, wallet, fetchImpl = globalThi
|
|
|
39531
39639
|
if (resource === "questions") questions.set(id, { ...entry, local: true });
|
|
39532
39640
|
else localAnswers.set(id, entry);
|
|
39533
39641
|
} });
|
|
39534
|
-
return { loadConfig, loadQuestions, readAnswers, replacedWrite,
|
|
39642
|
+
return { loadConfig, loadQuestions, readAnswers, replacedWrite, containsBlock, get windowKey() {
|
|
39643
|
+
return windowKey;
|
|
39644
|
+
}, ...writer, get config() {
|
|
39535
39645
|
return sessionConfig;
|
|
39536
39646
|
}, workerOrigin };
|
|
39537
39647
|
};
|
|
39538
39648
|
|
|
39539
39649
|
// shared/storage/canonicalStorageVersions.mjs
|
|
39540
|
-
var
|
|
39650
|
+
var trim6 = (value) => (typeof value === "string" ? value : value == null ? "" : String(value)).trim();
|
|
39541
39651
|
var compareStorageIds = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
39542
|
-
var compareVersionAge = (left, right) => (Number(left.createdAtMs) || 0) - (Number(right.createdAtMs) || 0) || compareStorageIds(
|
|
39652
|
+
var compareVersionAge = (left, right) => (Number(left.createdAtMs) || 0) - (Number(right.createdAtMs) || 0) || compareStorageIds(trim6(left.storageRefId), trim6(right.storageRefId));
|
|
39543
39653
|
var isAdminStorageVersion = (candidate) => candidate.uploadAuthority === "admin";
|
|
39544
39654
|
var isPreferredStorageVersion = (candidate, current) => {
|
|
39545
39655
|
if (!current) return true;
|
|
@@ -39550,8 +39660,46 @@ var isPreferredStorageVersion = (candidate, current) => {
|
|
|
39550
39660
|
return candidateAdmin ? age > 0 : age < 0;
|
|
39551
39661
|
};
|
|
39552
39662
|
|
|
39553
|
-
//
|
|
39663
|
+
// shared/sessionContext.mjs
|
|
39664
|
+
var SESSION_CONTEXT_LIMITS = Object.freeze({
|
|
39665
|
+
titleChars: 80,
|
|
39666
|
+
paragraphs: 6,
|
|
39667
|
+
paragraphChars: 2e3,
|
|
39668
|
+
links: 8,
|
|
39669
|
+
labelChars: 120,
|
|
39670
|
+
urlChars: 2e3,
|
|
39671
|
+
htmlChars: 2e4
|
|
39672
|
+
});
|
|
39673
|
+
var L = SESSION_CONTEXT_LIMITS;
|
|
39674
|
+
var isRecord5 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
39554
39675
|
var text2 = (value) => typeof value === "string" ? value.trim() : "";
|
|
39676
|
+
var NAMED_ENTITIES = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " " };
|
|
39677
|
+
var decodeEntity = (match, entity) => {
|
|
39678
|
+
const code = /^#x/i.test(entity) ? parseInt(entity.slice(2), 16) : /^#/.test(entity) ? parseInt(entity.slice(1), 10) : NaN;
|
|
39679
|
+
if (Number.isInteger(code)) return code > 0 && code <= 1114111 ? String.fromCodePoint(code) : " ";
|
|
39680
|
+
return NAMED_ENTITIES[entity.toLowerCase()] ?? match;
|
|
39681
|
+
};
|
|
39682
|
+
var htmlToPlainText = (html) => String(html ?? "").replace(/<(script|style|template)\b[\s\S]*?<\/\1\s*>/gi, " ").replace(/<!--[\s\S]*?-->/g, " ").replace(/<br\s*\/?>|<\/(?:p|div|li|h[1-6]|tr|summary|details|blockquote|pre|table|ul|ol|dt|dd)>/gi, "\n").replace(/<[^>]*>/g, " ").replace(/&(#x[0-9a-f]+|#\d+|[a-z]+);/gi, decodeEntity).split("\n").map((line) => line.replace(/\s+/g, " ").trim()).filter(Boolean).join("\n");
|
|
39683
|
+
var isHttpsUrl = (value) => {
|
|
39684
|
+
if (typeof value !== "string" || !value || value.length > L.urlChars) return false;
|
|
39685
|
+
try {
|
|
39686
|
+
return new URL(value).protocol === "https:";
|
|
39687
|
+
} catch {
|
|
39688
|
+
return false;
|
|
39689
|
+
}
|
|
39690
|
+
};
|
|
39691
|
+
var normalizeSessionContext = (value) => {
|
|
39692
|
+
const context = isRecord5(value) ? value : {};
|
|
39693
|
+
const title = text2(context.title).slice(0, L.titleChars);
|
|
39694
|
+
const html = text2(context.html).slice(0, L.htmlChars);
|
|
39695
|
+
if (html) return { title, html, paragraphs: [], links: [] };
|
|
39696
|
+
const paragraphs = (Array.isArray(context.paragraphs) ? context.paragraphs : [context.body]).map(text2).filter(Boolean).slice(0, L.paragraphs).map((paragraph) => paragraph.slice(0, L.paragraphChars));
|
|
39697
|
+
const links = (Array.isArray(context.links) ? context.links : []).filter(isRecord5).map((link) => ({ label: text2(link.label).slice(0, L.labelChars), url: text2(link.url) })).filter((link) => isHttpsUrl(link.url)).slice(0, L.links).map((link) => ({ label: link.label || link.url, url: link.url }));
|
|
39698
|
+
return { title, paragraphs, links };
|
|
39699
|
+
};
|
|
39700
|
+
|
|
39701
|
+
// mcp/lib/results.mjs
|
|
39702
|
+
var text3 = (value) => typeof value === "string" ? value.trim() : "";
|
|
39555
39703
|
var MAX_FREEFORM_SAMPLES = 5;
|
|
39556
39704
|
var MAX_SAMPLE_LENGTH = 280;
|
|
39557
39705
|
var isNewer = (candidate, current) => !current || candidate.createdAt > current.createdAt || candidate.createdAt === current.createdAt && candidate.storageId > current.storageId;
|
|
@@ -39560,11 +39708,11 @@ var latestAnswersByQuestion = (entries, { sessionSlug, sessionId, registryConfig
|
|
|
39560
39708
|
for (const entry of entries) {
|
|
39561
39709
|
const payload = entry?.payload;
|
|
39562
39710
|
if (!payload || typeof payload !== "object" || Array.isArray(payload)) continue;
|
|
39563
|
-
const questionId = (
|
|
39711
|
+
const questionId = (text3(payload.questionID) || text3(payload.questionId)).toLowerCase();
|
|
39564
39712
|
if (registryConfig) {
|
|
39565
39713
|
if (!questionIds?.has(questionId) || !registryResponseMatchesSession(payload, registryConfig) || payload.answer?.encrypted === true) continue;
|
|
39566
|
-
} else if (
|
|
39567
|
-
const responder =
|
|
39714
|
+
} else if (text3(payload.sessionSlug) !== sessionSlug || normalizeSessionIdHex(text3(payload.sessionId)) !== sessionId) continue;
|
|
39715
|
+
const responder = text3(entry.responder).toLowerCase();
|
|
39568
39716
|
if (!questionId || !responder) continue;
|
|
39569
39717
|
const answers = byQuestion.get(questionId) || /* @__PURE__ */ new Map();
|
|
39570
39718
|
const current = answers.get(responder);
|
|
@@ -39596,25 +39744,21 @@ var BINARY_VOTES = Object.freeze({
|
|
|
39596
39744
|
0: "Unsure"
|
|
39597
39745
|
});
|
|
39598
39746
|
var validValue = (question, entry) => {
|
|
39599
|
-
const payloadType =
|
|
39747
|
+
const payloadType = text3(entry?.payload?.type);
|
|
39600
39748
|
if (payloadType && payloadType !== question.type) return void 0;
|
|
39601
39749
|
const value = rawValue(entry);
|
|
39602
39750
|
if (value === void 0 || value === null || value === "*") return void 0;
|
|
39603
39751
|
switch (question.type) {
|
|
39604
39752
|
case "binary": {
|
|
39605
39753
|
const scalar = Array.isArray(value) && value.every((item) => ["string", "number"].includes(typeof item)) ? value.join(",") : value;
|
|
39606
|
-
const key = typeof scalar === "boolean" || typeof scalar === "number" ? String(scalar) :
|
|
39754
|
+
const key = typeof scalar === "boolean" || typeof scalar === "number" ? String(scalar) : text3(scalar).toLowerCase();
|
|
39607
39755
|
return Object.hasOwn(BINARY_VOTES, key) ? BINARY_VOTES[key] : void 0;
|
|
39608
39756
|
}
|
|
39609
|
-
case "rating":
|
|
39610
|
-
|
|
39611
|
-
const number = Number(value);
|
|
39612
|
-
const scale = ratingScaleFor(question);
|
|
39613
|
-
return Number.isFinite(number) && number >= scale.min && number <= scale.max ? number : void 0;
|
|
39614
|
-
}
|
|
39757
|
+
case "rating":
|
|
39758
|
+
return normalizeRatingAnswer(value, question) ?? void 0;
|
|
39615
39759
|
case "multichoice": {
|
|
39616
|
-
const options = (Array.isArray(question.options) ? question.options : []).map(
|
|
39617
|
-
const picks = (Array.isArray(value) ? value : [value]).map(
|
|
39760
|
+
const options = (Array.isArray(question.options) ? question.options : []).map(text3).filter(Boolean);
|
|
39761
|
+
const picks = (Array.isArray(value) ? value : [value]).map(text3);
|
|
39618
39762
|
if (!picks.length || picks.some((pick) => !pick)) return void 0;
|
|
39619
39763
|
const canonical = options.length ? picks.map((pick) => options.find((option) => option.toLowerCase() === pick.toLowerCase()) || "") : picks;
|
|
39620
39764
|
if (canonical.some((pick) => !pick)) return void 0;
|
|
@@ -39665,7 +39809,7 @@ var summarizeQuestion = (question, answersByResponder = /* @__PURE__ */ new Map(
|
|
|
39665
39809
|
return { ...summary, scale: { min: scale.min, max: scale.max }, mean, histogram };
|
|
39666
39810
|
}
|
|
39667
39811
|
case "multichoice": {
|
|
39668
|
-
const counts = new Map((Array.isArray(question.options) ? question.options : []).map(
|
|
39812
|
+
const counts = new Map((Array.isArray(question.options) ? question.options : []).map(text3).filter(Boolean).map((option) => [option, 0]));
|
|
39669
39813
|
answered.forEach((entry) => validValue(question, entry).forEach((option) => counts.set(option, (counts.get(option) || 0) + 1)));
|
|
39670
39814
|
return { ...summary, counts: Object.fromEntries(counts) };
|
|
39671
39815
|
}
|
|
@@ -39715,12 +39859,12 @@ var REVEAL_WAIT_MS = 9e4;
|
|
|
39715
39859
|
var POLL_MS = 2e3;
|
|
39716
39860
|
var GAS_HEADROOM_PERCENT = 130;
|
|
39717
39861
|
var PASSWORD_CLAIM_GAS_BUDGET = 4e5;
|
|
39718
|
-
var
|
|
39719
|
-
var
|
|
39862
|
+
var trim7 = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
39863
|
+
var isRecord6 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
39720
39864
|
var defaultSleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
39721
39865
|
var { deriveGroupPasswordWallet } = createGroupPasswordDerivation(import_ethers6.ethers);
|
|
39722
39866
|
var normalizeGroupPasswordInput = (raw) => {
|
|
39723
|
-
const compact =
|
|
39867
|
+
const compact = trim7(raw).replace(/\s+/g, "");
|
|
39724
39868
|
if (!compact) return "";
|
|
39725
39869
|
if (import_ethers6.ethers.utils.isHexString(compact)) {
|
|
39726
39870
|
try {
|
|
@@ -39732,14 +39876,14 @@ var normalizeGroupPasswordInput = (raw) => {
|
|
|
39732
39876
|
return compact;
|
|
39733
39877
|
};
|
|
39734
39878
|
var decodeInviteCode = (raw) => {
|
|
39735
|
-
let code =
|
|
39879
|
+
let code = trim7(raw);
|
|
39736
39880
|
const lower = code.toLowerCase();
|
|
39737
39881
|
if (lower.startsWith("inv:")) code = code.slice(4).trim();
|
|
39738
39882
|
else if (lower.startsWith("invite:")) code = code.slice(7).trim();
|
|
39739
39883
|
if (!code || code.length > 4096) return null;
|
|
39740
39884
|
try {
|
|
39741
39885
|
const parsed = JSON.parse(Buffer.from(code.replace(/-/g, "+").replace(/_/g, "/"), "base64").toString("utf8"));
|
|
39742
|
-
if (!
|
|
39886
|
+
if (!isRecord6(parsed) || Object.keys(parsed).sort().join(",") !== "a,c,n,s") return null;
|
|
39743
39887
|
const chainId = import_ethers6.ethers.BigNumber.from(String(parsed.c));
|
|
39744
39888
|
const slot = import_ethers6.ethers.BigNumber.from(String(parsed.n));
|
|
39745
39889
|
const sbtAddress = import_ethers6.ethers.utils.getAddress(String(parsed.a));
|
|
@@ -39760,13 +39904,13 @@ var accessConditionsOf = (config) => [
|
|
|
39760
39904
|
config?.sessionModeProfile?.encryption?.accessConditions,
|
|
39761
39905
|
config?.storageProfile?.payloadAccessControl?.accessConditions
|
|
39762
39906
|
].flatMap((document) => Array.isArray(document?.conditions) ? document.conditions : []);
|
|
39763
|
-
var conditionAddresses = (condition) => [condition?.contract, condition?.address, ...Array.isArray(condition?.sbtAddresses) ? condition.sbtAddresses : []].map((value) =>
|
|
39907
|
+
var conditionAddresses = (condition) => [condition?.contract, condition?.address, ...Array.isArray(condition?.sbtAddresses) ? condition.sbtAddresses : []].map((value) => trim7(value).toLowerCase()).filter(Boolean);
|
|
39764
39908
|
var positiveChainId = (value) => {
|
|
39765
39909
|
const number = typeof value === "number" ? value : typeof value === "string" && value.trim() ? Number(value) : NaN;
|
|
39766
39910
|
return Number.isSafeInteger(number) && number > 0 ? number : 0;
|
|
39767
39911
|
};
|
|
39768
39912
|
var resolveSbtChainId = (config, sbtAddress) => {
|
|
39769
|
-
const target =
|
|
39913
|
+
const target = trim7(sbtAddress).toLowerCase();
|
|
39770
39914
|
const condition = accessConditionsOf(config).find(
|
|
39771
39915
|
(entry) => entry?.kind === "sbt_onchain" && conditionAddresses(entry).includes(target) && positiveChainId(entry.chainId)
|
|
39772
39916
|
);
|
|
@@ -39784,7 +39928,7 @@ var listSessionSbts = (config) => {
|
|
|
39784
39928
|
return [...seen.values()];
|
|
39785
39929
|
};
|
|
39786
39930
|
var defaultCreateProvider = (rpcOverride) => (chainId) => {
|
|
39787
|
-
const url =
|
|
39931
|
+
const url = trim7(rpcOverride) || import_rpcDefaults3.default.getPublicRpcUrls(chainId)[0] || import_rpcDefaults3.default.getPathRpcUrl(chainId);
|
|
39788
39932
|
if (!url) throw new Error(`No public RPC is known for chain ${chainId}; set CE_MCP_RPC_URL.`);
|
|
39789
39933
|
return new import_ethers6.ethers.providers.StaticJsonRpcProvider(url, chainId);
|
|
39790
39934
|
};
|
|
@@ -39903,7 +40047,7 @@ var createSbtClaimer = ({
|
|
|
39903
40047
|
const claimWithGroupPassword = async ({ ctx, provider, chainId, contract, sbtAddress, password }) => {
|
|
39904
40048
|
const normalized2 = normalizeGroupPasswordInput(password);
|
|
39905
40049
|
if (!normalized2) throw new ClaimError("This SBT needs a group password.");
|
|
39906
|
-
const expectedHash =
|
|
40050
|
+
const expectedHash = trim7(await contract.groupPasswordHash()).toLowerCase();
|
|
39907
40051
|
if (!expectedHash || expectedHash === import_ethers6.ethers.constants.HashZero) throw new ClaimError("This SBT has no group password set.");
|
|
39908
40052
|
const groupWallet = await deriveGroupPasswordWallet({ password: normalized2, sbtAddress });
|
|
39909
40053
|
if (import_ethers6.ethers.utils.solidityKeccak256(["address"], [groupWallet.address]) !== expectedHash) {
|
|
@@ -39937,7 +40081,7 @@ var createSbtClaimer = ({
|
|
|
39937
40081
|
signal = callSignal;
|
|
39938
40082
|
let address;
|
|
39939
40083
|
try {
|
|
39940
|
-
address = import_ethers6.ethers.utils.getAddress(
|
|
40084
|
+
address = import_ethers6.ethers.utils.getAddress(trim7(sbtAddress));
|
|
39941
40085
|
} catch {
|
|
39942
40086
|
throw new ClaimError("Pass the SBT contract address (0x\u2026).");
|
|
39943
40087
|
}
|
|
@@ -39970,7 +40114,7 @@ var createSbtClaimer = ({
|
|
|
39970
40114
|
const args = { ctx, provider, chainId, contract, sbtAddress: address };
|
|
39971
40115
|
let transactions;
|
|
39972
40116
|
if (mode === "public") transactions = [(await send({ ...args, method: "claim", args: [] })).transactionHash];
|
|
39973
|
-
else if (mode === "password") transactions = await claimWithCommitReveal({ ...args, password:
|
|
40117
|
+
else if (mode === "password") transactions = await claimWithCommitReveal({ ...args, password: trim7(claimPassword) || trim7(groupPassword) });
|
|
39974
40118
|
else if (mode === "group_password") transactions = await claimWithGroupPassword({ ...args, password: groupPassword });
|
|
39975
40119
|
else transactions = await claimWithInviteCode({ ...args, code: inviteCode || groupPassword });
|
|
39976
40120
|
return { ...base, mode, status: "claimed", transactions };
|
|
@@ -39996,11 +40140,9 @@ var MAX_CACHED_RECORDS = 2e4;
|
|
|
39996
40140
|
var MISSING_RECORD_RETRY_MS = 6e4;
|
|
39997
40141
|
var MAX_OWN_ANSWER_ITEMS = 5e3;
|
|
39998
40142
|
var MAX_TITLE_LENGTH = 120;
|
|
39999
|
-
var
|
|
40000
|
-
var
|
|
40001
|
-
var
|
|
40002
|
-
var trim7 = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
40003
|
-
var isRecord6 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
40143
|
+
var MAX_DESCRIPTION_LENGTH = 2e3;
|
|
40144
|
+
var trim8 = (value) => typeof value === "string" ? value.trim() : typeof value === "number" ? String(value) : "";
|
|
40145
|
+
var isRecord7 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
|
|
40004
40146
|
var sessionKey = (info) => info.kind === "registry" ? `registry ${info.chainId || 11155420} ${info.slug}` : `${info.workerOrigin} ${info.slug}`;
|
|
40005
40147
|
var mapLimit = async (items, limit, task) => {
|
|
40006
40148
|
const results = new Array(items.length);
|
|
@@ -40016,10 +40158,10 @@ var mapLimit = async (items, limit, task) => {
|
|
|
40016
40158
|
return results;
|
|
40017
40159
|
};
|
|
40018
40160
|
var contextOf = (config) => {
|
|
40019
|
-
const context =
|
|
40020
|
-
|
|
40021
|
-
const
|
|
40022
|
-
return {
|
|
40161
|
+
const { html, ...context } = normalizeSessionContext(config?.sessionContext);
|
|
40162
|
+
if (!html) return context;
|
|
40163
|
+
const words = htmlToPlainText(html);
|
|
40164
|
+
return { ...context, paragraphs: words ? [words] : [] };
|
|
40023
40165
|
};
|
|
40024
40166
|
var idList = (value) => new Set((Array.isArray(value) ? value : []).map((id) => text(id).toLowerCase()).filter(Boolean));
|
|
40025
40167
|
var stringOptions = (payload) => Array.isArray(payload.options) ? payload.options.filter((option) => typeof option === "string") : [];
|
|
@@ -40028,9 +40170,9 @@ var finiteNumber = (value) => {
|
|
|
40028
40170
|
if (typeof value === "string" && value.trim() && Number.isFinite(Number(value))) return Number(value);
|
|
40029
40171
|
return void 0;
|
|
40030
40172
|
};
|
|
40031
|
-
var SCALE_KEYS = ["min", "minimum", "max", "maximum", "minLabel", "lowLabel", "maxLabel", "highLabel"];
|
|
40173
|
+
var SCALE_KEYS = ["step", "min", "minimum", "max", "maximum", "minLabel", "lowLabel", "maxLabel", "highLabel"];
|
|
40032
40174
|
var cleanScale = (record) => {
|
|
40033
|
-
if (!
|
|
40175
|
+
if (!isRecord7(record)) return {};
|
|
40034
40176
|
const out = {};
|
|
40035
40177
|
SCALE_KEYS.forEach((key) => {
|
|
40036
40178
|
if (typeof record[key] === "string" || typeof record[key] === "number" && Number.isFinite(record[key])) out[key] = record[key];
|
|
@@ -40099,7 +40241,9 @@ var sameAuthoringInputs = (stored, record) => {
|
|
|
40099
40241
|
var progressNotes = (questions, mine) => ({
|
|
40100
40242
|
...questions.locked ? { lockedQuestions: questions.locked } : {},
|
|
40101
40243
|
...questions.complete === false ? { questionsComplete: false } : {},
|
|
40102
|
-
...
|
|
40244
|
+
...questions.unread ? { unreadQuestions: questions.unread } : {},
|
|
40245
|
+
...mine.unread ? { unreadMyAnswers: mine.unread } : {},
|
|
40246
|
+
...mine.complete === false ? { myAnswersComplete: false, note: "Some answers could not be read or the scan is unfinished; the answers shown may be incomplete." } : {}
|
|
40103
40247
|
});
|
|
40104
40248
|
var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = () => Date.now(), sbt = null, createProvider, sleep, registry = {} }) => {
|
|
40105
40249
|
const requestTestEth = createTestEthRequester({ config, wallet, createProvider, now, sleep });
|
|
@@ -40125,9 +40269,9 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40125
40269
|
state = await updateAgentState(config.stateDir, mutate);
|
|
40126
40270
|
};
|
|
40127
40271
|
const profile = () => ({
|
|
40128
|
-
displayName:
|
|
40129
|
-
modelId:
|
|
40130
|
-
platform:
|
|
40272
|
+
displayName: trim8(state?.profile?.displayName ?? config.profile.displayName),
|
|
40273
|
+
modelId: trim8(state?.profile?.modelId ?? config.profile.modelId),
|
|
40274
|
+
platform: trim8(state?.profile?.platform ?? config.profile.platform)
|
|
40131
40275
|
});
|
|
40132
40276
|
const trustedOriginsFor = (preferred) => config.trustedAppOrigins.includes(preferred) ? [preferred, ...config.trustedAppOrigins.filter((origin) => origin !== preferred)] : config.trustedAppOrigins;
|
|
40133
40277
|
const openSession = async (info) => {
|
|
@@ -40155,7 +40299,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40155
40299
|
};
|
|
40156
40300
|
const remember = (ctx, title, recruitmentSource) => saveState((fresh) => {
|
|
40157
40301
|
const key = sessionKey(ctx.info);
|
|
40158
|
-
const stored =
|
|
40302
|
+
const stored = isRecord7(fresh.sessions[key]) ? fresh.sessions[key] : {};
|
|
40159
40303
|
const previous = stored.sessionId && stored.sessionId !== ctx.client.sessionId ? {} : stored;
|
|
40160
40304
|
fresh.sessions[key] = {
|
|
40161
40305
|
...previous,
|
|
@@ -40172,12 +40316,12 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40172
40316
|
});
|
|
40173
40317
|
const sessionState = (ctx) => {
|
|
40174
40318
|
const entry = state?.sessions?.[sessionKey(ctx.info)];
|
|
40175
|
-
return
|
|
40319
|
+
return isRecord7(entry) ? entry : {};
|
|
40176
40320
|
};
|
|
40177
40321
|
const rememberAnswers = (ctx, answered) => saveState((fresh) => {
|
|
40178
40322
|
const entry = fresh.sessions[sessionKey(ctx.info)];
|
|
40179
|
-
if (!
|
|
40180
|
-
entry.answers =
|
|
40323
|
+
if (!isRecord7(entry) || entry.sessionId !== ctx.client.sessionId) return;
|
|
40324
|
+
entry.answers = isRecord7(entry.answers) ? entry.answers : {};
|
|
40181
40325
|
answered.forEach(({ questionId, record, answeredAt, chainOrder, requestId }) => {
|
|
40182
40326
|
entry.answers[questionId] = {
|
|
40183
40327
|
value: record.answer.value,
|
|
@@ -40190,7 +40334,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40190
40334
|
});
|
|
40191
40335
|
const resolveSession = async (session) => {
|
|
40192
40336
|
await loadState();
|
|
40193
|
-
const ref =
|
|
40337
|
+
const ref = trim8(session);
|
|
40194
40338
|
if (/^https?:\/\//i.test(ref)) {
|
|
40195
40339
|
const parsed = parseSessionLink(ref, { allowLocalWorkers: config.allowLocalWorkers });
|
|
40196
40340
|
const key2 = sessionKey(parsed);
|
|
@@ -40206,7 +40350,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40206
40350
|
if (!key) throw new Error(`No joined session named "${slug}". Join it first with join_session.`);
|
|
40207
40351
|
}
|
|
40208
40352
|
const entry = state.sessions[key];
|
|
40209
|
-
if (!key || !
|
|
40353
|
+
if (!key || !isRecord7(entry)) throw new Error("No session joined yet. Call join_session with a session link.");
|
|
40210
40354
|
return openSession({
|
|
40211
40355
|
workerOrigin: normalizeWorkerOrigin(entry.workerOrigin, { allowLocalWorkers: config.allowLocalWorkers }),
|
|
40212
40356
|
slug: normalizeSessionSlug(entry.slug),
|
|
@@ -40226,33 +40370,27 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40226
40370
|
};
|
|
40227
40371
|
const readCached = async (ctx, storageId) => {
|
|
40228
40372
|
if (ctx.records.has(storageId)) return ctx.records.get(storageId);
|
|
40229
|
-
if (now() - (ctx.missing.get(storageId) ?? -Infinity) < MISSING_RECORD_RETRY_MS) return
|
|
40230
|
-
let payload = null;
|
|
40373
|
+
if (now() - (ctx.missing.get(storageId) ?? -Infinity) < MISSING_RECORD_RETRY_MS) return void 0;
|
|
40231
40374
|
try {
|
|
40232
|
-
payload = await ctx.client.read(storageId);
|
|
40375
|
+
const payload = await ctx.client.read(storageId);
|
|
40376
|
+
ctx.missing.delete(storageId);
|
|
40377
|
+
cacheRecord(ctx, storageId, payload);
|
|
40378
|
+
return payload;
|
|
40233
40379
|
} catch (error) {
|
|
40234
40380
|
if (!(error instanceof WorkerRequestError) || error.status !== 404) throw error;
|
|
40235
|
-
}
|
|
40236
|
-
if (payload === null) {
|
|
40237
40381
|
ctx.missing.set(storageId, now());
|
|
40238
40382
|
if (ctx.missing.size > MAX_CACHED_RECORDS) ctx.missing.delete(ctx.missing.keys().next().value);
|
|
40239
|
-
|
|
40240
|
-
ctx.missing.delete(storageId);
|
|
40241
|
-
cacheRecord(ctx, storageId, payload);
|
|
40383
|
+
return void 0;
|
|
40242
40384
|
}
|
|
40243
|
-
return payload;
|
|
40244
40385
|
};
|
|
40245
40386
|
const readMany = async (ctx, storageIds) => {
|
|
40246
40387
|
const deadline = now() + READ_DEADLINE_MS;
|
|
40247
|
-
let complete = true;
|
|
40248
40388
|
const payloads = await mapLimit(storageIds, READ_CONCURRENCY, async (storageId) => {
|
|
40249
|
-
if (!ctx.records.has(storageId) && (now() >= deadline || signal?.aborted))
|
|
40250
|
-
|
|
40251
|
-
return void 0;
|
|
40252
|
-
}
|
|
40253
|
-
return readCached(ctx, storageId);
|
|
40389
|
+
if (!ctx.records.has(storageId) && (now() >= deadline || signal?.aborted)) return void 0;
|
|
40390
|
+
return readCached(ctx, storageId).catch(() => void 0);
|
|
40254
40391
|
});
|
|
40255
|
-
|
|
40392
|
+
const unread = payloads.filter((payload) => payload === void 0).length;
|
|
40393
|
+
return { payloads, complete: unread === 0, unread };
|
|
40256
40394
|
};
|
|
40257
40395
|
const loadQuestions = async (ctx) => {
|
|
40258
40396
|
const sessionConfig = await ensureReady(ctx);
|
|
@@ -40262,7 +40400,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40262
40400
|
const all2 = [];
|
|
40263
40401
|
for (const row of result.items) {
|
|
40264
40402
|
try {
|
|
40265
|
-
if (!
|
|
40403
|
+
if (!isRecord7(row.payload) || typeof row.payload.type !== "string") continue;
|
|
40266
40404
|
const payload = isLockedQuestion(row.payload) ? { ...row.payload, prompt: "[encrypted]", locked: true } : row.payload;
|
|
40267
40405
|
if (typeof payload.prompt !== "string") continue;
|
|
40268
40406
|
all2.push({
|
|
@@ -40283,15 +40421,15 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40283
40421
|
}
|
|
40284
40422
|
const { items, complete } = await ctx.client.listAll("questions", { maxItems: MAX_QUESTIONS2, signal });
|
|
40285
40423
|
const hidden = new Set(items.filter((item) => item.hidden === true).map((item) => text(item.metadata?.resourceId).toLowerCase()));
|
|
40286
|
-
const rows = items.filter((item) => item.hidden !== true && text(item.storageRef?.id));
|
|
40287
|
-
const { payloads, complete: readComplete } = await readMany(ctx, rows.map((item) => text(item.storageRef.id)));
|
|
40288
40424
|
const blocked = idList(sessionConfig.BLOCKED_QUESTION_IDS);
|
|
40425
|
+
const rows = items.filter((item) => item.hidden !== true && text(item.storageRef?.id) && !hidden.has(text(item.metadata?.resourceId).toLowerCase()) && !blocked.has(text(item.metadata?.resourceId).toLowerCase()));
|
|
40426
|
+
const { payloads, complete: readComplete, unread } = await readMany(ctx, rows.map((item) => text(item.storageRef.id)));
|
|
40289
40427
|
const highlighted = idList(sessionConfig.HIGHLIGHTED_QUESTION_IDS);
|
|
40290
40428
|
const versions = /* @__PURE__ */ new Map();
|
|
40291
40429
|
rows.forEach((item, index) => {
|
|
40292
40430
|
try {
|
|
40293
40431
|
const payload = payloads[index];
|
|
40294
|
-
if (!
|
|
40432
|
+
if (!isRecord7(payload) || typeof payload.prompt !== "string" || typeof payload.type !== "string") return;
|
|
40295
40433
|
if (text(payload.sessionSlug) !== ctx.info.slug) return;
|
|
40296
40434
|
if (text(payload.sessionId) && normalizeSessionIdHex(text(payload.sessionId)) !== ctx.client.sessionId) return;
|
|
40297
40435
|
const id = (text(payload.id) || text(item.metadata?.resourceId)).toLowerCase();
|
|
@@ -40328,11 +40466,12 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40328
40466
|
questions.locked = all.length - questions.length;
|
|
40329
40467
|
questions.lockedIds = new Set(all.filter((question) => isLockedQuestion(question)).map((question) => question.id));
|
|
40330
40468
|
questions.complete = complete && readComplete;
|
|
40469
|
+
questions.unread = unread;
|
|
40331
40470
|
return questions;
|
|
40332
40471
|
};
|
|
40333
40472
|
const toEntries = async (ctx, items) => {
|
|
40334
|
-
const rows = items.filter((item) => text(item.storageRef?.id));
|
|
40335
|
-
const { payloads, complete } = await readMany(ctx, rows.map((item) => text(item.storageRef.id)));
|
|
40473
|
+
const rows = items.filter((item) => item.hidden !== true && text(item.storageRef?.id));
|
|
40474
|
+
const { payloads, complete, unread } = await readMany(ctx, rows.map((item) => text(item.storageRef.id)));
|
|
40336
40475
|
const entries = rows.map((item, index) => ({
|
|
40337
40476
|
storageId: text(item.storageRef.id),
|
|
40338
40477
|
createdAt: text(item.metadata?.createdAt) || text(item.storageRef?.createdAt),
|
|
@@ -40340,22 +40479,23 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40340
40479
|
payload: payloads[index]
|
|
40341
40480
|
}));
|
|
40342
40481
|
entries.complete = complete;
|
|
40482
|
+
entries.unread = unread;
|
|
40343
40483
|
return entries;
|
|
40344
40484
|
};
|
|
40345
40485
|
const scanMyAnswers = async (ctx) => {
|
|
40346
|
-
if (ctx.ownScan &&
|
|
40486
|
+
if (ctx.ownScan && ctx.ownScan.complete && now() - ctx.ownScan.at < OWN_ANSWER_SCAN_MAX_AGE_MS && ctx.ownScan.sessionId === ctx.client.sessionId && ctx.ownScan.windowKey === ctx.registry?.windowKey) {
|
|
40347
40487
|
return ctx.ownScan;
|
|
40348
40488
|
}
|
|
40349
40489
|
if (ctx.registry) {
|
|
40350
40490
|
const questions = await loadQuestions(ctx);
|
|
40351
40491
|
const questionIds = new Set(questions.map((question) => question.id));
|
|
40352
|
-
const { entries: entries2, complete: complete2, chainOrders } = await ctx.registry.readAnswers({ questionIds, maxRecords: MAX_OWN_ANSWER_ITEMS, mine: true, signal });
|
|
40492
|
+
const { entries: entries2, complete: complete2, chainOrders, unreadAnswers } = await ctx.registry.readAnswers({ questionIds, maxRecords: MAX_OWN_ANSWER_ITEMS, mine: true, signal });
|
|
40353
40493
|
const latest2 = latestAnswersByQuestion(entries2, { registryConfig: ctx.client.config, questionIds });
|
|
40354
40494
|
const answers2 = /* @__PURE__ */ new Map();
|
|
40355
40495
|
latest2.forEach((byResponder, id) => {
|
|
40356
40496
|
if (byResponder.has(wallet.address.toLowerCase())) answers2.set(id, byResponder.get(wallet.address.toLowerCase()));
|
|
40357
40497
|
});
|
|
40358
|
-
ctx.ownScan = { at: now(), sessionId: ctx.client.sessionId, answers: answers2, complete: complete2, chainOrders };
|
|
40498
|
+
ctx.ownScan = { at: now(), sessionId: ctx.client.sessionId, windowKey: ctx.registry.windowKey, answers: answers2, complete: complete2, chainOrders, unread: unreadAnswers };
|
|
40359
40499
|
return ctx.ownScan;
|
|
40360
40500
|
}
|
|
40361
40501
|
const { items, complete: listed } = await ctx.client.listAll("responses", {
|
|
@@ -40374,7 +40514,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40374
40514
|
const entry = byResponder.get(self2);
|
|
40375
40515
|
if (entry) answers.set(questionId, entry);
|
|
40376
40516
|
});
|
|
40377
|
-
ctx.ownScan = { at: now(), sessionId: ctx.client.sessionId, answers, complete };
|
|
40517
|
+
ctx.ownScan = { at: now(), sessionId: ctx.client.sessionId, answers, complete, unread: entries.unread };
|
|
40378
40518
|
return ctx.ownScan;
|
|
40379
40519
|
};
|
|
40380
40520
|
const loadMyAnswers = async (ctx) => {
|
|
@@ -40384,10 +40524,10 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40384
40524
|
let complete = scan.complete;
|
|
40385
40525
|
const blocks = /* @__PURE__ */ new Map();
|
|
40386
40526
|
await loadState();
|
|
40387
|
-
const local = sessionState(ctx).sessionId === ctx.client.sessionId &&
|
|
40527
|
+
const local = sessionState(ctx).sessionId === ctx.client.sessionId && isRecord7(sessionState(ctx).answers) ? sessionState(ctx).answers : {};
|
|
40388
40528
|
for (const [questionId, answer] of Object.entries(local)) {
|
|
40389
|
-
if (!
|
|
40390
|
-
if (ctx.registry && !scan.complete) continue;
|
|
40529
|
+
if (!isRecord7(answer)) continue;
|
|
40530
|
+
if (ctx.registry && (!scan.complete || !ctx.registry.containsBlock(answer.blockNumber))) continue;
|
|
40391
40531
|
const known = mine.get(questionId);
|
|
40392
40532
|
const chainOrder = scan.chainOrders?.get(questionId);
|
|
40393
40533
|
if (ctx.registry && chainOrder && compareChainOrder(answer, chainOrder) < 0) continue;
|
|
@@ -40408,6 +40548,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40408
40548
|
if (value === "" || value === null || value === void 0 || Array.isArray(value) && !value.length) mine.delete(questionId);
|
|
40409
40549
|
});
|
|
40410
40550
|
mine.complete = complete;
|
|
40551
|
+
mine.unread = scan.unread;
|
|
40411
40552
|
return mine;
|
|
40412
40553
|
};
|
|
40413
40554
|
const sessionSummary = (ctx, sessionConfig) => ({
|
|
@@ -40423,7 +40564,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40423
40564
|
address: wallet.address,
|
|
40424
40565
|
profile: profile(),
|
|
40425
40566
|
currentSession: state.sessions[state.current]?.slug || null,
|
|
40426
|
-
sessions: await mapLimit(Object.values(state.sessions).filter(
|
|
40567
|
+
sessions: await mapLimit(Object.values(state.sessions).filter(isRecord7), READ_CONCURRENCY, async (entry) => ({
|
|
40427
40568
|
session: entry.slug,
|
|
40428
40569
|
title: entry.title || entry.slug,
|
|
40429
40570
|
webUrl: buildSessionWebUrl(entry),
|
|
@@ -40444,9 +40585,9 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40444
40585
|
},
|
|
40445
40586
|
async joinSession({ link, worker, session, inviteCode, groupPassword, claimPassword } = {}) {
|
|
40446
40587
|
let parsed;
|
|
40447
|
-
if (
|
|
40588
|
+
if (trim8(link)) {
|
|
40448
40589
|
parsed = parseSessionLink(link, { allowLocalWorkers: config.allowLocalWorkers });
|
|
40449
|
-
} else if (
|
|
40590
|
+
} else if (trim8(worker) && trim8(session)) {
|
|
40450
40591
|
parsed = {
|
|
40451
40592
|
appOrigin: config.appOrigin,
|
|
40452
40593
|
slug: normalizeSessionSlug(session),
|
|
@@ -40467,9 +40608,9 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40467
40608
|
const offered = parsed.sbtClaims.filter((claim) => !claim.auto).map((claim) => claim.sbt);
|
|
40468
40609
|
if (offered.length) outcome.sbtsToClaimWithClaimSbt = offered;
|
|
40469
40610
|
const separateCodes = {
|
|
40470
|
-
inviteCode:
|
|
40471
|
-
groupPassword:
|
|
40472
|
-
claimPassword:
|
|
40611
|
+
inviteCode: trim8(inviteCode),
|
|
40612
|
+
groupPassword: trim8(groupPassword),
|
|
40613
|
+
claimPassword: trim8(claimPassword)
|
|
40473
40614
|
};
|
|
40474
40615
|
const hasSeparateCodes = Object.values(separateCodes).some(Boolean);
|
|
40475
40616
|
if (hasSeparateCodes && claims.length !== 1) {
|
|
@@ -40513,19 +40654,19 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40513
40654
|
outcome.readOnlyReason = describeError(loginError);
|
|
40514
40655
|
outcome.note = "Joined read-only: public questions and results are available, but uploads, answers, statements, and faucet requests need Worker access.";
|
|
40515
40656
|
}
|
|
40516
|
-
const scopes =
|
|
40657
|
+
const scopes = isRecord7(tokenClaims?.scopes) ? tokenClaims.scopes : {};
|
|
40517
40658
|
outcome.scopes = Object.keys(scopes).filter((scope) => scopes[scope] === true);
|
|
40518
40659
|
if (parsed.joinGroupId) {
|
|
40519
40660
|
checkpoint();
|
|
40520
40661
|
try {
|
|
40521
40662
|
if (ctx.registry) throw new Error("Worker groups are not available in on-chain sessions.");
|
|
40522
|
-
await ctx.client.joinGroup(parsed.joinGroupId);
|
|
40663
|
+
await ctx.client.joinGroup(parsed.joinGroupId, { signal });
|
|
40523
40664
|
outcome.joinedGroup = parsed.joinGroupId;
|
|
40524
40665
|
} catch (error) {
|
|
40525
40666
|
outcome.groupJoinError = describeError(error);
|
|
40526
40667
|
}
|
|
40527
40668
|
}
|
|
40528
|
-
outcome.description = text(sessionConfig.sessionInfo).slice(0,
|
|
40669
|
+
outcome.description = text(sessionConfig.sessionInfo).slice(0, MAX_DESCRIPTION_LENGTH);
|
|
40529
40670
|
outcome.context = contextOf(sessionConfig);
|
|
40530
40671
|
const sessionSbts = listSessionSbts(sessionConfig);
|
|
40531
40672
|
if (sessionSbts.length) outcome.sessionSbts = sessionSbts;
|
|
@@ -40545,7 +40686,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40545
40686
|
return {
|
|
40546
40687
|
...sessionSummary(ctx, sessionConfig),
|
|
40547
40688
|
testEth: await ctx.client.describeTestEth(),
|
|
40548
|
-
description: text(sessionConfig.sessionInfo).slice(0,
|
|
40689
|
+
description: text(sessionConfig.sessionInfo).slice(0, MAX_DESCRIPTION_LENGTH),
|
|
40549
40690
|
context: contextOf(sessionConfig),
|
|
40550
40691
|
...endsAt ? { endsAt } : {},
|
|
40551
40692
|
...sessionSbts.length ? { sessionSbts } : {},
|
|
@@ -40588,7 +40729,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40588
40729
|
let reconciliationRequired = false;
|
|
40589
40730
|
const seen = /* @__PURE__ */ new Set();
|
|
40590
40731
|
for (const item of answers) {
|
|
40591
|
-
const questionId =
|
|
40732
|
+
const questionId = trim8(item?.questionId).toLowerCase();
|
|
40592
40733
|
if (seen.has(questionId)) {
|
|
40593
40734
|
results.push({ questionId, ok: false, error: "This question appears more than once in the call; send one answer per question." });
|
|
40594
40735
|
continue;
|
|
@@ -40633,13 +40774,14 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40633
40774
|
let requestId;
|
|
40634
40775
|
await saveState((fresh) => {
|
|
40635
40776
|
const entry = fresh.sessions[sessionKey(ctx.info)];
|
|
40636
|
-
if (!
|
|
40637
|
-
entry.pendingUploads =
|
|
40777
|
+
if (!isRecord7(entry) || entry.sessionId !== ctx.client.sessionId) throw new Error("Session identity changed; join again before answering.");
|
|
40778
|
+
entry.pendingUploads = isRecord7(entry.pendingUploads) ? entry.pendingUploads : {};
|
|
40638
40779
|
const previous = entry.pendingUploads[questionId];
|
|
40639
|
-
requestId = previous?.payloadDigest === digest &&
|
|
40780
|
+
requestId = previous?.payloadDigest === digest && trim8(previous.requestId) ? previous.requestId : `answer:v1:${operationId}:${questionId}`;
|
|
40640
40781
|
entry.pendingUploads[questionId] = { payloadDigest: digest, requestId };
|
|
40641
40782
|
});
|
|
40642
|
-
|
|
40783
|
+
checkpoint();
|
|
40784
|
+
const storageRef = await ctx.client.upload({ resource: "responses", data, requestId, signal });
|
|
40643
40785
|
if (text(storageRef?.id)) cacheRecord(ctx, text(storageRef.id), built.record);
|
|
40644
40786
|
answered.push({ questionId, requestId, record: built.record, answeredAt: text(storageRef?.createdAt) || new Date(now()).toISOString() });
|
|
40645
40787
|
results.push({ questionId, ok: true, answer: built.record.answer.value });
|
|
@@ -40726,7 +40868,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40726
40868
|
];
|
|
40727
40869
|
checkpoint();
|
|
40728
40870
|
try {
|
|
40729
|
-
const storageRef = await ctx.client.upload({ resource: "questions", data: built.record, tags: tagList });
|
|
40871
|
+
const storageRef = await ctx.client.upload({ resource: "questions", data: built.record, tags: tagList, signal });
|
|
40730
40872
|
if (text(storageRef?.id)) cacheRecord(ctx, text(storageRef.id), built.record);
|
|
40731
40873
|
return { session: ctx.info.slug, questionId: built.id, created: true, prompt: built.record.prompt };
|
|
40732
40874
|
} catch (error) {
|
|
@@ -40770,18 +40912,21 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40770
40912
|
let entries;
|
|
40771
40913
|
let complete;
|
|
40772
40914
|
let listedCount;
|
|
40915
|
+
let unreadAnswers;
|
|
40773
40916
|
const knownIds = new Set(questions.map((question) => question.id));
|
|
40774
40917
|
if (ctx.registry) {
|
|
40775
40918
|
const result = await ctx.registry.readAnswers({ questionIds: knownIds, maxRecords: cap, signal });
|
|
40776
40919
|
entries = result.entries;
|
|
40777
40920
|
complete = result.complete;
|
|
40778
40921
|
listedCount = entries.length;
|
|
40922
|
+
unreadAnswers = result.unreadAnswers;
|
|
40779
40923
|
} else {
|
|
40780
40924
|
const result = await ctx.client.listAll("responses", { maxItems: MAX_RESULT_RECORDS, signal });
|
|
40781
40925
|
const listed = result.items.filter((item) => text(item.storageRef?.id)).sort((left, right) => text(left.metadata?.createdAt) < text(right.metadata?.createdAt) ? 1 : -1);
|
|
40782
40926
|
entries = await toEntries(ctx, listed.slice(0, cap));
|
|
40783
40927
|
complete = result.complete;
|
|
40784
40928
|
listedCount = listed.length;
|
|
40929
|
+
unreadAnswers = entries.unread;
|
|
40785
40930
|
}
|
|
40786
40931
|
const latest = latestAnswersByQuestion(entries, {
|
|
40787
40932
|
sessionSlug: ctx.info.slug,
|
|
@@ -40794,6 +40939,7 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40794
40939
|
resultsPublic: true,
|
|
40795
40940
|
webUrl: buildSessionWebUrl(ctx.info),
|
|
40796
40941
|
participants: participants.size,
|
|
40942
|
+
unreadAnswers,
|
|
40797
40943
|
partial: !complete || listedCount > cap || questions.complete === false || entries.complete === false,
|
|
40798
40944
|
questions: questions.filter((question) => !wanted || wanted.has(question.id)).map((question) => summarizeQuestion(question, latest.get(question.id)))
|
|
40799
40945
|
};
|
|
@@ -40802,10 +40948,10 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40802
40948
|
const ctx = await resolveSession(session);
|
|
40803
40949
|
if (ctx.registry) throw new Error("Worker groups are not available in on-chain sessions.");
|
|
40804
40950
|
await ensureReady(ctx);
|
|
40805
|
-
const id =
|
|
40951
|
+
const id = trim8(groupId);
|
|
40806
40952
|
if (!/^[A-Za-z0-9._:-]{1,128}$/.test(id)) throw new Error("Pass a valid group id.");
|
|
40807
40953
|
checkpoint();
|
|
40808
|
-
await ctx.client.joinGroup(id);
|
|
40954
|
+
await ctx.client.joinGroup(id, { signal });
|
|
40809
40955
|
return { session: ctx.info.slug, joinedGroup: id };
|
|
40810
40956
|
},
|
|
40811
40957
|
async claimSbt({ session, sbt: sbtAddress, inviteCode, groupPassword, claimPassword } = {}) {
|
|
@@ -40817,10 +40963,10 @@ var createParticipant = ({ config, wallet, fetchImpl = globalThis.fetch, now = (
|
|
|
40817
40963
|
});
|
|
40818
40964
|
const result = await sbt.claim({
|
|
40819
40965
|
ctx,
|
|
40820
|
-
sbtAddress:
|
|
40821
|
-
inviteCode:
|
|
40822
|
-
groupPassword:
|
|
40823
|
-
claimPassword:
|
|
40966
|
+
sbtAddress: trim8(sbtAddress),
|
|
40967
|
+
inviteCode: trim8(inviteCode),
|
|
40968
|
+
groupPassword: trim8(groupPassword),
|
|
40969
|
+
claimPassword: trim8(claimPassword),
|
|
40824
40970
|
signal
|
|
40825
40971
|
});
|
|
40826
40972
|
await ctx.client.login().catch(() => {
|
|
@@ -40844,7 +40990,7 @@ var sessionParam = {
|
|
|
40844
40990
|
type: "string",
|
|
40845
40991
|
description: "Session slug or link. Defaults to the session joined most recently."
|
|
40846
40992
|
};
|
|
40847
|
-
var
|
|
40993
|
+
var text4 = (description, extra = {}) => ({ type: "string", description, ...extra });
|
|
40848
40994
|
var READ = { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true };
|
|
40849
40995
|
var WRITE = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true };
|
|
40850
40996
|
var SPENDS = { ...WRITE, destructiveHint: true };
|
|
@@ -40864,9 +41010,9 @@ var buildTools = (participant) => [
|
|
|
40864
41010
|
inputSchema: {
|
|
40865
41011
|
type: "object",
|
|
40866
41012
|
properties: {
|
|
40867
|
-
displayName:
|
|
40868
|
-
modelId:
|
|
40869
|
-
platform:
|
|
41013
|
+
displayName: text4("Name shown in reports; up to 80 characters. Empty string clears it."),
|
|
41014
|
+
modelId: text4("Model identifier, for example the model you run on."),
|
|
41015
|
+
platform: text4("Agent platform or harness.")
|
|
40870
41016
|
},
|
|
40871
41017
|
additionalProperties: false
|
|
40872
41018
|
},
|
|
@@ -40880,12 +41026,12 @@ var buildTools = (participant) => [
|
|
|
40880
41026
|
inputSchema: {
|
|
40881
41027
|
type: "object",
|
|
40882
41028
|
properties: {
|
|
40883
|
-
link:
|
|
40884
|
-
worker:
|
|
40885
|
-
session:
|
|
40886
|
-
inviteCode:
|
|
40887
|
-
groupPassword:
|
|
40888
|
-
claimPassword:
|
|
41029
|
+
link: text4("Session link, including any invite parameters."),
|
|
41030
|
+
worker: text4("Worker origin, when you have no link."),
|
|
41031
|
+
session: text4("Session slug, when you have no link."),
|
|
41032
|
+
inviteCode: text4("SBT invite code, if one was given separately from the link."),
|
|
41033
|
+
groupPassword: text4("SBT group password, if one was given separately."),
|
|
41034
|
+
claimPassword: text4("SBT claim password, if one was given separately.")
|
|
40889
41035
|
},
|
|
40890
41036
|
additionalProperties: false
|
|
40891
41037
|
},
|
|
@@ -40911,7 +41057,7 @@ var buildTools = (participant) => [
|
|
|
40911
41057
|
{
|
|
40912
41058
|
name: "list_questions",
|
|
40913
41059
|
title: "List questions",
|
|
40914
|
-
description: "List the session\u2019s statements and questions with their type, options or scale, and your latest answer. Unanswered ones come first by default.",
|
|
41060
|
+
description: "List the session\u2019s statements and questions with their type, options or scale, and your latest answer. Unanswered ones come first by default. questionsComplete or myAnswersComplete is false when listing or payload reads are unfinished; unreadQuestions and unreadMyAnswers count listed payloads that could not be read.",
|
|
40915
41061
|
inputSchema: {
|
|
40916
41062
|
type: "object",
|
|
40917
41063
|
properties: {
|
|
@@ -40927,7 +41073,7 @@ var buildTools = (participant) => [
|
|
|
40927
41073
|
{
|
|
40928
41074
|
name: "answer",
|
|
40929
41075
|
title: "Answer questions",
|
|
40930
|
-
description: 'Submit answers. Values by type: binary "Agree" | "Unsure" | "Disagree"; rating a
|
|
41076
|
+
description: 'Submit answers. Values by type: binary "Agree" | "Unsure" | "Disagree"; rating a number on the question\u2019s scale and step grid (default step 1); multichoice the option text (an array when several are allowed); quadratic one signed whole-number vote per option whose squares sum within the credit budget; freeform text. Answering again replaces your previous answer.',
|
|
40931
41077
|
inputSchema: {
|
|
40932
41078
|
type: "object",
|
|
40933
41079
|
properties: {
|
|
@@ -40939,9 +41085,9 @@ var buildTools = (participant) => [
|
|
|
40939
41085
|
items: {
|
|
40940
41086
|
type: "object",
|
|
40941
41087
|
properties: {
|
|
40942
|
-
questionId:
|
|
41088
|
+
questionId: text4("Question id from list_questions."),
|
|
40943
41089
|
value: { description: "The answer value; see the tool description for each type." },
|
|
40944
|
-
comment:
|
|
41090
|
+
comment: text4("Optional reasoning shown with your answer (up to 4000 characters)."),
|
|
40945
41091
|
importance: { type: "integer", minimum: 0, maximum: 10, description: "How much this question matters to you." },
|
|
40946
41092
|
conviction: { type: "integer", minimum: 0, maximum: 10, description: "How sure you are of your answer." }
|
|
40947
41093
|
},
|
|
@@ -40964,7 +41110,7 @@ var buildTools = (participant) => [
|
|
|
40964
41110
|
type: "object",
|
|
40965
41111
|
properties: {
|
|
40966
41112
|
session: sessionParam,
|
|
40967
|
-
prompt:
|
|
41113
|
+
prompt: text4("The statement or question text."),
|
|
40968
41114
|
type: { type: "string", enum: ["binary", "rating", "multichoice", "quadratic", "freeform"] },
|
|
40969
41115
|
options: { type: "array", items: { type: "string" }, description: "Options for multichoice or quadratic." },
|
|
40970
41116
|
singleSelect: { type: "boolean", description: "Multichoice: allow only one option." },
|
|
@@ -40980,7 +41126,7 @@ var buildTools = (participant) => [
|
|
|
40980
41126
|
{
|
|
40981
41127
|
name: "get_results",
|
|
40982
41128
|
title: "Get results",
|
|
40983
|
-
description: "Summarize everyone\u2019s latest answers per question when the session publishes results: agree/unsure/disagree counts, rating means, option counts, and how many answers came from self-declared agents.",
|
|
41129
|
+
description: "Summarize everyone\u2019s latest answers per question when the session publishes results: agree/unsure/disagree counts, rating means, option counts, and how many answers came from self-declared agents. partial is true when a scan is unfinished, capped, or any listed question or answer payload could not be read. unreadAnswers counts the selected listed answer records that could not be read; readable older answers may still appear until those records recover.",
|
|
40984
41130
|
inputSchema: {
|
|
40985
41131
|
type: "object",
|
|
40986
41132
|
properties: {
|
|
@@ -40999,7 +41145,7 @@ var buildTools = (participant) => [
|
|
|
40999
41145
|
description: "Join an open group in the session by its id (from a ?joinGroup= link).",
|
|
41000
41146
|
inputSchema: {
|
|
41001
41147
|
type: "object",
|
|
41002
|
-
properties: { session: sessionParam, groupId:
|
|
41148
|
+
properties: { session: sessionParam, groupId: text4("Group id.") },
|
|
41003
41149
|
required: ["groupId"],
|
|
41004
41150
|
additionalProperties: false
|
|
41005
41151
|
},
|
|
@@ -41014,10 +41160,10 @@ var buildTools = (participant) => [
|
|
|
41014
41160
|
type: "object",
|
|
41015
41161
|
properties: {
|
|
41016
41162
|
session: sessionParam,
|
|
41017
|
-
sbt:
|
|
41018
|
-
inviteCode:
|
|
41019
|
-
groupPassword:
|
|
41020
|
-
claimPassword:
|
|
41163
|
+
sbt: text4("SBT contract address."),
|
|
41164
|
+
inviteCode: text4("Invite code, when the SBT uses invites."),
|
|
41165
|
+
groupPassword: text4("Group password, when the SBT uses one."),
|
|
41166
|
+
claimPassword: text4("Claim password, when the SBT uses per-claim passwords.")
|
|
41021
41167
|
},
|
|
41022
41168
|
required: ["sbt"],
|
|
41023
41169
|
additionalProperties: false
|