@amoshydra/oktoso 0.1.3 → 0.1.4
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 +1 -0
- package/dist/apps/even-g2/assets/index-CRXCF3g3.js +35 -0
- package/dist/apps/even-g2/index.html +18 -6
- package/dist/hub.js +309 -47
- package/dist/hub.js.map +1 -1
- package/dist/web/assets/index-D2oQD3bO.js +79 -0
- package/dist/web/assets/index-D2oQD3bO.js.map +1 -0
- package/dist/web/index.html +1 -1
- package/package.json +3 -2
- package/dist/apps/even-g2/assets/index-BKW-Hu3E.js +0 -33
- package/dist/web/assets/index-CTPOuR7U.js +0 -79
- package/dist/web/assets/index-CTPOuR7U.js.map +0 -1
package/dist/hub.js
CHANGED
|
@@ -21289,7 +21289,8 @@ var zSendAnswer = external_exports.object({
|
|
|
21289
21289
|
});
|
|
21290
21290
|
var zSendInput = external_exports.object({
|
|
21291
21291
|
text: external_exports.string().min(1),
|
|
21292
|
-
answer: zSendAnswer.optional()
|
|
21292
|
+
answer: zSendAnswer.optional(),
|
|
21293
|
+
answers: external_exports.array(zSendAnswer).min(1).max(20).optional()
|
|
21293
21294
|
});
|
|
21294
21295
|
var zSendResult = external_exports.object({
|
|
21295
21296
|
accepted: external_exports.boolean(),
|
|
@@ -21342,6 +21343,20 @@ var zQuestionPrompt = external_exports.object({
|
|
|
21342
21343
|
var zQuestionResponse = external_exports.object({
|
|
21343
21344
|
data: zQuestionPrompt.nullable()
|
|
21344
21345
|
});
|
|
21346
|
+
var zPendingQuestionSummary = external_exports.object({
|
|
21347
|
+
sessionRef: external_exports.string(),
|
|
21348
|
+
messageId: external_exports.string(),
|
|
21349
|
+
revision: external_exports.string(),
|
|
21350
|
+
askedAt: external_exports.number().int(),
|
|
21351
|
+
questionCount: external_exports.number().int().min(1),
|
|
21352
|
+
text: external_exports.string(),
|
|
21353
|
+
context: external_exports.string().optional(),
|
|
21354
|
+
attentionID: external_exports.string().optional()
|
|
21355
|
+
});
|
|
21356
|
+
var zQuestionSummaryPage = external_exports.object({
|
|
21357
|
+
data: external_exports.array(zPendingQuestionSummary),
|
|
21358
|
+
failed: external_exports.array(external_exports.string()).optional()
|
|
21359
|
+
});
|
|
21345
21360
|
|
|
21346
21361
|
// packages/contracts/src/events.ts
|
|
21347
21362
|
var zHubEventType = external_exports.enum([
|
|
@@ -26769,7 +26784,10 @@ function splitSentences(value) {
|
|
|
26769
26784
|
return (normalized.match(/[^.!?]+[.!?]+|[^.!?]+$/g) ?? []).map((sentence) => sentence.trim()).filter(Boolean);
|
|
26770
26785
|
}
|
|
26771
26786
|
function cleanQuestion(value) {
|
|
26772
|
-
return value.trim().replace(/^[“"'‘]+/, "").replace(/[”"'’]+$/, "").replace(/\s+/g, " ").trim();
|
|
26787
|
+
return value.trim().replace(/^[“"'‘]+/, "").replace(/[”"'’]+$/, "").replace(/^(?:\d+[.)]|[A-Za-z][.)]|[-*•])\s+/, "").replace(/\s+/g, " ").trim();
|
|
26788
|
+
}
|
|
26789
|
+
function questionCore(value) {
|
|
26790
|
+
return value.replace(/^(?:and|also|then|so)\s+/i, "").trim();
|
|
26773
26791
|
}
|
|
26774
26792
|
function truncate2(value, max) {
|
|
26775
26793
|
const clean = value.replace(/\s+/g, " ").trim();
|
|
@@ -26814,7 +26832,8 @@ function listGroups(lines) {
|
|
|
26814
26832
|
for (let index = 0; index < lines.length; index += 1) {
|
|
26815
26833
|
const line = lines[index] ?? "";
|
|
26816
26834
|
const item = parseListLine(line);
|
|
26817
|
-
|
|
26835
|
+
const questionItem = item ? /\?\s*$/.test(item) && !COURTESY.test(item) : false;
|
|
26836
|
+
if (item && !questionItem) {
|
|
26818
26837
|
if (!current) {
|
|
26819
26838
|
current = { start: index, end: index, items: [] };
|
|
26820
26839
|
}
|
|
@@ -26910,15 +26929,15 @@ function makeChoice(messageID, questionIndex, index, text, options) {
|
|
|
26910
26929
|
...risk.sensitive ? { sensitive: true } : {}
|
|
26911
26930
|
};
|
|
26912
26931
|
}
|
|
26913
|
-
function buildQuestion(message, questionText, context,
|
|
26914
|
-
const items = listItemsNearQuestion(lines, questionText);
|
|
26932
|
+
function buildQuestion(message, questionText, context, items, rawText, questionIndex) {
|
|
26915
26933
|
let choices = [];
|
|
26916
26934
|
let kind = "freeform";
|
|
26917
26935
|
let source = "heuristic";
|
|
26918
26936
|
let confidence = "high";
|
|
26937
|
+
const core = questionCore(questionText);
|
|
26919
26938
|
if (items) {
|
|
26920
26939
|
choices = items.map(
|
|
26921
|
-
(item, index) => makeChoice(message.id,
|
|
26940
|
+
(item, index) => makeChoice(message.id, questionIndex, index, item, {
|
|
26922
26941
|
kind: "choice",
|
|
26923
26942
|
source: "explicit"
|
|
26924
26943
|
})
|
|
@@ -26927,10 +26946,10 @@ function buildQuestion(message, questionText, context, lines, rawText) {
|
|
|
26927
26946
|
source = "explicit";
|
|
26928
26947
|
confidence = "high";
|
|
26929
26948
|
} else {
|
|
26930
|
-
const alternatives = inlineAlternatives(
|
|
26949
|
+
const alternatives = inlineAlternatives(core) ?? (/\b(which|what|choose|prefer|option)\b/i.test(core) ? contextAlternatives(context) : void 0);
|
|
26931
26950
|
if (alternatives) {
|
|
26932
26951
|
choices = alternatives.map(
|
|
26933
|
-
(item, index) => makeChoice(message.id,
|
|
26952
|
+
(item, index) => makeChoice(message.id, questionIndex, index, item, {
|
|
26934
26953
|
kind: "choice",
|
|
26935
26954
|
source: "heuristic"
|
|
26936
26955
|
})
|
|
@@ -26938,15 +26957,15 @@ function buildQuestion(message, questionText, context, lines, rawText) {
|
|
|
26938
26957
|
kind = "choice";
|
|
26939
26958
|
source = "heuristic";
|
|
26940
26959
|
confidence = "medium";
|
|
26941
|
-
} else if (AUXILIARY.test(
|
|
26960
|
+
} else if (AUXILIARY.test(core) && !INFORMATION_REQUEST.test(core)) {
|
|
26942
26961
|
const confirm = isDestructive(questionText) || isDestructive(rawText);
|
|
26943
26962
|
choices = [
|
|
26944
|
-
makeChoice(message.id,
|
|
26963
|
+
makeChoice(message.id, questionIndex, 0, "Yes", {
|
|
26945
26964
|
kind: "boolean",
|
|
26946
26965
|
source: "heuristic",
|
|
26947
26966
|
confirm
|
|
26948
26967
|
}),
|
|
26949
|
-
makeChoice(message.id,
|
|
26968
|
+
makeChoice(message.id, questionIndex, 1, "No", {
|
|
26950
26969
|
kind: "boolean",
|
|
26951
26970
|
source: "heuristic"
|
|
26952
26971
|
})
|
|
@@ -26958,7 +26977,7 @@ function buildQuestion(message, questionText, context, lines, rawText) {
|
|
|
26958
26977
|
}
|
|
26959
26978
|
const risk = riskFor(questionText, choices, rawText);
|
|
26960
26979
|
return {
|
|
26961
|
-
id: `${message.id}:
|
|
26980
|
+
id: `${message.id}:q${questionIndex}`,
|
|
26962
26981
|
text: questionText,
|
|
26963
26982
|
...context ? { context } : {},
|
|
26964
26983
|
kind,
|
|
@@ -26983,6 +27002,70 @@ function choiceCueLine(lines) {
|
|
|
26983
27002
|
}
|
|
26984
27003
|
return void 0;
|
|
26985
27004
|
}
|
|
27005
|
+
function isQuotedQuestion(sentence) {
|
|
27006
|
+
return /(?:asked|said|wrote|quoted)\s*[:,]?\s*[“"]/i.test(sentence);
|
|
27007
|
+
}
|
|
27008
|
+
function questionEntries(lines) {
|
|
27009
|
+
const entries = [];
|
|
27010
|
+
const seen = /* @__PURE__ */ new Set();
|
|
27011
|
+
const add = (text, line) => {
|
|
27012
|
+
if (!text || seen.has(text)) return;
|
|
27013
|
+
seen.add(text);
|
|
27014
|
+
entries.push({ text, line });
|
|
27015
|
+
};
|
|
27016
|
+
for (const [index, line] of lines.entries()) {
|
|
27017
|
+
const item = parseListLine(line);
|
|
27018
|
+
if (!item) continue;
|
|
27019
|
+
if (!/\?\s*$/.test(item) || COURTESY.test(item)) continue;
|
|
27020
|
+
if (isQuotedQuestion(line)) continue;
|
|
27021
|
+
add(cleanQuestion(item), index);
|
|
27022
|
+
}
|
|
27023
|
+
const prose = lines.filter(
|
|
27024
|
+
(line) => !parseListLine(line) && !/^\s*[-*]\s+\[[ xX]\]/.test(line)
|
|
27025
|
+
).join(" ");
|
|
27026
|
+
for (const sentence of splitSentences(prose)) {
|
|
27027
|
+
const trimmed = sentence.trim();
|
|
27028
|
+
if (!/\?\s*$/.test(trimmed) || COURTESY.test(trimmed)) continue;
|
|
27029
|
+
if (isQuotedQuestion(trimmed)) continue;
|
|
27030
|
+
const text = cleanQuestion(trimmed);
|
|
27031
|
+
if (!text) continue;
|
|
27032
|
+
const prefix = text.slice(0, Math.min(24, text.length)).toLowerCase();
|
|
27033
|
+
const line = lines.findIndex(
|
|
27034
|
+
(value) => value.toLowerCase().includes(prefix)
|
|
27035
|
+
);
|
|
27036
|
+
add(text, line >= 0 ? line : 0);
|
|
27037
|
+
}
|
|
27038
|
+
return entries.sort((left, right) => left.line - right.line);
|
|
27039
|
+
}
|
|
27040
|
+
function multipleChoiceItems(lines, entry, nextLine, previousLine, groups, used) {
|
|
27041
|
+
const after = groups.find(
|
|
27042
|
+
(group2) => !used.has(group2.start) && group2.start > entry.line && group2.start <= entry.line + 3 && group2.end < nextLine
|
|
27043
|
+
);
|
|
27044
|
+
const before = groups.find(
|
|
27045
|
+
(group2) => !used.has(group2.start) && group2.end < entry.line && entry.line - group2.end <= 3 && group2.start > previousLine
|
|
27046
|
+
);
|
|
27047
|
+
const group = after ?? before;
|
|
27048
|
+
if (!group) return void 0;
|
|
27049
|
+
if (group.items.length < 2 || group.items.length > 6) return void 0;
|
|
27050
|
+
if (group.items.some((item) => item.length < 2 || item.length > 80)) {
|
|
27051
|
+
return void 0;
|
|
27052
|
+
}
|
|
27053
|
+
if (group.items.some(
|
|
27054
|
+
(item) => /\?\s*$/.test(item) && !COURTESY.test(item)
|
|
27055
|
+
)) {
|
|
27056
|
+
return void 0;
|
|
27057
|
+
}
|
|
27058
|
+
const core = questionCore(entry.text);
|
|
27059
|
+
const cue = /\b(which|choose|pick|prefer|option|one of)\b/i.test(core) || /:\s*$/.test(entry.text);
|
|
27060
|
+
if (!cue && AUXILIARY.test(core)) {
|
|
27061
|
+
if (group.items.some((item) => IMPERATIVE.test(item))) return void 0;
|
|
27062
|
+
if (group.items.some((item) => item.split(/\s+/).length > 8)) {
|
|
27063
|
+
return void 0;
|
|
27064
|
+
}
|
|
27065
|
+
}
|
|
27066
|
+
used.add(group.start);
|
|
27067
|
+
return group.items;
|
|
27068
|
+
}
|
|
26986
27069
|
function parseQuestion(messages, options) {
|
|
26987
27070
|
const latest = messages[0];
|
|
26988
27071
|
if (!latest || latest.role !== "assistant" || latest.streaming === true) {
|
|
@@ -26999,68 +27082,116 @@ function parseQuestion(messages, options) {
|
|
|
26999
27082
|
const paragraph = paragraphs[paragraphIndex];
|
|
27000
27083
|
if (!paragraph) return null;
|
|
27001
27084
|
const localLines = stripNonProseLines(stripFencedCode(raw2)).split("\n");
|
|
27002
|
-
const
|
|
27085
|
+
const paragraphLines = paragraph.split("\n");
|
|
27086
|
+
const entries = questionEntries(paragraphLines);
|
|
27087
|
+
const proseParagraph = paragraphLines.filter(
|
|
27003
27088
|
(line) => !parseListLine(line) && !/^\s*[-*]\s+\[[ xX]\]/.test(line)
|
|
27004
27089
|
).join("\n").trim();
|
|
27005
27090
|
const sentences = splitSentences(proseParagraph || paragraph);
|
|
27006
|
-
|
|
27007
|
-
|
|
27008
|
-
|
|
27009
|
-
|
|
27010
|
-
|
|
27011
|
-
|
|
27012
|
-
|
|
27013
|
-
|
|
27014
|
-
|
|
27015
|
-
|
|
27016
|
-
|
|
27017
|
-
|
|
27018
|
-
|
|
27019
|
-
|
|
27020
|
-
|
|
27091
|
+
let questions;
|
|
27092
|
+
if (entries.length > 1) {
|
|
27093
|
+
if (entries.length > 20) return null;
|
|
27094
|
+
const groups = listGroups(paragraphLines);
|
|
27095
|
+
const used = /* @__PURE__ */ new Set();
|
|
27096
|
+
questions = [];
|
|
27097
|
+
for (const [index, entry] of entries.entries()) {
|
|
27098
|
+
const nextLine = entries[index + 1]?.line ?? paragraphLines.length;
|
|
27099
|
+
const previousLine = entries[index - 1]?.line ?? -1;
|
|
27100
|
+
const items = multipleChoiceItems(
|
|
27101
|
+
paragraphLines,
|
|
27102
|
+
entry,
|
|
27103
|
+
nextLine,
|
|
27104
|
+
previousLine,
|
|
27105
|
+
groups,
|
|
27106
|
+
used
|
|
27107
|
+
);
|
|
27108
|
+
const pending = buildQuestion(
|
|
27109
|
+
latest,
|
|
27110
|
+
entry.text,
|
|
27111
|
+
void 0,
|
|
27112
|
+
items,
|
|
27113
|
+
raw2,
|
|
27114
|
+
index
|
|
27115
|
+
);
|
|
27116
|
+
if (!pending) return null;
|
|
27117
|
+
questions.push(pending);
|
|
27021
27118
|
}
|
|
27022
|
-
|
|
27119
|
+
} else if (entries.length === 1) {
|
|
27120
|
+
const entry = entries[0];
|
|
27121
|
+
const questionIndex = sentences.findIndex(
|
|
27122
|
+
(sentence) => cleanQuestion(sentence) === entry.text
|
|
27123
|
+
);
|
|
27124
|
+
const trailing = questionIndex >= 0 ? sentences.slice(questionIndex + 1).filter(
|
|
27023
27125
|
(sentence) => !/^(let me know|thanks|thank you|cheers|please let me know)\b/i.test(
|
|
27024
27126
|
sentence
|
|
27025
27127
|
)
|
|
27026
|
-
);
|
|
27128
|
+
) : [];
|
|
27027
27129
|
if (trailing.length > 2) return null;
|
|
27028
|
-
const previous = sentences[questionIndex - 1]?.trim();
|
|
27029
|
-
context = previous && previous.length <= 120 && !COURTESY.test(previous) ? previous : void 0;
|
|
27130
|
+
const previous = questionIndex > 0 ? sentences[questionIndex - 1]?.trim() : void 0;
|
|
27131
|
+
const context = previous && previous.length <= 120 && !COURTESY.test(previous) ? previous : void 0;
|
|
27132
|
+
const pending = buildQuestion(
|
|
27133
|
+
latest,
|
|
27134
|
+
entry.text,
|
|
27135
|
+
context,
|
|
27136
|
+
listItemsNearQuestion(localLines, entry.text),
|
|
27137
|
+
raw2,
|
|
27138
|
+
0
|
|
27139
|
+
);
|
|
27140
|
+
if (!pending) return null;
|
|
27141
|
+
questions = [pending];
|
|
27030
27142
|
} else {
|
|
27031
|
-
question = choiceCueLine(localLines) ?? "";
|
|
27143
|
+
const question = choiceCueLine(localLines) ?? "";
|
|
27032
27144
|
if (!question) return null;
|
|
27145
|
+
const pending = buildQuestion(
|
|
27146
|
+
latest,
|
|
27147
|
+
question,
|
|
27148
|
+
void 0,
|
|
27149
|
+
listItemsNearQuestion(localLines, question),
|
|
27150
|
+
raw2,
|
|
27151
|
+
0
|
|
27152
|
+
);
|
|
27153
|
+
if (!pending) return null;
|
|
27154
|
+
questions = [pending];
|
|
27033
27155
|
}
|
|
27034
|
-
const pending = buildQuestion(
|
|
27035
|
-
latest,
|
|
27036
|
-
question,
|
|
27037
|
-
context,
|
|
27038
|
-
localLines,
|
|
27039
|
-
raw2
|
|
27040
|
-
);
|
|
27041
|
-
if (!pending) return null;
|
|
27042
27156
|
const hash2 = createHash("sha256").update(raw2).digest("hex").slice(0, 8);
|
|
27043
27157
|
return {
|
|
27044
27158
|
sessionRef: options.sessionRef,
|
|
27045
27159
|
messageId: latest.id,
|
|
27046
27160
|
revision: `${latest.id}:${hash2}`,
|
|
27047
27161
|
askedAt: latest.createdAt,
|
|
27048
|
-
questions
|
|
27162
|
+
questions,
|
|
27049
27163
|
...options.attentionID ? { attentionID: options.attentionID } : {},
|
|
27050
27164
|
generatedAt: options.now ?? Date.now()
|
|
27051
27165
|
};
|
|
27052
27166
|
}
|
|
27053
27167
|
|
|
27054
27168
|
// packages/hub/src/services/question-service.ts
|
|
27169
|
+
var MAX_SUMMARY_REFS = 10;
|
|
27170
|
+
function summarize(prompt) {
|
|
27171
|
+
const first = prompt.questions[0];
|
|
27172
|
+
return {
|
|
27173
|
+
sessionRef: prompt.sessionRef,
|
|
27174
|
+
messageId: prompt.messageId,
|
|
27175
|
+
revision: prompt.revision,
|
|
27176
|
+
askedAt: prompt.askedAt,
|
|
27177
|
+
questionCount: prompt.questions.length,
|
|
27178
|
+
text: first.text,
|
|
27179
|
+
...first.context ? { context: first.context } : {},
|
|
27180
|
+
...prompt.attentionID ? { attentionID: prompt.attentionID } : {}
|
|
27181
|
+
};
|
|
27182
|
+
}
|
|
27055
27183
|
var QuestionService = class {
|
|
27056
27184
|
constructor(sessions, options = {}) {
|
|
27057
27185
|
this.sessions = sessions;
|
|
27058
27186
|
this.ttlMs = options.ttlMs ?? 3e4;
|
|
27187
|
+
this.summaryTtlMs = options.summaryTtlMs ?? 15e3;
|
|
27059
27188
|
this.now = options.now ?? Date.now;
|
|
27060
27189
|
}
|
|
27061
27190
|
sessions;
|
|
27062
27191
|
cache = /* @__PURE__ */ new Map();
|
|
27192
|
+
summaryCache = /* @__PURE__ */ new Map();
|
|
27063
27193
|
ttlMs;
|
|
27194
|
+
summaryTtlMs;
|
|
27064
27195
|
now;
|
|
27065
27196
|
async get(ref) {
|
|
27066
27197
|
const page = await this.sessions.messages(ref, {
|
|
@@ -27068,13 +27199,22 @@ var QuestionService = class {
|
|
|
27068
27199
|
order: "desc"
|
|
27069
27200
|
});
|
|
27070
27201
|
const latest = page.data[0];
|
|
27071
|
-
if (!latest)
|
|
27072
|
-
|
|
27202
|
+
if (!latest) {
|
|
27203
|
+
this.rememberSummary(ref, null);
|
|
27204
|
+
return null;
|
|
27205
|
+
}
|
|
27206
|
+
if (latest.streaming === true) {
|
|
27207
|
+
this.rememberSummary(ref, null);
|
|
27208
|
+
return null;
|
|
27209
|
+
}
|
|
27073
27210
|
const text = latest.parts.filter((part) => part.type === "text").map((part) => part.text).join("\n");
|
|
27074
27211
|
const hash2 = createHash2("sha256").update(text).digest("hex").slice(0, 8);
|
|
27075
27212
|
const key = `${ref}:${latest.id}:${hash2}`;
|
|
27076
27213
|
const cached2 = this.cache.get(key);
|
|
27077
|
-
if (cached2 && cached2.expiresAt > this.now())
|
|
27214
|
+
if (cached2 && cached2.expiresAt > this.now()) {
|
|
27215
|
+
this.rememberSummary(ref, cached2.value);
|
|
27216
|
+
return cached2.value;
|
|
27217
|
+
}
|
|
27078
27218
|
const value = parseQuestion(page.data, {
|
|
27079
27219
|
sessionRef: ref,
|
|
27080
27220
|
now: this.now()
|
|
@@ -27087,10 +27227,58 @@ var QuestionService = class {
|
|
|
27087
27227
|
const oldest = this.cache.keys().next().value;
|
|
27088
27228
|
if (oldest) this.cache.delete(oldest);
|
|
27089
27229
|
}
|
|
27230
|
+
this.rememberSummary(ref, value);
|
|
27090
27231
|
return value;
|
|
27091
27232
|
}
|
|
27233
|
+
/**
|
|
27234
|
+
* Cheap discovery for the glass home and inbox. Results are cached briefly
|
|
27235
|
+
* and provider failures are reported separately so callers do not treat an
|
|
27236
|
+
* outage as a resolved question.
|
|
27237
|
+
*/
|
|
27238
|
+
async summaries(refs) {
|
|
27239
|
+
const unique = [...new Set(refs.map((ref) => ref.trim()).filter(Boolean))];
|
|
27240
|
+
const limited = unique.slice(0, MAX_SUMMARY_REFS);
|
|
27241
|
+
const failed = [];
|
|
27242
|
+
const results = await Promise.all(
|
|
27243
|
+
limited.map(async (ref) => {
|
|
27244
|
+
const cached2 = this.summaryCache.get(ref);
|
|
27245
|
+
if (cached2 && cached2.expiresAt > this.now()) return cached2.value;
|
|
27246
|
+
try {
|
|
27247
|
+
const prompt = await this.get(ref);
|
|
27248
|
+
return prompt ? summarize(prompt) : null;
|
|
27249
|
+
} catch {
|
|
27250
|
+
failed.push(ref);
|
|
27251
|
+
return null;
|
|
27252
|
+
}
|
|
27253
|
+
})
|
|
27254
|
+
);
|
|
27255
|
+
return {
|
|
27256
|
+
data: results.filter(
|
|
27257
|
+
(item) => item !== null
|
|
27258
|
+
),
|
|
27259
|
+
failed
|
|
27260
|
+
};
|
|
27261
|
+
}
|
|
27092
27262
|
clear() {
|
|
27093
27263
|
this.cache.clear();
|
|
27264
|
+
this.summaryCache.clear();
|
|
27265
|
+
}
|
|
27266
|
+
invalidate(ref) {
|
|
27267
|
+
if (ref) {
|
|
27268
|
+
this.summaryCache.delete(ref);
|
|
27269
|
+
return;
|
|
27270
|
+
}
|
|
27271
|
+
this.summaryCache.clear();
|
|
27272
|
+
}
|
|
27273
|
+
rememberSummary(ref, prompt) {
|
|
27274
|
+
this.summaryCache.set(ref, {
|
|
27275
|
+
value: prompt ? summarize(prompt) : null,
|
|
27276
|
+
expiresAt: this.now() + this.summaryTtlMs
|
|
27277
|
+
});
|
|
27278
|
+
if (this.summaryCache.size > 100) {
|
|
27279
|
+
const oldest = this.summaryCache.keys().next().value;
|
|
27280
|
+
if (oldest) this.summaryCache.delete(oldest);
|
|
27281
|
+
}
|
|
27094
27282
|
}
|
|
27095
27283
|
};
|
|
27096
27284
|
|
|
@@ -29256,7 +29444,7 @@ var IdempotencyService = class {
|
|
|
29256
29444
|
};
|
|
29257
29445
|
|
|
29258
29446
|
// package.json
|
|
29259
|
-
var version2 = "0.1.
|
|
29447
|
+
var version2 = "0.1.4";
|
|
29260
29448
|
|
|
29261
29449
|
// packages/hub/src/version.ts
|
|
29262
29450
|
var VERSION = version2;
|
|
@@ -29843,7 +30031,49 @@ function registerSessionRoutes(app, sessions, replies, questions, idempotency) {
|
|
|
29843
30031
|
}
|
|
29844
30032
|
}
|
|
29845
30033
|
const answer = parsed.data.answer;
|
|
29846
|
-
|
|
30034
|
+
const answers = parsed.data.answers;
|
|
30035
|
+
if (answer && answers) {
|
|
30036
|
+
throw badRequest("Use either answer or answers, not both");
|
|
30037
|
+
}
|
|
30038
|
+
if (answers) {
|
|
30039
|
+
const prompt = await questions.get(ref);
|
|
30040
|
+
if (!prompt) {
|
|
30041
|
+
throw conflict("This question is no longer pending", {
|
|
30042
|
+
reason: "question_resolved"
|
|
30043
|
+
});
|
|
30044
|
+
}
|
|
30045
|
+
if (answers.some(
|
|
30046
|
+
(item) => item.messageId !== prompt.messageId || item.revision !== prompt.revision
|
|
30047
|
+
)) {
|
|
30048
|
+
throw conflict("Question changed", {
|
|
30049
|
+
reason: "question_changed",
|
|
30050
|
+
current: prompt
|
|
30051
|
+
});
|
|
30052
|
+
}
|
|
30053
|
+
const known = new Set(prompt.questions.map((question) => question.id));
|
|
30054
|
+
const seen = /* @__PURE__ */ new Set();
|
|
30055
|
+
for (const item of answers) {
|
|
30056
|
+
if (!known.has(item.questionId)) {
|
|
30057
|
+
throw conflict("Question changed", {
|
|
30058
|
+
reason: "question_changed",
|
|
30059
|
+
current: prompt
|
|
30060
|
+
});
|
|
30061
|
+
}
|
|
30062
|
+
if (seen.has(item.questionId)) {
|
|
30063
|
+
throw badRequest("Duplicate question in answer batch");
|
|
30064
|
+
}
|
|
30065
|
+
seen.add(item.questionId);
|
|
30066
|
+
}
|
|
30067
|
+
const missing = prompt.questions.filter(
|
|
30068
|
+
(question) => !seen.has(question.id)
|
|
30069
|
+
);
|
|
30070
|
+
if (missing.length > 0) {
|
|
30071
|
+
throw conflict("Answer every question in this batch", {
|
|
30072
|
+
reason: "question_incomplete",
|
|
30073
|
+
current: prompt
|
|
30074
|
+
});
|
|
30075
|
+
}
|
|
30076
|
+
} else if (answer) {
|
|
29847
30077
|
const prompt = await questions.get(ref);
|
|
29848
30078
|
if (!prompt) {
|
|
29849
30079
|
throw conflict("This question is no longer pending", {
|
|
@@ -29861,6 +30091,7 @@ function registerSessionRoutes(app, sessions, replies, questions, idempotency) {
|
|
|
29861
30091
|
}
|
|
29862
30092
|
}
|
|
29863
30093
|
const result = await sessions.sendMessage(ref, { text: parsed.data.text });
|
|
30094
|
+
questions.invalidate(ref);
|
|
29864
30095
|
if (cacheKey2) await idempotency.set(cacheKey2, result);
|
|
29865
30096
|
return c.json(result, 202);
|
|
29866
30097
|
});
|
|
@@ -29880,7 +30111,38 @@ function registerSessionRoutes(app, sessions, replies, questions, idempotency) {
|
|
|
29880
30111
|
}
|
|
29881
30112
|
|
|
29882
30113
|
// packages/hub/src/http/routes/questions.ts
|
|
30114
|
+
var MAX_SUMMARY_REFS2 = 10;
|
|
30115
|
+
function summaryRefs(values) {
|
|
30116
|
+
const refs = (values ?? []).flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
|
|
30117
|
+
return [...new Set(refs)];
|
|
30118
|
+
}
|
|
29883
30119
|
function registerQuestionRoutes(app, questions, attention) {
|
|
30120
|
+
app.get("/api/v1/questions", async (c) => {
|
|
30121
|
+
const refs = summaryRefs(c.req.queries("ref"));
|
|
30122
|
+
if (refs.length === 0) {
|
|
30123
|
+
throw badRequest("At least one session ref is required");
|
|
30124
|
+
}
|
|
30125
|
+
if (refs.length > MAX_SUMMARY_REFS2) {
|
|
30126
|
+
throw badRequest(`At most ${MAX_SUMMARY_REFS2} session refs are allowed`);
|
|
30127
|
+
}
|
|
30128
|
+
if (refs.some((ref) => ref.length > 256)) {
|
|
30129
|
+
throw badRequest("Session ref is too long");
|
|
30130
|
+
}
|
|
30131
|
+
const [summaryResult, attentionPage] = await Promise.all([
|
|
30132
|
+
questions.summaries(refs),
|
|
30133
|
+
attention.list({ type: "question" })
|
|
30134
|
+
]);
|
|
30135
|
+
const attentionBySession = new Map(
|
|
30136
|
+
attentionPage.data.map((item) => [item.sessionRef, item.id])
|
|
30137
|
+
);
|
|
30138
|
+
return c.json({
|
|
30139
|
+
data: summaryResult.data.map((summary) => {
|
|
30140
|
+
const attentionID = attentionBySession.get(summary.sessionRef);
|
|
30141
|
+
return attentionID ? { ...summary, attentionID } : summary;
|
|
30142
|
+
}),
|
|
30143
|
+
failed: summaryResult.failed
|
|
30144
|
+
});
|
|
30145
|
+
});
|
|
29884
30146
|
app.get("/api/v1/sessions/:ref/question", async (c) => {
|
|
29885
30147
|
const ref = c.req.param("ref");
|
|
29886
30148
|
if (!ref) throw notFound("Session not found");
|