@konneal/engine 0.2.33 → 0.2.35
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/apicalls.d.ts +72 -0
- package/dist/ask-P6KLPBKL.js +12 -0
- package/dist/{chunk-JGKSUSF5.js → chunk-4GJGBGJK.js} +3 -3
- package/dist/{chunk-NHHQAGBW.js → chunk-GHDRKT4K.js} +115 -25
- package/dist/{chunk-2RKYO3OC.js → chunk-R2V3X6SQ.js} +1 -1
- package/dist/{chunk-OMXAE27N.js → chunk-V46XM2GU.js} +4 -0
- package/dist/{chunk-WSLADX7O.js → chunk-YSWKFXXG.js} +306 -12
- package/dist/{chunk-5LSEBH3J.js → chunk-Z7AQEW6G.js} +4 -4
- package/dist/config.d.ts +1 -0
- package/dist/context.d.ts +37 -0
- package/dist/delegated.d.ts +2 -0
- package/dist/drafts.d.ts +5 -0
- package/dist/env.d.ts +2 -0
- package/dist/livedata.d.ts +14 -0
- package/dist/oidc.d.ts +12 -0
- package/dist/prompts/system.md +2 -1
- package/dist/requestScope.d.ts +10 -2
- package/dist/search-IBZ2BK2E.js +12 -0
- package/dist/worker_mcp/src/index.js +2 -2
- package/dist/worker_public/src/config.js +1 -1
- package/dist/worker_public/src/index.js +8 -8
- package/dist/worker_public/src/requestScope.js +2 -2
- package/docs/API.md +83 -0
- package/package.json +1 -1
- package/workers/shared/session.ts +10 -0
- package/workers/worker_public/prompts/system.md +2 -1
- package/workers/worker_public/src/apicalls.ts +447 -0
- package/workers/worker_public/src/ask.ts +58 -8
- package/workers/worker_public/src/auth.ts +7 -1
- package/workers/worker_public/src/config.ts +4 -0
- package/workers/worker_public/src/context.ts +89 -4
- package/workers/worker_public/src/delegated.ts +83 -0
- package/workers/worker_public/src/drafts.ts +10 -0
- package/workers/worker_public/src/env.ts +5 -1
- package/workers/worker_public/src/index.ts +4 -1
- package/workers/worker_public/src/livedata.ts +24 -2
- package/workers/worker_public/src/oidc.ts +35 -19
- package/workers/worker_public/src/ports/cloudflare/adapters.ts +8 -0
- package/workers/worker_public/src/requestScope.ts +9 -3
- package/dist/ask-GU554Y45.js +0 -12
- package/dist/search-LGDQR43R.js +0 -12
|
@@ -8,15 +8,17 @@ import {
|
|
|
8
8
|
contextNote,
|
|
9
9
|
editionNote,
|
|
10
10
|
embed,
|
|
11
|
-
exchangeForLiveToken,
|
|
12
11
|
generateOnce,
|
|
13
12
|
graphExpand,
|
|
14
13
|
identityNote,
|
|
15
14
|
listwiseRerank,
|
|
16
15
|
liveDataConfig,
|
|
16
|
+
liveTokenFor,
|
|
17
|
+
machineOffers,
|
|
17
18
|
namedDocumentIn,
|
|
18
19
|
parseContext,
|
|
19
20
|
portModelRunner,
|
|
21
|
+
portStore,
|
|
20
22
|
rawSessionToken,
|
|
21
23
|
refCodec,
|
|
22
24
|
resolveDocScope,
|
|
@@ -28,14 +30,14 @@ import {
|
|
|
28
30
|
syntheticUnderstanding,
|
|
29
31
|
telemetry,
|
|
30
32
|
understandQuery
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-GHDRKT4K.js";
|
|
32
34
|
import {
|
|
33
35
|
corsHeaders,
|
|
34
36
|
err,
|
|
35
37
|
json,
|
|
36
38
|
readJson,
|
|
37
39
|
validateQuery
|
|
38
|
-
} from "./chunk-
|
|
40
|
+
} from "./chunk-R2V3X6SQ.js";
|
|
39
41
|
import {
|
|
40
42
|
canonicalRefusal,
|
|
41
43
|
refusalAnswer
|
|
@@ -43,8 +45,9 @@ import {
|
|
|
43
45
|
import {
|
|
44
46
|
entitlementScope,
|
|
45
47
|
requestSalt,
|
|
46
|
-
resolveRequestScope
|
|
47
|
-
|
|
48
|
+
resolveRequestScope,
|
|
49
|
+
standardKeysFrom
|
|
50
|
+
} from "./chunk-4GJGBGJK.js";
|
|
48
51
|
import {
|
|
49
52
|
LIMITS,
|
|
50
53
|
MODELS,
|
|
@@ -54,7 +57,7 @@ import {
|
|
|
54
57
|
requestEffort,
|
|
55
58
|
roleModel,
|
|
56
59
|
sha256Hex
|
|
57
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-V46XM2GU.js";
|
|
58
61
|
import {
|
|
59
62
|
P
|
|
60
63
|
} from "./chunk-3FYJM7LH.js";
|
|
@@ -1196,6 +1199,11 @@ ${transcript}` }
|
|
|
1196
1199
|
}
|
|
1197
1200
|
var norm = (s) => s.toLowerCase().replace(/[^a-z0-9-]+/g, " ").replace(/\s+/g, " ").trim();
|
|
1198
1201
|
var docNorm = (s) => norm(s).replace(/\s+/g, "");
|
|
1202
|
+
function valueTracesToUser(value, userTurns) {
|
|
1203
|
+
if (typeof value !== "string" || !value.trim()) return false;
|
|
1204
|
+
const haystack = norm(userTurns.join("\n"));
|
|
1205
|
+
return haystack.includes(norm(value));
|
|
1206
|
+
}
|
|
1199
1207
|
var DROP_REASON = "not stated in your own words";
|
|
1200
1208
|
function traceabilityGuard(extraction, userTurns) {
|
|
1201
1209
|
const haystack = norm(userTurns.join("\n"));
|
|
@@ -1385,6 +1393,263 @@ The draft opens in the real application form with every field editable \u2014 re
|
|
|
1385
1393
|
};
|
|
1386
1394
|
}
|
|
1387
1395
|
|
|
1396
|
+
// workers/worker_public/src/apicalls.ts
|
|
1397
|
+
function actsProfile() {
|
|
1398
|
+
const acts = P().publisher?.acts;
|
|
1399
|
+
return acts && typeof acts === "object" ? acts : null;
|
|
1400
|
+
}
|
|
1401
|
+
function neverOffered(path) {
|
|
1402
|
+
const prefixes = actsProfile()?.never_offer ?? [];
|
|
1403
|
+
return prefixes.some((p) => typeof p === "string" && path.startsWith(p));
|
|
1404
|
+
}
|
|
1405
|
+
async function operationById(store, id) {
|
|
1406
|
+
try {
|
|
1407
|
+
return await store.prepare("SELECT operation_id, method, path, act_class, summary, tag FROM api_ops WHERE operation_id = ?1").bind(id).first();
|
|
1408
|
+
} catch {
|
|
1409
|
+
return null;
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1412
|
+
async function operationByMethodPath(store, method, path) {
|
|
1413
|
+
try {
|
|
1414
|
+
return await store.prepare("SELECT operation_id, method, path, act_class, summary, tag FROM api_ops WHERE method = ?1 AND path = ?2").bind(method.toLowerCase(), path).first();
|
|
1415
|
+
} catch {
|
|
1416
|
+
return null;
|
|
1417
|
+
}
|
|
1418
|
+
}
|
|
1419
|
+
async function preferenceOps(store) {
|
|
1420
|
+
try {
|
|
1421
|
+
const rows = await store.prepare("SELECT operation_id, method, path, act_class, summary, tag FROM api_ops WHERE act_class = 'preference' ORDER BY operation_id LIMIT 32").bind().all();
|
|
1422
|
+
return rows.results ?? [];
|
|
1423
|
+
} catch {
|
|
1424
|
+
return [];
|
|
1425
|
+
}
|
|
1426
|
+
}
|
|
1427
|
+
function resolveEntityRoute(route) {
|
|
1428
|
+
const patterns = actsProfile()?.entity_routes ?? [];
|
|
1429
|
+
if (!route) return null;
|
|
1430
|
+
const segs = route.split("?")[0].split("/").filter(Boolean);
|
|
1431
|
+
for (const p of patterns) {
|
|
1432
|
+
const psegs = String(p.pattern ?? "").split("/").filter(Boolean);
|
|
1433
|
+
if (psegs.length !== segs.length) continue;
|
|
1434
|
+
let id = null;
|
|
1435
|
+
let ok = true;
|
|
1436
|
+
for (let i = 0; i < psegs.length; i++) {
|
|
1437
|
+
const ps = psegs[i];
|
|
1438
|
+
if (ps.startsWith(":")) {
|
|
1439
|
+
id = decodeURIComponent(segs[i]);
|
|
1440
|
+
} else if (ps !== segs[i]) {
|
|
1441
|
+
ok = false;
|
|
1442
|
+
break;
|
|
1443
|
+
}
|
|
1444
|
+
}
|
|
1445
|
+
if (ok && id && id.length <= 120 && /^[A-Za-z0-9._~-]+$/.test(id)) return { store: String(p.store), id };
|
|
1446
|
+
}
|
|
1447
|
+
return null;
|
|
1448
|
+
}
|
|
1449
|
+
var MACHINE_INTENT_RE = /\b(accept|reject|submit|resubmit|withdraw|suspend|reinstate|renew|revise|transfer|issue|register|log|record|dispatch|complete|sign|approve|verify)\b[\s\S]{0,40}\b(this|that|the|it)\b|\b(this|that|the|it)\b[\s\S]{0,40}\b(accept|reject|submit|resubmit|withdraw|suspend|reinstate|renew|revise|transfer|issue|register|log|dispatch|complete|sign|approve|verify)\b/i;
|
|
1450
|
+
var PREFERENCE_INTENT_RE = /\b(mute|unmute|unsubscribe|subscribe|notification prefs?|notification rules?|email prefs?|email preferences|saved? filters?|save (?:this|the|that) filter|notify me|stop notifying|inbox)\b/i;
|
|
1451
|
+
var QUESTION_OPENER_RE = /^\s*(?:what|how|why|where|when|which|who|whose|explain|describe|define|is|are|does|do)\b/i;
|
|
1452
|
+
function detectApiCallIntent(query, declared) {
|
|
1453
|
+
if (QUESTION_OPENER_RE.test(query)) return null;
|
|
1454
|
+
if (declared?.kind === "entity" && declared.machine && MACHINE_INTENT_RE.test(query)) return "machine_act";
|
|
1455
|
+
if (PREFERENCE_INTENT_RE.test(query)) return "preference";
|
|
1456
|
+
return null;
|
|
1457
|
+
}
|
|
1458
|
+
function pickPrompt(kind, candidates) {
|
|
1459
|
+
if (kind === "machine_act") {
|
|
1460
|
+
return {
|
|
1461
|
+
system: `You map the user's request to one machine act from the OFFERED list, or to none.
|
|
1462
|
+
|
|
1463
|
+
Rules:
|
|
1464
|
+
- Output ONLY a JSON object \u2014 no prose, no code fence: {"target": "<action id or null>", "title": "<what the act does, plain words>"}.
|
|
1465
|
+
- The target must be one of the offered action ids, copied exactly, or null when the request matches none.
|
|
1466
|
+
- The title names what the act DOES for the user ("Accept the application"), never the wire (no method, no path, no "/api/").
|
|
1467
|
+
- Never invent an act that is not listed.
|
|
1468
|
+
|
|
1469
|
+
Offered acts (action id \u2014 lands the entity on):
|
|
1470
|
+
${candidates.join("\n")}`,
|
|
1471
|
+
max: 300
|
|
1472
|
+
};
|
|
1473
|
+
}
|
|
1474
|
+
return {
|
|
1475
|
+
system: `You map the user's request to one operation from the PREFERENCE list (the user's own settings), or to none.
|
|
1476
|
+
|
|
1477
|
+
Rules:
|
|
1478
|
+
- Output ONLY a JSON object \u2014 no prose, no code fence: {"target": "<operation id or null>", "title": "<what the act does, plain words>", "body": {...}}.
|
|
1479
|
+
- The target must be one of the listed operation ids, copied exactly, or null when the request matches none.
|
|
1480
|
+
- "body" carries only values the user stated in their own words; omit it when the request names no values.
|
|
1481
|
+
- The title names what the act DOES for the user ("Save the filter", "Mute these emails"), never the wire (no method, no path, no "/api/").
|
|
1482
|
+
- Never invent an operation that is not listed.
|
|
1483
|
+
|
|
1484
|
+
Preference operations (id \u2014 method path \u2014 summary):
|
|
1485
|
+
${candidates.join("\n")}`,
|
|
1486
|
+
max: 800
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
async function pickTarget(runner, model, kind, candidates, userTurns) {
|
|
1490
|
+
const { system, max } = pickPrompt(kind, candidates);
|
|
1491
|
+
const transcript = userTurns.map((t, i) => `${i + 1}. ${t}`).join("\n").slice(0, 8e3);
|
|
1492
|
+
try {
|
|
1493
|
+
const res = await runner.run({
|
|
1494
|
+
model,
|
|
1495
|
+
messages: [
|
|
1496
|
+
{ role: "system", content: system },
|
|
1497
|
+
{ role: "user", content: `The user's messages, oldest first:
|
|
1498
|
+
${transcript}` }
|
|
1499
|
+
],
|
|
1500
|
+
maxTokens: max,
|
|
1501
|
+
effort: "low",
|
|
1502
|
+
temperature: 0.1
|
|
1503
|
+
});
|
|
1504
|
+
const text = res.text;
|
|
1505
|
+
if (typeof text !== "string") return null;
|
|
1506
|
+
const start = text.indexOf("{");
|
|
1507
|
+
const end = text.lastIndexOf("}");
|
|
1508
|
+
if (start < 0 || end <= start) return null;
|
|
1509
|
+
const parsed = JSON.parse(text.slice(start, end + 1));
|
|
1510
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
1511
|
+
return {
|
|
1512
|
+
target: typeof parsed.target === "string" && parsed.target.trim() ? parsed.target.trim().slice(0, 120) : null,
|
|
1513
|
+
title: typeof parsed.title === "string" && parsed.title.trim() ? parsed.title.trim().slice(0, 120) : void 0,
|
|
1514
|
+
body: parsed.body && typeof parsed.body === "object" ? parsed.body : void 0
|
|
1515
|
+
};
|
|
1516
|
+
} catch {
|
|
1517
|
+
return null;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
function honestTitle(proposed, fallback) {
|
|
1521
|
+
const t = (proposed ?? "").trim();
|
|
1522
|
+
if (!t) return fallback;
|
|
1523
|
+
if (/\b(GET|POST|PUT|PATCH|DELETE)\b/.test(t) || t.includes("/api/") || t.includes("{")) return fallback;
|
|
1524
|
+
return t.slice(0, 120);
|
|
1525
|
+
}
|
|
1526
|
+
function bodyTraces(body, userTurns) {
|
|
1527
|
+
if (body == null) return true;
|
|
1528
|
+
if (typeof body === "boolean" || typeof body === "number") return true;
|
|
1529
|
+
if (typeof body === "string") return valueTracesToUser(body, userTurns);
|
|
1530
|
+
if (Array.isArray(body)) return body.every((v) => bodyTraces(v, userTurns));
|
|
1531
|
+
if (typeof body === "object") return Object.values(body).every((v) => bodyTraces(v, userTurns));
|
|
1532
|
+
return false;
|
|
1533
|
+
}
|
|
1534
|
+
function refusal2(reason, answer) {
|
|
1535
|
+
return { status: "refused", reason, answer };
|
|
1536
|
+
}
|
|
1537
|
+
async function prepareApiCall(env, opts) {
|
|
1538
|
+
if (!opts.member) {
|
|
1539
|
+
return refusal2(
|
|
1540
|
+
"sign_in_required",
|
|
1541
|
+
"Preparing an act starts from your own account \u2014 sign in and ask again. The draft would still be yours alone: the card asks for your confirmation, and only your own tap executes it \u2014 I never hold a write credential."
|
|
1542
|
+
);
|
|
1543
|
+
}
|
|
1544
|
+
const acts = actsProfile();
|
|
1545
|
+
const store = portStore(env);
|
|
1546
|
+
const runner = portModelRunner(env);
|
|
1547
|
+
const userTurns = [...opts.history.filter((h) => h.role === "user").map((h) => h.content), opts.query];
|
|
1548
|
+
if (opts.intent === "machine_act") {
|
|
1549
|
+
const machine = opts.declared?.machine;
|
|
1550
|
+
const label = opts.declared?.label || "this record";
|
|
1551
|
+
if (!machine) {
|
|
1552
|
+
return refusal2("no_matching_act", "This page did not declare the record's lifecycle state, so I cannot propose an act on it honestly. Open the record itself and ask again, or act from the platform's own controls \u2014 they always show exactly what your role may do.");
|
|
1553
|
+
}
|
|
1554
|
+
if (machine.acts.length === 0) {
|
|
1555
|
+
return refusal2(
|
|
1556
|
+
"machine_read_only",
|
|
1557
|
+
`The record's lifecycle is at ${machine.state}, and the machine offers your role no acts there \u2014 you can read this record but not act on it. Nothing was drafted. If that looks wrong, an officer of your organization can check the role your account carries.`
|
|
1558
|
+
);
|
|
1559
|
+
}
|
|
1560
|
+
const entity = resolveEntityRoute(opts.declared?.route);
|
|
1561
|
+
if (!entity) {
|
|
1562
|
+
return refusal2("entity_unresolved", "I cannot tell which record the act would land on from this page, so nothing was drafted. The platform's own controls on the record always act on the right one.");
|
|
1563
|
+
}
|
|
1564
|
+
const candidates2 = machine.acts.map((a) => `${a.action} \u2014 lands on ${a.to}${a.guard ? ` (requires ${a.guard})` : ""}`);
|
|
1565
|
+
const pick2 = await pickTarget(runner, opts.model, "machine_act", candidates2, userTurns);
|
|
1566
|
+
if (!pick2) {
|
|
1567
|
+
return refusal2("pick_failed", "I could not map your request to an act reliably just now \u2014 nothing was drafted. Ask again in a moment, or act from the platform's own controls.");
|
|
1568
|
+
}
|
|
1569
|
+
if (!pick2.target || !machineOffers(machine, pick2.target)) {
|
|
1570
|
+
const offered = machine.acts.map((a) => a.action).join(", ");
|
|
1571
|
+
return refusal2(
|
|
1572
|
+
"no_matching_act",
|
|
1573
|
+
`None of the acts the machine offers your role at ${machine.state} matches that request \u2014 the offered set is exactly: ${offered}. I never propose an act outside it. Nothing was drafted.`
|
|
1574
|
+
);
|
|
1575
|
+
}
|
|
1576
|
+
const act = machine.acts.find((a) => a.action === pick2.target);
|
|
1577
|
+
const write = acts?.entity_write;
|
|
1578
|
+
if (!write?.method || !write?.path) {
|
|
1579
|
+
return refusal2("operation_unknown", "This deployment has not wired the entity write operation, so I cannot prepare the act here.");
|
|
1580
|
+
}
|
|
1581
|
+
const op2 = await operationByMethodPath(store, write.method, write.path);
|
|
1582
|
+
if (!op2) {
|
|
1583
|
+
return refusal2("operation_unknown", "The act's operation is not in this deployment's API directory, so I cannot prepare it honestly \u2014 nothing was drafted.");
|
|
1584
|
+
}
|
|
1585
|
+
if (neverOffered(op2.path)) {
|
|
1586
|
+
return refusal2("operation_never_offered", "That act is not one the assistant may propose \u2014 nothing was drafted.");
|
|
1587
|
+
}
|
|
1588
|
+
const path = write.path.replace("{store}", entity.store).replace("{id}", entity.id);
|
|
1589
|
+
const title2 = honestTitle(pick2.title, `${act.action} \u2014 ${label}`.slice(0, 120));
|
|
1590
|
+
const notes = [
|
|
1591
|
+
`The machine act ${act.action} moves the record from ${machine.state} to ${act.to}; the platform re-judges the act against the machine and your role when you confirm.`,
|
|
1592
|
+
...act.guard ? [`This act declares the ${act.guard} input \u2014 the confirmation card collects it; the draft carries none.`] : []
|
|
1593
|
+
];
|
|
1594
|
+
const draft2 = {
|
|
1595
|
+
kind: "draft",
|
|
1596
|
+
act: "api_call",
|
|
1597
|
+
version: 1,
|
|
1598
|
+
title: title2,
|
|
1599
|
+
prepared_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1600
|
+
requires_confirmation: true,
|
|
1601
|
+
call: { method: write.method, path, body: { status: act.to } },
|
|
1602
|
+
notes
|
|
1603
|
+
};
|
|
1604
|
+
const answer2 = `I've prepared the act "${title2}" for ${label}: the machine act ${act.action}, from ${machine.state} to ${act.to}.
|
|
1605
|
+
|
|
1606
|
+
The confirmation card carries it \u2014 a record act, so your own confirmation signs it and the platform's gates judge the write as you. I never hold a write credential, and I never propose an act the machine does not offer your role.`;
|
|
1607
|
+
return { status: "draft", draft: draft2, answer: answer2 };
|
|
1608
|
+
}
|
|
1609
|
+
const family = (await preferenceOps(store)).filter((o) => !neverOffered(o.path));
|
|
1610
|
+
if (!family.length) {
|
|
1611
|
+
return refusal2("operation_unknown", "This deployment's API directory lists no preference operations, so I cannot prepare that here \u2014 nothing was drafted.");
|
|
1612
|
+
}
|
|
1613
|
+
const candidates = family.map((o) => `${o.operation_id} \u2014 ${o.method.toUpperCase()} ${o.path} \u2014 ${o.summary ?? ""}`.slice(0, 300));
|
|
1614
|
+
const pick = await pickTarget(runner, opts.model, "preference", candidates, userTurns);
|
|
1615
|
+
if (!pick) {
|
|
1616
|
+
return refusal2("pick_failed", "I could not map your request to a preference act reliably just now \u2014 nothing was drafted. Ask again in a moment, or change the setting on your account page directly.");
|
|
1617
|
+
}
|
|
1618
|
+
if (!pick.target) {
|
|
1619
|
+
return refusal2("no_matching_act", "None of the preference acts I may propose matches that request \u2014 nothing was drafted. Your account's settings page carries the full set.");
|
|
1620
|
+
}
|
|
1621
|
+
const op = await operationById(store, pick.target);
|
|
1622
|
+
if (!op || op.act_class !== "preference") {
|
|
1623
|
+
return refusal2("operation_unknown", "I cannot match that request to a preference act the platform declares \u2014 nothing was drafted.");
|
|
1624
|
+
}
|
|
1625
|
+
if (neverOffered(op.path)) {
|
|
1626
|
+
return refusal2("operation_never_offered", "That act is not one the assistant may propose \u2014 delegation and sign-in acts stay in your own hands on the settings page. Nothing was drafted.");
|
|
1627
|
+
}
|
|
1628
|
+
if (pick.body !== void 0 && !bodyTraces(pick.body, userTurns)) {
|
|
1629
|
+
return refusal2(
|
|
1630
|
+
"body_untraced",
|
|
1631
|
+
"I can't prepare that change because the values I would set are not ones you stated \u2014 I never invent settings. Tell me exactly what to set, in your own words, and I'll prepare the draft."
|
|
1632
|
+
);
|
|
1633
|
+
}
|
|
1634
|
+
const title = honestTitle(pick.title, (op.summary ?? op.operation_id).slice(0, 120));
|
|
1635
|
+
const draft = {
|
|
1636
|
+
kind: "draft",
|
|
1637
|
+
act: "api_call",
|
|
1638
|
+
version: 1,
|
|
1639
|
+
title,
|
|
1640
|
+
prepared_at: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1641
|
+
requires_confirmation: true,
|
|
1642
|
+
call: { method: op.method.toUpperCase(), path: op.path, ...pick.body !== void 0 ? { body: pick.body } : {} },
|
|
1643
|
+
notes: [
|
|
1644
|
+
"A preference act: with your standing grant the card executes it straight away; without one, your own tap on the card confirms it. The grant is yours on the settings page \u2014 granted or revoked by your hand, never by a message."
|
|
1645
|
+
]
|
|
1646
|
+
};
|
|
1647
|
+
const answer = `I've prepared the act "${title}" \u2014 a preference act on your own settings.
|
|
1648
|
+
|
|
1649
|
+
With your standing grant it executes under the grant's authority; without one, the card asks once and your tap confirms it. The platform re-checks the act against its own specification either way, and the grant never covers record acts.`;
|
|
1650
|
+
return { status: "draft", draft, answer };
|
|
1651
|
+
}
|
|
1652
|
+
|
|
1388
1653
|
// workers/worker_public/src/memories.ts
|
|
1389
1654
|
var MAX_FILES = 10;
|
|
1390
1655
|
var MAX_CONTENT = 8e3;
|
|
@@ -1629,6 +1894,7 @@ async function handleAsk(env, ctx, req, tier, key) {
|
|
|
1629
1894
|
if (!q) return err(400, "invalid_input", `query is required (1-${LIMITS.maxInputChars} chars)`);
|
|
1630
1895
|
const declaredCtx = parseContext(body);
|
|
1631
1896
|
const draftAct = P().publisher.features?.drafts ? detectDraftIntent(q.query) : null;
|
|
1897
|
+
const apiCallIntent = !draftAct && P().publisher.features?.api_call_drafts ? detectApiCallIntent(q.query, declaredCtx) : null;
|
|
1632
1898
|
const member = tier === "member" ? await sessionFrom(req, env) : null;
|
|
1633
1899
|
const effort = requestEffort(env, member, body?.effort);
|
|
1634
1900
|
const limit = tier === "key" ? key.day_limit : tier === "member" || member ? num(env, "MEMBER_DAY_ASK", 300) : num(env, "ANON_DAY_ASK", 20);
|
|
@@ -1649,14 +1915,15 @@ async function handleAsk(env, ctx, req, tier, key) {
|
|
|
1649
1915
|
cookie: req.headers.get("cookie") ?? "",
|
|
1650
1916
|
authorization: req.headers.get("authorization") ?? ""
|
|
1651
1917
|
};
|
|
1652
|
-
const
|
|
1918
|
+
const keyLicensed = tier === "key" && standardKeysFrom(body).size > 0;
|
|
1919
|
+
const scope = resolveRequestScope(body, member, { keyWithEntitlements: keyLicensed });
|
|
1653
1920
|
if ("error" in scope) return err(400, "invalid_input", "datasets: at least one dataset must stay enabled");
|
|
1654
1921
|
const { corpora, narrowed, isoOn } = scope;
|
|
1655
1922
|
const standardKeys = entitlementScope(scope.standardKeys);
|
|
1656
1923
|
const [memNote, memoryUsed] = member && scope.memoryIds.length ? await memoryNote(env, member.sub, scope.memoryIds) : [null, []];
|
|
1657
1924
|
const requestSaltStr = requestSalt(scope, memoryUsed);
|
|
1658
1925
|
const salt = requestSaltStr ? `${requestSaltStr}|effort:${effort}` : `effort:${effort}`;
|
|
1659
|
-
const federate = member && service && isoOn ? (q2) => retrieveInternal(service, fedAuth, q2) : void 0;
|
|
1926
|
+
const federate = (member || keyLicensed) && service && isoOn ? (q2) => retrieveInternal(service, fedAuth, q2) : void 0;
|
|
1660
1927
|
const ns = tier === "key" ? `k:${key.id}` : member ? `m:${member.sub}` : "anon";
|
|
1661
1928
|
const model = member ? MODELS.member : MODELS.anon;
|
|
1662
1929
|
const prev = typeof body?.prev === "string" ? body.prev.slice(0, 800) : void 0;
|
|
@@ -1673,7 +1940,7 @@ async function handleAsk(env, ctx, req, tier, key) {
|
|
|
1673
1940
|
let retrieved;
|
|
1674
1941
|
const fresh = freshRequested(body);
|
|
1675
1942
|
const gen = await corpusGen(env.CACHE);
|
|
1676
|
-
const cached = fresh || contextual || declaredCtx || draftAct || userImage ? null : await cacheGet(env, gen, ns, q.query, q.lang, salt);
|
|
1943
|
+
const cached = fresh || contextual || declaredCtx || draftAct || apiCallIntent || userImage ? null : await cacheGet(env, gen, ns, q.query, q.lang, salt);
|
|
1677
1944
|
const wantsStream = body?.stream === true || tier === "anon" && body?.stream !== false;
|
|
1678
1945
|
if (cached) {
|
|
1679
1946
|
telemetry(env, ctx, tier, "ask", null, true, (cached.value.answer ?? "").length, cached.value.query_hash, q.lang, "exact", telemetryMeta());
|
|
@@ -1697,7 +1964,7 @@ async function handleAsk(env, ctx, req, tier, key) {
|
|
|
1697
1964
|
}
|
|
1698
1965
|
let understanding = null;
|
|
1699
1966
|
const nodeScoped = !!modelNodeRefIn(q.query) || !!modelNodeRefIn(declaredCtx?.label);
|
|
1700
|
-
if (!cached && !nodeScoped && !contextual && !declaredCtx && !draftAct && !q.lang && !userImage && !fresh) {
|
|
1967
|
+
if (!cached && !nodeScoped && !contextual && !declaredCtx && !draftAct && !apiCallIntent && !q.lang && !userImage && !fresh) {
|
|
1701
1968
|
const wv0 = await warmEmbed ?? null;
|
|
1702
1969
|
if (wv0) {
|
|
1703
1970
|
const sc0 = await semanticCacheGet(env, gen, wv0, salt);
|
|
@@ -1795,7 +2062,7 @@ async function handleAsk(env, ctx, req, tier, key) {
|
|
|
1795
2062
|
console.log("understand:", understanding?.intent ?? "null", understanding?.doc_number ? `doc#${understanding.doc_number}${understanding.edition ? "@" + understanding.edition : ""}` : "nodoc", "|", q.query.slice(0, 50));
|
|
1796
2063
|
const graphDocNumbers = await graphExpand(env, understanding);
|
|
1797
2064
|
const eNote = await editionNote(env, understanding);
|
|
1798
|
-
if (understanding?.intent !== "conversational" && !nodeScoped && !contextual && !declaredCtx && !draftAct && !userImage && !fresh) {
|
|
2065
|
+
if (understanding?.intent !== "conversational" && !nodeScoped && !contextual && !declaredCtx && !draftAct && !apiCallIntent && !userImage && !fresh) {
|
|
1799
2066
|
const warmVec = await warmEmbed ?? null;
|
|
1800
2067
|
if (warmVec) {
|
|
1801
2068
|
const sc = await semanticCacheGet(env, gen, warmVec, salt);
|
|
@@ -1871,7 +2138,7 @@ ${summary}` }] : [],
|
|
|
1871
2138
|
if (!member || !sessionRaw) delegation = { status: "unsigned" };
|
|
1872
2139
|
else if (!liveCfg) delegation = { status: "not_configured" };
|
|
1873
2140
|
else {
|
|
1874
|
-
const exchanged = await
|
|
2141
|
+
const exchanged = await liveTokenFor(env, sessionRaw, member);
|
|
1875
2142
|
delegation = exchanged.ok ? { status: "ok", token: exchanged.token } : { status: exchanged.reason };
|
|
1876
2143
|
}
|
|
1877
2144
|
const verdict = await prepareDraft(env, {
|
|
@@ -1900,6 +2167,33 @@ ${summary}` }] : [],
|
|
|
1900
2167
|
}
|
|
1901
2168
|
return json({ answer: verdict.answer, citations: citations2, model, query_hash: queryHash2, follow_ups: [], context_applied: draftCtxApplied, read: readAs(), ...draftPayload ? { draft: draftPayload } : {}, quota });
|
|
1902
2169
|
}
|
|
2170
|
+
if (apiCallIntent) {
|
|
2171
|
+
const callCtxApplied = declaredCtx ? appliedContext(declaredCtx, null) : NO_CONTEXT;
|
|
2172
|
+
const queryHash2 = await sha256Hex(q.query);
|
|
2173
|
+
const verdict = await prepareApiCall(env, {
|
|
2174
|
+
intent: apiCallIntent,
|
|
2175
|
+
query: q.query,
|
|
2176
|
+
history: keptHistory,
|
|
2177
|
+
member,
|
|
2178
|
+
declared: declaredCtx,
|
|
2179
|
+
model: roleModel(env, "acts")
|
|
2180
|
+
});
|
|
2181
|
+
console.log("api_call draft:", apiCallIntent, "\u2192", verdict.status === "draft" ? `draft (${verdict.draft.call.method} ${verdict.draft.call.path})` : `refused (${verdict.reason})`);
|
|
2182
|
+
const draftPayload = verdict.status === "draft" ? verdict.draft : void 0;
|
|
2183
|
+
telemetry(env, ctx, tier, "ask", model, true, verdict.answer.length, queryHash2, q.lang, void 0, telemetryMeta());
|
|
2184
|
+
if (wantsStream) {
|
|
2185
|
+
return sseResponse(
|
|
2186
|
+
[
|
|
2187
|
+
...readAs() ? [{ type: "read", read: readAs() }] : [],
|
|
2188
|
+
{ type: "citations", citations: [], context_applied: callCtxApplied, ...draftPayload ? { draft: draftPayload } : {}, quota },
|
|
2189
|
+
{ type: "token", v: verdict.answer },
|
|
2190
|
+
{ type: "done", model, query_hash: queryHash2, context_applied: callCtxApplied, read: readAs() }
|
|
2191
|
+
],
|
|
2192
|
+
corsHeaders(req)
|
|
2193
|
+
);
|
|
2194
|
+
}
|
|
2195
|
+
return json({ answer: verdict.answer, citations: [], model, query_hash: queryHash2, follow_ups: [], context_applied: callCtxApplied, read: readAs(), ...draftPayload ? { draft: draftPayload } : {}, quota });
|
|
2196
|
+
}
|
|
1903
2197
|
let liveRecords;
|
|
1904
2198
|
let accountNote;
|
|
1905
2199
|
const modelDocHint = named ?? docScope ?? namedDocumentIn(q.query);
|
|
@@ -7,24 +7,24 @@ import {
|
|
|
7
7
|
sessionFrom,
|
|
8
8
|
telemetry,
|
|
9
9
|
understandQuery
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-GHDRKT4K.js";
|
|
11
11
|
import {
|
|
12
12
|
corsHeaders,
|
|
13
13
|
err,
|
|
14
14
|
json,
|
|
15
15
|
readJson,
|
|
16
16
|
validateQuery
|
|
17
|
-
} from "./chunk-
|
|
17
|
+
} from "./chunk-R2V3X6SQ.js";
|
|
18
18
|
import {
|
|
19
19
|
entitlementScope,
|
|
20
20
|
standardKeysFrom
|
|
21
|
-
} from "./chunk-
|
|
21
|
+
} from "./chunk-4GJGBGJK.js";
|
|
22
22
|
import {
|
|
23
23
|
LIMITS,
|
|
24
24
|
MODELS,
|
|
25
25
|
num,
|
|
26
26
|
sha256Hex
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-V46XM2GU.js";
|
|
28
28
|
|
|
29
29
|
// workers/worker_public/src/search.ts
|
|
30
30
|
async function handleSearch(env, ctx, req, tier, key) {
|
package/dist/config.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ export declare const MODELS: {
|
|
|
4
4
|
readonly anon: "@cf/zai-org/glm-5.3-flash";
|
|
5
5
|
readonly member: "@cf/zai-org/glm-5.3-flash";
|
|
6
6
|
readonly understand: "@cf/qwen/qwen3-30b-a3b-fp8";
|
|
7
|
+
readonly acts: "@cf/qwen/qwen3-30b-a3b-fp8";
|
|
7
8
|
readonly fallback: "@cf/qwen/qwen3-30b-a3b-fp8";
|
|
8
9
|
readonly grader: "@cf/deepseek-ai/deepseek-v4-flash-0731";
|
|
9
10
|
readonly enrich: "@cf/deepseek-ai/deepseek-v4-pro-0813";
|
package/dist/context.d.ts
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
/** One act the declared entity's lifecycle machine offers at its current
|
|
2
|
+
* state, FOR THE DECLARING USER'S ROLE (the platform filters before
|
|
3
|
+
* publishing; the wire is advisory — the platform re-validates every
|
|
4
|
+
* proposed act authoritatively on the way back). */
|
|
5
|
+
export interface MachineAct {
|
|
6
|
+
/** the machine's own action id (the model's vocabulary) */
|
|
7
|
+
action: string;
|
|
8
|
+
/** the state the act lands the entity on */
|
|
9
|
+
to: string;
|
|
10
|
+
/** the declared guard (the caller-supplied computed input the
|
|
11
|
+
* transition requires), when the transition declares one */
|
|
12
|
+
guard?: string;
|
|
13
|
+
}
|
|
14
|
+
/** The affordance channel (TODO.ai-platform/08): the entity declaration's
|
|
15
|
+
* machine facet — the lifecycle machine's current state (the fact,
|
|
16
|
+
* published even when the role fires nothing) + the acts offered to the
|
|
17
|
+
* declaring user's role (EMPTY means "the user can read but not act").
|
|
18
|
+
* Only ever present on the entity kind. */
|
|
19
|
+
export interface MachineContext {
|
|
20
|
+
state: string;
|
|
21
|
+
acts: MachineAct[];
|
|
22
|
+
}
|
|
1
23
|
export interface DeclaredContext {
|
|
2
24
|
kind: "page" | "entity" | "document" | "account";
|
|
3
25
|
/** display label ("this certificate R60/2021-A-EX1-26.01") — echoed
|
|
@@ -10,6 +32,8 @@ export interface DeclaredContext {
|
|
|
10
32
|
* (urn:oiml:pub:r:60-1:2021) or the plain docidentifier */
|
|
11
33
|
doc?: string;
|
|
12
34
|
edition?: string;
|
|
35
|
+
/** the affordance channel's machine facet (entity kind only) */
|
|
36
|
+
machine?: MachineContext;
|
|
13
37
|
}
|
|
14
38
|
/** The account context's live-read echo (TODO.ai-platform/03): WHEN the
|
|
15
39
|
* live data was read, WHICH stores answered, and how many records the
|
|
@@ -44,8 +68,21 @@ export interface AppliedContext {
|
|
|
44
68
|
standard: string;
|
|
45
69
|
clause?: string;
|
|
46
70
|
};
|
|
71
|
+
/** the affordance channel's echo (TODO.ai-platform/08): the declared
|
|
72
|
+
* machine's state + how many acts it offered the declaring user's role
|
|
73
|
+
* — the panel's honest context line reads THIS, never its own copy */
|
|
74
|
+
machine?: {
|
|
75
|
+
state: string;
|
|
76
|
+
offered: number;
|
|
77
|
+
};
|
|
47
78
|
}
|
|
48
79
|
export declare const NO_CONTEXT: AppliedContext;
|
|
80
|
+
export declare function parseMachine(v: any): MachineContext | undefined;
|
|
81
|
+
/** The proposal bound (TODO.ai-platform/08): a draft act the offered set
|
|
82
|
+
* does not carry is never proposed. An absent facet is not a bound (the
|
|
83
|
+
* page publishes none); a present facet with an empty acts array bounds
|
|
84
|
+
* to NOTHING — the user can read but not act. */
|
|
85
|
+
export declare function machineOffers(machine: MachineContext | undefined, action: string): boolean;
|
|
49
86
|
/** Parse + bound the ask body's optional `context` field. Anything
|
|
50
87
|
* malformed degrades to null (no context), never to a 400 — a context
|
|
51
88
|
* the service can't parse is a context it must not apply. */
|
package/dist/drafts.d.ts
CHANGED
|
@@ -104,6 +104,11 @@ interface Extraction {
|
|
|
104
104
|
source?: string;
|
|
105
105
|
}>;
|
|
106
106
|
}
|
|
107
|
+
/** The traceability primitive, shared with the api_call act's body guard
|
|
108
|
+
* (apicalls.ts): a value traces when it appears in the user's own
|
|
109
|
+
* messages (normalized). The proposing model never gets the benefit of
|
|
110
|
+
* the doubt — the user's words are the only source. */
|
|
111
|
+
export declare function valueTracesToUser(value: unknown, userTurns: string[]): boolean;
|
|
107
112
|
export interface GuardedFields {
|
|
108
113
|
standard?: string;
|
|
109
114
|
family_designation?: string;
|
package/dist/env.d.ts
CHANGED
|
@@ -47,10 +47,12 @@ import type { VectorIndex } from "./ports/vector.ts";
|
|
|
47
47
|
import type { Kv } from "./ports/kv.ts";
|
|
48
48
|
import type { Blobs } from "./ports/blobs.ts";
|
|
49
49
|
import type { Runtime } from "./ports/runtime.ts";
|
|
50
|
+
import type { StoreQuery } from "./ports/store.ts";
|
|
50
51
|
export declare function portModelRunner(env: Env): ModelRunner;
|
|
51
52
|
export declare function portIndex(env: Env, which?: "public" | "primmel" | "composed" | "plain" | "adoc" | "mko" | "pflat" | "glossary"): VectorIndex;
|
|
52
53
|
export declare function portKv(env: Env): Kv;
|
|
53
54
|
export declare function portBlobs(env: Env): Blobs;
|
|
55
|
+
export declare function portStore(env: Env): StoreQuery;
|
|
54
56
|
/** Does the deployment bind this lane index? Presence wiring stays in
|
|
55
57
|
* the ports layer so domain stages never touch raw bindings. */
|
|
56
58
|
export declare function hasLane(env: Env, which: "glossary"): boolean;
|
package/dist/livedata.d.ts
CHANGED
|
@@ -30,6 +30,18 @@ export type LiveTokenVerdict = {
|
|
|
30
30
|
* platform-scoped JWT (identity's §9b). The exchanged token caches for
|
|
31
31
|
* its own short life; the refusal lattice is honest per leg. */
|
|
32
32
|
export declare function exchangeForLiveToken(env: any, sessionRaw: string): Promise<LiveTokenVerdict>;
|
|
33
|
+
/** The live read token for one ask (TODO.ai-platform/12 — the session
|
|
34
|
+
* bridge): when the member arrived on the delegated bearer, the Bearer
|
|
35
|
+
* IS already the OP-minted platform-scoped JWT — the platform exchanged
|
|
36
|
+
* it before forwarding, so a second exchange here would have no subject
|
|
37
|
+
* token to ride (the bubble never signed into THIS service). If the
|
|
38
|
+
* token's scope cone covers the platform read, present it directly;
|
|
39
|
+
* otherwise (a service session, or a delegation that never scoped the
|
|
40
|
+
* platform in) fall through to the RFC 8693 exchange. */
|
|
41
|
+
export declare function liveTokenFor(env: any, sessionRaw: string, member: {
|
|
42
|
+
via?: string;
|
|
43
|
+
scope?: string;
|
|
44
|
+
} | null): Promise<LiveTokenVerdict>;
|
|
33
45
|
export interface LiveRecord {
|
|
34
46
|
/** the platform store the record came from */
|
|
35
47
|
store: string;
|
|
@@ -73,4 +85,6 @@ export type LiveAccount = {
|
|
|
73
85
|
* invented record. */
|
|
74
86
|
export declare function resolveLiveAccount(env: any, sessionRaw: string | null, member: {
|
|
75
87
|
sub: string;
|
|
88
|
+
via?: string;
|
|
89
|
+
scope?: string;
|
|
76
90
|
} | null): Promise<LiveAccount>;
|
package/dist/oidc.d.ts
CHANGED
|
@@ -64,6 +64,18 @@ export interface OidcIdTokenClaims {
|
|
|
64
64
|
org?: unknown;
|
|
65
65
|
[claim: string]: unknown;
|
|
66
66
|
}
|
|
67
|
+
/** Decode + signature-verify a JWT against the issuer's JWKS (RS256 or
|
|
68
|
+
* ES256; the JWKS fetch caches an hour and force-refreshes once on a
|
|
69
|
+
* miss). Claim semantics (issuer, audience, expiry, nonce) are the
|
|
70
|
+
* CALLER's — the ID token and the delegated bearer check different
|
|
71
|
+
* claim sets over the same verified signature. */
|
|
72
|
+
export declare function verifyJwtSignature(token: string, jwksUri: string): Promise<{
|
|
73
|
+
header: {
|
|
74
|
+
alg?: string;
|
|
75
|
+
kid?: string;
|
|
76
|
+
};
|
|
77
|
+
claims: Record<string, unknown>;
|
|
78
|
+
}>;
|
|
67
79
|
export declare function validateIdToken(idToken: string, expectations: {
|
|
68
80
|
issuer: string;
|
|
69
81
|
clientId: string;
|
package/dist/prompts/system.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
You are
|
|
1
|
+
You are {{ASSISTANT_IDENTITY}}; be precise, professional and warm — a knowledgeable colleague, not a search box.{{HISTORY_CONTEXT}}
|
|
2
2
|
Conversational turns — greetings, thanks, small talk, or questions about you and this service (who you are, which model you are, what you can do, what you search, how you work) — answer naturally, briefly, in first person, without citations. Never refuse them.
|
|
3
3
|
Questions about the publisher itself ({{PUBLISHER_NAME}} — what it is, who it is, its role) are the same class: you know your own publisher a priori — {{PUBLISHER_IDENTITY}} — so answer briefly without citations and never refuse them. When context passages about the publisher do appear, prefer grounding the answer in them and cite them like any other passage.
|
|
4
4
|
When earlier turns are provided, answer the LATEST message; earlier turns are context for resolving pronouns and ellipses.
|
|
@@ -15,6 +15,7 @@ MANDATORY: when the question asks how to do something (get certified, apply, com
|
|
|
15
15
|
If the passages cover only part of the question, answer the covered part fully, then state precisely what the indexed publications do not cover — do not pad with outside knowledge.
|
|
16
16
|
Refuse ONLY when no passage relates to the question's topic. Use exactly this sentence: {{REFUSAL_SENTENCE}} Then add one short line naming what you can answer instead, so the refusal redirects rather than dead-ends.
|
|
17
17
|
{{LICENSE_POSTURE}}
|
|
18
|
+
{{SERVICE_POSTURE}}
|
|
18
19
|
{{CORPUS_NOTES}}
|
|
19
20
|
Lead with the direct answer, then supporting detail; no preamble like 'Based on the passages'. Use short paragraphs or bullets for multi-part answers. Be concise and precise. Answer in the question's language{{LANG_CLAUSE}}.
|
|
20
21
|
- HARD RULE — typed units: passages whose header shows `unit u:xxxx (table)` contain a typed table. If your answer presents that table's data, you MUST write the token `[[u:xxxx]]` where the table belongs and MUST NOT render the table as markdown or reproduce more than ONE of its rows inline. Summarize the pattern in prose ("classes A–D with lower limits from 100 to 50 000"), cite the clause normally, and let `[[u:xxxx]]` stand for the full table — the interface renders it exactly from the source. The same rule applies to `unit u:xxxx (formula|figure|term)` objects.
|
package/dist/requestScope.d.ts
CHANGED
|
@@ -32,8 +32,16 @@ export declare function entitlementScope(keys: Set<string>): Set<string> | null;
|
|
|
32
32
|
/** Validate + intersect. Returns { error } when the request explicitly
|
|
33
33
|
* disables every dataset (a user error, not a scope). The corpora a
|
|
34
34
|
* dataset searches travel WITH the declaration (profile datasets.yaml,
|
|
35
|
-
* `corpora:`) — the engine maps no publisher names.
|
|
36
|
-
|
|
35
|
+
* `corpora:`) — the engine maps no publisher names.
|
|
36
|
+
*
|
|
37
|
+
* `opts.keyWithEntitlements` (the key-tier licensed federation): an
|
|
38
|
+
* API-key caller whose request carries a VALIDATED entitlement set is
|
|
39
|
+
* admitted to the session-gated (federated) datasets — the key's
|
|
40
|
+
* entitlement set is the licensed scope the internal lane honors; the
|
|
41
|
+
* internal worker re-validates the key server-side before it answers. */
|
|
42
|
+
export declare function resolveRequestScope(body: any, member: unknown, opts?: {
|
|
43
|
+
keyWithEntitlements?: boolean;
|
|
44
|
+
}): RequestScope | {
|
|
37
45
|
error: "empty-datasets";
|
|
38
46
|
};
|
|
39
47
|
/** The answer-cache salt: request-scoped context that materially changes
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import {
|
|
2
|
+
handleSearch
|
|
3
|
+
} from "./chunk-Z7AQEW6G.js";
|
|
4
|
+
import "./chunk-GHDRKT4K.js";
|
|
5
|
+
import "./chunk-R2V3X6SQ.js";
|
|
6
|
+
import "./chunk-A3QHHUN5.js";
|
|
7
|
+
import "./chunk-4GJGBGJK.js";
|
|
8
|
+
import "./chunk-V46XM2GU.js";
|
|
9
|
+
import "./chunk-3FYJM7LH.js";
|
|
10
|
+
export {
|
|
11
|
+
handleSearch
|
|
12
|
+
};
|